Ansible幂等MySQL安装Playbook

我想在AWS上设置一个MySQL服务器,使用Ansible进行configurationpipe理。 我正在使用Amazon的默认AMI( ami-3275ee5b ),它使用yum进行包pipe理。

当下面的Playbook被执行时,一切顺利。 但是,当我再次运行它时, Configure the root credentials的任务失败,因为MySQL的旧密码不再匹配,因为上次运行此Playbook时已更新。

这使得Playbook不具有幂等性,这是我不喜欢的。 我希望能够根据需要多次运行Playbook。

 - 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 

什么是解决这个问题的最好方法,这意味着使Playbook幂等性? 提前致谢!

我在coderwall上发布了这个消息 ,但是我会在原始post的评论中重现dennisjac的改进。

这样做的诀窍就是知道mysql_user模块会find一个〜/ .my.cnf文件。

我首先更改密码,然后用密码凭证复制.my.cnf文件。 当您尝试第二次运行时,myqsl_user可选模块将find.my.cnf并使用新密码。

 - 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 

.my.cnf模板如下所示:

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

编辑:在评论中增加了由Dhananjay Nene推荐的特权,并且改变了variables插值使用大括号而不是美元符号

Ansible版本用于安全的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 

模板/根/ my.cnf.j2

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

参考

这是@LorinHochStein提出的解决scheme

我的约束之一是确保没有密码存储在服务器上的任何地方的纯文本文件。 因此.my.cnf不是一个实际的命题

解答:

 - 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 

并在variables文件

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

在不改变mysql密码的情况下,像往常一样在命令行上运行正确的操作手册。

更改mysql密码时,将以下内容添加到命令行中。 在命令行上指定它允许在命令行中设置的参数优先于在vars文件中默认的参数。

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

运行该命令后,如下所示更改variables文件

 current_password=buzzz new_password={{ current_password }} 

除了之前的答案之外,在运行命令之前,我并不需要手动步骤,也就是说,我想启动一个新的服务器,只需运行操作手册,而无需第一次手动更改root密码。 我不相信{{mysql_password}}将在第一次工作,当root密码为空时,因为mysql_password仍然需要在某处定义(除非你想用-e覆盖它)。

所以我添加了一个规则来做到这一点,如果失败,它将被忽略。 这是除此之外的任何其他命令之前出现的。

 - 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 

为了正确的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 

那么,这有点复杂。 我已经花了整整一天的时间,并提出了下面列出的解决scheme。 关键是Ansible如何安装MySQL服务器。 从mysql_user模块的文档(页面上的最后一个注释):

 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. 

这个空白或空密码的问题是一个很大的惊喜。

作用

 --- - 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 

处理程序

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

.my.cnf.j2

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

以下将工作(在2个mysql_user调用之间插入my.cnf)


 - 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" 

我知道这是一个古老的问题,但我正在为那些正在寻找它的人分享我的工作剧本:

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 }} 

在设置root密码之前启动/重新启动mysql服务器非常重要。 此外,我已经尝试了所有张贴到这个职位[date]的一切,并发现必须通过login_passwordlogin_user

(即)任何播放设置mysql_user user:rootpassword= {{ SOMEPASSWORD }} ,您必须连接使用login_passwordlogin_user进行后续播放。

注意:下面的with_items是基于Ansible&MariaDB默认主机创build的

保护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' 

我join了自己的各种方法(七号)。

variablesmysql_root_password应该存储在一个不可变的保险库中(更好)或传递给命令行(更糟糕)

 - 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 }}