Gravar microvirtuais do Firecracker. Adotamos dois métodos populares para isolar cargas de trabalho multiusuário - máquinas virtuais e contêineres. Apertamos o melhor de ambas as abordagens, simplificamos o máximo possível, testamos em uma carga alta real. Como resultado, obtemos um isolamento impenetrável de computadores virtuais que podem ser iniciados em centenas de milissegundos. Essa solução funciona sob o capô da AWS Lambda e Fargate, executando milhões de funções e contêineres sem servidor a cada segundo na nuvem. Chama-se Firecracker.
Essa ferramenta de microvirtualização está disponível no
OpenSource . Se suas tarefas exigem isolamento de vários locatários (por exemplo, você decide criar sua própria nuvem), o Firecracker é o que você precisa.
Vasily Pantyukhin , arquiteto da Amazon Web Services, fala sobre a arquitetura Firecracker, como é usada pela AWS Lambda, a compara com soluções alternativas e fornece exemplos de integração.
Isenção de responsabilidade: tudo abaixo é da opinião pessoal de Vasily e pode não coincidir com a posição da Amazon Web Services.Características naturais de nuvens públicas
Uma das propriedades fundamentais das nuvens públicas é a multilocação.
Alguém traduz esse termo como "multilocação" ou "ambiente multiusuário". Mas, do meu ponto de vista, isso não reflete a essência. A multilocação é quando usuários diferentes e suas cargas vivem na mesma infraestrutura física, compartilham entre si, mas não sabem nada um do outro. Das cargas de trabalho para vários usuários, a multilocação é diferenciada por requisitos fundamentalmente mais rigorosos para isolamento de recursos e acesso a eles.
Outra propriedade inerente às nuvens públicas é a carga alta.
Acredite, no caso da AWS, essa é uma carga enorme! A captura de tela é um exemplo de dados reais. Não vou dizer por quanto tempo e em que região esses milhões de "papagaios" foram medidos, mas isso não é algum tipo de emergência, mas o modo operacional usual para nós.

Acontece uma certa contradição. Por um lado, precisamos manter os usuários o mais isolados possível. Por outro lado, devemos garantir um nível muito alto de produtividade e utilização de recursos. Melhorar um geralmente leva às limitações do outro. Como encontrar um compromisso e, melhor ainda, obter o máximo em todas as frentes?
Máquinas virtuais ou contêineres?
Existem duas abordagens básicas que podem potencialmente ajudar. Essas são máquinas e contêineres virtuais. Cada um tem seus prós e contras.
A principal desvantagem das máquinas virtuais é que elas levam
muito tempo para carregar . Geralmente, leva dezenas de segundos ou até minutos para iniciar a máquina. Mas os virtualoks têm uma virtude - eles
isolam cargas
concretas um do outro. E de ambos os pontos de vista:
- segurança quando uma máquina virtual não é capaz de acessar dados em outra máquina;
- recursos , quando pedi 8 GB de memória, espero que essa RAM seja minha e que ninguém possa reivindicar o recurso pelo qual paguei.
O oposto é o caso dos contêineres: eles são leves e, portanto,
carregam muito rapidamente. Eles podem ser facilmente dimensionados horizontalmente. Mas há um recurso com o qual nós, como provedor de nuvem pública, não podemos viver. Eles usam um
kernel compartilhado - o kernel do sistema operacional é compartilhado entre todos os contêineres .

