Em Chelyabinsk, ocorrem meetups para administradores de sistemas Sysadminka, e na última reunião, fiz uma apresentação sobre nossa solução para rodar aplicativos no 1C-Bitrix no Kubernetes.
Bitrix, Kubernetes, Ceph - uma combinação excelente?
Vou explicar como montamos uma solução funcional a partir de tudo isso.
Vamos lá!

O meetup aconteceu em 18 de abril em Chelyabinsk. Você pode ler sobre nossos meetups em e assistir no .
Se você quiser se juntar a nós com uma apresentação ou como ouvinte - fique à vontade, escreva para vadim.isakanov@gmail.com e no Telegram t.me/vadimisakanov.
Minha apresentação
Solução «Bitrix no Kubernetes, versão Southbridge 1.0»
Vou falar sobre nossa solução no formato «para iniciantes no Kubernetes», como foi feita no meetup. Mas presumo que você já conhece os termos Bitrix, Docker, Kubernetes, Ceph, pelo menos no nível de artigos da Wikipedia.
O que já existe sobre Bitrix no Kubernetes?
Na internet, há muito pouca informação sobre como os aplicativos funcionam no Bitrix no Kubernetes.
Encontrei apenas esses materiais:
Apresentação de Alexander Serbul, 1C-Bitrix, e Anton Tuzlukov da Qsoft:

Recomendo ouvi-lo.
Desenvolvimento de uma solução própria pelo usuário .
Encontrei ainda .
E isso é tudo.
Atenção, não verificamos a qualidade das soluções nos links acima 🙂
Aliás, ao preparar nossa solução, conversei com Alexander Serbul, e na época, sua apresentação ainda não existia, portanto, em meus slides, há um item que diz 'Bitrix não usa Kubernetes'.
Mas já existem muitas imagens Docker prontas para uso do Bitrix no Docker:
Isso é suficiente para criar uma solução completa para Bitrix no Kubernetes?
Não. Há uma série de problemas que precisam ser resolvidos.
Quais são os problemas com Bitrix no Kubernetes?
O primeiro - as imagens prontas do Dockerhub não são adequadas para Kubernetes
Se quisermos construir uma arquitetura de microsserviços (e no Kubernetes geralmente queremos), precisamos dividir o aplicativo em contêineres e garantir que cada contêiner execute uma única função pequena (e faça isso bem). Por que apenas uma? Em resumo - quanto mais simples, mais confiável.
Se quiser mais detalhes - por favor, assista a este artigo e vídeo:
As imagens Docker do Dockerhub são principalmente construídas sob o princípio 'tudo em um', por isso tivemos que realmente criar nossa própria solução e até fazer as imagens do zero.
O segundo - o código do site é ajustado do painel administrativo
Criamos uma nova seção no site - o código foi atualizado (uma diretório com o nome da nova seção foi adicionado).
Alteramos as propriedades do componente pelo painel de administração - o código foi alterado.
Kubernetes não consegue trabalhar com isso 'por padrão', os containers devem ser imutáveis (Stateless).
Motivo: cada container (pod) no cluster processa apenas uma parte do tráfego. Se o código for alterado apenas em um container (pod), o código será diferente em diferentes pods, o site funcionará de forma diferente, e diferentes versões do site serão mostradas para os diferentes usuários. Isso não é viável.
Terceiro - precisamos resolver a questão do deploy.
Se tivermos um monolito e um único servidor 'clássico', tudo é bem simples: implementamos uma nova base de código, realizamos a migração do banco de dados, e redirecionamos o tráfego para a nova versão do código. A troca ocorre instantaneamente.
Se nosso site estiver no Kubernetes, dividido em microsserviços, com muitos containers de código - ai ai. Precisamos compilar containers com a nova versão do código, substituí-los pelos antigos, realizar a migração do banco de dados corretamente e, idealmente, fazer isso sem que os visitantes percebam. Felizmente, o Kubernetes nos ajuda, suportando uma série de diferentes tipos de deploy.
Quarto - precisamos resolver a questão do armazenamento de arquivos estáticos.
Se o seu site pesa 'apenas' 10 gigabytes e você o implementar completamente em containers, você terá containers pesando 10 gigabytes que levarão uma eternidade para serem implantados.
Precisamos armazenar as partes 'mais pesadas' do site fora dos containers, e surge a questão de como fazer isso corretamente.
O que não está em nossa solução.
Todo o código do Bitrix não foi dividido em microfunções/microsserviços (como registro separado, módulo de e-commerce separado, etc.). Mantemos toda a base de código em cada container na íntegra.
A base no Kubernetes também não é armazenada (eu já implementei soluções com base no Kubernetes para ambientes de desenvolvimento, mas não para produção).
Os administradores do site ainda perceberão que o site está rodando no Kubernetes. A função 'verificação do sistema' não funciona corretamente, para editar o código do site a partir do painel de administração, é necessário primeiro pressionar o botão 'quero editar o código'.
Resolvemos os problemas, entendemos a necessidade de implementar microserviços, e o objetivo está claro — obter um sistema funcional para operar aplicativos no Bitrix em Kubernetes, preservando tanto as funcionalidades do Bitrix quanto as vantagens do Kubernetes. Vamos iniciar a implementação.
Arquitetura
Muitos pods 'ativos' com servidor web (workers).
Um pod com tarefas cron (obrigatoriamente apenas um).
Um pod de upgrade para edição do código do site a partir do painel de administração (também obrigatoriamente apenas um).

