上一篇我们介绍了常用的ansilbe模块,如果熟练掌握了这些模块,你以为这就精通了ansible,那就大错特错了,anislbe的精华还没开始呢,当然熟练掌握模块是基础,接下来我们就要学习playbook,什么是playbook呢,可以说之前我们学习的那些模块都是ansible系统的基础组件,而playbook通过灵活的组装这些组件,可以实现更为复杂的业务操作场景,所以呢,playbook就是ansilble的另一种运行模式,除了直接命令行调模块,真正在线上展示威力的还得依靠playbook,那么这篇我们就来通过例子来介绍如何使用,开始前我们先假设一个场景:
最近不知道领导的脑袋里那两个脑触突然碰到了一起,突然今天跟部门开会说,我们部门要搭建一个技术博客,把咱们的技术都沉淀下来,环境呢我看也别太复杂,就选择wordpress就行,哪个同事给搭建下,这时你发现大家的目光都聚集到了你这里,别想了,就是你了,全桌就你一个干运维的,这活铁定你干,接下来开始准备服务器(也可能就是台式机什么的),服务器安装好系统后,你ssh进入系统(当然如果你装了windows,这篇文章到这你就不用看了,省下的时间重装完系统再回来看也不迟,反正我也不会删),开始下载所需的软件nginx,mysql,workdress,php-fpm,然后开始编译安装,过程不在赘述,经过几个小时,你终于搞定了,领导来审查,拍着你肩膀说,小四五呀,做的不错,这么快就搞定了,就在你心底一乐,腰板刚要挺直,感觉自己光芒万射的时候,领导突然说,咱们客户那边还有2000台机器要安装wordpress环境,你去帮你一起安装下吧,小伙子能干,明天下班前可以把? 这时你的cpu粗算了下,搭一个环境预计二小时,2000台就是4000个小时,4000个小时就是166天,卧槽,半年过去了,还没算自己吃饭睡觉,XX的时间,这时你弱弱的跟领导说,2年行不? 领导沉稳的反问了你一句:你小子打算去财务交工牌么?。故事到此结束,这个故事只是了解下背景,当然写的有点夸张,所以喜欢较劲的朋友在后台留言的时候千万别问我,”为什么不写脚本完成这个需求?“,那样的话我只能默默的关闭你的留言了,顺便问一句,咱还能好好一起坐友谊的小船么?
背景有点长了,我们进入技术阶段,那我们用ansible如何完成上面的需求呢,我们就来看如何组装我们的模块吧,因为ansible用的是yaml语言,如果有不了解的自己补补,在这就不多说了,在开始前我们先来了解几个概念:
var:ansible里变量的概念是重用某些定义值,主要是模板会用到。
tasks:任务就是按配置文件的定义的去执行的操作。
handlers:当被操作的主机配置发生改变时要进行的操作,这里需要通知它,然后handlers定义的动作会被执行。
了解了这三个,我们再了解一个概念role,role在ansible可以将任务等模块化了,使他们复用性更强,概念介绍到这里,如果以上没完全理解也没关系,我们一会看实际的例子就明白了,了解了以上概念,就可以给出出整体的配置文件目录结构了,这样大家先有一个大致的框架,接下来我们我们再一一讲解。
|-- group_vars
| `-- all
|-- hosts
|-- LICENSE.md
|-- README.md
|-- roles
| |-- common
| | |-- files
| | | |-- epel.repo
| | | |-- iptables-save
| | | `-- RPM-GPG-KEY-EPEL-6
| | |-- handlers
| | | `-- main.yml
| | `-- tasks
| | `-- main.yml
| |-- mysql
| | |-- handlers
| | | `-- main.yml
| | |-- tasks
| | | `-- main.yml
| | `-- templates
| | `-- my.cnf.j2
| |-- nginx
| | |-- handlers
| | | `-- main.yml
| | |-- tasks
| | | `-- main.yml
| | `-- templates
| | `-- default.conf
| |-- php-fpm
| | |-- handlers
| | | `-- main.yml
| | |-- tasks
| | | `-- main.yml
| | `-- templates
| | `-- wordpress.conf
| `-- wordpress
| |-- tasks
| | `-- main.yml
| `-- templates
| `-- wp-config.php
`-- site.yml
以上就是整体的目录结构,还有2个文件没介绍,hosts是要操作的主机组或ip,site.yml是playbook的入口文件,定义了主机,角色等,内容如下:
hosts: wordpress-server
remote_user: root
roles:
- common
- mysql
- nginx
- php-fpm
- wordpress
这里看到了我们定义的4个角色,每个角色会对应完成自己的功能,我们一会再说,先从头看起。
group_vars,目录下的all定义了所有的变量,内容如下:
wp_version: 4.2.4
wp_sha256sum: 42ca594afc709cbef8528a6096f5a1efe96dcf3164e7ce321e87d57ae015cc82
wp_db_name: wordpress
wp_db_user: wordpress
wp_db_password: mypassword
mysql_port: 3306
server_hostname: www.mindg.cn
auto_up_disable: false
core_update_level: true
这些定义的值都是给模板传值用的,一会就会看到。
我们看来每个role的定义,common是通用的role,就是表示其他角色都可能用到的可以放这里,common有点特殊,它有个file目录,主要是存储一些服务器需要的系统配置文件,要拷贝到目标服务器上,然后tasks,handlers就比较熟悉了,我们先看tasks目录,这个目录下只有一个文件,定义了要完成的任务,内容如下:
---
- name: Install libselinux-python
yum: name=libselinux-python state=present
- name: Copy the EPEL repository definition
copy: src=epel.repo dest=/etc/yum.repos.d/epel.repo
- name: Create the GPG key for EPEL
copy: src=RPM-GPG-KEY-EPEL-6 dest=/etc/pki/rpm-gpg
- name: Set up iptables rules
copy: src=iptables-save dest=/etc/sysconfig/iptables
notify: restart iptables
注意看最后一句notify,这条语句表示iptables配置文件变更后,通知restart iptables ,这个定义在然后看handler的main.yml,下:
---
- name: restart iptables
service: name=iptables state=restarted
如果理解了common,那以下几个模式基本都一样了,我们来看看mysql目录的内容,
tasks目录下的main.yml文件:
---
- name: Install Mysql package
yum: name={{ item }} state=present
with_items:
- mysql-server
- MySQL-python
- libselinux-python
- libsemanage-python
- name: Configure SELinux to start mysql on any port
seboolean: name=mysql_connect_any state=true persistent=yes
when: ansible_selinux.status == "enabled"
- name: Create Mysql configuration file
template: src=my.cnf.j2 dest=/etc/my.cnf
notify:
- restart mysql
- name: Start Mysql Service
service: name=mysqld state=started enabled=yes
handlers/main.yml:
---
- name: restart mysql
service: name=mysqld state=restarted
templates/my.cnf.j2:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
port={{ mysql_port }}
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
这里我们说2个内容,一个是with_items,这是常用的循环方法,这个语句下的内容会依次传入{{ item}}来替换item,第二个说下模板,my.cnf.j2里的内凡是{{ }}的内容都在group_var/all里做了定义,顺便说下,ansible模板文件用的jinja2的模板,如果有了解flask的肯定会理解,jinja2是flask框架默认的模板,想深入了解的,自己可以补补。
php-fpm内容,php-fpm/tasks/main.yml:
---
- name: Install php-fpm and deps
yum: name={{ item }} state=present
with_items:
- php
- php-fpm
- php-enchant
- php-IDNA_Convert
- php-mbstring
- php-mysql
- php-PHPMailer
- php-process
- php-simplepie
- php-xml
- name: Disable default pool
command: mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.disabled creates=/etc/php-fpm.d/www.disabled
notify: restart php-fpm
- name: Copy php-fpm configuration
template: src=wordpress.conf dest=/etc/php-fpm.d/
notify: restart php-fpm
handlers/main.yml:
---
- name: restart php-fpm
service: name=php-fpm state=restarted
templates/wordpress.conf :
[wordpress]
listen = /var/run/php-fpm/wordpress.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
user = wordpress
group = wordpress
pm = dynamic
pm.max_children = 10
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500
chdir = /srv/wordpress/
php_admin_value[open_basedir] = /srv/wordpress/:/tmp
这部分没特殊的,不多说了,大家看看配置文件了解下即可。
最后一个workpress/tasks/main.yml;
---
- name: Download WordPress
get_url: url=http://wordpress.org/wordpress-{{ wp_version }}.tar.gz dest=/srv/wordpress-{{ wp_version }}.tar.gz
sha256sum="{{ wp_sha256sum }}"
- name: Extract archive
command: chdir=/srv/ /bin/tar xvf wordpress-{{ wp_version }}.tar.gz creates=/srv/wordpress
- name: Add group "wordpress"
group: name=wordpress
- name: Add user "wordpress"
user: name=wordpress group=wordpress home=/srv/wordpress/
- name: Fetch random salts for WordPress config
local_action: command curl https://api.wordpress.org/secret-key/1.1/salt/
register: "wp_salt"
sudo: no
- name: Create WordPress database
mysql_db: name={{ wp_db_name }} state=present
- name: Create WordPress database user
mysql_user: name={{ wp_db_user }} password={{ wp_db_password }} priv={{ wp_db_name }}.*:ALL host='localhost' state=present
- name: Copy WordPress config file
template: src=wp-config.php dest=/srv/wordpress/
- name: Change ownership of WordPress installation
file: path=/srv/wordpress/ owner=wordpress group=wordpress state=directory recurse=yes
- name: Start php-fpm Service
service: name=php-fpm state=started enabled=yes
templates/wp-config.php:
<?php
/** The name of the database for WordPress */
define('DB_NAME', '{{ wp_db_name }}');
/** MySQL database username */
define('DB_USER', '{{ wp_db_user }}');
/** MySQL database password */
define('DB_PASSWORD', '{{ wp_db_password }}');
/** MySQL hostname */
define('DB_HOST', 'localhost');
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
{{ wp_salt.stdout }}
$table_prefix = 'wp_';
define('WPLANG', '');
define('WP_DEBUG', false);
/** Disable Automatic Updates Completely */
define( 'AUTOMATIC_UPDATER_DISABLED', {{auto_up_disable}} );
/** Define AUTOMATIC Updates for Components. */
define( 'WP_AUTO_UPDATE_CORE', {{core_update_level}} );
/* That's all, stop editing! Happy blogging. */
/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');
wordpress模板基本都是wordpress的配置,没什么特殊要讲的,到这里,篇幅已经很长了,如果有什么没说明白的地方可以给我留言,最后一个问题,配置这么一大堆,到底怎么运行呀,运行命令是这样地:
#ansible-playbook -i hosts site.yml
就可以运行了,如果机器多就并发去做,ansible都可以支持,这篇文章就到这里,这是系列2,还剩最后的开发篇,我们下篇见。