Fazendo deploy de aplicações Yii no Docker Swarm com Caddy
Este guia mostra como fazer o deploy de uma aplicação Yii no Docker Swarm a partir de um servidor vazio, usando o Caddy como proxy reverso e fazendo o deploy a partir de um registro de containers (Forgejo ou Gitea).
graph LR
A[Internet] --> B[Proxy reverso: Caddy]
B --> C[app1.example.com]
B --> D[app2.example.com]
subgraph Docker Swarm Cluster
B
C
D
endPré-requisitos
- Um servidor com uma distribuição Linux recém-instalada (recomendado Ubuntu 22.04 LTS ou mais recente)
- Um nome de domínio apontando para o IP do seu servidor
- Acesso SSH ao seu servidor
- Conhecimento básico de Docker e de ferramentas de linha de comando
Preparando o servidor
Instale o Docker
Para as instruções de instalação, veja a documentação oficial do Docker.
Inicialize o Docker Swarm
Inicialize o seu servidor como manager do Docker Swarm:
docker swarm init --advertise-addr <YOUR_SERVER_IP>Substitua <YOUR_SERVER_IP> pelo IP público do seu servidor.
Configure a rede do proxy reverso
Crie uma rede overlay dedicada para o proxy reverso se comunicar com os seus serviços:
docker network create --driver=overlay reverse_proxy_publicConfigurando o Caddy como proxy reverso
Para fazer o deploy do Caddy como proxy reverso, crie um arquivo caddy-stack.yml:
services:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy_data:/data
networks:
- reverse_proxy_public
volumes:
caddy_data:
networks:
reverse_proxy_public:
external: trueFaça o deploy do Caddy:
docker stack deploy -c caddy-stack.yml caddyO Caddy descobre automaticamente os serviços com labels do Caddy e configura HTTPS usando o Let's Encrypt. Os templates de aplicação do Yii3 usam labels do Caddy por padrão:
deploy:
labels:
- caddy: ${PROD_HOST:-app.example.com}
- caddy.reverse_proxy: "{{upstreams 80}}"IMPORTANT
Garanta que os registros DNS do seu domínio estejam configurados e apontando para o seu servidor antes de fazer o deploy de serviços com labels do Caddy, porque o Let's Encrypt exige a validação do domínio.
Configurando um registro de containers
Você precisa de um registro de containers para guardar as suas imagens Docker. Escolha uma das opções a seguir.
Opção 1: usando o Forgejo
Para fazer o deploy do Forgejo, crie um arquivo forgejo-stack.yml:
services:
forgejo:
image: codeberg.org/forgejo/forgejo:1.21
ports:
- "3000:3000"
volumes:
- forgejo_data:/data
networks:
- reverse_proxy_public
deploy:
labels:
- "caddy=git.example.com"
- "caddy.reverse_proxy={{upstreams 3000}}"
volumes:
forgejo_data:
networks:
reverse_proxy_public:
external: trueFaça o deploy do Forgejo:
docker stack deploy -c forgejo-stack.yml forgejoSubstitua git.example.com pelo subdomínio desejado.
Depois do deploy, acesse o Forgejo em https://git.example.com e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações.
Opção 2: usando o Gitea
Para fazer o deploy do Gitea, crie um arquivo gitea-stack.yml:
services:
gitea:
image: gitea/gitea:latest
ports:
- "3000:3000"
volumes:
- gitea_data:/data
networks:
- reverse_proxy_public
deploy:
labels:
- "caddy=git.example.com"
- "caddy.reverse_proxy={{upstreams 3000}}"
volumes:
gitea_data:
networks:
reverse_proxy_public:
external: trueFaça o deploy do Gitea:
docker stack deploy -c gitea-stack.yml giteaSubstitua git.example.com pelo subdomínio desejado.
Depois do deploy, acesse o Gitea em https://git.example.com e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações.
Configurando a sua aplicação Yii
Atualize a configuração do Makefile
O template de aplicação do Yii inclui um Makefile com comandos de deploy. Atualize o arquivo docker/.env do seu projeto:
STACK_NAME=myapp
#
# Produção
#
PROD_HOST=app.example.com
PROD_SSH="ssh://user@your-server-ip"
IMAGE=git.example.com/username/myapp
IMAGE_TAG=latestSubstitua os valores: - STACK_NAME: um nome único para a stack da sua aplicação - PROD_HOST: o nome de domínio em que a aplicação vai ficar acessível - PROD_SSH: a string de conexão SSH com o seu servidor (formato: ssh://user@host) - IMAGE: o caminho completo da imagem do container no registro - IMAGE_TAG: a tag da imagem, normalmente latest ou um número de versão
Configure o ambiente de produção
Atualize o docker/prod/.env com as variáveis de ambiente de produção:
APP_ENV=prod
YII_DEBUG=false
YII_ENV=prod
# Configuração do banco de dados
DB_HOST=db
DB_NAME=myapp
DB_USER=myapp
DB_PASSWORD=secure_password_here
# Adicione outras variáveis específicas do ambienteWARNING
Nunca faça commit de credenciais sensíveis no controle de versão. Use docker/prod/override.env para valores sensíveis e adicione-o ao .gitignore.
Revise a configuração do Docker Compose de produção
O docker/prod/compose.yml padrão inclui:
services:
app:
image: ${IMAGE}:${IMAGE_TAG}
networks:
- reverse_proxy_public
volumes:
- runtime:/app/runtime
- caddy_data:/data
- caddy_config:/config
env_file:
- path: ./prod/.env
- path: ./prod/override.env
required: false\
environment:
CADDY_EXTRA_CONFIG: 'auto_https off'
deploy:
replicas: 2
update_config:
delay: 10s
parallelism: 1
order: start-first
failure_action: rollback
monitor: 10s
rollback_config:
parallelism: 0
order: stop-first
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
labels:
caddy: ${PROD_HOST:-app.example.com}
caddy.reverse_proxy: "{{upstreams 80}}"Essa configuração:
- Roda 2 réplicas para alta disponibilidade
- Usa uma estratégia de rolling update com rollback automático em caso de falha
- Configura
labelspara HTTPS automático no proxy reverso - Desabilita a obtenção de certificados HTTPS no próprio container, já que o proxy se comunica com o container via HTTP. Isso é o
auto_https off.
Se você precisa de um banco de dados, adicione-o à stack:
services:
app:
# ... configuração existente ...
db:
image: postgres:18-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_INITDB_ARGS: "--locale-provider=icu --icu-locale=und --encoding=UTF8"
volumes:
- db_data:/var/lib/postgresql
networks:
- reverse_proxy_public
deploy:
placement:
constraints:
- node.role == manager
secrets:
- db_password
volumes:
runtime:
db_data:
secrets:
db_password:
external: trueCrie o secret com a senha do banco de dados no servidor:
echo "your_secure_password" | docker secret create db_password -Construindo e enviando a imagem
Configure o login do Docker na sua máquina local
Configure o Docker para se autenticar no seu registro de containers:
docker login git.example.comInforme o seu usuário e a sua senha quando solicitado.
Construa a imagem de produção
Use o Makefile para construir a imagem de produção:
make prod-buildIsso executa o comando definido no Makefile:
docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} .O Dockerfile usa um build multi-stage: 1. Instala as dependências do Composer em um estágio de build 2. Cria uma imagem de produção mínima, só com os arquivos necessários 3. Roda como um usuário não root (www-data)
Envie a imagem para o registro
Envie a imagem construída para o registro de containers:
make prod-pushIsso executa:
docker push ${IMAGE}:${IMAGE_TAG}Fazendo deploy no Docker Swarm
Configure o acesso SSH
Configure a autenticação por chave SSH no seu servidor:
# Gera uma chave SSH (se você ainda não tiver uma)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Copia a chave para o seu servidor
ssh-copy-id user@your-server-ip
# Adiciona o host SSH à sua configuração SSH (~/.ssh/config)
cat >> ~/.ssh/config << EOF
Host docker-web
HostName your-server-ip
User user
IdentityFile ~/.ssh/id_ed25519
EOFConfigure o contexto do Docker
Crie um contexto do Docker para o deploy remoto:
docker context create swarm-prod --docker "host=ssh://docker-web"Como alternativa, configure a variável de ambiente DOCKER_HOST:
export DOCKER_HOST=ssh://docker-webFaça o deploy da aplicação
Faça o deploy da stack da sua aplicação no Docker Swarm:
make prod-deployIsso executa:
docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME}A flag --with-registry-auth garante que os nós do Swarm consigam baixar imagens do seu registro privado.
Verifique o deploy
Verifique o status dos seus serviços:
docker -H ssh://docker-web service ls
docker -H ssh://docker-web service ps ${STACK_NAME}_appVeja os logs:
docker -H ssh://docker-web service logs ${STACK_NAME}_appMonitoramento e manutenção
Veja os logs do serviço
# Mostra todos os logs
docker -H ssh://docker-web service logs -f ${STACK_NAME}_app
# Mostra as últimas 100 linhas de log
docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app
# Mostra os logs com timestamps
docker -H ssh://docker-web service logs -t ${STACK_NAME}_appEscale a aplicação
Ajuste o número de réplicas:
docker -H ssh://docker-web service scale ${STACK_NAME}_app=3Ou atualize o valor de replicas em docker/prod/compose.yml e faça o deploy de novo.
Limites de recursos
Adicione limites de recursos para evitar que os containers consumam todos os recursos do servidor. Atualize o docker/prod/compose.yml:
services:
app:
# ... configuração existente ...
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256MConsiderações de segurança
Use Docker secrets para dados sensíveis
Em vez de variáveis de ambiente, use Docker secrets para informações sensíveis:
# Cria os secrets
echo "database_password" | docker secret create db_password -
echo "api_key" | docker secret create api_key -Atualize o docker/prod/compose.yml:
services:
app:
secrets:
- db_password
- api_key
secrets:
db_password:
external: true
api_key:
external: trueAcesse os secrets na sua aplicação em /run/secrets/secret_name.
Configure um firewall
Configure o UFW (Uncomplicated Firewall) no seu servidor:
# Libera SSH
sudo ufw allow 22/tcp
# Libera HTTP e HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Libera as portas do Docker Swarm (se você pretende adicionar mais nós)
sudo ufw allow 2377/tcp
sudo ufw allow 7946/tcp
sudo ufw allow 7946/udp
sudo ufw allow 4789/udp
# Habilita o firewall
sudo ufw enableMantenha o sistema atualizado
Atualize regularmente o seu servidor e o Docker:
# Atualiza os pacotes do sistema
sudo apt-get update && sudo apt-get upgrade -y
# Atualiza as imagens Docker
docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_appSolução de problemas
O serviço não sobe
Verifique os eventos e os logs do serviço:
docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc
docker -H ssh://docker-web service logs ${STACK_NAME}_appProblemas comuns: - Erros ao baixar a imagem: verifique a autenticação no registro com docker -H ssh://docker-web login - Conflitos de porta: garanta que nenhum outro serviço esteja usando as portas 80/443 - Limitação de recursos: verifique os recursos disponíveis com docker -H ssh://docker-web node ls
Problemas com certificados SSL
Se o Caddy não consegue obter os certificados: - Verifique se o DNS aponta para o seu servidor - Verifique se as portas 80 e 443 estão acessíveis pela internet - Garanta que o e-mail na configuração do Let's Encrypt é válido - Verifique os logs: docker -H ssh://docker-web service logs caddy
Problemas de conexão com o registro de containers
Teste a conectividade com o registro:
# Na sua máquina local
docker pull git.example.com/username/myapp:latest
# No servidor
docker -H ssh://docker-web pull git.example.com/username/myapp:latestResumo
Você fez o deploy de uma aplicação Yii no Docker Swarm com: - Um registro de containers (Forgejo ou Gitea) - HTTPS automático via Caddy - Deploys sem downtime com rolling updates - Alta disponibilidade com várias réplicas
Os comandos do Makefile simplificam o fluxo de deploy: - make prod-build - Constrói a imagem de produção - make prod-push - Envia para o registro - make prod-deploy - Faz o deploy no Docker Swarm
Para mais informações, veja: - Template de aplicação do Yii - Documentação do Docker Swarm - Caddy Docker Proxy