Pode-se dizer que os contêineres são inseguros? Não, mesmo que haja sérias vulnerabilidades.
Acredito que hoje um contêiner "soldado" adequadamente oferece um nível de segurança suficiente.
O problema é diferente - um kernel compartilhado não garante fundamentalmente que, em algum momento no futuro, não ocorram vulnerabilidades que quebrem o isolamento dos inquilinos. A nuvem pública não pode pagar, mesmo em teoria.
Existe ainda outra contradição, e uma solução deve ser buscada. A maneira mais fácil é tirar o melhor proveito da mãe - uma máquina virtual e do pai - um contêiner, atravessar e obter algo
convergente . Na verdade, nós fizemos isso. Acabou Firecracker.
Firecracker já está em produção. Na mesma carga de serviços críticos, por exemplo, AWS Lambda (funções sem servidor) e AWS Fargate (contêineres sem servidor).
Problemas do antigo AWS Lambda
O AWS Lambda é um serviço de recursos sem servidor. Pegamos a função em Java, Go, Python ou outra linguagem, a jogamos no Lambda, e ela é executada magicamente. Não é necessário alocar e gerenciar recursos. Como isso foi implementado antes?

Para cada conta da AWS, uma ou mais máquinas virtuais EC2 separadas foram alocadas para isolar funções que pertencem a diferentes inquilinos. Essa máquina virtual consome recursos, mesmo quando não faz nada. Suponha que executemos uma função a cada 10 minutos e ela seja executada em 200 ms como um Lambda comum. Acontece que dentro de uma hora a máquina EC2 é usada apenas alguns segundos. Além disso, mesmo em tempo de execução, ele não consome todos os recursos disponíveis - descarte abaixo do rodapé. Isso é furiosamente inútil.

Como você resolveu o problema de reciclagem?
Desenvolvido a partir do zero, sua própria solução Firecracker. Isso é óbvio no título do relatório :)
Para começar a desenvolver um novo produto, você precisa de uma tarefa técnica. Tem muito texto, mas se você selecionar apenas o significado, obterá o seguinte.
- Desenvolvido pela KVM como um hypervisor. Quem trabalha com a AWS sabe que temos dois hipervisores favoritos. VMs herdadas executadas no Xen. Desde o final de 2017, a KVM vive sob o capô de todos os carros.
- Começa o mais rápido possível. No hardware de referência, o requisito era uma carga completa do microvirtual em 125 ms.
- Sobrecarga mínima de virtualização . Na arquitetura de referência, uma única máquina micro-virtual do Firecracker consome adicionalmente apenas 5 MB de memória.
- A possibilidade do começo mais denso . Parâmetros de projeto - carga total de 5 microvirtuais por núcleo por segundo. Esse requisito é fundamental para serviços como o AWS Lambda. As funções devem decolar, trabalhar e morrer rapidamente, liberando recursos para o próximo.
- A possibilidade de reinscrição . É uma oportunidade - não é necessário usá-lo. De fato, essa é a alocação de recursos virtuais em maior extensão do que eles estão fisicamente disponíveis. Isso significa que o servidor possui 16 GB de RAM e você executa simultaneamente 4 máquinas virtuais, cada uma das quais tem 8 GB de memória.
AWS Lambda com Firecracker sob o capô
O que mudou na nova versão do AWS Lambda? Do ponto de vista do usuário final, nada mudou. A migração para uma arquitetura atualizada na produção foi completamente transparente e invisível para os consumidores. Os recursos do Lambda têm vida curta - foi fácil de fazer.
Como é a arquitetura moderna?
No nível mais baixo, agora não é uma máquina virtual, mas um bare-metal físico.
Esses servidores permitem o uso completo de todas as funções da CPU, por exemplo, Intel VT. Isso fornece benefícios adicionais ao usar a virtualização em níveis mais altos.

No topo da peça de ferro, está o
sistema operacional host com o módulo KVM no kernel.
Os microvirtuais do
Firecracker com seus próprios
SOs convidados são lançados acima. Bem, eles já implementaram componentes do próprio serviço da AWS Lambda.
Anteriormente, para cada cliente que usa os recursos do Lambda, alocamos máquinas virtuais EC2 separadas com baixa utilização. A nova abordagem permite executar um microvirtual leve apenas quando você realmente precisa. Isolar os recursos do Firecracker um do outro nos permite fazer isso em um hardware comum com densidade máxima. A utilização de recursos melhorou fundamentalmente.
O que há na caixa?
Prometi o anboxing, então vamos examinar os principais componentes do Firecracker, considerar cada um deles separadamente e, em seguida, juntar tudo.

