Como Configurar um Site WordPress Altamente Disponível do Zero, Parte 3: Ansible e Dependências

Nesta série de tutoriais, estamos a criar um site WordPress altamente disponível do zero.

Vamos usar o Ansible, uma ferramenta fantástica para gerir sistemas e aplicações. Poderia instalá-lo no node1 e usá-lo para controlar os três nós, mas eu já tenho um master do Ansible que estou a utilizar. Isso realmente não faz diferença.

Para instalar o Ansible:

Bash
apt install ansible

Instalando Dependências Adicionais

Será preciso alguns pacotes e módulos adicionais:

Bash
sudo apt install python3-pip
pip3 install ansible[community]

Nota: O módulo community.general.timezone faz parte da collection community.general. Para usá-lo, instale a collection com o seguinte comando:

Bash
ansible-galaxy collection install community.general

Para os módulos relacionados ao MySQL/MariaDB, como mysql_db e mysql_user, instale a collection community.mysql:

Bash
ansible-galaxy collection install community.mysql

Se for a utilizar o GlusterFS, adicione o repositório do GlusterFS e instale o servidor:

Bash
sudo add-apt-repository ppa:gluster/glusterfs-11
sudo apt update
sudo apt install glusterfs-server

Para o Certbot e os módulos do Let’s Encrypt:

Bash
sudo apt install certbot python3-certbot-nginx

Configuração do Ansible

No meu master do Ansible, tenho um sistema de ficheiros montado em /ansible que contém tudo o que preciso. No entanto, se instalar o Ansible a partir do apt, ele configura várias coisas em /etc/ansible, então vamos usar isso.

Aqui está o meu ficheiro /etc/ansible/hosts:

Bash
[nodes]
node1.homeserver.pt
node2.homeserver.pt
node3.homeserver.pt

O que isto faz é criar um grupo chamado “nodes” que tem os nossos três nós. Certifique-se de que estes nós estão no DNS, ou pode criar entradas em /etc/hosts como estas:

Bash
123.456.789.123 node1.homeserver.pt node1
456.123.456.789 node2.homeserver.pt node2
789.123.456.789 node3.homeserver.pt node3

No ficheiro /etc/ansible/ansible.cfg, não deverá ser necessário fazer alterações.

Agora, vamos ao que interessa, o playbook em si. No Ansible, um playbook é uma lista de tarefas (e outras coisas, mas estamos focados nas tarefas aqui) que serão realizadas. Vamos chamar ao nosso playbook wordpress_ha.yml. O .yml indica que o ficheiro está no formato YaML.

Aqui está o playbook:

Bash
---
  - name: configurar nós HA WordPress
    hosts: nodes
    tasks:
      - name: hostname
        hostname: name={{ ansible_host }}
      - name: /etc/hostname
        lineinfile:
          path=/etc/hostname line="{{ ansible_host }}" create=yes
      - name: geração de locale
        locale_gen: name=en_US.UTF-8 state=present
      - name: apt-get update
        apt: update_cache=yes
      - name: upgrade
        apt: upgrade=dist
      - name: pacotes apt
        apt: name=nginx,mariadb-server,php-fpm,php-mysql,python3-pymysql,python3-pexpect,glusterfs-server,rsyslog,parted,certbot,python3-certbot-nginx
      - name: Definir timezone para US/Pacific
        community.general.timezone:
          name: US/Pacific
      - name: modificações em /etc/profile
        blockinfile:
          path: /etc/profile
          block: |
            alias ll='ls -al'
            set -o vi
      - name: executar mysql_secure_installation
        expect:
          command: mysql_secure_installation
          responses:
            'Enter current password for root': ''
            'Switch to unix_socket authentication': 'Y'
            'Change the root password': 'Y'
            'Set root password': 'Y'
            'New password': 'StrongPassword'
            'Re-enter new password': 'StrongPassword'
            'Remove anonymous users': 'Y'
            'Disallow root login remotely': 'Y'
            'Remove test database': 'Y'
            'Reload privilege tables now': 'Y'
          timeout: 1
      - name: criar base de dados wp
        mysql_db: login_user=root login_password="StrongPassword" name=wp state=present collation=utf8_general_ci
      - name: criar utilizador da base de dados
        mysql_user: login_user=root login_password="StrongPassword" name=wp password=ComplexPassword priv=wp.*:ALL host=localhost 
      - name: logrotate nginx
        copy: src=/ansible/src/nodes/nginx_diretorios_web dest=/etc/logrotate.d owner=root group=root mode=0644 force=yes 
      - name: nginx www.homeserver.pt
        copy: src=/ansible/src/nodes/www.homeserver.pt dest=/etc/nginx/sites-available owner=root group=root mode=0644 force=yes 
      - name: criar symlink sites-enabled
        file: src=/etc/nginx/sites-available/www.homeserver.pt dest=/etc/nginx/sites-enabled/www.homeserver.pt state=link
      - name: diretório de logs nginx
        file: path=/var/log/nginx/www.homeserver.pt state=directory owner=www-data group=adm mode=0775 
      - name: log de acesso nginx
        file: path=/var/log/nginx/www.homeserver.pt/access.log state=touch owner=www-data group=adm mode=0664 state=touch
      - name: log de erro nginx
        file: path=/var/log/nginx/www.homeserver.pt/error.log state=touch owner=www-data group=adm mode=0664 state=touch
      - name: nginx /web
        file: path=/web state=directory owner=www-data group=adm mode=0775 
      - name: nginx /web/www.homeserver.pt
        file: path=/web/www.homeserver.pt state=directory owner=www-data group=adm mode=0775 
      - name: reiniciar nginx
        service: name=nginx enabled=yes state=restarted
      - name: ponto de montagem gluster
        file: path=/gluster state=directory owner=root group=root mode=0777

