Ansible automatiza y simplifica las operaciones repetitivas, complejas y tediosas. Es un motor de automatización de TI que automatiza el aprovisionamiento en la nube, la gestión de la configuración, la implementación de aplicaciones, la orquestación dentro del servicio y muchas otras necesidades de TI. No requiere agentes, usa solo SSH para enviar cambios desde una sola fuente a múltiples recursos remotos sin configuración de infraestructura de seguridad personalizada adicional y usa un formato de lenguaje simple (YAML) para describir los trabajos de automatización.
Instalar un servidor MySQL independiente es una tarea simple y directa, pero esto puede ser problemático si tiene varios servidores de bases de datos, versiones, plataformas y entornos para admitir. Por lo tanto, tener una herramienta de gestión de la configuración es el camino a seguir para mejorar la eficiencia, eliminar la repetitividad y reducir los errores humanos.
En esta publicación de blog, lo guiaremos a través de los conceptos básicos de la automatización de Ansible para MySQL, así como la administración de la configuración con ejemplos y explicaciones. Comenzaremos con una implementación de MySQL independiente simple, como se ilustra en el siguiente diagrama de alto nivel:

Instalación de Ansible
Para este tutorial, necesitamos tener al menos dos hosts:un host es para Ansible (podría usar una estación de trabajo en lugar de un servidor) y otro es el host de destino en el que queremos implementar un servidor mysql
Para instalar Ansible en CentOS 7, simplemente ejecute los siguientes comandos:
(ansible-host)$ yum install -y epel-release
(ansible-host)$ yum install -y ansible
Para otras distribuciones de SO, consulte la guía de instalación de Ansible.
Configuración de SSH sin contraseña
Se admite el uso de contraseña durante SSH, pero las claves SSH sin contraseña con ssh-agent son una de las mejores formas de usar Ansible. El paso inicial es configurar SSH sin contraseña ya que Ansible realizará la implementación únicamente por este canal. En primer lugar, genere una clave SSH en el host de Ansible:
(ansible-host)$ whoami
root
(ansible-host)$ ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
Debe generar al menos los siguientes archivos:
(ansible-host)$ ls -al ~/.ssh/
-rw-------. 1 root root 1679 Jan 14 03:40 id_rsa
-rw-r--r--. 1 root root 392 Jan 14 03:40 id_rsa.pub
Para permitir SSH sin contraseña, necesitamos copiar la clave pública SSH (id_rsa.pub) al host remoto al que queremos acceder. Podemos usar una herramienta llamada ssh-copy-id para hacer esta tarea por nosotros. Sin embargo, debe conocer la contraseña de usuario del host de destino y la autenticación de contraseña está permitida en el host de destino:
(ansible-host)$ whoami
root
(ansible-host)$ ssh-copy-id [email protected]
El comando anterior solicitará la contraseña raíz 192.168.0.221, simplemente ingrese la contraseña y la clave SSH para el usuario actual del host Ansible se copiará en el host de destino, 192.168.0.221 en ~/.ssh/authorized_keys, lo que significa que autorizamos esa clave en particular para acceder a este servidor de forma remota. Para probar, debería poder ejecutar el siguiente comando remoto sin ninguna contraseña desde el host de Ansible:
(ansible-host)$ ssh [email protected] "hostname -I"
192.168.0.221
En caso de que no tenga permitido usar el usuario root para SSH (por ejemplo, "PermitRootLogin no" en la configuración de SSH), puede usar un usuario sudo en su lugar. En el siguiente ejemplo, configuramos SSH sin contraseña para un usuario sudo llamado "vagabundo":
(ansible-host)$ whoami
vagrant
(ansible-host)$ ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
(ansible-host)$ ls -al ~/.ssh/
-rw-------. 1 vagrant vagrant 1679 Jan 14 03:45 id_rsa
-rw-r--r--. 1 vagrant vagrant 392 Jan 14 03:45 id_rsa.pub
(ansible-host)$ ssh-copy-id [email protected]
Si el servidor de destino no permite la autenticación de contraseña a través de SSH, simplemente copie el contenido de la clave pública SSH en ~/.ssh/id_rsa.pub manualmente en el servidor de destino ~/.ssh/authorized_keys expediente. Por ejemplo, en el host de Ansible, recupere el contenido de la clave pública:
(ansible-host)$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5MZjufN0OiKyKa2OG0EPBEF/w23FnOG2x8qpAaYYuqHlVc+ZyRugtGm+TdTJDfLA1Sr/rtZpXmPDuLUdlAvPmmwqIhgiatKiDw5t2adNUwME0sVgAlBv/KvbusTTdtpFQ1o+Z9CltGiENDCFytr2nVeBFxImoZu2H0ilZed/1OY2SZejUviXTQ0Dh0QYdIeiQHkMf1CiV2sNYs8j8+ULV26OOKCd8c1h1O9M5Dr4P6kt8E1lVSl9hbd4EOHQmeZ3R3va5zMesLk1A+iadIGJCJNCVOA2RpxDHmmaX28zQCwrpCliH00g9iCRixlK+cB39d1coUWVGy7SeaI8bzfv3 [email protected]
Conéctese al host de destino y pegue la clave pública del host de Ansible en ~/.ssh/authorized_keys:
(target-host)$ whoami
root
(target-host)$ vi ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5MZjufN0OiKyKa2OG0EPBEF/w23FnOG2x8qpAaYYuqHlVc+ZyRugtGm+TdTJDfLA1Sr/rtZpXmPDuLUdlAvPmmwqIhgiatKiDw5t2adNUwME0sVgAlBv/KvbusTTdtpFQ1o+Z9CltGiENDCFytr2nVeBFxImoZu2H0ilZed/1OY2SZejUviXTQ0Dh0QYdIeiQHkMf1CiV2sNYs8j8+ULV26OOKCd8c1h1O9M5Dr4P6kt8E1lVSl9hbd4EOHQmeZ3R3va5zMesLk1A+iadIGJCJNCVOA2RpxDHmmaX28zQCwrpCliH00g9iCRixlK+cB39d1coUWVGy7SeaI8bzfv3 [email protected]
Ahora puede intentar ejecutar un comando remoto desde el host de Ansible para verificar y no se le debe solicitar ninguna contraseña. En este punto, nuestro SSH sin contraseña está configurado.
Definición del host de destino
A continuación, debemos definir el host de destino, el host que queremos administrar con Ansible. Según nuestra arquitectura, implementaremos solo un servidor MySQL que es 192.168.0.221. Agregue las siguientes líneas en /etc/ansible/hosts:
[db-mysql]
192.168.0.221
Lo anterior simplemente significa que definimos un grupo llamado "db-mysql", que será el identificador cuando nos referimos al host de destino en el libro de jugadas de Ansible. También podemos enumerar todas las direcciones IP o nombres de host de los hosts de destino en este grupo. En este punto, solo tenemos un servidor MySQL para implementar, por lo tanto, solo hay una entrada. También puede especificar cualquier regla de coincidencia para hacer coincidir los hosts de un grupo, por ejemplo:
[db-mysql]
192.168.0.[221:223]
La definición anterior significa que tenemos 3 hosts en este mismo grupo con las siguientes direcciones IP:
- 192.168.0.221
- 192.168.0.222
- 192.168.0.223
Hay muchas formas y reglas para hacer coincidir y agrupar los hosts de destino, como se muestra en la guía de inventario de Ansible.
Elegir un rol de Ansible
Para decirle a Ansible qué implementar, debemos definir los pasos de implementación en un archivo con formato YML llamado playbook. Como sabrá, la instalación de un servidor MySQL completo requiere varios pasos para satisfacer todas las dependencias de MySQL, la configuración posterior a la instalación, la creación de usuarios y esquemas, etc. Ansible ha proporcionado una serie de módulos de MySQL que pueden ayudarnos, pero aún tenemos que escribir un libro de jugadas para los pasos de implementación.
Para simplificar los pasos de implementación, podemos usar roles de Ansible existentes. El rol de Ansible es un componente independiente que permite la reutilización de pasos de configuración comunes. Se debe usar un rol de Ansible dentro del libro de jugadas. Hay una serie de roles de MySQL Ansible disponibles en Ansible Galaxy, un repositorio para los roles de Ansible que están disponibles para colocarlos directamente en sus playbooks.
Si busca "mysql", obtendrá muchos roles de Ansible para MySQL:

