Implante o código diretamente no contêiner do docker. Ou como não procrastinar após cada confirmação

A tarefa veio WEB-12982
Crie uma ramificação web-12982 no repositório
Enquanto o ramo está indo, leia tz e beba café
Prossiga diretamente para o desenvolvimento

git commit, git push
Enquanto o ramo está remontando
git commit, git push
Enquanto o ramo é reconstruído, lançando o twitter
git commit, git push
...
Você entrega uma ramificação de revisão com 50 confirmações

Você entende que 50 confirmações são exatamente 50 minutos de tempo puro, que são coletados em intervalos e partidas, porque os intervalos de 1 minuto são muito pequenos para fazer algo além de procrastinação e necessidades básicas.


A situação é familiar? Na minha empresa, a infraestrutura de desenvolvimento está organizada da seguinte forma:


  • Hitlab tem muitos repositórios de projetos
  • Para garantir facilidade de desenvolvimento ao criar uma nova ramificação, as janelas de encaixe criam automaticamente sua própria caixa de proteção em um endereço exclusivo, uma cópia completa da ramificação pai com todo o ambiente necessário.
  • Tudo o que você precisa está pronto - basta escrever o código e testar-ver-avaliar o resultado após cada confirmação, é muito conveniente!

Mas, lentamente ... Se esta situação estiver próxima de você, seja bem-vindo, sob o gato.



A essência do problema


tldr: as alterações feitas no código exigem a remontagem dos contêineres e o tempo gasto (mais de um minuto, isso depende do projeto, especialmente se o CI \ CD estiver configurado), que na verdade não pode ser gasto com utilidade, mas que tira totalmente um pedaço decente do tempo de trabalho do programador.

Problemas semelhantes aparecem periodicamente em todos

Por exemplo, o mesmo liveReload para o front-end foi claramente inventado por um motivo


Eu publiquei anteriormente um artigo sobre um tópico relacionado , mas relacionado ao processo de depuração (a propósito, obrigado pelos comentários informativos e feedback positivo). No entanto, o problema do corte não desapareceu, continuamos também a aguardar a remontagem do ramo.


Mesmo se você pular as etapas adicionais e deixar apenas build-dev e deploy-dev, o tempo de espera será insignificante para qualquer ação útil, mas significativamente no tempo total gasto, especialmente no que diz respeito ao CI \ CD, por exemplo, do Gitlab.


Obviamente, você pode acelerar o processo montando o projeto localmente, desde que o programador tenha um computador relativamente poderoso, o gitlab-runner esteja configurado, o mesmo ambiente esteja configurado no servidor remoto e as tags correspondentes sejam adicionadas ao gitlab-ci.yml, mas duvido que a velocidade de criação será a mesma que a implantação automática do código FTP após as teclas ctrl + s.


Especialmente queima enfurecido é cansativo quando, durante o processo de desenvolvimento, você faz erros de digitação / erro que geralmente não afetam a operação do aplicativo, mas que não podem ser deixados assim, e você os percebe apenas quando observa o resultado após a montagem.


O que é necessário e opções de solução


tldr: encontre uma maneira de ver o resultado de suas edições da maneira mais simples e rápida possível. Para não confirmar todas as vezes e não esperar pela reconstrução da ramificação. Selecionei o rsync do computador local para a pasta do servidor remoto montada com a pasta do contêiner.

Não encontrei uma solução completa na Internet, mas na verdade existem várias opções:


  • Configure ftp \ ssh diretamente no contêiner com a base de código, inclua-o na imagem, conecte-se via FTP diretamente ao contêiner
    • Pessoalmente, essa opção me pareceu um pouco complicada e muito "muleta", embora aqui todas as opções sejam muletas
  • (para uso local) use o docker cp para carregar o código diretamente no contêiner
    • A opção não é adequada para trabalhar com um servidor remoto.
    • O docker cp possui uma funcionalidade extremamente limitada, dadas as pastas de fornecedores que não devem ser copiadas todas as vezes e o próprio algoritmo de cópia, isso será bastante lento.
  • (para uso remoto \ local) Monte a pasta do contêiner desejada na pasta do host externo. Faça o download dos arquivos locais diretamente para a pasta do host montada. Já existem muitas opções de implementação:
    • Use docker-machine e especificamente docker-machine scp
      • Novamente, você precisa configurar o ambiente, configurar a docker-machine, talvez isso faça sentido quando você trabalha constantemente com servidores diferentes
    • No IDE, configure uma conexão FTP com a pasta host desejada
      • Cada nova ramificação requer a criação de uma nova conexão ou a alteração de mapeamentos
    • Use scp ou rsync para fazer upload de arquivos para a pasta host desejada, para isso use um pequeno script bash e pendure-o nas teclas de atalho
      • A princípio, parece desnecessariamente complicado, mas na verdade não é. O script em si é o mais simples possível e é necessário para automatizar o processo, para que você não precise reconfigurar os mapeamentos sempre

Solução em si: volumes rsync +