Vamos detalhar isto passo a passo.

Bash
---
  - name: configurar nós HA WordPress
    hosts: nodes

O parâmetro name: é apenas uma descrição para o playbook. O parâmetro hosts: indica a que grupo em /etc/ansible/hosts ele será aplicado.

Bash
    tasks:
      - name: hostname
        hostname: name={{ ansible_host }}
      - name: /etc/hostname
        lineinfile:
          path=/etc/hostname line="{{ ansible_host }}" create=yes

Cada comando Ansible utiliza um dos módulos do Ansible. Não é necessário escrever o seu próprio código Bash ou algo semelhante, mas sim passar argumentos para os módulos Ansible, que fazem todo o trabalho. Isso liberta-o da preocupação com a sintaxe, lógica, citação, etc.

Aqui utilizamos o módulo hostname, dando-lhe a variável Ansible “ansible_host”. Esta variável será node1.homeserver.pt, etc., e este módulo definirá o nome de host do sistema de forma apropriada.

Em seguida, utilizamos o módulo “lineinfile” para garantir que o nome de host está em /etc/hostname (uma prática comum no Debian) para que a máquina sempre reconheça o seu nome de host correto ao iniciar.

Bash
      - name: geração de locale
        locale_gen: name=en_US.UTF-8 state=present

A seguir, geramos os locales apropriados para o nosso ambiente, garantindo que o en_US.UTF-8 esteja selecionado. Obviamente, ajuste conforme as suas necessidades.

Bash
      - name: apt-get update
        apt: update_cache=yes
      - name: upgrade
        apt: upgrade=dist
      - name: pacotes apt
        apt: name=nginx,mariadb-server,php-fpm,php-mysql,python3-pymysql,python3-pexpect,glusterfs-server,rsyslog,parted,certbot,python3-certbot-nginx

Aqui estamos usando o módulo apt do Ansible para fazer três coisas:

  1. apt-get update
  2. apt-get upgrade
  3. Instalar alguns pacotes apt que precisaremos. Se deseja usar o rsyslog, é uma escolha sua. Pessoalmente, prefiro ter logs em texto tradicional em vez de usar o journalctl para tudo, mas é uma decisão sua.
Bash
      - name: Definir timezone para Europe/Lisbon
        community.general.timezone:
          name: Europe/Lisbon

Aqui definimos o fuso horário. Ajuste conforme o seu gosto.

Bash
      - name: modificações em /etc/profile
        blockinfile:
          path: /etc/profile
          block: |
            alias ll='ls -al'
            set -o vi

Deixei isto como exemplo, mas é totalmente opcional. Gosto de ter essas duas linhas no meu /etc/profile porque, independentemente do utilizador com que estou a trabalhar, quero ter esse alias e opção definidos. O módulo blockinfile garante que o bloco (os dois comandos listados aqui) está presente no ficheiro especificado, neste caso /etc/profile.

Bash
      - name: executar mysql_secure_installation
        expect:
          command: mysql_secure_installation
          responses:
            'Enter current password for root': ''
            'Switch to unix_socket authentication': 'Y'
            'Change the root password': 'Y'
            'Set root password': 'Y'
            'New password': '

StrongPassword'
            'Re-enter new password': 'StrongPassword'
            'Remove anonymous users': 'Y'
            'Disallow root login remotely': 'Y'
            'Remove test database': 'Y'
            'Reload privilege tables now': 'Y'
          timeout: 1

Ao instalar o MySQL (na verdade, MariaDB), é recomendado executar o mysql_secure_installation. Mas, em vez de fazer isso manualmente, usaremos o módulo expect do Ansible. Indica-se o comando a ser executado e uma lista do que se espera como saída e as respostas a dar. Esta secção percorre as perguntas do mysql_secure_installation e fornece as respostas apropriadas. Claro, deve substituir StrongPassword por uma palavra-passe realmente forte!