Usaremos el más popular llamado "mysql" por geerlingguy. Puede optar por usar otras funciones, pero la mayoría de las veces, la más descargada tiende a ser de uso general, lo que generalmente funciona bien en la mayoría de los casos.
En el host de Ansible, ejecute el siguiente comando para descargar la función de Ansible:
(ansible-host)$ ansible-galaxy install geerlingguy.mysql
El rol se descargará en ~/.ansible/roles/geerlingguy.mysql/ del usuario actual.
Escribir el libro de jugadas de Ansible
Al consultar el archivo Léame de la función de Ansible, podemos seguir el manual de estrategias de ejemplo que se proporciona. En primer lugar, cree un archivo de guía llamado deployment-mysql.yml y agregue las siguientes líneas:
(ansible-host)$ vim ~/deploy-mysql.yml
- hosts: db-mysql
become: yes
vars_files:
- vars/main.yml
roles:
- { role: geerlingguy.mysql }
En las líneas anteriores, definimos el host de destino, que son todos los hosts bajo las entradas de db-mysql en /etc/ansible/hosts. La siguiente línea (convertirse) le dice a Ansible que ejecute el libro de jugadas como usuario raíz, lo cual es necesario para el rol (se indica allí en el archivo Léame). A continuación, definimos la ubicación del archivo de variables (var_files) ubicado en vars/main.yml, en relación con la ruta del libro de jugadas.
Vamos a crear el directorio y archivo de variables y especificar la siguiente línea:
(ansible-host)$ mkdir vars
(ansible-host)$ vim vars/main.yml
mysql_root_password: "theR00tP455w0rd"
Para obtener más información, consulte la sección Variables del rol en el archivo Léame de este rol.
Iniciar la implementación
Ahora estamos listos para iniciar la implementación de MySQL. Use el comando ansible-playbook para ejecutar nuestras definiciones de libro de jugadas:
(ansible-host)$ ansible-playbook deploy-mysql.yml
Debería ver aparecer un montón de líneas en la salida. Concéntrese en la última línea donde resume la implementación:
PLAY RECAP ***************************************************************************************************************************************
192.168.0.221 : ok=36 changed=8 unreachable=0 failed=0 skipped=16 rescued=0 ignored=0
Si todo se vuelve verde y está bien, puede verificar en el host de la base de datos que nuestro servidor MySQL ya está instalado y ejecutándose:
(mysql-host)$ rpm -qa | grep -i maria
mariadb-server-5.5.64-1.el7.x86_64
mariadb-libs-5.5.64-1.el7.x86_64
mariadb-5.5.64-1.el7.x86_64
(mysql-host)$ mysqladmin -uroot -p ping
Enter password:
mysqld is alive
Como puede ver en lo anterior, para CentOS 7, la instalación predeterminada de MySQL es MariaDB 5.5 como parte del repositorio de paquetes estándar. En este punto, nuestra implementación se considera completa; sin embargo, nos gustaría personalizar aún más nuestra implementación como se muestra en las siguientes secciones.
Personalización de la implementación
La definición más simple en el libro de jugadas nos brinda una instalación muy básica y usa todas las opciones de configuración predeterminadas. Podemos personalizar aún más la instalación de MySQL extendiendo/modificando/agregando el libro de jugadas para hacer lo siguiente:
- modificar las opciones de configuración de MySQL
- añadir usuario de base de datos
- añadir esquema de base de datos
- configurar privilegios de usuario
- configurar la replicación de MySQL
- instalar MySQL de otros proveedores
- importar un archivo de configuración de MySQL personalizado
Instalación de MySQL desde el repositorio de Oracle
De forma predeterminada, la función instalará el paquete MySQL predeterminado que viene con la distribución del sistema operativo. En cuanto a CentOS 7, tendría instalado MariaDB 5.5 de forma predeterminada. Supongamos que queremos instalar MySQL de otro proveedor, podemos extender el playbook con pre_tasks, una tarea que Ansible ejecuta antes de ejecutar cualquier tarea mencionada en cualquier archivo .yml, como se muestra en el siguiente ejemplo:
(ansible-host)$ vim deploy-mysql.yml
- hosts: db-mysql
become: yes
vars_files:
- vars/main.yml
roles:
- { role: geerlingguy.mysql }
pre_tasks:
- name: Install the MySQL repo.
yum:
name: http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
state: present
when: ansible_os_family == "RedHat"
- name: Override variables for MySQL (RedHat).
set_fact:
mysql_daemon: mysqld
mysql_packages: ['mysql-server']
mysql_log_error: /var/lib/mysql/error.log
mysql_syslog_tag: mysqld
mysql_pid_file: /var/run/mysqld/mysqld.pid
mysql_socket: /var/lib/mysql/mysql.sock
when: ansible_os_family == "RedHat"
Ejecutar el libro de jugadas:
(ansible-host)$ ansible-playbook deploy-mysql.yml
Lo anterior instalará MySQL desde el repositorio de Oracle en su lugar. La versión predeterminada que obtendría es MySQL 5.6. Ejecutar el libro de jugadas anterior en un host de destino que ya tiene una versión anterior de MySQL/MariaDB en ejecución probablemente fallaría debido a la incompatibilidad.
Creación de bases de datos y usuarios MySQL
Dentro de vars/main.yml, podemos definir la base de datos MySQL y los usuarios que queremos que Ansible configure en nuestro servidor MySQL usando los módulos mysql_database y mysql_users, justo después de nuestra definición anterior en mysql_root_password:
(ansible-host)$ vim vars/main.yml
mysql_root_password: "theR00tP455w0rd"
mysql_databases:
- name: myshop
encoding: latin1
collation: latin1_general_ci
- name: sysbench
encoding: latin1
collation: latin1_general_ci
mysql_users:
- name: myshop_user
host: "%"
password: mySh0pPassw0rd
priv: "myshop.*:ALL"
- name: sysbench_user
host: "192.168.0.%"
password: sysBenchPassw0rd
priv: "sysbench.*:ALL"
La definición le indica a Ansible que cree dos bases de datos, "myshop" y "sysbench", seguido de su respectivo usuario de MySQL con los privilegios adecuados, host permitido y contraseña.
Vuelva a ejecutar el libro de jugadas para aplicar el cambio en nuestro servidor MySQL:
(ansible-host)$ ansible-playbook deploy-mysql.yml
Esta vez, Ansible recogerá todos los cambios que hicimos en vars/main.yml para aplicarlos a nuestro servidor MySQL. Podemos verificar en el servidor MySQL con los siguientes comandos:
(mysql-host)$ mysql -uroot -p -e 'SHOW DATABASES'
Enter password:
+--------------------+
| Database |
+--------------------+
| information_schema |
| myshop |
| mysql |
| performance_schema |
| sysbench |
+--------------------+
(mysql-host)$ mysql -uroot -p -e 'SHOW GRANTS FOR [email protected]"192.168.0.%"'
Enter password:
+------------------------------------------------------------------------------------------------------------------------+
| Grants for [email protected]% |
+------------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'sysbench_user'@'192.168.0.%' IDENTIFIED BY PASSWORD '*4AC2E8AD02562E8FAAF5A958DC2AEA4C47451B5C' |
| GRANT ALL PRIVILEGES ON `sysbench`.* TO 'sysbench_user'@'192.168.0.%' |
+------------------------------------------------------------------------------------------------------------------------+
Habilitación del registro de consultas lentas
Este rol admite habilitar el registro de consultas lentas de MySQL, podemos definir la ubicación del archivo de registro, así como el tiempo de consulta lenta. Agregue las variables necesarias dentro del archivo vars/main.yml:
mysql_root_password: "theR00tP455w0rd"
mysql_databases:
- name: example_db
encoding: latin1
collation: latin1_general_ci
- name: sysbench
encoding: latin1
collation: latin1_general_ci
mysql_users:
- name: example_user
host: "%"
password: similarly-secure-password
priv: "example_db.*:ALL"
- name: sysbench_user
host: "192.168.0.%"
password: sysBenchPassw0rd
priv: "sysbench.*:ALL"
mysql_slow_query_log_enabled: true
mysql_slow_query_log_file: 'slow_query.log'
mysql_slow_query_time: '5.000000'
Vuelva a ejecutar el libro de jugadas para aplicar los cambios:
(ansible-host)$ ansible-playbook deploy-mysql.yml
El libro de jugadas realizará los cambios necesarios en las opciones relacionadas con la consulta lenta de MySQL y reiniciará el servidor MySQL automáticamente para cargar las nuevas configuraciones. Entonces podemos verificar si las nuevas opciones de configuración se cargan correctamente en el servidor MySQL:
(mysql-host)$ mysql -uroot -p -e 'SELECT @@slow_query_log, @@slow_query_log_file, @@long_query_time'
+------------------+-----------------------+-------------------+
| @@slow_query_log | @@slow_query_log_file | @@long_query_time |
+------------------+-----------------------+-------------------+
| 1 | slow_query.log | 5.000000 |
+------------------+-----------------------+-------------------+
Incluyendo archivo de configuración de MySQL personalizado
Las variables de rol de Ansible y las variables de MySQL son dos cosas diferentes. El autor de este rol ha creado una serie de variables relacionadas con MySQL que se pueden representar con variables de roles de Ansible. Tomados del archivo Léame, estos son algunos de ellos:
mysql_port: "3306"
mysql_bind_address: '0.0.0.0'
mysql_datadir: /var/lib/mysql
mysql_socket: *default value depends on OS*
mysql_pid_file: *default value depends on OS*
mysql_log_file_group: mysql *adm on Debian*
mysql_log: ""
mysql_log_error: *default value depends on OS*
mysql_syslog_tag: *default value depends on OS*
Si la configuración generada no cumple con nuestro requisito de MySQL, podemos incluir archivos de configuración de MySQL personalizados en la implementación usando la variable mysql_config_include_files. Acepta una matriz de valores separados por una coma, con un "src" como prefijo para la ruta real en el host de Ansible.
En primer lugar, tenemos que preparar los archivos de configuración personalizados en el host de Ansible. Cree un directorio y un archivo de configuración simple de MySQL:
(ansible-host)$ mkdir /root/custom-config/
(ansible-host)$ vim /root/custom-config/my-severalnines.cnf
[mysqld]
max_connections=250
log_bin=binlog
expire_logs_days=7
Digamos que tenemos otro archivo de configuración específicamente para la configuración de mysqldump:
(ansible-host)$ vim /root/custom-config/mysqldump.cnf
[mysqldump]
max_allowed_packet=128M
Para importar estos archivos de configuración a nuestra implementación, defínalos en la matriz mysql_config_include_files en el archivo vars/main.yml:
mysql_root_password: "theR00tP455w0rd"
mysql_databases:
- name: example_db
encoding: latin1
collation: latin1_general_ci
- name: sysbench
encoding: latin1
collation: latin1_general_ci
mysql_users:
- name: example_user
host: "%"
password: similarly-secure-password
priv: "example_db.*:ALL"
- name: sysbench_user
host: "192.168.0.%"
password: sysBenchPassw0rd
priv: "sysbench.*:ALL"
mysql_slow_query_log_enabled: true
mysql_slow_query_log_file: slow_query.log
mysql_slow_query_time: 5
mysql_config_include_files: [
src: '/root/custom-config/my-severalnines.cnf',
src: '/root/custom-config/mysqldump.cnf'
]
Tenga en cuenta que /root/custom-config/mysqld-severalnines.cnf y /root/custom-config/mysqldump.cnf existen dentro del host de Ansible.
Vuelva a ejecutar el libro de jugadas:
(ansible-host)$ ansible-playbook deploy-mysql.yml
El libro de jugadas importará esos archivos de configuración y los colocará en el directorio de inclusión (dependiendo del sistema operativo) que es /etc/my.cnf.d/ para CentOS 7. El libro de jugadas reiniciará automáticamente el Servidor MySQL para cargar las nuevas opciones de configuración. Entonces podemos verificar si las nuevas opciones de configuración se cargan correctamente:
(mysql-host)$ mysql -uroot -p -e 'select @@max_connections'
250
(mysql-host)$ mysqldump --help | grep ^max-allowed-packet
max-allowed-packet 134217728
Conclusión
Ansible se puede utilizar para automatizar la implementación de la base de datos y la gestión de la configuración con un poco de conocimiento de secuencias de comandos. Mientras tanto, ClusterControl utiliza un enfoque SSH sin contraseña similar para implementar, monitorear, administrar y escalar su clúster de base de datos de la A a la Z, con una interfaz de usuario y no necesita habilidades adicionales para lograr el mismo resultado.