Estamos resolvendo questões:
- Onde armazenar as sessões?
- Onde armazenar o cache?
- Onde armazenar a estática? Não podemos colocar gigabytes de estática em um monte de contêineres.
- Como o banco de dados vai funcionar?
Imagem Docker
Começamos pela construção da imagem Docker.
A opção ideal — temos uma única imagem universal, a partir da qual obtemos tanto os pods worker quanto os pods com tarefas cron e os pods de upgrade.
.
Ela inclui nginx, apache/php-fpm (que pode ser escolhido durante a construção), msmtp para envio de emails, e cron.
Durante a construção da imagem, toda a base de código do site é copiada para o diretório /app (exceto as partes que vamos mover para um armazenamento compartilhado separado).
Microserviços, serviços
Pods worker:
- Contêiner com nginx + contêiner apache/php-fpm + msmtp.
- Não foi possível mover msmtp para um microserviço separado, o Bitrix começa a reclamar que não consegue enviar emails diretamente.
- Dentro de cada contêiner, há uma base de código completa.
- É proibido modificar o código nos contêineres.
Pod cron:
- Contêiner com apache, php, cron.
- Inclui a base de código completa.
- É proibido modificar o código nos contêineres.
Pod de upgrade:
- Contêiner com nginx + contêiner apache/php-fpm + msmtp.
- Não há proibição de modificar o código nos contêineres.
Armazenamento de sessões.
Armazenamento de cache do Bitrix.
Outra coisa importante: as senhas para conexão a tudo, desde o banco de dados até o email, são armazenadas em segredos do Kubernetes. Temos a vantagem de que as senhas são visíveis apenas para aqueles a quem concedemos acesso aos segredos, e não para todos que têm acesso à base de código do projeto.
Armazenamento para estática.
Pode-se usar qualquer coisa: ceph, nfs (mas não recomendamos nfs para produção), armazenamento em rede de provedores 'nublados', etc.
O armazenamento precisará ser conectado dentro dos contêineres ao diretório /upload/ do site e a outros diretórios com estática.
Banco de dados
Para simplificar, recomendamos manter o banco de dados fora do Kubernetes. Um banco de dados no Kubernetes é uma tarefa separada e complexa, que tornará o esquema significativamente mais complicado.
Armazenamento de sessões.
Usamos memcached 🙂
Ele lida bem com o armazenamento de sessões, é clusterizável e é suportado "nativamente" como session.save_path no php. Esse sistema já foi testado inúmeras vezes na arquitetura monolítica clássica, quando construímos clusters com um grande número de servidores web. Para o deploy, usamos helm.
$ helm install stable/memcached --name sessionphp.ini - aqui na imagem estão definidas as configurações para armazenamento de sessões no memcached
Usamos Variáveis de Ambiente para transmitir dados sobre os hosts com memcached .
Isso permite usar o mesmo código em ambientes dev, stage, test, prod (os nomes dos hosts memcached serão diferentes entre eles, por isso precisamos passar um nome único de host para as sessões em cada ambiente).
Armazenamento de cache Bitrix
Precisamos de um armazenamento tolerante a falhas, onde todos os pods possam escrever e ler.
Também usamos memcached.
Essa solução é recomendada pelo próprio Bitrix.
$ helm install stable/memcached --name cachebitrix/.settings_extra.php - aqui no Bitrix é definido onde armazenamos o cache
Da mesma forma, usamos Variáveis de Ambiente.
Tarefas cron
Existem diferentes abordagens para executar tarefas cron no Kubernetes.
- deployment separado com pod para a execução de tarefas cron
- cronjob para executar tarefas cron (se for um aplicativo web - com wget , ou kubectl exec dentro de um dos pods worker, etc.)
- etc.
Pode-se debater sobre qual é a mais correta, mas neste caso escolhemos a opção "deployment separado com pods para tarefas cron"
Como isso é feito:
- adicionamos tarefas cron através do ConfigMap ou através do arquivo config/addcron
- executamos uma instância do contêiner, idêntica ao pod worker + permitimos a execução de tarefas cron nele
- é utilizada a mesma base de código, graças à unificação, a construção do contêiner é simples
O que conseguimos de bom:
- temos tarefas cron funcionais em um ambiente idêntico ao do ambiente dos desenvolvedores (docker)
- as tarefas cron não precisam ser "reescritas" para Kubernetes, elas funcionam da mesma forma e na mesma base de código que antes
- as tarefas cron podem ser adicionadas por todos os membros da equipe com direitos de commit na branch de produção, e não apenas pelos administradores
Módulo Southbridge K8SDeploy e edição de código a partir do painel de administração
Falamos sobre o upgrade do pod?
E como direcionar o tráfego para lá?
Uhul, escrevemos um módulo para isso em php 🙂 É um pequeno módulo clássico para o Bitrix. Ele ainda não está disponível publicamente, mas planejamos disponibilizá-lo.
O módulo é instalado como um módulo comum no Bitrix:

