A arquitetura do WordPress não favorece o uso em serviços na nuvem, mas usando volumes no Docker e um plugin para persistência de arquivos de mídia em um bucket é possível aproveitar bem os recursos da Google Cloud Platform (GCP) e GitOps. Acredito que tudo aqui possa ser replicado na AWS e outros provedores.
Os diagramas abaixo resumem a proposta (e podem ser editados no Excalidraw):
Solução (nem tão) rápida para ter o projeto online
O processo é um pouco longo, mas tentei deixar bem passo a passo para facilitar a execução.
Requisitos:
Prepare suas contas e instalações necessárias para seguir.
- Conta na GCP
- Conta no GitHub
- Docker rodando localmente
- Git CLI rodando localmente. Alternativamente, você pode usar o GitHub Desktop
- Se você for usar um domínio próprio/customizado:
Se você for adquirir um domínio na GCP
Se você vai usar um domínio ou subdomínio externo
Verifique como configurar o DNS em sua hospedagem.
Use o projeto do GitHub:
Se você usa o Git CLI
- Dê um fork no projeto do GitHub
- Crie um diretório para o projeto em seu computador
- De dentro do diretório, no terminal, use:
git init . git remote add origin https://github.com/SEUUSUARIO/alx-wp-gcp git pull origin main* Lembre-se de alterar "SEUUSUARIO" por seu nome de usuário no GitHub.
Se você usa o GitHub Desktop
- Dê um fork no projeto do GitHub
- Na página de seu fork, clique no botão verde "code" e em "Open with GitHub Desktop"
- Escolha o endereço local para salvar o projeto onde você vai trabalhar
Para rodar localmente:
- Ative o Docker
- Abra o terminal e, de dentro da pasta do projeto, digite
docker-compose up -d - Em seu navegador, acesse https://localhost
- Configure o site, plugins, tema... você pode deixar o site pronto localmente antes de subir para a nuvem
Na GCP, primeiro prepare os serviços:
Vamos iniciar ativando e configurando os serviços necessários na GCP.
- Acesse console.cloud.google.com e faça login na sua conta. Se você não tiver uma conta, crie, até aqui não há custos
- Na barra superior azul, clique ao lado da logo para selecionar/alternar projetos e, no modal que se abrirá, clique em "Novo Projeto", informe o nome e salve
- Você vai precisar ativar o faturamento clicando nos 3 pontos à direita do nome do projeto e em "Alterar faturamento". Veja como encerrar os custos futuros
- Confirme se você está no projeto correto (na barra superior azul) e ative o Cloud Storage
- Crie um "bucket", para o teste use o nome "alx-wp-gcp", como local selecione "us (várias regições dos Estados Unidos)", classe de armazenamento deve ser "Coldline", e para "Controle de acesso" selecione "Detalhado". Não altere os outros itens. Verifique as estimativas de custo no canto superior direito
- Configure acesso de leitura para todos os usuários
- Crie uma conta de serviço com papel "Administrador do Storage". Para os testes, use o nome "alx-wp-gcp-stateless"
- Gere uma chave de acesso e salve o arquivo JSON para configurar o WordPress depois
- Ative o Cloud Build
- Ative o Compute Engine
- Adicione uma rede VPC (se necessário, ative a API)
- Infome um nome
- Em "Modo de criação de sub-rede" selecione "Automática"
- Clique em "Criar"
- Ative o Cloud SQL e crie uma instância MySQL (esse é um dos recursos que deve gerar mais custos). Configure observando os itens abaixo:
- Para testes, use o ID "alx-wp-gcp" e uma senha aleatória
- Mais abaixo, escolha "Development"
- Vá até "Personalizar sua instância"
- Em "Tipo de máquina" escolha "Núcleo compartilhado"
- Em "Conexões" clique em "Adicionar rede" e informe o nome "alx-wp-gcp" e em "Rede *" informe 0.0.0.0/24
- Em "Conexões" marque a opção de IP Público
- Clique em "Adicionar rede", informe um nome e o IP "0.0.0.0/0". Esse IP permite que toda a Internet acesse a instância do banco de dados, para mais segurança você pode pesquisar o IP da instância Cloud Run (após criá-la) e substituir
- Em "Armazenamento" escolha "10 GB"
- Na página após salvar, procure e copie o "Endereço IP público" para usar depois no Cloud Run
- Instância criada (pode demorar de 10 a 20 minutos), crie um banco de dados com o nome "alx-wp-gcp"
- Crie um usuário para acesso ao banco, evite usar o root. Copie usuário e senha para usar depois
- Ative a Cloud SQL Admin API
- Acesse o IAM Admin
- Em "Conta de serviço padrão do Compute Engine" (ou "Compute Engine default service account"), clique no ícone do lápis
- Clique em "Adicionar outro papel"
- Adicione o papel "Cliente do Cloud SQL"
- Clique em "Salvar"
Configure o Cloud Run:
Considero o Cloud Run o centro de todo esse processo, todos os serviços e procedimentos visam dar suporte ao site que vai estar em containers rodando nesse serviço.
- acesse a página do Cloud Run e confirme se você está no projeto correto (veja na barra superior azul)
- Clique em "Criar serviço"
- Selecione "Implantar continuamente novas revisões de um repositório de origem" e "Configurar com Cloud Build"
- Em "Provedor de repositório" mantenha o GitHub e selecione o repositório "alx-wp-gcp", o qual você deu um "fork" antes. Clique em "Próxima", na "Ramificação" informe "^dev$" e em "Build type" informe "Dockerfile", não altere o "Local de origem". Clique em "Salvar"
- Em "Número máximo de instâncias" altere para 1
- Em "Autenticação" selecione "Permitir invocações não autenticadas"
- Clique em "Contêiner, conexões, segurança" e em "Capacidade" altere para 128MiB (ou a menor que houver)
- Na aba "Conexões", siga esses pasoss:
- No item "Conexões do Cloud SQL", clique em "Adicionar conexão"
- Clique em "Cloud SQL Admin API"
- Em "Instância do Cloud SQL 1", selecione a instância criada anteriormente
- Em "Variáveis de ambiente" informe os valores abaixo ou os que você tiver definido no Cloud SQL:
- WORDPRESS_DATABASE_NAME: alx-wp-gcp
- WORDPRESS_DATABASE_USER: alx-wp-gcp
- WORDPRESS_DATABASE_PASSWORD: INFORME-A-SENHA-DO-BANCO-DE-DADOS
- WORDPRESS_DATABASE_HOST: IP-PÚBLICO-DA-INSTÂNCIA-CLOUD-SQL
- Em seu projeto local, arquivo
/app_data/config/wp-config.staging.php, insira, também, as informações do Cloud SQL:- DB_NAME: alx-wp-gcp
- DB_USER: alx-wp-gcp
- DB_PASSWORD: INFORME-A-SENHA-DO-BANCO-DE-DADOS
- DB_HOST: IP-PÚBLICO-DA-INSTÂNCIA-CLOUD-SQL
- Na tela de "Detalhes do serviço" você já vai encontrar a URL de sua instalação. Para saber qual é a URL e outras informações acesse a tela inicial do Cloud Run e clique sobre o nome da instância
- Atenção: não prossiga com a instalação do WordPress, vamos usar os dados existentes e que você pode ter trabalhado em sua instalação local
Carregando os dados
Agora você precisa migrar o banco de dados de sua instalação local para a instalação da GCP e subir as imagens da pasta /wp-content/uploads.
Exporte os dados de sua instalação local:
- Confirme o endereço de sua instalação na GCP. Se você usar um domínio próprio, ele é o endereço correto, senão, siga essa orientação para descobrir a URL
- Faça login na instalação local com os dados que já informamos e acesse a página de exportação do plugin "WP Migrate Lite"
- Clique em "+ New migration", depois em "Export database" e configure conforme abaixo:
- Em "Advanced options" desmarque a opção "Compress file with gzip" (costuma dar problema)
- Em "Custom Find & Replace" informe o endereço da instalação da GCP ao lado de "//localhost" iniciando o endereço com duas barras (ex.: //alexlana.dev.br)
- Clique no "X" para remover as outras duas linhas
- Clique em "Export database". Localize o arquivo SQL salvo para a próxima etapa
Importe os arquivos da pasta /wp-content/uploads
- Acesse o Cloud Storage
- Entre no bucket criado em passos anteriores
- Arraste tudo dentro da pasta local "local_persistence/uploads" para a janela da GCP e aguarde até finalizar o upload. Essa pasta na pasta do projeto local é um volume para a "wp-content/uploads"
Importe os dados para o Cloud SQL:
- Ainda na página do bucket (Cloud Storage) envie o arquivo SQL exportado da instalação local
- Acesse o Cloud SQL, clique sobre o nome de sua instância e siga os próximos passos
- Clique em "Importar"
- Selecione o arquivo SQL enviado para o bucket
- Seleciona o banco de dados criado
- Clique no botão "Importar"
- Após concluir a importação, pode apagar o arquivo SQL no bucket
Agora você já pode acessar a URL do site na GCP. Se tudo deu certo, o site já estará rodando normalmente.
Faça as últimas configurações no WordPress
- Acesse a administração do WordPress (diretório /wp-admin)
- Acesse o menu "Plugins"
- Ative o plugin "WP-Stateless"
- No menu "Mídia" > "Stateless Settings", configure dessa forma:
- Em "General", selecione "Stateless"
- Em "File URL Replacement", selecione "Enable editor & meta"
- Em "Bucket", informe o nome "alx-wp-gcp"
- Em "Service Account JSON", cole o conteúdo do arquivo JSON gerado ao criar as chaves de acesso ao bucket
- Salve as alterações
- Para testar, envie uma imagem no gerenciador de mídia e verifique se o endereço da imagem enviada contém o domínio
Serviços para melhorar a performance e a segurança de sua aplicação
Você não precisa desses serviços para ter o site rodando e eles geram custos extras, mas eles devem conferir uma melhor qualidade à sua aplicação.
Rede interna
Para mais segurança você pode usar uma rede interna e ajustar configurações do Cloud SQL e do Cloud Run para utilizá-la. Atenção aos custos extras.
- Crie um conector para a rede VPC
- Informe um nome
- Em "Rede", selecione a rede criada anteriormente
- Em "Sub-rede", selecione "Intervalo de IP personalizado"
- Em "Intervalo de IP", informe 10.8.0.0 (se houver erro, tente usar outro IP, como 10.7.0.0, por exemplo)
- Clique em "Criar"
- Acesse a página de detalhes de sua instância do Cloud Run
- Clique em "Editar e implantar uma nova revisão" no topo
- Em "Contêiners", troque o valor de WORDPRESS_DATABASE_HOST para :/cloudsql/NOME-DA-CONEXÃO-SQL (você vai encontrar esse nome na página de detalhes da instância Cloud SQL criada)
- Em "Conexões", no item "VPC" selecione a rede VPC criada anteriormente
- Clique em "Implantar"
- Acesse o Cloud SQL e selecione a instância criada
- Clique em "Editar"
- Em "Conexões", marque "IP Particular", selecione a rede VPC criada anteriormente e desmarque a opção "IP Público"
- Clique em "Salvar"
Load balancing
Configurar um load balancer e uma CDN (Rede de Distribuição de Conteúdo, "Content Distribution Network", em inglês) vai melhorar muito a performance de sua aplicação. Mas atenção, esses serviços têm um custo extra.
Se você tiver um domínio que possa usar nos testes, configure um balanceador de carga e uma CDN, e aponte o domínio/subdomínio para a GCP.
Configurando o Load Balancer e a CDN
- Início da configuração:
- Busque por "load balancing" na caixa de busca no topo do site da GCP
- Na página do "Balanciamento de carga", clique em "Criar balanceador de carga"
- Na próxima tela, clique em "Iniciar configuração"
- Depois selecione "Da internet para VMs ou serviços sem servidor" e "Balanceador de carga HTTP(S) global" e clique em "Continuar"
- Na tela "Novo balanceador de carga de HTTPS(S)", informe "Nome" (campo à esquerda)
- Em "Configuração de front-end":
- Informe "Nome"
- Selecione protocolo "HTTPS (inclui HTTP/2)"
- Em "IP Address" escolha "Criar endereço IP" e informe um nome
- Em "Certificado", clique em "Criar um novo certificado" para enviar um certificado próprio, ou solicitar um gerenciado pelo Google, além de informar o domínio que será usado
- Selecione "Ativar redirecionamento de HTTP para HTTPS"
- Clique em "Concluir"
- Em "Configuração de back-end":
- Clique em "Criar um serviço de back-end"
- Informe um "Nome"
- Em "Tipo de back-end" selecione "Grupo de endpoints de rede sem servidor"
- Em "Novo back-end" clique em "Criar grupo de endpoints de rede sem servidor" e configure:
- Informe "Nome"
- Selecione a "Região" "us-central1 (Iowa)"
- Em "Tipo de grupo de endpoints de rede sem servidor" selecione "Cloud Run"
- Selecione o serviço criado na Cloud Run anteriormente
- Selecione "Ativar o Cloud CDN"
- Configure o cache de acordo com as necessidades de seu projeto (cuidado: estude e teste bastante se seu site mostra dados pessoais de um usuário para evitar que esses dados apareçam para outros usuários)
- Clique em "Criar"
- Em "Regras de roteamento" não é necessário alteração
- Revise em "Analisar e finalizar" e clique em "Criar"
- Siga os próximos passos para configuração do DNS o mais rápido possível para ativação correta do certificado
Se o domínio não foi comprado na GCP, configure o DNS da hospedagem do domínio
- Assim que o serviço de Load Balancing for criado na GCP, você pode visualizar o IP em "Front-end" (é mostrado o par "IP:Porta", só o IP importa para configuração), copie o IP
- Na hospedagem do domínio, procure a edição de DNS (ou zona DNS). Cada hospedagem tem sua própria interface, informe-se com o suporte da hospedagem se tiver dúvidas
- Na linha correspondente ao domínio principal, informe o IP da GCP e salve
Por fim, aguarde a ativação do certificado, o status "Provisioning" indica que ainda não foi gerado. O "Active" indica que seu site já deve estar acessível e para outros status será importante você verificar o erro para corrigir.
Sobre GitOps
Originalmente, o WordPress conta com facilidades para atualização do sistema, sendo possível atualizar o próprio WordPress, temas e plugins a partir da área de administração. Mas isso gera indisponibilidade e, eventualmente, cria bugs, podendo até derrubar o site permanentemente. Outra desvantagem é um prejuízo para o histórico de versões da aplicação.
Isso é um dos pontos a ser resolvido por este projeto. Se vamos tentar usar cada vez melhor a infraestrutura de nuvem, também podemos utilizar de forma mais eficiente os recursos de GitOps dessas plataformas.
As características do repositório listadas abaixo possibilitam ter uma melhor rotina de atualizações:
- A versão do WordPress é escolhida a partir das imagens da Bitnami disponíveis e é informada no
Dockerfile - Os plugins são instalados e testados localmente antes de subirem para staging / homologação e produção
- Arquivos de mídia são armazenados em um bucket com a utilização de plugin apropriado (para a GCP estou usando o WP-Stateless)
- Banco de dados não é atualizado quando os arquivos do sistema são atualizados, a menos que o próprio WordPress ou plugins necessitem. Isso evita sobrepor os dados da aplicação em produção, mas também é um ponto de atenção, é importante ter um backup do banco em produção antes de atualizar
Passo a passo
A rotina de atualização deve ocorrer normalmente como ocorre quando se utiliza frameworks e CMSs nascidos na era da nuvem:
- Utilizamos desenvolvimento local com Docker com Docker Compose e branchs separados por desenvolvedor para criação de novas ferramentas ou atualizações de CMS e plugins
- Se tudo estiver ok com a evolução do sistema em testes locais, podemos criar uma pull request para o branch de staging
- Se não houver indicação de problemas no merge, faça primeiro um backup do banco de dados do ambiente a ser atualizado online
- Aprove a pull request e ela será enviada automaticamente para o ambiente de staging. Uma sugestão que considero importante tanto no ambiente de staging, quanto no de produção: configure seu serviço na Cloud Run, na aba "Revisões", em "Gerenciar tráfego" para fazer manualmente o gerenciamento das versões:
- Não utilize a opção "Latest healthy revision", ao invés disso, selecione manualmente qual revisão deve ficar acessível
- Ao lado direito de cada revisão, ao passar o mouse por cima, você vai ver o ícone "+". Ele serve para gerar um endereço para você fazer um primeiro teste da nova revisão sem afetar os serviço disponível para o público
- Se tudo estiver ok você pode passar a distribuir a nova revisão e, se o serviço for crítico, você pode substituir gradualmente a revisão antiga pela nova definindo o percentual de entrega de cada uma até substituir 100%
- Atenção à questão do banco de dados, se WordPress ou algum plugin precisarem atualizar o banco, essa transição aos poucos pode gerar comportamentos inesperados
- Se tudo correr bem em staging, envie um pull request para produção e siga os mesmos passos
Dessa forma você e sua equipe terão um registro das versões, possibilidade de testar a aplicação o suficiente antes de liberar para o público, possibilidade de verificar erros durante o merge e facilidade em efetuar o roll back do ambiente online se necessário (veja em seu serviço na Cloud Run, aba "Revisões").
Sobre as escolhas feitas
Pela praticidade, utilizei uma imagem Docker da Bitnami que contém Nginx, PHP-FPM e WordPress, o que permitiu acelerar a conclusão do projeto. No futuro, penso em testar o uso de containers Nginx e WordPress separados, porque acredito que a separação pode melhorar os tempos do cold start ao trabalhar com o cache do Nginx, talvez, em um volume.
Arquivos de configuração e inicialização do container
Algumas escolhas não usuais foram feitas com relação ao wp-config.php (arquivo de configuração do WordPress) e aos entrypoints.
Como padrão, a Bitnami fornece a possibilidade de variáveis de ambiente para configurar o wp-config.php, mas, em testes que fiz, a utilização dessas variáveis aumentou consideravelmente o tempo do cold start. Acredito que será necessário fazer novos testes agora que a solução está finalizada. No estágio atual do projeto é necessário ter atenção extra a um problema de segurança que foi criado com essa escolha se formos displicentes: é importantíssimo que repositórios Git sejam privados, se forem públicos vão expor os dados de acesso ao banco de dados e outros, os dados também ficam expostos para toda a equipe de desenvolvimento.
Outro ponto de atenção é que removi o teste de acesso ao banco de dados no arquivo libwordpress.sh e isso também cortou tempo do cold start. Pelo que pude verificar, mesmo sem esse teste o pod não sobe na GCP. Caso a conexão não ocorra a versão fica marcada como "falha". De qualquer forma, acompanhe o processo de criação das revisões da Cloud Run.
Durante o início do desenvolvimento foi muito comum receber um erro 502 no cold start. Esse foi o motivo para alteração do entrypoint /nginx-php-fpm/run.sh e inclusão do /php/wait.sh. Vi que antecipar a execução de um comando simples do PHP-FPM resolve esse problema.