/Desenvolvimento

voltar
/Desenvolvimento

Migrando um blog do WordPress para um contêiner Docker

PorGiovanni Bassi em

O blog Lambda3 foi migrado para uma máquina mais nova. É um WordPress, rodando numa máquina no Azure. Ele estava, inicialmente, em uma máquina pequena, e conforme a audiência foi crescendo, a máquina cresceu junto. Mas ainda estava no modelo antigo de gestão do Azure (ASM), e a máquina era menos eficiente que as mais novas, que têm SSD, entre outros pontos.

Resolvemos migrá-lo para o modelo ARM e máquinas melhores. No processo, oras, por que não colocá-lo pra rodar num contêiner com Docker? Foi exatamente o que fizemos! E este artigo é pra contar para vocês como fazer isso. Parecia meio complicado a princípio, mas foi bem tranquilo no final.

WordPress em contêiner e suas peculiaridades

O WordPress possui um repositório oficial no Docker Hub, e as imagens estão sempre taggeadas de acordo com a versão do WordPress que elas representam. Na home do repo há até indicações de como rodar um contêiner já com o MySql, e até um exemplo com docker-compose. Só que contêineres WordPress são um pouco peculiares. É importante eu fazer essa introdução para que algumas decisões que tomamos fiquem mais claras.

O WordPress possui um banco de dados para os dados estruturados, e um diretório wp-content para armazenar todo conteúdo, como imagens e arquivos em geral. É nesse diretório também que ficam os temas e plugins. Isso é ótimo, porque assumimos que tudo que está fora desse diretório é do engine do WordPress, e esse diretório mantém o estado do blog em si. Entretanto, isso não é verdade. Não é incomum plugins e temas instalarem recursos em outros diretórios do WordPress. Se todo conteúdo ficasse somente no diretório wp-content seria fácil: o diretório seria montado a partir de um volume, e poderíamos trocar a imagem de base quando quiséssemos atualizar o WordPress. Mas, como há conteúdo fora desse diretório, isso não é possível.

Outro problema é o próprio sistema de atualizações do WordPress. Ele é capaz de atualizar não só plugins, mas o WordPress em si. E quando o WordPress é atualizado, não somente os arquivos diversos do WordPress são atualizados (todos os que não estão no diretório wp-content), mas também o banco de dados. Ou seja, trocar a imagem de base do WordPress gerará um problema de inconsistência com a base de dados.

Isso quer dizer que o volume do Docker para o WordPress não pode ser somente o diretório wp-content, mas todo o conteúdo do WordPress, inclusive os arquivos do WordPress em si, e não só o conteúdo do blog. O que fica estranho depois é que, ao inspecionar o contêiner, você pode ver a versão, por exemplo, 4.2.0, mas na verdade, a versão que está rodando já foi atualizada, e agora é a 4.4.0. Mas não há como resolver esse problema. O próprio repo do Docker Hub te direciona a isso. A imagem de base e a versão servem somente para fazer o bootstrap inicial do WordPress, depois disso, não significam nada.

O interessante é que, se você montar o diretório onde o WordPress vai rodar, que é o /var/www/html (ele é baseado na imagem de PHP, e no caso estamos falando de Apache2), o contêiner vai respeitar isso e não vai sobrescrever nenhum arquivo. Guarde essa informação.

O banco de dados é um conteiner simples de MySQL. Pode ser também um MariaDb, que é um fork feito pela comunidade quando o MySQL foi parar na mão da Oracle (tire suas próprias conclusões do porquê) plenamente compatível, e é o que estou usando. A escolha é sua. Tanto o MariaDb, quanto o MySQL possuem repositórios oficiais no Docker Hub.

Preparando o banco de dados

O primeiro passo é fazer um dump do MySQL/MariaDb que contém o banco de dados atual do WordPress. Isso é bem simples, basta rodar, no server, o mysqldump:

mysqldump -u <usuario> -p<Senha> <nomedobancodedados> > /caminho/pro/backup.sql

Você também pode fazer com um server remoto, veja mais nos docs do mysqldump pra ver as opções. Isso vai gerar um dump, que você vai poder usar pra restaurar depois. É um arquivo de texto simples, você pode abri-lo pra ver o que ele gerou. No entanto, ele não contém o nome do banco, assim, abra o arquivo, e na primeira linha coloque:

use <nomedobancodedados>;

Escolhi montar o contêiner do MariaDb com um volume montado a partir do file system do host. Poderia ser também com um volume do Docker direto, não montado no host, não faria diferença. Vamos criar um server MariaDb que inicialmente não conterá nenhum dado, depois que ele subir eu vou acessá-lo e restaurar o dump, o que vai gerar os dados no volume. Assim, rodei:

docker run --name mariadbtemp -e MYSQL_ROOT_PASSWORD=<senha> -v /data/blog/mysql/:/var/lib/mysql/ -v /tmp/dump/:/backup/ -ti -d mariadb

O diretório do contêiner /var/lib/mysql é onde o MariaDb coloca os dados, e montei esse diretório no host em /data/blog/mysql. E meu dump estava em /tmp/dump que montei no contêiner no diretório /backup. Depois disso, basta acessar o contêiner, que já estava rodando:

docker exec -ti mariadbtemp /bin/bash

Com isso, estamos com um terminal dentro do contêiner que está rodando o banco de dados. Agora vamos acessar a console do MariaDb e criar o banco. Digite:

mysql -u root -p

Em seguida, digite sua senha. Você deve estar na console.

Então, crie o banco de dados:

create database <nomedobancodedados>;

E crie um usuário para acessar o banco de dados do WordPress. É importante o uso do @’%’ que identifica o usuário porque o acesso vai vir pra um ip/host que você não controlará. Se colocar @’localhost’ não vai funcionar:

GRANT ALL PRIVILEGES ON *.* To '<nomedousuario>'@'%' IDENTIFIED BY '<senha>';

(Você provavelmente não quer dar todos os privilégios a esse usuário. Estude os docs para dar as permissões mais apropriadas ao seu cenário.)

Então, saia da console, e importe o arquivo de dump que foi montado no diretório /backup:

mysql -u root -p < /backup/backup.sql

Com isso feito, você já pode matar esse contêiner. A essa altura, o banco já foi restaurado com sucesso e os arquivos já estão no volume. Não queremos manter esse mesmo contêiner porque que tem um diretório de backup montado.

docker rm -f mariadbtemp

E assim, a parte do banco está concluída.

Preparando o WordPress

O WordPress é bem simples de se preparar. Eu resolvi montar uma imagem própria porque eu tinha configurações a fazer no PHP e no Apache, assim, criei esse Dockerfile:

FROM wordpress:4.7.1-apache
COPY config/php.ini /usr/local/etc/php/conf.d/
COPY config/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf
VOLUME /etc/ssl/certs/wordpress/
VOLUME /etc/ssl/private/wordpress/
RUN a2enmod ssl

A notar:

  • Estou usando o WordPress com Apache;
  • Tenho um arquivo php.ini pra configurar o PHP sendo montado no local indicado no repositório do Docker Hub do Php;
  • Tenho um arquivo default-ssl.conf sendo colocado como um site habilitado no Apache, ele vai ser responsável por habilitar SSL na minha aplicação;
  • Estou colocando como volumes os diretórios pra subir os certificados SSL e a chave;
  • Estou habilitando o SSL no Apache.

Se você não quiser usar SSL e não quiser configurar o PHP, pode usar direto a imagem de base do wordpress:4.7.1-apache (ou até outra, há opções com Alpine e FPM, por exemplo).

Meu arquivo de Php.ini possui somente 3 configs para o tamanho do upload e tempo de execução:

upload_max_filesize = 10M
post_max_size = 10M
max_execution_time = 30

Além disso, você vai precisar observar o arquivo wp-config.php e notar se precisa alterar algo. Minhas informações do banco de dados mudaram. Especificamente a variável DB_HOST vai mudar – utilize MySQL para o novo nome. Vamos linkar o contêiner do MariaDb com esse nome.

Eu também precisei alterar as variável WPCACHEHOME porque eu uso o plugin WP Super Cache (que é muito bom, por sinal), e essa variável aponta o local do cache. O novo local ficou como: /var/www/html/wp-content/plugins/wp-super-cache/. E esse plugin mantinha o local também no arquivo wp-content/wp-cache-config.php, que também precisei alterar.

