Ansible é uma das ferramentas de automação de TI mais conhecidas e amplamente usadas, nos ajuda a automatizar tarefas operacionais de TI, como...
- Reinicializando o host (VM ou máquina bare-metal) do zero
- Configurando hosts e serviços
- Gerenciando implantações e atualizações de software
- O Ansible também tem suporte para orquestrar a infraestrutura de nuvem, como criar várias instâncias do EC2 e RDS para seus aplicativos em nuvens públicas (AWS, GCP, Azure). Mais informações sobre o provisionamento de nuvem podem ser encontradas aqui
Como este blog trata principalmente do gerenciamento do PostgreSQL usando o Ansible, não entraremos em detalhes sobre os usos do Ansible, no entanto, passaremos por alguns conceitos básicos do Ansible. Eu recomendo acessar o link do documento Ansible se você quiser saber mais sobre ele.
Noções básicas do Ansible
Ansible é um projeto de código aberto escrito em python cujo código fonte está disponível no GitHub. Como é um pacote python, podemos instalar facilmente o Ansible usando pip.
O Ansible precisa ser instalado em apenas um host a partir do qual orquestraremos nossas tarefas operacionais usando comandos do Ansible (Ansible, Ansible-playbook). Chamamos esse host de orquestração de nó de controle.
Os comandos do Ansible usam bibliotecas OpenSSH para fazer login nos hosts de destino para executar tarefas operacionais, chamamos esses hosts de destino Managed Node. O nome de host ou IP do nó gerenciado é mencionado em um arquivo chamado Inventory, esse nome de arquivo de inventário é então especificado como uma entrada para os comandos do Ansible.
No arquivo de inventário, podemos listar vários hosts em um único grupo, isso evitará repetir as mesmas tarefas várias vezes para diferentes hosts. Mais detalhes sobre o uso do arquivo de inventário podem ser encontrados aqui.
Como o comando Ansible usa SSH para fazer login, não há necessidade de instalar o Ansible em todo o host, ele só precisa ser instalado no nó de controle. No entanto, todos os nós de controle e nós gerenciados devem ter python e quaisquer bibliotecas python necessárias instaladas. Mais informações sobre a instalação do Ansible podem ser encontradas aqui.
Para a demonstração, usarei um laptop como nó de controle e uma VM CentOS-7 convidada como nó gerenciado. A VM CentOS-7 foi provisionada usando o Vagrant no provedor VirtualBox.
Instalando o Ansible no nó de controle
Instalaremos o Ansible usando o pip conforme referenciado na página do documento do Ansible. Os comandos a seguir foram executados como usuário “Ansible”.
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.py --user
Usando a opção --user, faz com que os comandos pip e Ansible sejam instalados no diretório HOME e precisamos adicionar o caminho bin à nossa variável de ambiente PATH.
$ echo 'export PATH=$HOME/Library/Python/2.7/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
O comando pip a seguir instalou o Ansible versão 2.8.0 (que é a versão estável mais recente no momento da redação deste blog.)
$ pip install --user ansible
$ which ansible
/Users/Ansible/Library/Python/2.7/bin/Ansible
$ ansible --version
Ansible 2.8.0
...
...
Pré-verificações de nó de controle e nó gerenciado
Certifique-se de ter uma conexão de rede adequada entre o nó de controle e o nó gerenciado.
Verifique em seu Firewall quaisquer regras que possam bloquear conexões de entrada e saída na porta SSH, se for o caso, abra a porta SSH para fornecer acesso nos nós de controle e gerenciados.
Primeiro, tente se conectar via SSH ao nó gerenciado. Você deve ser capaz de efetuar login no nó gerenciado a partir do nó de controle.
Você pode configurar o acesso SSH sem senha aos nós gerenciados de acordo com as políticas de segurança da sua organização. Para esta demonstração, configurei sem senha para SSH para meu nó gerenciado “pg01” (CentOS-7) para o usuário “vagrant”. Isso faz com que o nó gerenciado tenha o poder do sudo, a maioria das tarefas de instalação e configuração do host serão executadas como usuário “vagrant” com “sudo”.
No nó de controle, temos o arquivo de configuração ansible.cfg que será utilizado pelos comandos do Ansible. Abaixo estão algumas opções de configuração que são definidas no arquivo de configuração. Para saber mais sobre as outras opções de configuração disponíveis, confira o arquivo de configuração de amostra.
- remote_port - Se o servidor SSH no nó gerenciado for executado em uma porta diferente da porta padrão 22, podemos alterá-la
- remote_user - O nome de usuário de login que será usado pelo Ansible para conectar o nó gerenciado, para executar as tarefas
- private_key_file - chave privada SSH que será usada para o Ansible fazer login
Como a configuração acima mencionada se aplica globalmente a todos os nós gerenciados, se quisermos ter uma configuração diferente para um host ou grupo de hosts específico, podemos especificá-los no arquivo de inventário. Você pode ver um exemplo disso abaixo no arquivo de inventário “development.yaml”.
Executando uma simulação do Ansible
Crie um arquivo de inventário “development.yaml” conforme mostrado abaixo.
$ pwd
/Users/Ansible/postgres-setup
$ cat development.yaml
all:
hosts:
children:
postgres_clusters:
hosts:
pg01:
vars:
ansible_port: 22
ansible_user: "vagrant"
ansible_private_key_file: "/Users/Ansible/postgres-setup/private_key"
No arquivo de inventário acima, o host pg01 é um dos membros do grupo de hosts postgres_clusters. As variáveis ansible_port, ansible_user e ansible_private_key_file se aplicam apenas aos hosts do grupo postgres_clusters.
Agora vamos verificar se o Ansible pode executar as tarefas no nó gerenciado. No exemplo abaixo, o comando ansible executa o módulo ping no nó gerenciado pg01, se o Ansible conseguiu executar o módulo ping, você deverá ver SUCCESS como resposta.
$ ansible -i development.yaml -m ping pg01
pg01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Ao executar o Ansible no nó gerenciado como a primeira tarefa, ele coleta informações como nome do host, endereço IP e memória do nó gerenciado. Para verificar isso, podemos chamar a configuração do módulo que retornaria um JSON grande. Podemos fazer uso de qualquer um deles em nosso manual do Ansible.
$ ansible -i development.yaml -m setup pg01
pg01 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.100.4",
"10.0.2.15"
],
"ansible_all_ipv6_addresses": [
"fe80::a00:27ff:fe29:ac89",
"fe80::5054:ff:fe26:1060"
],
Função Ansible
Ansible Role é uma maneira de agrupar um determinado conjunto de tarefas relacionadas e definições de configuração em uma única unidade apenas atribuindo uma função a um host ou grupo de hosts específico. O Ansible aplicará todas as configurações e tarefas relacionadas. Isso evita repetir as tarefas várias vezes para cada host ou grupo de hosts diferente.
Cada função é representada como um diretório e dentro do diretório de funções haverá subdiretórios como arquivos padrão, manipuladores, meta, tarefas, modelos, testes, vars. A finalidade desses diretórios pode ser encontrada aqui.
Os comandos do Ansible, por padrão, pesquisam o diretório de funções nos caminhos mencionados em DEFAULT_ROLES_PATH.
$ ansible-config list | grep -A2 '^DEFAULT_ROLES_PATH'
DEFAULT_ROLES_PATH:
default: ~/.Ansible/roles:/usr/share/Ansible/roles:/etc/Ansible/roles
description: Colon separated paths in which Ansible will search for Roles.
Ansible Galaxy
O Ansible Galaxy é um portal onde o pessoal da comunidade compartilha o repositório GitHub de suas funções do Ansible. Podemos navegar pelo portal da galáxia para as funções Ansible necessárias. Usando o comando ansible-galaxy, podemos baixar e reutilizar a função. Antes de usar uma função, analise detalhadamente todos os arquivos Ansible YAML nos diretórios defaults, vars, tasks, templates, handlers e esteja ciente de como a função funciona.
Para nossa implantação do PostgreSQL, usaremos o papel “postgresql” desenvolvido pelo autor ANXS e repo GitHub.
Instalando a função Ansible “anxs.postgresql”
$ ansible-galaxy install anxs.postgresql
- downloading role 'postgresql', owned by anxs
- downloading role from https://github.com/ANXS/postgresql/archive/v1.10.1.tar.gz
- extracting anxs.postgresql to /Users/ansible/.Ansible/roles/anxs.postgresql
- anxs.postgresql (v1.10.1) was installed successfully
O comando acima instala o diretório de funções ”anxs.postgresql” sob o diretório “/Users/ansible/.Ansible/roles”, este é um dos diretórios no DEFAULT_ROLES_PATH e o comando ansible buscará neste diretório quaisquer funções.
Manual do Ansible
Um Ansible Playbook é um arquivo YAML no qual listaremos as tarefas ou funções que devem ser executadas em um host específico ou grupo de hosts. Você pode ler mais sobre o desenvolvimento de playbooks, bem como aprender a definição de tags como hosts, tasks, roles, vars aqui.
Por padrão, todas as tarefas são executadas como o usuário ansible que fez login. Para executar tarefas específicas com um usuário diferente (ou com privilégio 'root') podemos usar o make. Como usar este comando pode ser encontrado aqui.
No playbook abaixo (postgres-play.yaml), listei o papel “anxs.postgresql” no grupo de hosts “postgres_clusters”, então todas as tarefas no papel anxs.postgresql serão executadas para todos os hosts do grupo “postgres_clusters”.
$ cat postgres-play.yaml
---
- hosts: postgres_clusters
become: yes
roles:
- role: anxs.postgresql
torne-se:sim no YAML define que este papel será executado com maior privilégio usando o DEFAULT_BECOME_METHOD “sudo”
$ ansible-config list | grep -A2 '^DEFAULT_BECOME_METHOD'
DEFAULT_BECOME_METHOD:
default: sudo
description: Privilege escalation method to use when `become` is enabled.
Estaremos executando este manual como o usuário “vagrant” e o usuário já foi provisionado com sudo power.
[[email protected] ~]$ sudo cat /etc/sudoers.d/vagrant
%vagrant ALL=(ALL) NOPASSWD: ALL
Guia de DevOps para gerenciamento de banco de dados de vários novesSaiba mais sobre o que você precisa saber para automatizar e gerenciar seus bancos de dados de código abertoBaixe gratuitamente Implantando o PostgreSQL usando o Ansible
Agora executaremos o manual ‘postgres-play.yaml’ que instalará todos os pacotes relacionados ao PostgreSQL e o configurará usando as configurações padrão.
Para este exemplo, o Ansible instalará o PostgreSQL 9.6 na porta 5432, com o postgres max_connections definido como 100. Todas as configurações padrão podem ser encontradas no arquivo /Users/ansible/.Ansible/roles/anxs.postgresql/defaults/main.yml .
$ grep -E '^postgresql_(version|port|max_connections):' ~/.Ansible/roles/anxs.postgresql/defaults/main.yml
postgresql_version: 9.6
postgresql_port: 5432
postgresql_max_connections: 100
Executando o manual
$ ansible-playbook -i development.yaml postgres-play.yaml
PLAY [postgres_clusters] ***************************************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************************************************
ok: [pg01]
...
...
PLAY RECAP *****************************************************************************************************************************************************************************************************
pg01 : ok=21 changed=14 unreachable=0 failed=0 skipped=32 rescued=0 ignored=0
Depois que o Ansible tiver executado todas as tarefas, um resumo das execuções de tarefas será mostrado em PLAY RECAP.
- ok=21, 21 tarefas executadas sem alterações.
- changed=14, 14 tasks fizeram alterações no host, como instalar o postgres, criar diretórios, arquivos, iniciar o postgres.
- skipped=32, 32 tarefas foram ignoradas, pode ser porque algum recurso não foi ativado. Como estamos instalando no entOS, as tarefas relacionadas ao Ubuntu foram ignoradas.
Verifique o status e a configuração do serviço PostgreSQL.
[[email protected] ~]$ systemctl status postgresql-9.6
● postgresql-9.6.service - PostgreSQL 9.6 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-9.6.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/postgresql-9.6.service.d
└─custom.conf
Active: active (running) since Wed 2019-05-29 07:15:25 UTC; 24min ago
Docs: https://www.postgresql.org/docs/9.6/static/
Process: 7559 ExecStartPre=/usr/pgsql-9.6/bin/postgresql96-check-db-dir /var/lib/pgsql/9.6/data (code=exited, status=0/SUCCESS)
Main PID: 7564 (postmaster)
CGroup: /system.slice/postgresql-9.6.service
├─7564 /usr/pgsql-9.6/bin/postmaster -D /etc/postgresql/9.6/data
├─7567 postgres: checkpointer process
├─7568 postgres: writer process
├─7569 postgres: wal writer process
├─7570 postgres: autovacuum launcher process
└─7571 postgres: stats collector process
[[email protected] ~]$ psql -U postgres
psql (9.6.13)
Type "help" for help.
postgres=# show max_connections ;
max_connections
-----------------
100
(1 row)
postgres=# show statement_timeout ;
statement_timeout
-------------------
(1 row)
postgres=# show log_min_duration_statement ;
log_min_duration_statement
----------------------------
-1
(1 row)
Agora instalamos o PostgreSQL no host gerenciado “pg01” usando a configuração padrão.
Mudando a configuração do PostgreSQL
Agora vamos reconfigurar a instância do PostgreSQL usando nossas configurações personalizadas.
Eu criei o arquivo custom.yaml (como mostrado abaixo) que tem a lista de variáveis definidas para modificar as configurações do PostgreSQL como listen_addresses, max_connections, wal_level, hot_standby, statement_timeout, log_checkpoint, log_lock_waits, log_destination, log_min_duration_statement.
$ pwd
/Users/ansible/postgres-setup
$ cat custom.yaml
postgresql_listen_addresses: "*"
postgresql_max_connections: 300
postgresql_wal_level: "hot_standby"
postgresql_hot_standby: "on"
postgresql_statement_timeout: 60000
postgresql_log_lock_waits: "on"
postgresql_log_destination: "csvlog"
postgresql_log_min_duration_statement: 0
Agora, mudaremos nosso manual postgres-play.yaml para usar este custom.yaml.
$ cat postgres-play.yaml
---
- hosts: postgres_clusters
become: yes
vars_files:
- ./custom.yaml
roles:
- role: anxs.postgresql
Usando as tags vars_files, especifiquei o arquivo de configuração personalizado custom.yaml, que substituirá a configuração padrão especificada na função anxs.postgresql. Mais detalhes sobre a precedência de variáveis podem ser encontrados aqui.
Podemos agora executar novamente o mesmo comando ansible-playbook que executamos anteriormente, mas isso executará todas as tarefas, como instalar o PostgreSQL, configurar, criar usuários e bancos de dados. Para isso devemos restringir o Ansible a executar apenas as tarefas relacionadas à configuração do PostgreSQL usando a opção --tags
Para conhecer a lista de tags suportadas, poderíamos executar o comando com --list-tags.
$ ansible-playbook -i development.yaml postgres-play.yaml --list-tags
playbook: postgres-play.yaml
play #1 (postgres_clusters): postgres_clusters TAGS: []
TASK TAGS: [always, postgresql, postgresql-configure, postgresql-databases, postgresql-extensions, postgresql-install, postgresql-monit, postgresql-users]
Das tags acima, especificaremos apenas a tag postgresql-configure para modificar as configurações do postgresql.
$ ansible-playbook -i development.yaml postgres-play.yaml --tags postgresql-configure
PLAY [postgres_clusters] ***************************************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************************************************
ok: [pg01]
...
...
TASK [anxs.postgresql : PostgreSQL | Update configuration - pt. 2 (postgresql.conf)] ***************************************************************************************************************************
changed: [pg01]
...
...
TASK [anxs.postgresql : PostgreSQL | Reload all conf files] ****************************************************************************************************************************************************
changed: [pg01]
PLAY RECAP *****************************************************************************************************************************************************************************************************
pg01 : ok=13 changed=2 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0
Como você vê no PLAY RECAP, apenas 2 alterações foram propagadas para o nó gerenciado pg01. O primeiro é atualizar a configuração e o segundo é recarregar as configurações.
Verifique se as alterações de configuração entraram em vigor no nó gerenciado.
postgres=# show listen_addresses ;
listen_addresses
------------------
localhost
(1 row)
postgres=# show max_connections ;
max_connections
-----------------
100
(1 row)
postgres=# show wal_level ;
wal_level
-----------
minimal
(1 row)
postgres=# show hot_standby ;
hot_standby
-------------
off
(1 row)
postgres=# show statement_timeout;
statement_timeout
-------------------
1min
(1 row)
postgres=# show log_lock_waits ;
log_lock_waits
----------------
on
(1 row)
postgres=# show log_destination ;
log_destination
-----------------
csvlog
(1 row)
postgres=# show log_min_duration_statement;
log_min_duration_statement
----------------------------
(1 row)
Como você pode ver, algumas configurações como listen_addresses, max_connections, wal_level, hot_standby ainda não entraram em vigor. Essas alterações de configuração precisam de uma reinicialização do PostgreSQL e a função anxs.postgresql apenas recarregou o próprio serviço.
Para evitar uma reinicialização abrupta do PostgreSQL durante o horário de produção, o autor original pode não ter adicionado a tarefa de reinicialização à função. Podemos reiniciar manualmente o serviço postgresql, durante o tempo de inatividade programado.
[[email protected] ~]$ sudo systemctl restart postgresql-9.6
[[email protected] ~]$ psql -U postgres
psql (9.6.13)
postgres=# show listen_addresses ;
listen_addresses
------------------
(1 row)
postgres=# show max_connections ;
max_connections
-----------------
300
(1 row)
postgres=# show wal_level;
wal_level
-----------
replica
(1 row)
postgres=# show hot_standby;
hot_standby
-------------
on
(1 row)
Criando usuários e bancos de dados PostgreSQL
Agora vamos criar os usuários “app1” e “app2” e os bancos de dados “app1_db” e “app2_db” de propriedade dos usuários “app1” e “app2” respectivamente.
Eu adicionei duas novas variáveis, postgresql_users e postgresql_database ao custom.yaml, que tem a lista de usuários e bancos de dados que precisam ser criados. A função anxs.postgresql usa o módulo Ansible postgresql_users e postgresql_db para criar o usuário e o banco de dados. Você pode consultar esses documentos para adicionar as variáveis.
$ cat custom.yaml
...
...
postgresql_users:
- name: app1
pass: md5bb0592c05941d14c231da96950c71b60
encrypted: yes
- name: app2
pass: md5bbb1e4d09b64ca54a237727af46cba7c
encrypted: yes
postgresql_databases:
- name: app1_db
owner: app1
- name: app2_db
owner: app2
Agora executaremos apenas as tarefas associadas às tags postgresql-users e postgresql-databases.
$ ansible-playbook -i development.yaml postgres-play.yaml --tags postgresql-users,postgresql-databases
PLAY [postgres_clusters] ***************************************************************************************************************************************************************************************
...
...
TASK [anxs.postgresql : PostgreSQL | Make sure the PostgreSQL users are present] *******************************************************************************************************************************
changed: [pg01] => (item=None)
changed: [pg01] => (item=None)
changed: [pg01]
...
...
TASK [anxs.postgresql : PostgreSQL | Make sure the PostgreSQL databases are present] ***************************************************************************************************************************
changed: [pg01] => (item={u'owner': u'app1', u'name': u'app1_db'})
changed: [pg01] => (item={u'owner': u'app2', u'name': u'app2_db'})
...
...
PLAY RECAP *****************************************************************************************************************************************************************************************************
pg01 : ok=6 changed=2 unreachable=0 failed=0 skipped=9 rescued=0 ignored=0
Verifique se os usuários e bancos de dados foram criados no host gerenciado.
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
app1 | | {}
app2 | | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
app1_db | app1 | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
app2_db | app2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
(5 rows)
Permitindo que hosts externos se conectem ao servidor PostgreSQL
Agora vamos permitir que os hosts externos conectem o serviço PostgreSQL adicionando a variável postgresql_pg_hba_custom a custom.yaml
$ cat custom.yaml
...
...
postgresql_pg_hba_custom:
- {type: "host", database: "all", user: "all", address: "0.0.0.0/0", method: "md5" }
Executando as tarefas marcadas com postgresql-configure, para aplicar a configuração.
$ ansible-playbook -i development.yaml postgres-play.yaml --tags postgresql-configure
Verificando se consigo me conectar ao servidor PostgreSQL a partir do meu nó de controle.
$ PGPASSWORD=password psql -h pg01 -U app1 -d app1_db -c 'Select true'
bool
------
(1 row)
Conclusão
Este blog deve fornecer o básico que você precisa saber para usar o Ansible para implantar e gerenciar o PostgreSQL. No entanto, cobrimos apenas algumas tarefas de administração do PostgreSQL. Dependendo da infraestrutura da sua organização, pode ser necessário substituir várias configurações padrão e adicionar ainda mais tarefas à função do Ansible.