Boas Práticas na Criação de Containers

Hoje em dia desenvolver sem gerenciamento de container quase não existe, e o Docker é uma referencia de como criamos, distribuímos e executamos programas. A imagem Docker, funciona como um pacote compacto, independente e executável contendo todos os componentes necessários para executar um software, incluindo código, tempo de execução, ferramentas de sistema e bibliotecas.

E trabalhar de maneira eficiente para que seus aplicativos em contêineres sejam robustos, se torna crucial para custos, segurança e boas práticas. Então que tal falarmos sobre as boas práticas que podem lhe ajudar com isso.

Começamos com o Tamanho da Imagem

É essencial começar com uma imagem básica e mínima. Iniciando assim, você já começa minimizando as preocupações de segurança ao mesmo tempo ajuda a manter reduzido o tamanho da imagem. E quando falamos de imagens básicas, Alpine Linux e scratch (uma imagem base vazia) são opções comuns. Então, evite utilizar imagens de base pesadas, a menos que seja absolutamente essencial, e claro que ela precisa atender a necessidade de sua aplicação.

E isso traz vários beneficios, já que você começa com menos pacotes e bibliotecas incluídos, e com isso diminui a superfície de ataque do seu contêiner. Em segundo lugar, você tem o resultado de tamanhos de imagem reduzidos, tornando mais simples compartilhar e implantar seu contêiner.

Trabalhe com Multi-Stage Builds

Essa tem sido uma opção muito popular entre os desenvolvedores, já que permite utilizar várias imagens Docker durante o processo de construção e depois a remoção dos artefatos de construção que não são mais necessários, ajudando a reduzir o tamanho da imagem final.

A ideia por trás aqui é ter uma etapa para desenvolver e compilar seu software e outra para a imagem final. Essa separação garante que a imagem final contenha apenas as informações necessárias para a execução do seu programa. Na etapa de construção, ferramentas de construção, bibliotecas e arquivos intermediários desnecessários ficam ali.

Por exemplo, vamos pegar uma aplicação Java, você pode ter um estágio para construir o binário com a JDK e outro para o ambiente de execução levando uma JVM só com o que você precisa. Essa abordagem reduz significativamente o tamanho da imagem e garante que apenas os componentes binários compilados e de tempo de execução necessários sejam incluídos. Isso é uma grande diferencial para as aplicações Java.

Otimização do Layers

Vamos lá, caso você não saiba, as imagens Docker são construídas a partir de múltiplas camadas, e a otimização dessas camadas pode ter um impacto significativo no tamanho da imagem e na velocidade de construção. E tem várias práticas para conseguirmos fazer isso.

Se você não está fazendo isso, comece a combinar operações relacionadas em uma única instrução RUN. Cada instrução RUN cria uma nova camada na imagem. Ao agrupar comandos relacionados, você reduz o número de camadas, o que resulta em uma imagem menor.

Vamos pegar o exemplo abaixo:

RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2

Esse comando acima vai gerar 3 layers, mas se você montar ele desta maneira:

RUN apt-get update && apt-get install -y package1 package2

Com isso reduz para 1 layer e faz a mesma coisa que o primeiro, e com isso ajuda na redução do tamanho da imagem.

Use a instrução RUN para remover pacotes, código-fonte ou artefatos de construção que foram necessários durante a construção, mas não são mais necessários na imagem final. Isso não apenas reduz o tamanho da imagem, mas também minimiza possíveis riscos de segurança ao remover componentes desnecessários.

Por exemplo:

# Instala a Dependencias do Build
RUN apt-get update && apt-get install -y build-essential

# Faça o Build da Aplicação
RUN make

# Remove as Dependencias do Build
RUN apt-get purge -y build-essential

# Limpa o cache pra reduzir o tamanho da imagem
RUN apt-get clean

