Você ainda abre o FileZilla para enviar arquivo por arquivo para o servidor? Chegou a hora de mudar! Depois deste post bastará subir os arquivos para um repositório no GitHub e eles serão enviados para o servidor automaticamente.
Se você está com pressa… tudo bem!
Não tem problema se você está com pressa. De forma bem resumida isso é o que vamos fazer:
- Criar um par de chaves SSH que se conectem ao seu servidor;
- Criar os segredos
DEPLOY_SSH_HOST
,DEPLOY_SSH_USER
eDEPLOY_SSH_KEY
no GitHub; - Criar o arquivo
bin/rsync-excludes.txt
no seu repositório; - Criar o arquivo
.github/workflows/deploy.yml
no seu repositório; - Fazer qualquer modificação na branch
trunk
.
Se este post ajudar, não se esqueça de compartilhá-lo nas suas redes sociais. Assine a newsletter para receber os novos posts!
O que você precisa
A lista do que vamos precisar para esse post é bem simples:
- Acesso SSH ao seu servidor: Disponível em quase todas as hospedagens atualmente;
- Um repositório no GitHub: Grátis e ilimitados, inclusive os privados.
Não se esqueça de fazer um backup do conteúdo do seu servidor antes de continuar. Assim, se algo der errado, será mais fácil reverter.
O que a GitHub Action vai fazer
Basicamente, o que vai acontecer é que ao atualizar os arquivos em uma determinada branch do repositório, uma GitHub Action se conectará via SSH com o servidor e enviará os arquivos usando o comando rsync
.
Acesso SSH
A sua GitHub Action precisará se conectar através do SSH (Secure SHell) com o seu servidor para enviar os arquivos. Para que isso seja possível, vamos criar um par de chaves SSH e configurar o servidor para aceitá-lo.
1. Criar um par de chaves SSH
A criptografia usada pelo protocolo SSH usa duas chaves: uma pública e uma privada. Para que a sua GitHub Action consiga enviar os arquivos para o seu servidor, você precisará de um novo par de chaves. Embora possível, não recomendo usar a mesma chave que você usa normalmente.
O comando para criar uma nova chave é o seguinte:
ssh-keygen -t ed25519 -C "usuario@dominio"
ssh-keygen
: O comando que gera uma nova chave;-t ed25519
: O algoritmo usado na criação da chave;-C "usuario@dominio"
: Não precisa ser um e-mail de verdade. Só é usado para diferenciar as chaves, como um comentário. Algo como[email protected]
já é o suficiente.
O comando pedirá:
- Uma senha: deixe em branco para facilitar o processo;
- Um nome de arquivo: não use o padrão, coloque um novo como
deploy
ou o nome do projeto. Não use nenhuma extensão.
2. Autorizar a chave a conectar com o seu servidor
Cada serviço de hospedagem cuida disso de uma forma diferente. Em hospedagens com algum tipo de painel de controle isso pode estar em Minha conta > SSH ou similar.
Na Cloudways, por exemplo, as chaves SSH são gerenciadas por aplicação. Na seção Access Details, é possível gerenciar as chaves SSH em Application Credentials.
Na imagem vemos setas para três elementos:
- Public IP: Será usado como Host na nossa configuração. Em muitos casos é a URL do próprio site.
- Username: A Cloudways tem um username diferente por aplicação. Algumas hospedagens usam o mesmo usuário para acessar tanto o painel quanto o servidor via SSH.
- SSH Keys: Este é o lugar onde é possível configurar novas chaves para essa aplicação. Lá você deve fornecer a chave pública (
arquivo.pub
) do par gerado.
3. Testar a chave SSH (Opcional)
Do seu computador é possível testar o acesso com a nova chave. Para isso basta executar o seguinte comando:
ssh -i <caminho-chave-privada> <usuario>@<servidor>
<caminho-chave-privada>
: O caminho do arquivo da chave privada (sem.pub
) no seu computador<usuario>@<servidor>
: Varia de serviço para serviço. No caso da Cloudways teríamos[email protected]
.
Se usássemos a chave gerada no exemplo, a chamada ficaria assim:
ssh -i /home/elia/.ssh/exemplopost [email protected]
Se tudo deu certo você vai conseguir acessar o terminal do seu servidor.
GitHub Actions
GitHub Actions é a ferramenta de automação do GitHub. Basicamente, o GitHub vai analisar qualquer arquivo .yml
na pasta .github/workflows
do seu repositório e tentar executá-lo cada vez que alguma coisa acontecer no seu repositório.
No nosso caso vamos criar um arquivo chamado .github/workflows/deploy.yml
. Você pode dar o nome que quiser, desde que mantenha a extensão .yml
e a localização do arquivo.
ATENÇÃO: Arquivos .yml não permitem tabs, só espaços (2 ou 4).
O conteúdo do nosso arquivo .github/workflows/deploy.yml
será o seguinte:
name: Deploy
env:
SSH_USER: ${{ secrets.DEPLOY_SSH_USER }}
SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}
on:
push:
branches:
- trunk
jobs:
deploy_cloudways:
name: Deploy to Cloudways
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure SSH
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/deploy.key
chmod 600 ~/.ssh/deploy.key
cat >>~/.ssh/config <<END
Host cloudways
HostName $SSH_HOST
User $SSH_USER
IdentityFile ~/.ssh/deploy.key
StrictHostKeyChecking no
END
env:
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
- name: Send files
run: "rsync --delete -avO ${{ env.RSYNC_FLAGS }} --exclude-from=${{ env.EXCLUDES }} ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}"
env:
RSYNC_FLAGS: '' #--dry-run
EXCLUDES: bin/rsync-excludes.txt
SSH_HOST: cloudways
DESTINATION: "~/public_html/wp-content/"
Nome do fluxo de trabalho
A primeira linha do nosso arquivo simplesmente dá nome ao nosso workflow. O nome é usado simplesmente para visualizações e não interfere no funcionamento da automação.
name: Deploy
Segredos no GitHub Action
A segunda seção do nosso arquivo configura algumas variáveis de ambiente compartilhadas por alguns “passos” mais adiante.
env:
SSH_USER: ${{ secrets.DEPLOY_SSH_USER }}
SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}
Como a descrição do fluxo de trabalho é feita em um arquivo visível para qualquer um que tenha acesso ao repositório, o GitHub fornece um jeito de criar segredos, editáveis apenas por administradores do repositório ou organização.
Como criar um segredo no GitHub Actions
Vamos relembrar o comando de acesso SSH que usamos para testar anteriormente:
ssh -i <caminho-chave-privada> <usuario>@<servidor>
Com esse comando em mente, acesse o repositório e vá até Settings > Secrets and Variables > Actions. Vamos criar três segredos:
DEPLOY_SSH_KEY
: O conteúdo da chave privada que você criou.DEPLOY_SSH_USER
: O que você usou como<usuario>
;DEPLOY_SSH_HOST
: O que você usou como<servidor>
;
Repare que DEPLOY_SSH_KEY
é diferente das outras: passamos o caminho do arquivo no comando, mas o segredo tem o conteúdo do arquivo. Isso acontece porque criaremos o arquivo durante a execução da action.
O segredo DEPLOY_SSH_KEY
não está nessa seção env
de propósito. Ele será usado mais adiante.
Gatilhos e eventos
on:
push:
branches:
- trunk
O conteúdo dessa seção é bem auto-explicativo: os passos neste arquivo só devem ser executados quando o conteúdo da branch trunk
for modificado.
Ao invés de push
, poderia ser pull_request
ou schedule
, por exemplo.
Jobs
Um conjunto de passos que serão executados. Nosso arquivo de workflow só tem um job, mas é possível ter mais de um. Diferentes jobs são executados em paralelo.
jobs:
deploy_cloudways:
name: Deploy to Cloudways
runs-on: ubuntu-latest
No nosso caso deploy_cloudways
poderia ser qualquer slug, assim como Deploy to Cloudways
. Esses são só nomes.
A string ubuntu-latest
especifica em que sistema operacional o job deve ser executado. É possível especificar versões de Linux, Windows e MacOS. Veja a lista completa.
Etapas ou steps
Steps são subdivisões do nosso job, executadas em ordem.
steps:
- name: Checkout
uses: actions/checkout@v2
O nosso primeiro passo é o checkout do repositório. Essa é, normalmente, a primeira etapa de todos os workflows que você verá por aí. Simplesmente traz o conteúdo do repositório para dentro do ambiente da action.
Configuração do SSH
Esta seção configura o SSH da máquina executando a nossa ação no GitHub.
- name: Configure SSH
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/deploy.key
chmod 600 ~/.ssh/deploy.key
cat >>~/.ssh/config <<END
Host cloudways
HostName $SSH_HOST
User $SSH_USER
IdentityFile ~/.ssh/deploy.key
StrictHostKeyChecking no
END
env:
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
mkdir -p ~/.ssh/
: Cria o diretório.ssh
dentro da pasta$HOME
do servidor.echo "$SSH_KEY" > ~/.ssh/deploy.key
: Coloca o conteúdo da variávelSSH_KEY
dentro do arquivodeploy.key
.chmod 600 ~/.ssh/deploy.key
: Configura as permissões do arquivodeploy.key
. Nessa caso,600
significa que o dono do arquivo tem permissão de leitura e escrita. Nenhum outro usuário pode acessá-lo.cat >>~/.ssh/config <<END
: O que estiver entre<<END
eEND
será inserido no arquivoconfig
da pasta.ssh
.Host cloudways
: Cria um nome para a configuração a seguir. Ao chamar o SSH passandocloudways
, os dados seguintes serão usados;HostName $SSH_HOST
: O endereço do servidor. Se você lembrar do que falamos na seçãoenv
, essa variável receberá o valor do segredoDEPLOY_SSH_HOST
;User $SSH_USER
: Similar aoHostName
, mas aplicado ao usuário;IdentityFile ~/.ssh/deploy.key
: Especifica o caminho da chave a ser usada para se conectar com oHost
;StrictHostKeyChecking no
: Pula a verificação da identificação do servidor com o conteúdo do arquivoknown_hosts
.
Logo abaixo vemos uma seção env
, similar àquela global, declarada no começo do nosso arquivo. Repare que nesse caso a variável é criada apenas para esse passo. No caso, estamos passando o conteúdo do segredo DEPLOY_SSH_KEY
para uma variável de ambiente chamada SSH_KEY
. O conteúdo dessa variável será adicionado ao arquivo deploy.key
como vimos acima.
Enviar os arquivos com rsync
No último passo vamos finalmente alterar o conteúdo do servidor. Para isso vamos usar o comando rsync
, que sincroniza os arquivos de um lugar com outro. Nesse caso, os arquivos da máquina do GitHub (origem) com os arquivos no seu servidor (destino).
- name: Send files
run: "rsync --delete -avO ${{ env.RSYNC_FLAGS }} --exclude-from=${{ env.EXCLUDES }} ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}"
env:
RSYNC_FLAGS: '' #--dry-run
EXCLUDES: bin/rsync-excludes.txt
SSH_HOST: cloudways
DESTINATION: "~/public_html/wp-content/"
Se o comando rsync
é novidade para você, vamos ver cada um dos parâmetros passados:
--delete
: Se um arquivo não está na origem, ele deve ser excluído do destino.-avO
:-a
significa sincronizar todos os arquivos, pastas e links simbólicos preservando suas permissões. Ov
é paraverbose
, ou seja, imprime no terminal a lista de modificações sendo feitas.O
(um “o” maiúsculo) configurarsync
para não se preocupar com datas de modificações de pastas.${{ env.RSYNC_FLAGS }}
: Como você já deve imaginar, será substituído pelo conteúdo da variávelRSYNC_FLAGS
configurada mais abaixo. Normalmente, não recebe nada, mas você pode, por exemplo, passar--dry-run
que só simula o chamado ao comando, sem fazer nenhuma mudança.--exclude-from=${{ env.EXCLUDES }}
: Você pode passar o endereço de um arquivo com a lista de tudo o que deve ser ignorado porrsync
. Veja a próxima seção para saber mais sobre isso../
: o endereço da pasta local que deve ser sincronizada.${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}
: O endereço de destino. A última parte será substituída pela pasta no endereço de destino. No caso aqui o repositório contém os arquivos da pastawp-content
e o site está localizado na pasta$HOME/public_html
do servidor. No seu caso a pasta pode estar em outro lugar, como/var/www/html
. Acesse seu servidor ou procure nas configurações da sua hospedagem para saber a pasta em que seu site está localizado.
Sobre exclusões no rsync
No exemplo acima estamos usando um arquivo chamado rsync-excludes.txt
localizado na pasta bin
do repositório. Esse arquivo tem uma lista de arquivos e pastas que devem ser ignorados pelo comando rsync
. Por exemplo:
*.gitignore
*.gitmodules
*.git
*.gitkeep
*.github
/bin
*rsync-excludes.txt
/uploads
/upgrade
/themes/index.php
/plugins/index.php
Ao invés de usar --exclude-from=<arquivo>
você também pode alterar a chamada a rsync
e usar --exclude .git --exclude README.md
, por exemplo.
Fazendo mais com GitHub Actions
Se você quiser, também é possível chamar comandos como composer install
ou npm install
durante o processo, evitando que você tenha que versionar arquivos de terceiros no seu repositório. Além disso, o processo também pode ser iniciado pela criação de um Pull Request ou por períodos (uma vez a cada dia, semana, etc.).
Para exemplos reais, veja o repositório do ElasticPress. Lá tem ações executadas uma vez por dia, testes automatizados, deploy para o repositório do WordPress.org e mais.
Por que abandonar o SFTP
Para começar, você deve usar um controle de versão como o git, mesmo que trabalhe sozinho. Ter seus projetos em um repositório git serve tanto para o controle das mudanças quanto como backup, além de ser requisito mínimo para a maioria das vagas atualmente.
O processo descrito aqui tem várias vantagens sobre o método antigo de subir arquivo por arquivo em um programa de SFTP como FileZilla, por exemplo. O meu favorito é que com esse método somente os arquivos alterados serão enviados, tornando o processo mais rápido e simples. Também evitamos que pessoas diferentes sobrescrevam as mudanças umas das outras.
Usei GitHub e GitHub Actions neste post, mas existem outras alternativas disponíveis se achar necessário. O processo de enviar arquivos para um servidor através do repositório é chamado de Continuous Delivery e faz parte do conjunto Continuous Integration, Delivery e Deployment, comumente abreviados como CI/CD.
Conclusão
Nesse post vimos um método para enviar arquivos para um servidor a partir de um repositório git.
Para acessar o servidor é preciso um par de chaves SSH. A chave pública é armazenada no servidor, a privada é guardada em um segredo no GitHub.
Também vimos como é fácil criar um workflow no GitHub: basta criar um arquivo .yml
na pasta .github/workflows
. Para restringir o acesso a informações sensíveis usamos os segredos do GitHub.
A sincronização dos arquivos é feita pelo comando rsync
, que aceita vários parâmetros. Também é possível excluir arquivos da sincronização de formas diferentes: uma lista em um arquivo com o parâmetro --exclude-from
ou várias chamadas para --exclude
.
Este post é só o começo do que é possível com GitHub Actions. Também é possível usar ferramentas como o Composer ou NPM durante o processo.
Por fim, vimos porque essa forma de deployment é melhor que enviar arquivos individuais via SFTP.
Não se esqueça de compartilhar e comentar o post!
Boa dica.. mas tenho uma dúvia.
Usando actions para enviar arquivos via ftp direto do github serão enviados todos os arquivos toda vez que acionado ou é enviado apenas as alterações, inclusões e inclusões?
Oi Marcos! Se você enviar os arquivos via FTP através do GitHub, ele vai testar arquivo por arquivo. Se você seguir o post e enviar por SSH com rsync, só as modificações, inclusões e exclusões serão enviadas.
Show de bola!!! Alguma chance de fazer esse tuto em vídeo? Curto demais seus videos pois vão direto ao ponto, são rápidos, dão uma noção geral e são super bem feitos… Semm falar claro, dos conteúdos excelentes. Obrigado Felipe.
Oi Fernando! Puxa, antes de mais nada deixa eu agradecer pelo elogio! Eu gostaria de voltar com os vídeos, mas a trabalheira envolvida é demais pra minha rotina por enquanto. Quem sabe um dia? 🙂 Valeu demais, abraços!