Princípios de design
Quando começamos a discutir o desenvolvimento do Firecracker, concordamos em aderir a dois princípios.
Livre-se de tudo o que é desnecessário. Por que as máquinas virtuais clássicas carregavam lentamente? Em particular, porque o código está sobrecarregado. Eles precisam suportar um grande número de dispositivos herdados. Mas por que imitar um dispositivo que ninguém mais usava 10 anos atrás? Não há necessidade, portanto, nos livramos de tudo o que é supérfluo. Resolvemos uma tarefa restrita específica e qualquer funcionalidade que não ajude na solução desse problema é considerada desnecessária.
Livre-se de tudo que é supérfluo e concentre-se em uma tarefa.
Simplifique o que resta. Mesmo o que resta deve ser o mais simples possível.
No que eles escreveram?
Firecracker está escrito em Rust na moda porque:
- permite escrever código mais seguro , em particular em termos de memória;
- O desempenho e a sobrecarga são comparáveis ao C ++ moderno;
- A ferrugem é utilizada há muito tempo; desde 2015, ele criou muitas soluções legais de carga alta.
Ferro
Repito - o Firecracker requer instalação em hardware real. Como configuração de referência, foi escolhida a máquina bare metal i3.metal.
Nota: o relatório foi no início de abril de 2019. Naquela época, apenas a plataforma Intel era suportada. Em maio, eles adicionaram suporte alfa à AMD e em junho ao ARM. A AMD pode ser um pouco mais barata que a Intel, e o suporte a ARM oferece oportunidades interessantes para trabalhar com a IoT de vários locatários.Se você solicitar um i3.metal ou outra máquina bare metal na AWS, em experimentos, será uma configuração muito poderosa e cara. Portanto, se você decidir instalar o Firecracker neles, não esqueça de pagar essas máquinas após os experimentos. Caso contrário, uma pontuação decente chegará ao final do mês.
Existe uma opção mais barata? Sim, você pode inicializar o Firecracker em um ambiente virtual. Mas não mais na AWS - basicamente não oferecemos suporte à virtualização aninhada no EC2. Mas você pode fazer isso no GCP, Azure, DigitalOcean ou usar Proxmox, Parallels, VMware Fusion. Tudo funcionará se você seguir os requisitos, em particular, de acordo com a versão do kernel do sistema operacional convidado.
O núcleo
O elemento fundamental da solução é o módulo do kernel KVM.
Apenas no caso, descreverei como uma digressão o que é KVM. Este não é o hypervisor inteiro, mas apenas parte dele. Suas principais tarefas são
configurar um processador virtual (vCPU) e
iniciar uma máquina virtual .

Mas isso não é suficiente para um trabalho completo. Além do processador, alguns outros dispositivos são necessários. Sua emulação ocorre no espaço do usuário.
VMM
Para que pelo menos os dispositivos básicos apareçam, você precisa de outro componente - Virtual Machine Manager (VMM). Antes do Firecracker, a opção principal do VMM era QEMU.