# Remove tudo que temporário e desnecessário
RUN rm -rf /tmp/*

Mas você deve estar falando, que eu estou ficando doido, falei para juntar os RUN e dei um exemplo com alguns separados. Mas vale lembrar de que um Dockerfile também deve ser legível e fácil de manter. Embora a redução do número de instruções RUN seja benéfica para o tamanho da imagem, isso não deve prejudicar a clareza do código.

A ordem das instruções no seu Dockerfile também pode afetar o tamanho da imagem e o tempo de construção. O Docker armazena em cache cada camada e, quando encontra uma alteração nos argumentos de uma instrução, invalida o cache desse ponto em diante.

O mecanismo de cache funciona comparando os argumentos de uma instrução com a construção anterior. Se os argumentos não mudaram, o Docker reutiliza a camada em cache, economizando tempo e recursos.

A chave é tentar maximizar os benefícios do cache, colocando as instruções que mudam com pouca frequência ou que nunca mudam perto do topo do seu Dockerfile. Por exemplo, instalações de pacotes ou downloads de código devem ser colocados no final do seu Dockerfile, pois tendem a mudar com menos frequência durante o desenvolvimento.

Se você estiver usando variáveis ​​de ambiente em seu Dockerfile, defina-as antes da instrução RUN que as utiliza. Já que o Docker armazena camadas em cache com base em argumentos de instrução, e variáveis ​​de ambiente fazem parte desses argumentos.

Outro ponto que a maioria dos desenvolvedores esquecem é o arquivo .dockerignore, mas este cara pode afetar significativamente o tamanho da sua imagem Docker. Assim como .gitignore exclui arquivos do controle de versão, .dockerignore especifica quais arquivos e diretórios devem ser excluídos da adição à imagem. Senão ele vai jogar tudo pra dentro da imagem.

Então definir o que ignorar, você pode evitar que arquivos e diretórios desnecessários sejam incluídos na imagem, reduzindo ainda mais seu tamanho. As entradas típicas em um arquivo .dockerignore podem incluir artefatos de construção, arquivos de log e arquivos temporários.

Use variáveis de Ambiente com Sabedoria

Variáveis ​​de ambiente são uma parte essencial da configuração da sua aplicação, só que elas devem ser usadas com sabedoria. Evite “chumbar” informações confidenciais, como senhas ou chaves de API, diretamente na imagem, pois isso representa riscos de segurança.

Uma abordagem comum é usar arquivos de ambiente (.env) para armazenar informações confidenciais. Esses arquivos não estão incluídos na imagem, facilitando o gerenciamento e a proteção de dados confidenciais.

Além dos arquivos de ambiente, você pode usar ferramentas e recursos de gerenciamento de segredos fornecidos pelo Docker ou plataformas de orquestração de contêineres. Docker Swarm e Kubernetes, por exemplo, oferecem mecanismos para armazenar e injetar “secrets” em contêineres.

Essas ferramentas gerenciam dados confidenciais com segurança e fornecem uma maneira de passar segredos como variáveis ​​de ambiente para seus contêineres sem expô-los no Dockerfile ou na imagem.

Use Labels para Metadata

O Docker permite adicionar metadados às suas imagens usando rótulos. Esses rótulos podem fornecer informações essenciais sobre a imagem, como versão, mantenedor ou informações de licenciamento. O uso de rótulos ajuda na organização das imagens e fornece documentação valiosa para suas imagens.

Os rótulos ajudam a identificar e categorizar suas imagens. Você pode usar rótulos para especificar a versão do aplicativo, sua finalidade ou qualquer outra informação relevante. E isso ajuda muito na documentação das imagens. Quando outra pessoa ou equipe diferente trabalha com sua imagem Docker, ela pode encontrar rapidamente informações sobre a imagem, sua finalidade e detalhes de contato do mantenedor.

Segurança

A segurança deve ser uma prioridade máxima ao construir imagens Docker. Garantir que suas imagens estejam livres de vulnerabilidades e sigam as práticas recomendadas de segurança é essencial para proteger seus aplicativos e dados. Aqui estão algumas considerações de segurança a serem lembradas:


É parte de nossas atribuições hoje em dia construir softwares que sejam eficientes e seguros, e construir imagens Docker que atinjam isso é parte deste trabalho. Você pode gerar imagens menores, mais rápidas e mais seguras seguindo as práticas recomendadas, como começar com uma imagem base mínima, empregar construções em vários estágios, otimizar camadas e abordar a segurança.

Seguir essas práticas recomendadas aprimora não apenas seus aplicativos em contêineres, mas também leva a um melhor gerenciamento de recursos e a uma menor sobrecarga operacional.

Publicado por

serlopes

Nerd, geek, músico de garagem, gamer e pai. Curte tudo que envolve esse universo maravilhoso e muita música, desde que seja de qualidade.

Deixe um comentário