
O tema do monorepositório já foi discutido diversas vezes e, geralmente, provoca debates bastante acalorados. Ao criar uma ferramenta de código aberto, destinada a melhorar os processos de construção de código de aplicações do Git em imagens Docker (e sua posterior entrega no Kubernetes), raramente refletimos sobre qual escolha é melhor. Para nós, o primordial é garantir tudo que é necessário para os defensores de diferentes opiniões (se isso não contradizer o bom senso, é claro).
O apoio recente ao mono-repo no werf é um bom exemplo disso. Mas, antes de tudo, vamos entender como esse suporte se relaciona ao uso do werf e qual a conexão com o Docker Registry...
Problemas
Vamos imaginar a seguinte situação. A empresa possui várias equipes de desenvolvedores trabalhando em projetos independentes. A maioria das aplicações opera no Kubernetes, e, consequentemente, está conteinerizada. Para armazenar contêineres e imagens, é necessário um registro (registry). A empresa utiliza o Docker Hub com uma única conta COMPANY. Por analogia com a maioria dos sistemas de armazenamento de código fonte, o Docker Hub não permite criar uma hierarquia de repositórios aninhados, como COMPANY/PROJECT/IMAGE. Nesse caso... como armazenar no registro aplicações não monolíticas sem criar uma conta separada para cada projeto?

Talvez a situação descrita seja familiar para alguns, mas vamos considerar a questão da organização do armazenamento de aplicações de forma geral, ou seja, sem amarras ao exemplo mencionado acima e ao Docker Hub.
Soluções
Se a aplicação for monolítica, não há problemas e simplesmente armazenamos as imagens no registro de contêineres do projeto.
Quando a aplicação é apresentada na forma de vários componentes, microsserviços, é necessário escolher um determinado enfoque. Tomando como exemplo uma aplicação web típica, composta por duas imagens: frontend e backend — as opções possíveis são:
- Armazenar as imagens em repositórios aninhados separados:

- Armazenar tudo em um único repositório, considerando o nome da imagem no tag, por exemplo, da seguinte forma:

NB: Na verdade, há também a opção de armazenamento em diferentes repositórios, PROJECT-frontend e PROJECT-backend, mas não iremos considerar isso devido à complexidade de suporte, organização e distribuição de direitos entre os usuários.
Suporte no werf
Inicialmente, o werf limitou-se a repositórios aninhados — felizmente, a maioria dos registros suporta essa possibilidade. A partir da versão , foi adicionada a possibilidade de trabalhar com registros que não suportam aninhamento, incluindo o Docker Hub. A partir de agora, o usuário teve a opção de como armazenar as imagens da aplicação.
A implementação está disponível na opção --images-repo-mode=multirepo|monorepo (por padrão, multirepo, ou seja, armazenamento em repositórios aninhados). Ela determina os padrões de como as imagens são armazenadas no registro. É suficiente escolher o modo desejado ao usar os comandos principais, e tudo o mais permanecerá inalterado.
Como a maioria das opções do werf pode ser definida por variáveis de ambiente, em sistemas CI/CD, o modo de armazenamento geralmente é fácil de definir globalmente para todo o projeto. Por exemplo, no caso do GitLab, basta adicionar uma variável de ambiente nas configurações do projeto: Configurações -> CI / CD -> Variáveis: WERF_IMAGES_REPO_MODE: multirepo|monorepo.
Falando sobre a publicação de imagens e o lançamento de aplicações (sobre esses processos, pode-se ler em detalhes nos artigos correspondentes da documentação: e ), o modo define exclusivamente o padrão de como trabalhar com a imagem.
O diabo está nos detalhes.
A diferença e a principal dificuldade ao adicionar uma nova forma de armazenamento são o processo de limpeza do registro (as capacidades de limpeza suportadas no werf estão na ).
Ao limpar, o werf considera as imagens usadas nos clusters Kubernetes, bem como as políticas configuradas pelo usuário. A base das políticas é a divisão de tags em estratégias. As estratégias atualmente suportadas são:
- 3 estratégias relacionadas a primitivas do Git, como tag, ramo e commit;
- 1 estratégia para tags personalizadas arbitrárias.
As informações sobre a estratégia de tag são armazenadas ao publicar a imagem nos rótulos da imagem final. O próprio valor — o chamado metatag — é necessário para a aplicação de algumas políticas. Por exemplo, ao excluir um ramo ou uma tag do repositório Git, é lógico remover também as imagens não utilizadas do registro, o que é coberto por uma parte de nossas políticas.
Ao armazenar em um único repositório (monorepo), na tag da imagem, além do metatag, também pode ser armazenado o nome da imagem: PROJETO:frontend-META-TAG. Para separá-los, não introduzimos um delimitador específico, mas apenas adicionamos o valor necessário ao rótulo da imagem final ao publicá-la.
NB: Se estiver interessado em ver tudo que foi descrito no código-fonte do werf, um ponto de partida pode ser .
Neste artigo, não vamos nos aprofundar mais nos problemas e na justificativa da nossa abordagem: sobre estratégias de tagueamento, armazenamento de dados em rótulos e o processo de publicação em geral — tudo isso foi descrito em detalhes no recente relatório de Dmitry Stolyarov: “».
Resumindo
A falta de suporte para registros sem aninhamento não foi um fator bloqueador para nós ou para os usuários conhecidos do werf — sempre é possível levantar um registro separado de imagens (ou mudar para um Container Registry no Google Cloud)… No entanto, a remoção dessa limitação parecia lógica para que a ferramenta fosse mais conveniente para uma comunidade DevOps mais ampla. Ao implementá-la, encontramos a principal dificuldade na reestruturação do mecanismo de limpeza do registro de contêineres. Agora, com tudo pronto, é gratificante saber que facilitou a vida de alguém, e para nós (como principais desenvolvedores do projeto) não prevemos grandes dificuldades na manutenção futura dessa funcionalidade.
Fique conosco e em breve contaremos sobre outras inovações em !
P.S.
Confira também em nosso blog:
- «»;
- «».
Fonte: habr.com