E se parece assim:

Ele permite definir um cookie que identifica o administrador do site e permite que o Kubernetes envie tráfego para o pod de upgrade.
Quando as alterações são concluídas, você deve clicar em git push para que as alterações no código sejam enviadas para o git. Em seguida, o sistema construirá uma imagem com a nova versão do código e a "distribuirá" pelo cluster, substituindo os pods antigos.
Sim, um pouco improvisado, mas assim mantemos a arquitetura de microserviços e não retiramos dos usuários do Bitrix a valiosa possibilidade de corrigir o código a partir do painel de administração. Afinal, isso é uma opção; o problema da correção de código pode ser resolvido de outra forma.
Helm chart
Para construir aplicações no Kubernetes, geralmente usamos o gerenciador de pacotes Helm.
Para nossa solução Bitrix no Kubernetes, Sergey Bondarev, nosso administrador de sistemas principal, escreveu um Helm chart especial.
Ele executa a construção de pods worker, upgrade e cron, configura ingressos, serviços e transmite variáveis dos segredos do Kubernetes para os pods.
Nós armazenamos o código no Gitlab e também iniciamos a construção do Helm a partir do Gitlab.
De forma resumida, isso se parece com:
$ helm upgrade --install project .helm --set image=registrygitlab.local/k8s/bitrix -f .helm/values.yaml --wait --timeout 300 --debug --tiller-namespace=productionO Helm também permite fazer um rollback "sem emendas", caso algo dê errado durante o deploy. É bom saber que você não está em pânico "corrigindo o código via ftp porque o ambiente de produção caiu", mas sim que o Kubernetes faz isso automaticamente, sem downtime.
Deploy
Sim, somos fãs do Gitlab & Gitlab CI, usamos isso 🙂
Ao fazer um commit no Gitlab no repositório do projeto, o Gitlab inicia um pipeline que realiza a implantação de uma nova versão do ambiente.
Etapas:
- build (construímos uma nova imagem Docker)
- test (testamos)
- clean up (removemos o ambiente de teste)
- push (enviamos para o Docker registry)
- deploy (implementamos a aplicação no Kubernetes via Helm).

Uhul, pronto, vamos implementar!
Bem, ou fazemos perguntas, se houver.
Então, o que fizemos
Do ponto de vista técnico:
- dockerizamos o Bitrix;
- “dividimos” o Bitrix em contêineres, cada um dos quais executa funções mínimas;
- alcançamos um estado stateless para os contêineres;
- resolvemos o problema de atualização do Bitrix no Kubernetes;
- todas as funções do Bitrix continuaram funcionando (quase todas);
- executamos o deploy no Kubernetes e o rollback entre versões.
Do ponto de vista empresarial:
- alta disponibilidade;
- ferramentas do Kubernetes (integração simples com Gitlab CI, deploy sem emendas, etc);
- senhas em segredos (visíveis apenas para aqueles a quem o acesso às senhas foi diretamente concedido);
- é conveniente criar ambientes adicionais (para desenvolvimento, testes e outros) dentro de uma única infraestrutura.
Fonte: habr.com
