Nesta série de tutoriais, estamos a criar um site WordPress altamente disponível do zero.
- Parte 1 – Introdução, Considerações e Arquitetura
- Parte 2 – Criação dos Containers
- Parte 3 – Ansible e Dependências (este artigo)
- Parte 4 – Gluster
- Parte 5 – Instalação do WordPress
- Parte 6 – MariaDB Multi-Master
- Parte 7 – DNS Round-Robin, Let’s Encrypt e Conclusão
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:
apt install ansible
Instalando Dependências Adicionais
Será preciso alguns pacotes e módulos adicionais:
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:
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:
ansible-galaxy collection install community.mysql
Se for a utilizar o GlusterFS, adicione o repositório do GlusterFS e instale o servidor:
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:
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:
[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:
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:
---
- 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.
---
- 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.
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.
- 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.
- 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:
apt-get update
apt-get upgrade
- 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.
- name: Definir timezone para Europe/Lisbon
community.general.timezone:
name: Europe/Lisbon
Aqui definimos o fuso horário. Ajuste conforme o seu gosto.
- 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.
- 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!
- 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.
- 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.
- 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.
- 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.
- 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?).
- 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:
/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:
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!