Você já pensou em criar seu próprio Kubernetes em C#? Hoje eu vou mostrar como você pode dar os primeiros passos nessa direção.
Introdução
O Docker, assim como o Containerd possuem API´s. Essas API´s permitem que você lide com containers da forma que bem entender.
Você tanto pode criar containers, dropar containers, reiniciar containers e fazer o que que quiser. Os recursos estão disponíveis para todos nós.
Um ponto importante em comum é que essas API´s são gRPC. E essa é uma característica que habilita qualquer linguagem que suporte gRPC a operar e gerenciar tanto o docker quanto o containerd.
No passado eu já mostrei como usei a API do Docker para subir bancos de dados MySQL, Oracle, Postgres e SQL Server, dinamicamente, para poder lidar com testes integrados. Isso foi detalhado em Underwater – Construindo Libraries .NET Standard Profissionais.
E vale lembrar que a API gRPC dessas soluções não são API´s alternativas. gRPC é usado para a comunicação entre Kubernetes e diversos de seus componentes, assim como é usado para falar com Docker via DockerShim e com Containerd. Outro ponto legal é que o Docker fala com o containerd via gRPC também.
Sobre esse assunto, que tal olhar arquivos *.PROTO no repositório do Kubernetes.
Disclaimers
Como usar a API gRPC do Docker?
Você vai precisar instalar o pacote Docker.DotNet (Nuget, GitHub).
var dockerClientConfiguration = new DockerClientConfiguration(new Uri("npipe://./pipe/docker_engine"));
var client = dockerClientConfiguration.CreateClient();
Esse endereço “npipe://./pipe/docker_engine” só funciona se seu projeto estiver rodando no Windows e com o Docker Desktop instalado e funcionando. Já no Linux o endereço é “unix:///var/run/docker.sock” e está disponível para todos os processos que rodem sob contas que sejam do grupo Docker. Isso geralmente, mas não sempre, inclui o usuário root.
Aliás esse docker.sock dá o poder de um container controlar o host inteiro, na medida que dá total acesso à API de Containers do Docker.
Mas para nossa alegria, isso só está acessível se você expor para o container usando o -v /var/run/docker.sock:/var/run/docker.sock em um docker run.
Sobe segurança
Essa é uma questão super importante sobre segurança em containers:
Expor o docker.sock para um container dá a ele poderes ilimitados.
Dá para baixar uma imagem maliciosa de um registry inseguro, assumir o controle do host. Dá até para instalar um minerador de bitcoin ou uma infra inteira de vpn para a dark web.
O que quero dizer é que dar esse acesso é algo que pode ser feito, mas só e somente se você confia na imagem do container que está subindo. Como nesse caso é você mesmo então ok. Mas fique atento a quais containers pedem esse tipo de acesso, só entregue o docker.sock para os containers de imagens que você confia.
Voltando ao Docker Client
Como baixar uma imagem
É assim que baixamos uma imagem. Usando o Create Image e o FromImage como parâmetro.
dockerClient.Images.CreateImageAsync(new ImagesCreateParameters() { FromImage = "NomeImagem:Tag" }, null, logManager);
Como criar um container
Essa abaixo é a criação de um RabbitMQ, por exemplo.
CreateContainerResponse response = await this.dockerClient.Containers.CreateContainerAsync(new CreateContainerParameters()
{
Image = "rabbitmq:3.8-management",
Hostname = "masterclass-rabbitmq",
Env = new List<string>() {
"RABBITMQ_DEFAULT_USER=mc",
"RABBITMQ_DEFAULT_PASS=mc2",
"RABBITMQ_DEFAULT_VHOST=main"
},
HostConfig = new HostConfig()
{
PortBindings = new Dictionary<string, IList<PortBinding>>()
{
{ "5672", new List<PortBinding>(){ new PortBinding() { HostIP = "0.0.0.0", HostPort = "5672/tcp" } } },
{ "15672", new List<PortBinding>(){ new PortBinding() { HostIP = "0.0.0.0", HostPort = "15672/tcp" } } }
}
},
ExposedPorts = new Dictionary<string, EmptyStruct>() {
{ "5672", default },
{ "15672", default }
}
});
Como Iniciar um container
Criar o container não faz ele iniciar, você precisa iniciá-lo chamando um segundo método.
await this.dockerClient.Containers.StartContainerAsync(response.ID, new ContainerStartParameters() { });
Agora sim temos a chance de ver um container no ar, criado programaticamente.
Mas o que está disponível?
Tudo! Dá para criar containers, criar serviços, configurações, deployments e muito mais. Como é a interface default, ela suporta tudo do Docker!!
Não é incrível?
Pra que?
Aí você me pergunta: Qual a utilidade disso?
Você nunca ouviu alguém dizendo que ficaria muito feliz se pudesse testar a aplicação em conjunto com outras coisas? Eu já mostrei como subo Oracle, SQL Server, Postregres e MySQL para validar uma implementação de uma library. Esse é o poder. Fora isso, você tem a oportunidade de criar projetos que criam containers dinamicamente.
Seja para resolver um problema ou rodar uma rotina. Até uma rotina agendada.
O céu é o limite! Enjoy!
Mas e aí, Kubernetes em C#, afinal seria possível?
Possível sim, perfeitamente possível, no entanto a força do Kubernetes está no standard, na autonomia e na direção que o projeto e a comunidade deram para o projeto. São variáveis que extrapolam o código. Aliás, vale lembrar para quem ficou pilhado com a ideia que não basta saber operar o docker para construir o Kubernetes. É buraco é beeeeeeemmmm maior!
0 comentários