Antes tarde do que nunca. Ou como quase cometemos um grande erro por não termos suporte a Dockerfiles padrão para construir imagens de aplicativo.

Vamos falar sobre — uma ferramenta GitOps que se integra a qualquer sistema de CI/CD e garante o gerenciamento de todo o ciclo de vida do aplicativo, permitindo que:
- criem e publiquem imagens,
- implantem aplicativos no Kubernetes,
- e removam imagens não utilizadas por meio de políticas específicas.
A filosofia do projeto é reunir ferramentas de baixo nível em um único sistema unificado, dando aos engenheiros DevOps controle sobre os aplicativos. Sempre que possível, as ferramentas existentes (como Helm e Docker) devem ser utilizadas. Se uma solução para um problema específico não existir, podemos criar e manter tudo o que for necessário.
Histórico: nosso construtor de imagens
Foi assim que surgiu o construtor de imagens no werf: não tínhamos o Dockerfile usual. Ao olhar brevemente para a história do projeto, esse problema já se manifestou nas primeiras versões do werf (então ainda ).
). Ao criar uma ferramenta para empacotar aplicativos em imagens Docker, percebemos rapidamente que o Dockerfile não era adequado para algumas tarefas bastante específicas:
- A necessidade de compilar tipos típicos de aplicativos web pequenos de acordo com o seguinte esquema padrão:
- instalar as dependências do sistema do aplicativo,
- instalar o bundle de bibliotecas das dependências do aplicativo,
- compilar os assets,
- e o mais importante — atualizar o código na imagem de forma rápida e eficiente.
- Ao fazer alterações nos arquivos do projeto, o construtor deve criar rapidamente uma nova camada aplicando um patch nos arquivos alterados.
- Se certos arquivos forem modificados, a fase correspondente dependente deve ser recompilada.
Hoje em dia, nosso construtor tem muitas outras funcionalidades, mas os desejos e anseios iniciais eram esses.
No geral, sem pensar muito, escolhemos a linguagem de programação utilizada (veja abaixo) e partimos para implementar nossa própria DSL! Atingindo os objetivos estabelecidos, ela foi projetada para descrever o processo de construção em fases e determinar as dependências dessas fases em relação aos arquivos. E complementava isso com nosso próprio construtor, que transformava a DSL no objetivo final — a imagem construída. Inicialmente, a DSL era em Ruby, mas à medida que , a configuração do nosso construtor começou a ser descrita em um arquivo YAML.

Configuração antiga para dapp em Ruby

Configuração atual para werf em YAML
O mecanismo de trabalho do construtor também mudou ao longo do tempo. No início, nós apenas gerávamos um Dockerfile temporário a partir da nossa configuração, e depois começamos a executar instruções de construção em contêineres temporários e fazer commit.
NB: Atualmente, nosso construtor, que trabalha com sua própria configuração (em YAML) e é chamado de construtor Stapel, já se desenvolveu em uma ferramenta bastante poderosa. Sua descrição detalhada merece artigos separados, e os principais detalhes podem ser encontrados em .
Compreensão do problema
Mas percebemos, embora não imediatamente, que cometemos um erro: não adicionamos a possibilidade de construir imagens através de um Dockerfile padrão e integrá-las na mesma infraestrutura de gerenciamento complexo de aplicativo (ou seja, construir imagens, implantar e limpar). Como poderíamos ter feito uma ferramenta para implantação no Kubernetes e não implementar suporte ao Dockerfile, ou seja, o método padrão para descrever imagens para a maioria dos projetos?..
Em vez de responder a tal pergunta, oferecemos sua solução. O que fazer se você já tiver um Dockerfile (ou um conjunto de Dockerfiles) e quiser usar o werf?
NB: A propósito, por que você gostaria de usar o werf? Os principais recursos são:
- ciclo completo de gerenciamento de aplicativo, incluindo limpeza de imagens;
- capacidade de gerenciar a construção de várias imagens a partir de uma única configuração;
- processo de implantação aprimorado de charts compatíveis com Helm.
Para uma lista mais completa, você pode consultar .
Então, se antes teríamos sugerido reescrever o Dockerfile na nossa configuração, agora diremos com prazer: “Deixe o werf construir seus Dockerfiles!”
Como usar?
A implementação completa dessa funcionalidade surgiu na versão . O princípio geral é simples: o usuário especifica o caminho para o Dockerfile existente na configuração do werf, após o que Executa o comando werf build… e pronto — o werf construirá a imagem. Vamos considerar um exemplo abstrato.
Declararemos o seguinte Dockerfile na raiz do projeto:
FROM ubuntu:18.04
RUN echo Construindo ... E declararemos werf.yaml, que usa este Dockerfile:
configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: .\/Dockerfile Isso é tudo! Agora só falta executar werf build:

Além disso, você pode declarar o seguinte werf.yaml para construir várias imagens a partir de diferentes Dockerfiles:
configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: .\/dockerfiles\/Dockerfile-backend
---
image: frontend
dockerfile: .\/dockerfiles\/Dockerfile-frontend Finalmente, o suporte à transmissão de parâmetros adicionais de construção foi adicionado — como --build-arg e --add-host — através da configuração do werf. Uma descrição completa da configuração da imagem Dockerfile está disponível na .
Como funciona?
Durante o processo de construção, o cache padrão dos camadas locais do Docker é utilizado. No entanto, o que é importante, o werf também integra a configuração do Dockerfile em sua infraestrutura. O que isso significa?
- Cada imagem criada a partir do Dockerfile consiste em um único estágio chamado
dockerfile(mais informações sobre o que são estágios no werf podem ser lidas ). - Para o estágio
dockerfileo werf calcula uma assinatura que depende do conteúdo da configuração do Dockerfile. Quando a configuração do Dockerfile é alterada, a assinatura do estágio é mudadadockerfilee o werf inicia a reconstrução desse estágio com a nova configuração do Dockerfile. Se a assinatura não mudar, o werf pega a imagem do cache (informações sobre o uso de assinaturas no werf foram apresentadas na ). - Os comentários construídos podem ser publicados com o comando
werf publish(ouwerf build-and-publish) e utilizados para implantação no Kubernetes. As imagens publicadas no Docker Registry serão limpas utilizando os meios padrão de limpeza do werf, ou seja, ocorrerá a limpeza automática de imagens antigas (mais de N dias), imagens associadas a ramificações do Git inexistentes e de acordo com outras políticas.
Mais informações sobre os aspectos mencionados aqui podem ser encontradas na documentação:
- ;
- ;
- .
Notas e precauções
1. URL externo no ADD não é suportado
No momento, o uso de URL externo na diretiva ADD. O werf não iniciará a reconstrução ao mudar o recurso pelo URL especificado. Em breve, está previsto que essa funcionalidade será adicionada.
2. Não é permitido adicionar .git na imagem
De modo geral, adicionar o diretório .git na imagem é uma prática ruim e aqui está o porquê:
- Se
.gitpermanece na imagem final, isso viola os princípios : como a imagem final deve estar vinculada a um único commit, não deve haver possibilidade de fazergit checkoutum commit arbitrário. -
.gitaumenta o tamanho da imagem (o repositório pode ser grande devido a arquivos grandes que foram adicionados e depois removidos). O tamanho da árvore de trabalho, vinculado apenas a um commit específico, não dependerá do histórico de operações no Git. Além disso, adicionar e posteriormente remover.gitda imagem final não funcionará: a imagem ainda adquirirá uma camada extra — assim funciona o Docker. - O Docker pode iniciar uma recompilação desnecessária, mesmo que esteja construindo o mesmo commit, mas de diferentes work-trees. Por exemplo, o GitLab cria diretórios clonados separados em
/home/gitlab-runner/builds/HASH/[0-N]/yourprojectcom a compilação paralela ativada. A recompilação desnecessária estará relacionada ao fato de que o diretório.gité diferente nas várias versões clonadas do mesmo repositório, mesmo que esteja sendo compilado o mesmo commit.
O último ponto tem uma consequência ao usar o werf. O werf requer que o cache compilado esteja presente ao executar alguns comandos (por exemplo, werf deploy). Durante a execução de tais comandos, o werf calcula as assinaturas das fases para as imagens especificadas em werf.yaml, e elas devem estar no cache de compilação — caso contrário, o comando não conseguirá continuar a execução. Se a assinatura das fases depender do conteúdo .git, obtemos um cache instável a mudanças em arquivos irrelevantes, e o werf não poderá perdoar tal descuido (veja mais em ).
No geral adicionar apenas os arquivos necessários por meio da instrução ADD de qualquer forma aumenta a eficiência e a confiabilidade do que foi escrito Dockerfile, além de melhorar a resistência do cache gerado por este Dockerfile, a mudanças irrelevantes no Git.
Resultado
O nosso caminho inicial de escrever nosso próprio construtor para necessidades específicas foi pesado, honesto e direto: em vez de usar gambiarras em cima do Dockerfile padrão, nós escrevemos nossa própria solução com uma sintaxe personalizada. E isso trouxe suas vantagens: o construtor Stapel lida muito bem com sua tarefa.
No entanto, durante o processo de escrever nosso próprio construtor, deixamos de lado o suporte aos Dockerfiles já existentes. Agora, essa deficiência foi corrigida, e no futuro planejamos desenvolver o suporte ao Dockerfile junto com nosso construtor personalizado Stapel para compilação distribuída e para compilação usando Kubernetes (ou seja, compilações em runners dentro do Kubernetes, como feito no kaniko).
Portanto, se você tiver alguns Dockerfiles de sobra... tente !
P.S. Lista de documentação sobre o assunto
- ;
- ;
- ;
- ;
- ;
- ;
- .
Leia também em nosso blog: "».
Fonte: habr.com