Bash
      - name: criar base de dados wp
        mysql_db: login_user=root login_password="StrongPassword" name=wp state=present collation=utf8_general_ci
      - name: criar utilizador da base de dados
        mysql_user: login_user=root login_password="StrongPassword" name=wp password=ComplexPassword priv=wp.*:ALL host=localhost 

Aqui criamos uma base de dados MariaDB para o WordPress, um utilizador para essa base de dados e concedemos as permissões apropriadas. Note que mesmo que execute este playbook várias vezes, o Ansible é inteligente o suficiente para primeiro verificar se a base de dados existe e não gerar erro ao tentar recriá-la, etc.

Bash
      - name: logrotate nginx
        copy: src=/ansible/src/nodes/nginx_diretorios_web dest=/etc/logrotate.d owner=root group=root mode=0644 force=yes 
      - name: nginx www.homeserver.pt
        copy: src=/ansible/src/nodes/www.homeserver.pt dest=/etc/nginx/sites-available owner=root group=root mode=0644 force=yes 

Aqui estamos a distribuir dois ficheiros locais do nosso servidor master do Ansible para cada nó. Eu guardo-os em /ansible/src, mas pode armazená-los em qualquer lugar.

Veja abaixo o conteúdo destes ficheiros.

Bash
      - name: criar symlink sites-enabled
        file: src=/etc/nginx/sites-available/www.homeserver.pt dest=/etc/nginx/sites-enabled/www.homeserver.pt state=link

Criamos um link simbólico de /etc/nginx/sites-enabled/www.homeserver.pt para /etc/nginx/sites-available/www.homeserver.pt, o que é a configuração padrão do Nginx no Debian.

Bash
      - name: diretório de logs nginx
        file: path=/var/log/nginx/www.homeserver.pt state=directory owner=www-data group=adm mode=0775 
      - name: log de acesso nginx
        file: path=/var/log/nginx/www.homeserver.pt/access.log state=touch owner=www-data group=adm mode=0664 state=touch
      - name: log de erro nginx
        file: path=/var/log/nginx/www.homeserver.pt/error.log state=touch owner=www-data group=adm mode=0664 state=touch

Criamos um diretório e os logs de acesso e erro para o Nginx. Prefiro ter cada site no seu próprio diretório.

Bash
      - name: nginx /web
        file: path=/web state=directory owner=www-data group=adm mode=0775 
      - name: nginx /web/www.homeserver.pt
        file: path=/web/www.homeserver.pt state=directory owner=www-data group=adm mode=0775 

Organizo as minhas raízes web em /web (sim, mesmo a partir do diretório raiz – porquê não?).

Bash
      - name: reiniciar nginx
        service: name=nginx enabled=yes state=restarted
      - name: ponto de montagem gluster
        file: path=/gluster state=directory owner=root group=root mode=0777

Finalmente, reiniciamos o serviço nginx e criamos outro diretório que precisaremos para o gluster.

O ficheiro /etc/logrotate.d/nginx_diretorios_web que distribuímos para todos os nós a partir de /ansible/src/nginx_diretorios_web tem o seguinte aspeto:

Bash
/var/log/nginx/*/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi \
    endscript
    postrotate
        invoke-rc.d nginx rotate >/dev/null 2>&1
    endscript
}

Só precisa disto se estiver a usar rsyslog.

O ficheiro Nginx que é colocado em /etc/nginx/sites-available/www.homeserver.pt tem o seguinte aspeto:

Bash
server {
  server_name www.homeserver.pt;
  access_log /var/log/nginx/www.homeserver.pt/access.log;
  error_log /var/log/nginx/www.homeserver.pt/error.log;

  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    include /etc/nginx/fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param  SCRIPT_FILENAME  /web/www.homeserver.pt$fastcgi_script_name;
  }

  location / {
    root   /web/www.homeserver.pt;
    index  index.php index.html;
    try_files $uri $uri/ /index.php;
    if (!-e $request_filename) {
      rewrite . /index.php last;
    }
  }
}

Este é um ficheiro Nginx bastante padrão. Como pode ver, estamos a usar o PHP-FPM, que é um pacote que instalámos acima.

Uau, fizemos imenso com o Ansible:

  • Definir o nome de host, locales e fuso horário
  • Instalar pacotes com apt
  • Configurar e proteger a base de dados
  • Instalar e configurar o rsyslog para rotacionar logs do Nginx
  • Instalar o Nginx, configurá-lo, configurar o site e definir os logs do site

Na próxima vez, vamos pôr o GlusterFS a funcionar!

Artigos Relacionados