Skip to main content

Criando imagens Docker no Kubernetes

Escrito por
Headshot of Vitalis Ogbonna

Vitalis Ogbonna

feature docker k8s code

3 de maio de 2022

0 minutos de leitura

Hospedar uma plataforma de CI/CD no Kubernetes está se tornando cada vez mais comum entre engenheiros. Essa abordagem economiza tempo com automação, garante implantações consistentes e facilita o monitoramento e o gerenciamento de microsserviços. No entanto, criar imagens de contêiner em clusters Kubernetes envolve alguns desafios técnicos que exigem soluções alternativas.

Neste artigo, vamos conhecer algumas maneiras de criar imagens Docker em um cluster Kubernetes para processos de CI/CD. Também vamos abordar as vantagens e desvantagens desses métodos.

Ferramentas para criar imagens Docker no Kubernetes

Se você já criou uma imagem de contêiner, provavelmente executou um comando como docker build. Depois, quando chegou a hora de automatizar esse processo, talvez você tenha configurado seus recursos de CI/CD para também usar docker build. Isso funciona em servidores de CI simples, mas talvez você queira, mais adiante, implantar uma plataforma de CI baseada em Kubernetes.

O desafio é que o daemon do Docker não fica livremente acessível no cluster Kubernetes. Por isso, precisamos usar alternativas sem comprometer a integridade da aplicação nem a infraestrutura.

Há várias ferramentas para isso:

  • O Buildah é especializado na criação de imagens da Open Container Initiative (OCI). Seus comandos reproduzem todos os comandos de um Dockerfile. A ferramenta permite criar imagens com ou sem Dockerfiles, sem exigir privilégios de root.

  • O img é uma ferramenta independente para criar imagens de contêiner compatíveis com Dockerfile e OCI, sem daemon e sem privilégios. É eficiente no uso de cache e pode executar várias etapas de build simultaneamente, pois usa internamente o solucionador de DAG do BuildKit como ferramenta de criação de imagens.

  • O kaniko cria imagens de contêiner a partir de um Dockerfile dentro de um contêiner ou cluster Kubernetes. O kaniko não depende de um daemon do Docker e executa cada comando do Dockerfile inteiramente no espaço do usuário.

  • O Docker in Docker é uma receita para executar o Docker dentro do Docker. Ele cria contêineres Docker em clusters Kubernetes montando o arquivo /var/run/docker.sock como um volume em um contêiner Docker.

  • A Enterprise Edition (Sysbox-EE) do Sysbox, da Nestybox, permite que contêineres sem root executem cargas de trabalho como Docker, systemd e Kubernetes como máquinas virtuais.

  • A BuildKit CLI cria imagens OCI e Docker de arquitetura única e múltipla em clusters Kubernetes. Ela substitui o comando docker build por kubectl build para criar imagens em clusters Kubernetes.

  • O Jib para contêineres Java cria imagens de contêiner sem usar um Dockerfile nem exigir uma instalação do Docker. Há plugins do Jib para Maven e Gradle. O Jib também está disponível como uma biblioteca Java.

  • O KO é uma ferramenta rápida e simples de criação de imagens de contêiner para aplicações Go. Ela cria imagens executando, na prática, o go build na sua máquina local, sem exigir a instalação do Docker.

Vamos nos concentrar em duas abordagens populares para criar imagens Docker em um cluster Kubernetes: Docker in Docker e kaniko.

Docker in Docker

O método Docker in Docker (DIND) é usado com frequência em pipelines de CI/CD nos quais as imagens são criadas e enviadas após um build de código bem-sucedido. Esse método também é usado para integrar o Jenkins a pipelines de implantação (por exemplo, durante testes em ambientes isolados).

A abordagem DIND pode parecer conveniente e simples. No entanto, o ex-funcionário da Docker e colaborador do DIND Jérôme Petazzoni afirma que a Docker criou essa abordagem para acelerar processos internos e aponta preocupações de segurança como motivos para não usá-la em ambientes de produção.

Originalmente, a Docker criou contêineres para serem executados em modo privilegiado com a abordagem DIND. O daemon do Docker é executado como root, então o contêiner também é executado como root no host. Qualquer pessoa com acesso ao socket do Docker tem acesso root, o que permite executar qualquer software, criar novos usuários e acessar tudo o que está conectado ao contêiner. Isso deixa os contêineres vulneráveis a ataques que podem se espalhar por toda a arquitetura.