tldr:
  • Precisa de acesso ssh a um servidor remoto e rsync na máquina local
  • O servidor remoto deve ter uma pasta gravável
  • Monte a pasta do projeto no contêiner na pasta do host externo
  • Adicione um pequeno script bash à raiz do projeto para sincronizar arquivos com o servidor remoto
  • Configurar uma tecla de atalho para execução de script de sincronização

Vale ressaltar que a solução fornecida é excluída para o ambiente de desenvolvimento e teste


Nesse caso, examinarei os ambientes docker-compose e gitlab-ci, com docker-compose usando variáveis ​​de ambiente do gitlab-ci.


Formamos o caminho para a pasta de destino no gitlab-ci e exportamos esse caminho para o docker-compose.yml:


before_script: - export SHARED_DIR_BASE='/var/www/builds' #    ,      - export SHARED_BRANCH_DIR=${SHARED_DIR_BASE}/${PROJECT_GROUP}/${PROJECT_NAME}/${CI_COMMIT_REF_NAME} #     web-123   my_group/my_project,      /var/shared/my_group/my_project/web-123 Deploy dev: stage: deploy_dev script: #   ,         - mkdir -p ${SHARED_BRANCH_DIR} - rsync -r --exclude-from=.gitignore --exclude-from=.dockerignore . ${SHARED_BRANCH_DIR} - find ${SHARED_BRANCH_DIR} -type d -exec setfacl -d -mo:rwx {} \; - find ${SHARED_BRANCH_DIR} -type d -exec setfacl -mo:rwx {} \; - find ${SHARED_BRANCH_DIR} -type f -exec setfacl -mo:rwx {} \; - envsubst < docker-compose.tmpl > docker-compose.yml #     gitlab-ci.yml  docker-compose.yml,   docker-compose.tmpl - docker-compose up -d 

Em seguida, precisamos montar as pastas do projeto na pasta host externa no docker-compose, uma vez que usamos as variáveis ​​no docker-compose, precisamos do modelo docker-compose.tmpl no qual usaremos essas variáveis.


 version: '2.3' services: web: ... volumes: - ${SHARED_BRANCH_DIR}:/app/:rw #             #        .    ,      ,           .              ,     ,        - /app/protected/vendor/ 

A configuração atual já é suficiente. Agora, quando você cria a ramificação no servidor host, a pasta / var / www / builds / GROUP_NAME / PROJECT_NAME / BRANCH_NAME será criada e o projeto será transferido para lá, exceto pelos arquivos e pastas especificados em .gitignore e .dockerignore e, em seguida, você pode simplesmente configurar os mapeamentos de FTP, mas iremos um pouco mais além e tornaremos o processo um pouco mais automatizado.


De fato, para sincronizar arquivos, precisamos executar algo como isto:


 rsync -r -u \ --delete-after \ --exclude-from=.gitignore \ --exclude-from=.dockerignore \ . $sshUserName@$sshHost:$sharedBaseDir 

De fato, em projetos de pequeno e médio porte, esse comando será executado mais rapidamente do que você tem tempo para confirmar e enviar edições ao repositório. Resta trazer esse script para uma aparência mais completa e vincular sua execução às teclas de atalho.


Código de script completo: deploy.sh
 #!/usr/bin/env bash #    while [ -n "$1" ] do case "$1" in --sshUserName=*) sshUserName=${1#*=} ;; --sshHost=*) sshHost=${1#*=} ;; esac shift done #  shared    gitBranch=$(git branch | grep \* | cut -d ' ' -f2) gitProject=$(git config --local remote.origin.url|sed -n 's#.*/\([^.]*\)\.git#\1#p') gitGroup=$(git config --local remote.origin.url|sed -n 's#.*/\([^.]*\)/.*\.git#\1#p') sharedBaseDir=/var/www/builds/$gitGroup/$gitProject/$gitBranch #         rsync -r -u \ --delete-after \ --exclude-from=.gitignore \ --exclude-from=.dockerignore \ . $sshUserName@$sshHost:$sharedBaseDir echo "done" 

Deve-se notar que o script deve estar localizado na raiz da pasta do projeto do repositório ou indicar em qual diretório ele deve funcionar.


Resta apenas agilizar a execução desse script para teclas de atalho específicas e definir os parâmetros sshUserName e sshHost (entende-se que já existe acesso ao servidor remoto via ssh). Como fazer isso, darei um exemplo do PHPstorm.


  • Vá para Arquivo -> Configurações
  • Na janela de configurações no menu esquerdo, expanda Ferramentas , selecione Ferramentas externas
  • Escrevemos o caminho para o script e especificamos o real sshUserName e sshHost nos argumentos

  • Em seguida, vá para Keymap e procure o nome de nossas Ferramentas externas, defina a combinação necessária


Só isso. Agora, quando você clica na combinação desejada, todos os arquivos do projeto são sincronizados com a pasta remota, que é montada com a pasta do projeto dentro do contêiner. Ou seja, quaisquer alterações serão visíveis quase imediatamente.


Eu não pretendo ser "ideal" desta solução, provavelmente existem opções melhores, ficarei feliz se eu souber sobre elas nos comentários. Obrigada

Source: https://habr.com/ru/post/pt439262/


All Articles