Consideramos seriamente a possibilidade de usar o QEMU, mas decidimos desenvolver nossa própria “bicicleta”. Havia várias razões para isso.
Gerenciamento de desenvolvimento . O QEMU é um produto grande e maduro, com mais de um milhão de linhas de código. Para fazer alterações, você precisa visualizar muitos códigos-fonte. Muitas pessoas participam do desenvolvimento e da tomada de decisões sobre o desenvolvimento.
Segurança O QEMU pode emular muitos dispositivos. É por isso que possui uma superfície de ataque bastante grande. Nossa tarefa é fazer um microvirtual. Do ponto de vista da segurança, devemos minimizar a superfície de ataque.
A necessidade de implementar novos recursos. QEMU tem um bom código. Este é um produto maduro no qual todos os erros óbvios já foram detectados. Mas, na sua forma atual, a funcionalidade QEMU ainda não nos convinha - teríamos que adicionar muito. Desse ponto de vista, o novo código no QEMU e no novo produto teria a mesma qualidade. Portanto, uma vitória especial não funcionaria.
Aparelhos
O Firecracker implementa o VMM, usado para emular dispositivos. Emulamos os seguintes dispositivos:
- Console Uma coisa útil e necessária, embora possa ser desligada.
- Teclado Fizemos um teclado complicado - com apenas um botão "Reset". Simplesmente não confiamos no software "Reset" dos sistemas operacionais que poderiam ser executados no Firecracker. Portanto, eles fizeram ferro.
- Drivers Virtio para disco e rede . Virtio é um dispositivo muito primitivo. Em essência, este é um "buffer de anel". O sistema convidado gravou algo no buffer, clicou na chamada e o sistema host leu os dados desse buffer através de um arquivo.
Em alguns casos, por exemplo, para integração com contêineres, ainda precisamos de um dispositivo de rede que represente a funcionalidade básica de uma placa de rede comum. Virtio não se encaixa aqui, muito simples. Portanto, para a rede, usamos outro dispositivo -
Vsock .
Bem, também precisamos da capacidade de controlar o consumo de recursos. O
limitador de taxa é responsável por isso.
Existem dispositivos. Mas como gerenciar e configurar microvirtuais? A API de gerenciamento nos ajudará aqui.
Gerência
A Amazon possui vários princípios fundamentais inquebráveis. Uma delas é que qualquer serviço se comunica apenas através da API. Não importa se esses são serviços externos que você usa como usuário ou nossos serviços internos. Não acontece que um serviço vá diretamente para o banco de dados de outro serviço - é proibido e punível. O thread da API do Firecracker é usado apenas para acessar as configurações e a funcionalidade dos microvirtuais por meio da API REST.

Aderimos à especificação Open API, para que você possa usar o Swagger.
Metadados
Existe uma codificação tão maligna. É quando alguns dados são costurados diretamente no código, por exemplo, o login e a senha de acesso a outro recurso. Isso, é claro, não é permitido. Periodicamente, precisamos transferir alguns dados para dentro do microvirtual. Isso é feito através do
serviço de metadados .

Passamos as informações necessárias pelo soquete para o comércio de metadados do IMDS. Para obter essas informações dentro do microvirtual, é necessário solicitar
http://169.254.169.254/latest/meta-data usando a API REST. Os usuários da AWS já conhecem esse IP mágico. Da mesma forma, os microvirtuais podem obter informações detalhadas sobre sua própria configuração.
Logs
É imperativo poder lançar toras de microvirtual no mundo exterior antes de ela morrer. Isso é feito através de um
FIFO Unix comum.

Isolamento adicional
A principal vantagem da máquina virtual isolada. Parece que isso deve ser suficiente, mas fomos além. Para garantir a execução da produção, é recomendável colocar uma camada adicional de isolamento chamada
Jailer .

Estas são precauções padrão:
- cgroups para limitar recursos;
- espaço para nome para isolar processos;
- seccomp - um análogo do firewall para chamadas do sistema;
- e, claro, o chroot favorito de todos .
Integração com outros serviços
Existem soluções prontas baseadas no Firecracker? Claro que sim.
OSV
Este sistema operacional foi desenvolvido para executar apenas um aplicativo. Devido a isso, ela organizou de maneira muito simples o trabalho com memória e um agendador. Um sistema operacional poderoso e fácil de gerenciar agora
funciona em cima do Firecracker .
Containerd
Também fizemos a integração com o container. Se você já trabalha com ele, precisa de um mínimo de esforço para lançar os contêineres que estão envolvidos no Firecracker para isolamento.