Além disso, como o Kubernetes removeu oficialmente o suporte ao Dockershim, montar o docker.sock no host provavelmente deixará de funcionar no futuro, a menos que adicionemos o Docker a todos os nós do Kubernetes. A AWS oferece uma ferramenta útil para detectar o uso do socket do Docker em clusters.

O método DIND também apresenta problemas de compatibilidade com drivers de armazenamento. Além disso, gerenciar caches de imagens pode ser um desafio, pois precisamos baixar as imagens Docker sempre que iniciamos um build.

Uma maneira de resolver esses problemas é usar ferramentas que não exijam um runtime de contêiner para criar imagens. Uma delas é o kaniko, solução de código aberto do Google para criar imagens Docker em um cluster Kubernetes.

kaniko

O kaniko cria imagens de contêiner a partir de um Dockerfile dentro de um contêiner ou cluster Kubernetes. Ele não depende de um daemon do Docker e executa cada comando do Dockerfile inteiramente no espaço do usuário. Isso permite criar imagens de contêiner em ambientes nos quais não é fácil nem seguro executar um daemon do Docker, como clusters Kubernetes padrão.

Vamos usar ferramentas gratuitas e disponíveis publicamente para demonstrar o fluxo de trabalho do kaniko. Para acompanhar este tutorial, você vai precisar de:

  • Docker Desktop instalado no seu computador, com o Kubernetes habilitado

  • Uma conta válida do Docker Hub para que o pod do kaniko faça a autenticação e envie a imagem Docker

  • Uma conta do GitHub para que o kaniko acesse o Dockerfile

Vamos usar este projeto de exemplo no GitHub para demonstrar como o kaniko funciona. Clone o repositório com git clone https://github.com/agavitalis/kaniko-kubernetes.git para acompanhar.

Este projeto de exemplo tem dois arquivos e um arquivo README.md:

#sample project directory

kaniko-build-demo

  • dockerfile

  • pod.yml

  • README.md

O dockerfile contém este código com os comandos para criar a imagem:

FROM ubuntu
ENTRYPOINT ["/bin/bash", "-c", "echo Hello to Kaniko from Kubernetes"]

pod.yml contains this code for the kaniko configurations:

apiVersion: v1
kind: Pod
metadata:
  name: kaniko-demo
