mysql command-line amazon-web-services amazon-ec2 ansible

Ansible idempotent Instalación de MySQL Playbook



command-line amazon-web-services (10)

Quiero configurar un servidor MySQL en AWS, usando Ansible para la gestión de la configuración. Estoy usando el AMI predeterminado de Amazon ( ami-3275ee5b ), que usa yum para la administración de paquetes.

Cuando se ejecuta la Playbook a continuación, todo va bien. Pero cuando lo ejecuto por segunda vez, la tarea Configure the root credentials falla, porque la contraseña anterior de MySQL ya no coincide, ya que se actualizó la última vez que ejecuté esta Playbook.

Esto hace que el Playbook no sea idempotente, lo que no me gusta. Quiero poder ejecutar el Playbook todas las veces que quiera.

- hosts: staging_mysql user: ec2-user sudo: yes tasks: - name: Install MySQL action: yum name=$item with_items: - MySQL-python - mysql - mysql-server - name: Start the MySQL service action: service name=mysqld state=started - name: Configure the root credentials action: command mysqladmin -u root -p $mysql_root_password

¿Cuál sería la mejor manera de resolver esto, lo que significa que el Playbook es idempotente? ¡Gracias por adelantado!


Versión de Ansible para una instalación segura de MySQL.

mysql_secure_installation.yml

- hosts: staging_mysql user: ec2-user sudo: yes tasks: - name: Install MySQL action: yum name={{ item }} with_items: - MySQL-python - mysql - mysql-server - name: Start the MySQL service action: service name=mysqld state=started # ''localhost'' needs to be the last item for idempotency, see # http://ansible.cc/docs/modules.html#mysql-user - name: update mysql root password for all root accounts mysql_user: name=root host={{ item }} password={{ mysql_root_password }} with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost - name: copy .my.cnf file with root password credentials template: src=templates/root/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600 - name: delete anonymous MySQL server user for $server_hostname action: mysql_user user="" host="{{ server_hostname }}" state="absent" - name: delete anonymous MySQL server user for localhost action: mysql_user user="" state="absent" - name: remove the MySQL test database action: mysql_db db=test state=absent

templates / root / my.cnf.j2

[client] user=root password={{ mysql_root_password }}

Referencias


Agregando a las respuestas anteriores, no quería un paso manual antes de ejecutar el comando, es decir, quiero hacer girar un nuevo servidor y simplemente ejecutar el libro de jugadas sin tener que cambiar manualmente la contraseña de root la primera vez. No creo que {{mysql_password}} funcione la primera vez, cuando la contraseña de root sea nula, porque mysql_password aún tiene que definirse en algún lugar (a menos que desee sobrescribirlo con -e).

Así que agregué una regla para hacer eso, que se ignora si falla. Esto es además de, y aparece antes, cualquiera de los otros comandos aquí.

- name: Change root user password on first run mysql_user: login_user=root login_password='''' name=root password={{ mysql_root_password }} priv=*.*:ALL,GRANT host={{ item }} with_items: - $ansible_hostname - 127.0.0.1 - ::1 - localhost ignore_errors: true


Bueno, esto fue un poco complicado. He pasado un día entero sobre esto y se me ocurrió la solución que se detalla a continuación. El punto clave es cómo Ansible instala el servidor MySQL. De los documentos del módulo mysql_user (última nota en la página):

MySQL server installs with default login_user of ‘root’ and no password. To secure this user as part of an idempotent playbook, you must create at least two tasks: the first must change the root user’s password, without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from the file.

Ese problema con la contraseña en blanco o nulo fue una gran sorpresa.

Papel :

--- - name: Install MySQL packages sudo: yes yum: name={{ item }} state=present with_items: - mysql - mysql-server - MySQL-python - name: Start MySQL service sudo: yes service: name=mysqld state=started enabled=true - name: Update MySQL root password for root account sudo: yes mysql_user: name=root password={{ db_root_password }} priv=*.*:ALL,GRANT - name: Create .my.cnf file with root password credentials sudo: yes template: src=.my.cnf.j2 dest=/root/.my.cnf owner=root group=root mode=0600 notify: - restart mysql - name: Create a database sudo: yes mysql_db: name={{ db_name }} collation=utf8_general_ci encoding=utf8 state=present - name: Create a database user sudo: yes mysql_user: name={{ db_user }} password={{ db_user_password }} priv="{{ db_name }}.*:ALL" host=localhost state=present

Controlador :

--- - name: restart mysql service: name=mysqld state=restarted

.my.cnf.j2 :

[client] user=root password={{ db_root_password }}


Es importante iniciar / reiniciar el servidor mysql antes de configurar la contraseña de root. Además, había intentado todo lo publicado en esta publicación [fecha] y descubrí que es imprescindible pasar login_password y login_user .

(es decir) Cualquier Reproducción después de configurar el user:root mysql_user user:root y password= {{ SOMEPASSWORD }} , debe conectarse usando login_password y login_user para cualquier jugada posterior.

Nota: los elementos con los with_items continuación se basan en lo que crearon los hosts predeterminados de Ansible y / MariaDB .

Ejemplo para asegurar un servidor MariaDB:

--- # ''secure_mariadb.yml'' - name: ''Ensure MariaDB server is started and enabled on boot'' service: name={{ mariadb_service_name }} state=started enabled=yes # localhost needs to be the last item for idempotency, see # http://ansible.cc/docs/modules.html#mysql-user - name: ''Update Mysql Root Password'' mysql_user: name=root host={{ item }} password={{ root_db_password }} priv=*.*:ALL,GRANT state=present with_items: - 127.0.0.1 - ::1 - instance-1 # Created by MariaDB to prevent conflicts between port and sockets if multi-instances running on the same computer. - localhost - name: ''Create MariaDB main configuration file'' template: > src=my.cnf.j2 dest=/etc/mysql/my.cnf owner=root group=root mode=0600 - name: ''Ensure anonymous users are not in the database'' mysql_user: login_user=root login_password={{ root_db_password }} name='''' host={{ item }} state=absent with_items: - 127.0.0.1 - localhost - name: ''Remove the test database'' mysql_db: login_user=root login_password={{ root_db_password }} name=test state=absent - name: ''Reload privilege tables'' command: ''mysql -ne "{{ item }}"'' with_items: - FLUSH PRIVILEGES changed_when: False - name: ''Ensure MariaDB server is started and enabled on boot'' service: name={{ mariadb_service_name }} state=started enabled=yes # ''End Of File''


Esta es una solución alternativa a la propuesta por @LorinHochStein

Una de mis limitaciones era garantizar que no se almacenaran contraseñas en archivos de texto plano en ninguna parte del servidor. Por lo tanto .my.cnf no era una propuesta práctica

Solución:

- name: update mysql root password for all root accounts from local servers mysql_user: login_user=root login_password={{ current_password }} name=root host=$item password={{ new_password }} priv=*.*:ALL,GRANT with_items: - $ansible_hostname - 127.0.0.1 - ::1 - localhost

Y en el archivo vars

current_password: foobar new_password: "{{ current_password }}"

Cuando no se cambia la contraseña de mysql, ejecute el libro de jugadas ansible en la línea de comandos como de costumbre.

Al cambiar la contraseña de mysql, agregue lo siguiente a la línea de comando. Especificarlo en la línea de comandos permite que el parámetro establecido en la línea de comando tenga prioridad sobre el predeterminado en el archivo vars.

$ ansible-playbook ........ --extra-vars "new_password=buzzz"

Después de ejecutar el comando, cambie el archivo vars de la siguiente manera

current_password=buzzz new_password={{ current_password }}


Estoy agregando mi propia opinión sobre los diversos enfoques (centos 7).

La variable mysql_root_password debe almacenarse en una ansible-vault (mejor) o pasarla en la línea de comando (peor)

- name: "Ensure mariadb packages are installed" yum: name={{ item }} state="present" with_items: - mariadb - mariadb-server - name: "Ensure mariadb is running and configured to start at boot" service: name=mariadb state=started enabled=yes # idempotently ensure secure mariadb installation -- # - attempts to connect as root user with no password and then set the root@ mysql password for each mysql root user mode. # - ignore_errors is true because this task will always fail on subsequent runs (as the root user password has been changed from "") - name: Change root user password on first run, this will only succeed (and only needs to succeed) on first playbook run mysql_user: login_user=root login_password='''' name=root password={{ mysql_root_password }} priv=*.*:ALL,GRANT host={{ item }} with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost ignore_errors: true - name: Ensure the anonymous mysql user ""@{{ansible_hostname}} is deleted action: mysql_user user="" host="{{ ansible_hostname }}" state="absent" login_user=root login_password={{ mysql_root_password }} - name: Ensure the anonymous mysql user ""@localhost is deleted action: mysql_user user="" state="absent" login_user=root login_password={{ sts_ad_password }} - name: Ensure the mysql test database is deleted action: mysql_db db=test state=absent login_user=root login_password={{ mysql_root_password }}


Lo siguiente funcionará (Inserte my.cnf entre 2 llamadas a mysql_user)

- name: ''Install MySQL'' yum: name={{ item }} state=present with_items: - MySQL-python - mysql - mysql-server notify: - restart-mysql - name: ''Start Mysql Service'' action: service name=mysqld state=started enabled=yes - name: ''Update Mysql Root Password'' mysql_user: name=root host=localhost password={{ mysql_root_password }} state=present - name: ''Copy Conf file with root password credentials'' template: src=../templates/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600 - name: ''Update Rest-Mysql Root Password'' mysql_user: name=root host={{ item }} password={{ mysql_root_password }} state=present with_items: - "{{ ansible_hostname }}" - "{{ ansible_eth0.ipv4.address }}" - 127.0.0.1 - ::1 - name: ''Delete anonymous MySQL server user from server'' mysql_user: name="" host={{ ansible_hostname }} state="absent"


Para ansible 1.3+:

- name: ensure mysql local root password is zwx123 mysql_user: check_implicit_admin=True login_user=root login_password="zwx123" name=root password="zwx123" state=present


Sé que esta es una vieja pregunta, pero estoy compartiendo mi manual de trabajo para aquellos que lo están buscando:

mysql.yml

--- - name: Install the MySQL packages apt: name={{ item }} state=installed update_cache=yes with_items: - mysql-server-5.6 - mysql-client-5.6 - python-mysqldb - libmysqlclient-dev - name: Copy the configuration file (my.cnf) template: src=my.cnf.j2 dest=/etc/mysql/my.cnf notify: - Restart MySQL - name: Update MySQL root password for all root accounts mysql_user: name=root host={{ item }} password={{ mysql_root_pass }} state=present with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost - name: Copy the root credentials as .my.cnf file template: src=root.cnf.j2 dest=~/.my.cnf mode=0600 - name: Ensure Anonymous user(s) are not in the database mysql_user: name='''' host={{ item }} state=absent with_items: - localhost - "{{ ansible_hostname }}" - name: Remove the test database mysql_db: name=test state=absent notify: - Restart MySQL

vars.yml

--- mysql_port: 3306 #Default is 3306, please change it if you are using non-standard mysql_bind_address: "127.0.0.1" #Change it to "0.0.0.0",if you want to listen everywhere mysql_root_pass: mypassword #MySQL Root Password

my.cnf.j2

[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = {{ mysql_port }} basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking bind-address = {{ mysql_bind_address }} key_buffer = 16M max_allowed_packet = 64M thread_stack = 192K thread_cache_size = 8 myisam-recover = BACKUP query_cache_limit = 1M query_cache_size = 16M log_error = /var/log/mysql/error.log expire_logs_days = 10 max_binlog_size = 100M [mysqldump] quick quote-names max_allowed_packet = 64M [mysql] [isamchk] key_buffer = 16M !includedir /etc/mysql/conf.d/

root.cnf.j2

[client] user=root password={{ mysql_root_pass }}


coderwall sobre esto en coderwall , pero reproduciré la mejora de dennisjac en los comentarios de mi publicación original.

El truco para hacerlo idempotentemente es saber que el módulo mysql_user cargará un archivo ~ / .my.cnf si encuentra uno.

Primero cambio la contraseña y luego copio un archivo .my.cnf con las credenciales de la contraseña. Cuando intente ejecutarlo por segunda vez, el módulo ansible myqsl_user encontrará .my.cnf y usará la nueva contraseña.

- hosts: staging_mysql user: ec2-user sudo: yes tasks: - name: Install MySQL action: yum name={{ item }} with_items: - MySQL-python - mysql - mysql-server - name: Start the MySQL service action: service name=mysqld state=started # ''localhost'' needs to be the last item for idempotency, see # http://ansible.cc/docs/modules.html#mysql-user - name: update mysql root password for all root accounts mysql_user: name=root host={{ item }} password={{ mysql_root_password }} priv=*.*:ALL,GRANT with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost - name: copy .my.cnf file with root password credentials template: src=templates/root/.my.cnf dest=/root/.my.cnf owner=root mode=0600

La plantilla .my.cnf se ve así:

[client] user=root password={{ mysql_root_password }}

Editar: se agregaron los privilegios recomendados por Dhananjay Nene en los comentarios, y se cambió la interpolación variable para usar llaves en lugar de un signo de dólar .