Em vez do calço habitual, o contêiner refere-se ao calço do foguete. Já gerencia runc, através de um agente que é instalado dentro do microvirtual.
Verificado, funciona .
Contentores Kata
Quando anunciamos o Firecracker, uma das perguntas mais populares dos clientes era:
- O mecanismo de isolamento de contêineres já foi inventado - este é o Kata Containers. Por que você não os usou? Por que desenvolver o seu próprio?- O Kata trabalha com o QEMU, mas não queremos trabalhar com o QEMU. Por isso, decidimos cozinhar nossos próprios.Mas acabou sendo interessante. Os desenvolvedores de Kata se reuniram com os desenvolvedores do Firecracker e concordaram em integrar. Porque todo mundo vê isso como uma enorme vantagem.
O Kata Containers v1.5 já suporta QEMU e Firecracker.
Acontece que não competimos, mas que se complementam harmoniosamente. No Kubernetes com v1.12, você pode definir runtimeClassName como Kata FC ou Kata QEMU e executar seus contêineres em isolamento apropriado.
Como escolher o isolamento adequado à sua aplicação - Firecracker ou QEMU? Minha opinião pessoal é que o que
importa é se o seu aplicativo é
animal de estimação ou gado ?
Kata com QEMU é uma solução para animais de estimação. QEMU é um sistema grande e multifuncional. Potencialmente, oferece mais opções de suporte e tratamento para seus animais de estimação favoritos.
Firecracker é adequado quando a carga é de gado. Caso seu aplicativo sem estado tenha sido originalmente projetado para dimensionamento horizontal flexível e a falha de um ou mais contêineres não seja crítica. Fornecendo isolamento confiável, permite carregar rapidamente o número necessário de novos contêineres para substituir os que falharam.
Qual é o resultado?
Começamos com contradições. Parece que resolver a contradição é uma abordagem “tanto nossa quanto sua”, algo que satisfará a todos. Mas a experiência diz que o compromisso não é necessário.
Estabelecemos o objetivo de desenvolver uma nova solução na qual não haverá nada supérfluo que não seja necessário para resolver uma tarefa restrita. Também era importante simplificar tudo o que usamos, tanto quanto possível. Gostaria de acreditar que não conseguimos um compromisso, mas uma solução sólida, que permite lançar rápida e densamente milhares de microvirtuais sem sacrificar o isolamento.
Já utilizamos o Firecracker na produção de vários de nossos serviços. A principal vantagem que obtivemos é a melhoria da utilização do serviço. Isso permitiu economizar significativamente. Parte dessa economia que compartilhamos com os clientes. Por exemplo, após a introdução do Firecracker, os preços dos contêineres sem servidor da AWS Fargate em janeiro de 2019 caíram de 35 a 50%. O benefício é visível a olho nu, então não há dúvida de que continuaremos desenvolvendo este produto e compartilhando nossas melhores práticas com o código-fonte aberto. O fato de o Firecracker já ter começado a se integrar a outras soluções indica um crescente interesse por parte da comunidade.
Se você tem uma idéia ou um produto acabado na descrição com as palavras "isolamento de vários locatários" - este é um indicador claro do que você deve experimentar com os microvirtuais do Firecracker.
Este relatório ilustra perfeitamente o princípio que estamos tentando aderir nas conferências da Ontiko - para receber experiência mundial de especialistas em língua russa . E o ponto não está apenas em uma possível barreira do idioma, mas na cultura que estamos acostumados a compartilhar detalhes técnicos. Em novembro, Vasily se apresentará no HighLoad ++ novamente, e ele se juntará a , por exemplo, Artemy Kolesnikov do Facebook, Vittorio Cioe da Oracle e, é claro, Petr Zaitsev da Percona. Também teremos relatórios em inglês, assinaremos a newsletter - informaremos quando novos serão adicionados aos quarenta relatórios aceitos.