Ansible es una de las herramientas de automatización de TI más conocidas y utilizadas, nos ayuda a automatizar tareas operativas de TI como...
- Arrancar el host (VM o máquina completa) desde cero
- Configuración de hosts y servicios
- Gestionar implementaciones y actualizaciones de software
- Ansible también es compatible con la orquestación de la infraestructura de la nube, como la creación de un conjunto de instancias EC2 y RDS para sus aplicaciones en nubes públicas (AWS, GCP, Azure). Puede encontrar más información sobre el aprovisionamiento en la nube aquí
Dado que este blog se trata principalmente de administrar PostgreSQL usando Ansible, no entraremos en detalles sobre los usos de Ansible, sin embargo, repasaremos algunos conceptos básicos de Ansible. Recomiendo consultar el vínculo del documento de Ansible si desea obtener más información al respecto.
Conceptos básicos de Ansible
Ansible es un proyecto de código abierto escrito en python cuyo código fuente está disponible en GitHub. Dado que es un paquete de python, podemos instalar fácilmente Ansible usando pip.
Ansible debe instalarse en un solo host desde el cual organizaremos nuestras tareas operativas mediante los comandos de Ansible (Ansible, Ansible-playbook). Llamamos a este host de orquestación el Nodo de Control.
Los comandos de Ansible utilizan bibliotecas de OpenSSH para iniciar sesión en los hosts de destino para ejecutar tareas operativas; a estos hosts de destino los llamamos nodos administrados. El nombre de host o la IP del nodo administrado se mencionan en un archivo llamado Inventario, este nombre de archivo de inventario se especifica luego como una entrada para los comandos de Ansible.
En el archivo de inventario, podemos enumerar varios hosts en un solo grupo, esto evitará repetir las mismas tareas varias veces para diferentes hosts. Puede encontrar más detalles sobre el uso del archivo de inventario aquí.
Dado que el comando Ansible usa SSH para iniciar sesión, no es necesario instalar Ansible en todo el host, solo debe instalarse en el nodo de control. Sin embargo, todos los nodos de control y nodos administrados deben tener python y las bibliotecas de python necesarias instaladas. Puede encontrar más información sobre la instalación de Ansible aquí.
Para la demostración, usaré una computadora portátil como nodo de control y una máquina virtual CentOS-7 invitada como nodo administrado. La máquina virtual CentOS-7 se aprovisionó con Vagrant en el proveedor VirtualBox.
Instalación de Ansible en el nodo de control
Instalaremos Ansible usando pip como se indica en la página del documento de Ansible. Los siguientes comandos se ejecutaron como usuario de "Ansible".
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.py --user
Usando la opción --user, hace que los comandos pip y Ansible se instalen en el directorio HOME y necesitamos agregar la ruta bin a nuestra variable de entorno PATH.
$ echo 'export PATH=$HOME/Library/Python/2.7/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
El siguiente comando pip instaló la versión 2.8.0 de Ansible (que es la última versión estable al momento de escribir este blog).
$ pip install --user ansible
$ which ansible
/Users/Ansible/Library/Python/2.7/bin/Ansible
$ ansible --version
Ansible 2.8.0
...
...
Comprobaciones previas de nodos de control y nodos gestionados
Asegúrese de tener una conexión de red adecuada entre el nodo de control y el nodo administrado.
Verifique su Firewall para ver si hay reglas que puedan bloquear las conexiones entrantes y salientes en el puerto SSH, si es así, abra el puerto SSH para proporcionar acceso tanto a los nodos de control como a los administrados.
Primero, intente conectarse a través de SSH al nodo administrado. Debería poder iniciar sesión en el nodo administrado desde el nodo de control.
Puede configurar el acceso SSH sin contraseña a los nodos administrados de acuerdo con las políticas de seguridad de su organización. Para esta demostración, configuré SSH sin contraseña para mi nodo administrado "pg01" (CentOS-7) para el usuario "vagrant". Esto hace que el nodo administrado tenga el poder de sudo, la mayoría de las tareas de instalación y configuración del host se ejecutarán como un usuario "vagabundo" con "sudo".
En el nodo de control, tenemos el archivo de configuración ansible.cfg que será utilizado por los comandos de Ansible. A continuación se muestran algunas opciones de configuración que se definen en el archivo de configuración. Para obtener más información sobre las otras opciones de configuración disponibles, consulte el archivo de configuración de muestra.
- remote_port:si el servidor SSH en el nodo administrado se ejecuta en un puerto diferente al puerto predeterminado 22, podemos cambiarlo
- remote_user:el nombre de usuario de inicio de sesión que utilizará Ansible para conectar el nodo administrado, para ejecutar las tareas
- private_key_file:clave privada SSH que se usará para que Ansible inicie sesión
Dado que dicha configuración anterior se aplica globalmente para todos los nodos administrados, si queremos tener una configuración diferente para un host o grupo de host específico, podemos especificarlos en el archivo de inventario. Puede ver un ejemplo de esto a continuación en el archivo de inventario "desarrollo.yaml".
Realización de una ejecución en seco de Ansible
Cree un archivo de inventario "desarrollo.yaml" como se muestra a continuación.
$ 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"
En el archivo de inventario anterior, el host pg01 es uno de los miembros del grupo de host postgres_clusters. Las variables ansible_port, ansible_user y ansible_private_key_file solo se aplican a los hosts del grupo postgres_clusters.
Ahora comprobaremos si Ansible puede ejecutar las tareas en el nodo administrado. En el siguiente ejemplo, el comando ansible ejecuta el ping del módulo en el nodo administrado pg01, si Ansible pudo ejecutar el ping del módulo, debería ver SUCCESS como respuesta.
$ ansible -i development.yaml -m ping pg01
pg01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Cuando se ejecuta Ansible en el nodo administrado como primera tarea, recopila información como el nombre de host, la dirección IP y la memoria del nodo administrado. Para verificar esto, podemos llamar a la configuración del módulo, que devolvería un JSON grande. Podemos hacer uso de cualquiera de estos en nuestro libro de jugadas de 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"
],
Rol de Ansible
Ansible Role es una forma de agrupar un determinado conjunto de tareas relacionadas y ajustes de configuración en una sola unidad simplemente asignando un rol a un host o grupo de hosts en particular. Ansible aplicará todas las configuraciones y tareas relacionadas. Esto evita repetir las tareas varias veces para cada host o grupo de host diferente.
Cada rol se representa como un directorio y dentro del directorio de roles habrá subdirectorios como archivos predeterminados, controladores, meta, tareas, plantillas, pruebas, vars. El propósito de estos directorios se puede encontrar aquí.
Los comandos de Ansible, de forma predeterminada, buscan en el directorio de funciones en las rutas mencionadas en 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.
Galaxia ansible
Ansible Galaxy es un portal donde la gente de la comunidad comparte el repositorio de GitHub de sus roles de Ansible. Podemos navegar a través del portal de galaxias para los roles de Ansible requeridos. Usando el comando ansible-galaxy, pudimos descargar y reutilizar el rol. Antes de usar un rol, revise en detalle todos los archivos YAML de Ansible en los directorios predeterminados, vars, tareas, plantillas, controladores y sepa cómo funciona el rol.
Para nuestra implementación de PostgreSQL, utilizaremos el rol "postgresql" desarrollado por el autor ANXS y el repositorio de GitHub.
Instalación del rol de 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
El comando anterior instala el directorio de funciones "anxs.postgresql" en el directorio "/Users/ansible/.Ansible/roles", este es uno de los directorios en DEFAULT_ROLES_PATH y el comando ansible buscará en este directorio cualquier función.
Guía de Ansible
Un libro de jugadas de Ansible es un archivo YAML en el que enumeraremos las tareas o roles que deben ejecutarse en un host en particular o en el grupo de hosts. Puede leer más sobre el desarrollo de libros de jugadas, así como aprender la definición de etiquetas como hosts, tareas, roles, vars aquí.
De forma predeterminada, todas las tareas se ejecutan como el usuario ansible que ha iniciado sesión. Para ejecutar tareas particulares con un usuario diferente (o con privilegios de 'root') podemos hacer uso de Become. Puede encontrar cómo usar este comando aquí.
En el libro de jugadas a continuación (postgres-play.yaml), he enumerado el rol "anxs.postgresql" en el grupo de host "postgres_clusters", por lo que todas las tareas en el rol anxs.postgresql se ejecutarán para todos los hosts en el grupo “postgres_clusters”.
$ cat postgres-play.yaml
---
- hosts: postgres_clusters
become: yes
roles:
- role: anxs.postgresql
Become:yes en YAML define que este rol se ejecutará con mayor privilegio mediante el uso de 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.
Ejecutaremos este libro de jugadas como el usuario "vagabundo" y el usuario ya estaba aprovisionado con sudo power.
[[email protected] ~]$ sudo cat /etc/sudoers.d/vagrant
%vagrant ALL=(ALL) NOPASSWD: ALL
Guía de DevOps para la gestión de bases de datos de VariousninesConozca lo que necesita saber para automatizar y gestionar sus bases de datos de código abiertoDescargar gratis Implementación de PostgreSQL con Ansible
Ahora ejecutaremos el libro de jugadas 'postgres-play.yaml' que instalará todos los paquetes relacionados con PostgreSQL y lo configurará con la configuración predeterminada.
Para este ejemplo, Ansible instalará PostgreSQL 9.6 en el puerto 5432, con postgres max_connections establecido en 100. Todas las configuraciones predeterminadas se pueden encontrar en el archivo /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
Ejecutar el libro de jugadas
$ 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
Una vez que Ansible haya ejecutado todas las tareas, se mostrará un resumen de las tareas ejecutadas en PLAY RECAP.
- ok=21, 21 tareas ejecutadas sin cambios.
- cambiado=14, 14 tareas han realizado cambios en el host, como instalar postgres, crear directorios, archivos, iniciar postgres.
- skipped=32, se han omitido 32 tareas, puede deberse a que alguna característica no estaba habilitada. Dado que estamos instalando en entOS, se omitieron las tareas relacionadas con Ubuntu.
Compruebe el estado y la configuración del servicio de 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)
Ahora hemos instalado PostgreSQL en el host administrado "pg01" usando la configuración predeterminada.
Cambiar la configuración de PostgreSQL
Ahora volveremos a configurar la instancia de PostgreSQL utilizando nuestra configuración personalizada.
Creé un archivo custom.yaml (como se muestra a continuación) que tiene la lista de variables definidas para modificar la configuración de 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
Ahora cambiaremos nuestro playbook 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
Con las etiquetas vars_files, especifiqué el archivo de configuración personalizado custom.yaml, que anulará la configuración predeterminada especificada en el rol anxs.postgresql. Puede encontrar más detalles sobre la precedencia de variables aquí.
Ahora podríamos volver a ejecutar el mismo comando ansible-playbook que habíamos ejecutado anteriormente, pero esto ejecutará todas las tareas como instalar PostgreSQL, configurar, crear usuarios y bases de datos. Para esto, debemos restringir Ansible para que solo ejecute las tareas relacionadas con la configuración de PostgreSQL usando la opción --tags
Para conocer la lista de etiquetas admitidas, podríamos ejecutar el comando con --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]
De las etiquetas anteriores, especificaremos solo la etiqueta postgresql-configure para modificar la configuración de 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 puede ver en PLAY RECAP, solo se han propagado 2 cambios al nodo administrado pg01. El primero es actualizar la configuración y el segundo es recargar las configuraciones.
Verifique que los cambios de configuración hayan tenido efecto en el nodo administrado.
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 puede ver, algunas configuraciones cambian como listen_addresses, max_connections, wal_level, hot_standby aún no han tenido efecto. Estos cambios de configuración necesitan un reinicio de PostgreSQL y el rol anxs.postgresql solo ha recargado el servicio en sí.
Para evitar un reinicio abrupto de PostgreSQL durante las horas de producción, es posible que el autor original no haya agregado la tarea de reinicio al rol. Podemos reiniciar manualmente el servicio postgresql, durante el tiempo de inactividad 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)
Creación de usuarios y bases de datos de PostgreSQL
Ahora crearemos los usuarios "app1" y "app2" y las bases de datos "app1_db" y "app2_db" propiedad de los usuarios "app1" y "app2" respectivamente.
He agregado dos nuevas variables, postgresql_users y postgresql_database a custom.yaml, que tiene la lista de usuarios y bases de datos que deben crearse. El rol anxs.postgresql utiliza el módulo de Ansible postgresql_users y postgresql_db para crear el usuario y la base de datos. Puede consultar estos documentos para agregar las variables.
$ 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
Ahora ejecutaremos solo las tareas asociadas con las etiquetas postgresql-users y 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 que los usuarios y las bases de datos se creen en el host administrado.
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)
Permitir que hosts externos se conecten al servidor PostgreSQL
Ahora permitiremos que los hosts externos se conecten al servicio PostgreSQL agregando la variable 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" }
Ejecutando las tareas etiquetadas con postgresql-configure, para aplicar la configuración.
$ ansible-playbook -i development.yaml postgres-play.yaml --tags postgresql-configure
Verificando si puedo conectarme al servidor PostgreSQL desde mi nodo de control.
$ PGPASSWORD=password psql -h pg01 -U app1 -d app1_db -c 'Select true'
bool
------
(1 row)
Conclusión
Este blog debería brindarle los conceptos básicos que necesita saber para usar Ansible para implementar y administrar PostgreSQL. Sin embargo, solo hemos cubierto algunas tareas de administración de PostgreSQL. Dependiendo de la infraestructura de su organización, es posible que deba anular varias de las configuraciones predeterminadas y agregar aún más tareas al rol de Ansible.