spec:
  containers:
  - name: kaniko-demo
    image: gcr.io/kaniko-project/executor:latest
    args: ["--context=git://github.com/agavitalis/kaniko-kubernetes.git",
            "--destination=agavitalis/kaniko-build-demo:1.0.0",
            "--dockerfile=dockerfile"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: reg-credentials
        items:
          - key: .dockerconfigjson
            path: config.json

No código de configuração do kaniko, o executor de imagens do kaniko usa a versão mais recente. Também especificamos o local do Dockerfile e do repositório de imagens, além do nome das credenciais do registro de imagens no Kubernetes.

Como o kaniko funciona

O kaniko funciona de maneira simples. A imagem do executor do kaniko, gcr.io/kaniko-project/executor:latest, executa os comandos do Dockerfile para criar imagens. Ela lê o Dockerfile especificado, baixa a imagem base definida no comando FROM (neste caso, ubuntu) para o sistema de arquivos do contêiner definido e, em seguida, envia as imagens a um registro.

Depois de baixar a imagem base indicada pela diretiva FROM, o kaniko executa cada comando do Dockerfile individualmente e cria um snapshot do espaço do usuário após a execução de cada comando. Em seguida, a cada execução, adiciona a camada do snapshot à camada base.

Definimos estas configurações no arquivo pod.yml:

  • context: o local do Dockerfile. Neste caso, ele está no diretório raiz do repositório. Use as variáveis GIT_USERNAME e GIT_PASSWORD (token de API) para se autenticar em repositórios Git privados.

  • destination: substitua <dockerhub-username> pelo seu nome de usuário para que o kaniko envie a imagem ao registro do Docker Hub.

  • docker-file: o caminho do Dockerfile relativo ao contexto.

Agora que entendemos como o kaniko funciona, vamos criar um Secret do Kubernetes. Depois, vamos usá-lo para criar e implantar uma imagem.

Como criar um Secret do Kubernetes para o Docker Hub

Precisamos criar um Secret do Kubernetes para que o kaniko acesse o Docker Hub. Para isso, precisamos das seguintes informações:

  • docker-server: o servidor do registro do Docker que vai hospedar suas imagens. Se você usa o Docker Hub, o valor deve ser https://index.docker.io/v1/.

  • docker-username: seu nome de usuário do registro do Docker.

  • docker-password: sua senha do registro do Docker.

  • docker-email: o e-mail configurado no seu registro do Docker.

Execute os comandos a seguir, substituindo cada variável pelo valor correspondente:

#bash
$ kubectl create secret docker-registry reg-credentials
--docker-server=<docker-server> --docker-username=<username> --docker-password=<password> --docker-email=<email>

O comando acima monta esse Secret no pod do kaniko para facilitar a autenticação ao enviar a imagem criada para um registro do Docker. Você deverá receber uma mensagem de confirmação semelhante a esta:

Terminal exibindo um comando kubectl que cria um segredo de registro do Docker chamado reg-credentials, com os valores das credenciais ocultos.

Como implantar o pod do kaniko para criar uma imagem Docker

Agora, vamos iniciar o build criando o pod no nosso cluster Kubernetes. Implante o pod com o comando:

#bash
$ kubectl apply -f pod.yaml
Saída do terminal mostrando o comando "kubectl apply -f pod.yaml" e a confirmação de que pod/kaniko-demo foi criado

Isso inicia o processo de criação da imagem e, em seguida, envia a imagem ao registro do Docker especificado.

Você pode listar os pods disponíveis no seu cluster Kubernetes com o comando:

#bash
$ kubectl get pod
Terminal mostrando o comando kubectl get pod e um pod kaniko-demo com 0/1 pronto, status Concluído e zero reinicializações.

Isso exibe os pods disponíveis, o status e o tempo de existência de cada um. (Observe que pode ocorrer um erro se o kaniko estiver usando credenciais incorretas ou enviando a imagem para o repositório errado.)

Se quiser, use o comando kubectl delete pod <pod-name> para excluir os pods existentes.

Para ver informações detalhadas sobre o pod que você acabou de implantar, use o comando:

#bash
$ kubectl describe pod
Terminal mostrando comandos kubectl aplicando um manifesto de pod e descrevendo o pod kaniko-demo concluído.

Você também pode ver o log do build com o comando:

#bash
$ kubectl logs kaniko-demo -f
Terminal exibindo os logs de kubectl de um pod kaniko-demo concluído, incluindo a saída da criação de uma imagem Docker e o envio para o Docker Hub.

Confira a folha de consulta rápida do kubectl para ver outros comandos que você pode usar para explorar o cluster, solucionar problemas e obter mais informações.

Em seguida, acesse o Docker Hub para confirmar que tudo funcionou e que você implantou suas imagens no Docker com sucesso.

Página do repositório agavitalis/kaniko-demo no Docker Hub, com configurações do repositório, comando de push do Docker, tags e análises, além de builds automatizados

Criamos e implantamos com sucesso nossa imagem Docker a partir de um cluster Kubernetes usando o kaniko!

Snyk para segurança de contêineres

O kaniko oferece uma maneira segura de criar imagens Docker em clusters Kubernetes. Ele obtém o Dockerfile do contexto de build definido, cria a imagem e envia o resultado para um registro de imagens. Seu poderoso sistema de cache acelera a criação da imagem.

Mesmo que você não use um método inseguro para criar imagens Docker no Kubernetes, ainda pode estar exposto a vulnerabilidades de segurança do Kubernetes. O Snyk Container oferece uma solução confiável de segurança de contêineres para encontrar e corrigir vulnerabilidades em aplicações nativas da nuvem. A Snyk se integra perfeitamente ao Docker, GitHub, Kubernetes, Jenkins e outras ferramentas para manter sua aplicação e infraestrutura seguras.

Segurança de contêineres que prioriza os desenvolvedores

O Snyk encontra e corrige automaticamente vulnerabilidades em imagens de contêiner e workloads do Kubernetes.