Tive problemas com permissões nos arquivos. Como os arquivos já existem e vão ser montados a partir do file system do host, o Apache do contêiner não conseguia acessar. No host, tive que alterar o owner dos arquivos e diretórios para www-data. Isso é no host, não no contêiner – e é antes do contêiner subir. Vá ao diretório onde os arquivos do WordPress estão e rode:

chown -R www-data:www-data /caminho/para/arquivos/do/wordpress

Executando com docker-compose

Não vamos rodar tudo na mão, né? Pra isso, tempos o docker-compose. Aqui o meu compose file:

version: '3'
services:
  wordpress:
    image: custom-wordpress
    build: .
    container_name: my-wordpress
    environment:
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: ${DB_NAME}
    links:
      - db:mysql
    ports:
      - 80:80
      - 443:443
    volumes:
      - /data/blog/html/:/var/www/html
      - /caminho/para/certs/public/:/etc/ssl/certs/wordpress
      - /caminho/para/certs/private/:/etc/ssl/private/wordpress
    restart: always
  db:
    image: mariadb
    container_name: www-mariadb
    environment:
      MYSQL_ROOT_PASSWORD: ${ROOT_DB_PASSWORD}
    volumes:
      - /data/blog/mysql/:/var/lib/mysql
    restart: always

Pra criar os contêineres a partir da configuração do compose basta rodar:

docker-compose up -d

A notar:

  • O ambiente precisa ter 4 variáveis de ambiente configuradas, as senhas do banco, o usuário e o nome do banco de dados;
  • O link nomeado do WordPress pro MariaDb, com nome MySQL, o que permitiu usar esse nome na variável do wp-config.php que mencionei anteriormente;
  • Os diretórios montados pro WordPress, tanto o que contém os arquivos do WordPress que já estavam no blog (que coloquei em /data/blog/html) e os dos certificados, conforme o Dockerfile visto anteriormente;
  • O diretório montado pro MariaDb, apontando para os dados que salvamos antes;
  • O restart: always, fundamental para que os contêineres subam junto com o host, no caso de um reinício do servidor.

Resultado

Tudo funcionou perfeitamente. Testei na minha máquina primeiro, alterando o arquivo hosts para ver se funcionava. Com o sucesso, alterei o DNS do blog pra apontar para o novo local. No Azure, configurei a política do Network Security Group para abrir somente as portas 80 e 443.

O resultado é que uma máquina menor está com um desempenho melhor. Aqui os testes do Application Insights, que testam a app a cada 5 minutos. Notem que na madrugada do dia 26/1 o desempenho melhora significativamente.

Fiz ainda um outro teste. Derrubei os contêineres, e subi do zero. Como os dados estavam em volumes, nada deveria mudar. Foi exatamente o que aconteceu. Confiança total.

Tenho agora alguns outros sites bem pequenos (perto do blog da Lambda3) pra migrar. Vou avaliar como vou entregá-los usando o mesmo host, já que antes o Apache cuidava disso. Provavelmente vou rotear pelo Azure e usar portas diferentes.

A configuração do servidor foi feita com 4 discos SSD em RAID com stripe, utilizando mdadm. Desempenho excepcional, com 4TB de espaço e custo ridiculamente baixo (só pago pelo que uso). O storage do Azure ainda me garantiu replicação em 3 locais diferentes (sem que eu precise fazer nada para isso), com garantias absurdas de precisão e segurança na persistência.

Os logs estão direcionados via fluentd para o OMS, que também roda como SASS no Azure. Aqui, um dos relatórios que ele me dá, entre os diversos logs, alertas, etc. E é super simples de configurar, é uma linha no terminal do host.

E o servidor que hospeda tudo está limpo. Nada de Apache, MariaDb etc instalado. Ele roda somente uma coisa: Docker. E para que precisaria de mais?

***

Este artigo foi produzido em parceria com a Lambda3. Leia outros conteúdos no blog da empresa: blog.lambda3.com.br

Deixe um comentário! 0

0 comentário

Comentários

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Comentando como Anônimo

leia mais
Este projeto é mantido e patrocinado pelas empresas: