一、Ansible概述和运行机制
1、Ansible概述
Ansible是Red Hat公司使用python研发的开源的自动化运维工具,类似于saltstack和Puppet这样老牌的自动化运维工具。
ansible作为一个后起之秀,在发布的短时间内迅速崛起,超越了大部分老牌的自动化运维工具,其中就包括了Saltstack和Puppet,能获得这样成绩的原因,有一个不同和优点是我们不需要在节点中安装任何客户端。它使用SSH来和节点进行通信。所以只需要被管理节点具备SSH服务以及python即可,无需任何多余操作就可实现自动化管理,而管理节点只需要安装Ansible工具,以及python,openssl即可。
总结:
Ansible是一个部署一群远程主机的工具;Ansible通过SSH协议实现远程节点和管理节点之间的通信。理论上说,只要管理员通过ssh登录到一台远程主机上能做的操作,Ansible都可以做到。Ansible是python开发的,故依赖一些python库和组件,如:paramiko,PyYaml和jinja三个关键组件;
官方网站:https://www.ansible.com/
2、Ansible的工作模块
- 连接插件connection plugins:负责和被监控端实现通信;
- host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
- 各种模块核心模块、command模块、自定义模块;
- 借助于插件完成记录日志邮件等功能;
- playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
3、Ansible的工作原理
- 管理端支持local 、ssh、zeromq 三种方式连接被管理端,默认使用基于ssh的连接---这部分对应基本架构图中的连接模块;
- 可以按应用类型等方式进行Host Inventory(主机群)分类,管理节点通过各类模块实现相应的操作---单个模块,单条命令的批量执行,我们可以称之为ad-hoc;
- 管理节点可以通过playbooks 实现多个task的集合实现一类功能,如web服务的安装部署、数据库服务器的批量备份等。playbooks我们可以简单的理解为,系统通过组合多条ad-hoc操作的配置文件 。
4、Ansible基本架构
ansible系统由管理节点和被管理节点组成,Ansible 在管理节点将 Ansible 模块通过SSH 协议推送到被管理端执行,执行完之后自动删除,可以使用 SVN、GIT 等来管理自定义模块及编排。

由上面的图可以看到 Ansible 的组成由 5 个部分组成:
- Ansible: ansible的核心程序
- Modules:包括 Ansible 自带的核心模块及自定义模块。
- Core Modules:Ansible执行任何管理任务都不是由Ansible自己完成,而是由核心模块完成;Ansible管理主机之前,先调用core Modules中的模块,然后指明管理Host Inventory中的主机,就可以完成管理主机。
- Custom Modules:自定义模块,完成Ansible核心模块无法完成的功能,此模块支持任何语言编写。
- Plugins:模块功能补充,通过插件来实现记录日志,发送邮件或其他功能。
- Connectior Plugins:连接插件, ansible基于连接插件连接到各个主机上,默认是使用ssh。
- Playbooks:剧本,YAML格式文件。多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能定义,即实现自动化部署文件。
- Host Inventory: 记录由Ansible管理的主机信息,包括端口、密码、ip等。 [ˈɪnvəntri] 清单。
右边绿色部分是被管理的主机(虚拟机,物理机,云主机等),从以上架构图中可以看出ansible是由主机清单,playbook以及各模块插件组成。
简单的说就是,用户(管理员)通过ansible的主机清单配置或Playbook配置(一组任务),调用ansible的各种模块及参数来对清单中的主机进行统一管理。
5、Ansible特点
部署简单, 只需要在管理主机上部署ansible环境,被管理端上只要求安装ssh和python 2.5以上版本,这个对于类unix系统来说相当与无需配置。
1、部署简单,只需在管理端部署Ansible环境,被管理端无需做任何操作,即不需要安装agent
2、默认使用SSH协议对设备进行管理
3、易读的语法,基于yaml语法编写playbook
4、模块化设计,调用特定的模块来完成特定任务
5、基于Python语言实现,由Paramiko(python的一个可并发连接ssh主机功能库), PyYAML和Jinja2(模板化)三个关键模块实现。支持API(供第三方程序调用的应用程序编程接口)及自定义模块,可通过Python轻松扩展
6、支持playbook剧本,连续任务按先后设置顺序完成。通过Playbooks来定制强大的配置、状态管理
7、幂等性,一个任务执行一遍和执行n遍效果一样,不会因为重复执行带来意外情况。意味着在同一台服务器上多次执行同一个playbook是安全的
8、对云计算平台、大数据都有很好的支持;
6、安装Ansible
安装阿里源和epel源
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && yum install -y epel-release
# 安装ansible
yum install -y ansible
7、Ansible配置文件说明
通过rpm -ql ansible可以看到有很多文件,主要是配置文件和和可执行文件,以及所依赖的python库文件。
1)主配置文件**/etc/ansible/ansible.cfg**
- inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件的位置
- library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
- forks = 5 #并发连接数,默认为5
- sudo_user = root #设置默认执行命令的用户
- remote_port = 22 #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
- host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
- timeout = 60 #设置SSH连接的超时时间,单位为秒
- log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)
2)主机清单文件**/etc/ansible/hosts**

公钥认证检查关闭,这样我们就可以正常的访问被管理节点了
编辑主机清单文件
vim /etc/ansible/hosts
[all:vars]
ansible_ssh_user=root
ansible_ssh_pass=1
ansible_ssh_port=22
[kubernetes]
192.168.1.111
192.168.1.112
192.168.1.113
192.168.1.114
# ping测试
[root@master ~]# ansible all -m ping
192.168.1.114 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.1.112 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.1.113 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.1.111 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
8、Ansible命令参数
ansible详细参数:
-v #详细模式,如果命令执行成功,输出详细的结果 (-vv --vvv -vvvv)
-i #指定清单文件(hosts)的路径,默认是在 /etc/ansible/hosts
-m #指定使用的module名称,默认使用 command模块
-a #指定module模块的参数
-u #ssh连接的用户名,默认用root,ansible.cfg中可以配置
-k #提示输入ssh登录密码,当使用密码验证的时候用
-s,--sudo:远程执行命令时使用sudo方式,相当于Linux系统下的sudo命令。
-U SUDO_USERNAME,sudo到哪个用户,默认为root
注意:上述的-s和-U选项在新版中已经失效。新版本选项如下两项:
-s,--sudo 被改成 -b,--become
-U,--sudo-user被改成 --become-user
-K, --ask-become-pass:使用--become或者--become-user时使用的密码认证(即提示输入sudo密码,当不是NOPASSWD模式时使用)。
-C #测试此命令执行会改变什么内容,不会真正的去执行
-f FORKS, --forks=FORKS:并行线程数量,当有数量巨大的机器需要配置,可以使用高并发线程,默认是5个。
--list-host:只打印有哪些主机会执行这个命令,不会实际执行
ansible-doc详细参数:
ansible-doc -l #列出所有的模块列表
ansible-doc -s 模块名 #查看指定模块的参数 -s, --snippet # [ˈsnɪpɪt] 片断
二、Ansible常用模块
1、命令模块
command
command 模块可以帮助我们在远程主机上执行命令。
注意:使用 command 模块在远程主机中执行命令时,不会经过远程主机的 shell处理,在使用 command 模块时,如果需要执行的命令中含有重定向、管道符等操作时,这些符号也会失效,比如"<", ">", "|", ";" 和 "&" 这些符号,如果你需要这些功能,可以参考后面介绍的 shell 模块。还有一点需要注意,执行ansible时,不加-m 默认使用
默认如果使用别的模块,可以在/etc/ansible/ansible.cfg 中修改

|-----------|--------------------------|
| 参数 | 释义 |
| chdir | 在执行命令前,进入到指定目录中 |
| creates | 判断指定文件是否存在,如果存在,不执行后面的操作 |
| removes | 判断指定文件是否存在,如果存在,执行后面的操作 |
| free_form | 必须要输入一个合理的命令 |
# 用ansible查看远程主机的内存
[root@master ~]# ansible kubernetes -m command -a "free -h | grep Mem"
192.168.1.114 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 974M 393M 215M 7.7M 365M 381M
Swap: 2.0G 0B 2.0G
192.168.1.113 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 3.8G 571M 2.3G 4.6M 989M 2.8G
Swap: 0B 0B 0B
192.168.1.112 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 3.8G 778M 2.1G 5.6M 971M 2.6G
Swap: 0B 0B 0B
192.168.1.111 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 3.8G 836M 1.5G 4.1M 1.6G 2.7G
Swap: 0B 0B 0B
可以发现我们的管道符没有起作用。想解决这个问题把command替换为shell模块就可以
# chdir 在执行命令前进入到指定目录
[root@master ~]# ansible kubernetes -m command -a "chdir=/tmp ls -l"
192.168.1.114 | CHANGED | rc=0 >>
total 0
drwx------ 2 root root 41 Jul 18 15:04 ansible_command_payload_bkPqHr
drwx------ 3 root root 17 Jul 18 09:41 systemd-private-db3e50d8d9e947fa916d484e2d394644-chronyd.service-haCV0y
192.168.1.112 | CHANGED | rc=0 >>
total 0
drwx------ 2 root root 41 Jul 18 23:04 ansible_command_payload_sRyXPw
drwx------ 2 root root 6 Jul 11 18:27 vmware-root
192.168.1.113 | CHANGED | rc=0 >>
total 0
drwx------ 2 root root 41 Jul 18 23:04 ansible_command_payload_gER0WV
drwx------ 2 root root 6 Jul 18 17:41 vmware-root
192.168.1.111 | CHANGED | rc=0 >>
total 0
drwx------ 2 root root 41 Jul 18 23:04 ansible_command_payload_xYA2ms
drwx------ 2 root root 6 Jul 9 02:34 vmware-root
# creates 判断判断指定文件是否存在,如果存在,不执行操作
[root@master ~]# ansible kubernetes -m command -a "touch /root/1.txt creates=/root/1.txt"
[root@master ~]# ansible kubernetes -m command -a "touch /root/2.txt creates=/root/1.txt"
# romoves 判断指定文件是否存在,如果存在,执行操作
[root@master ~]# ansible kubernetes -m command -a "rm -rf /root/1.txt removes=/root/1.txt"
shell
shell 模块可以帮助我们在远程主机上执行命令。与 command 模块不同的是,shell模块在远程主机中执行命令时,会经过远程主机上的/bin/sh程序处理,shell模块支持管道与重定向等符号;所以,我们在终端输入的各种命令方式,都可以使用。
[root@master ~]# ansible kubernetes -m shell -a "free -h | grep Mem"
192.168.1.114 | CHANGED | rc=0 >>
Mem: 974M 393M 215M 7.8M 365M 380M
192.168.1.112 | CHANGED | rc=0 >>
Mem: 3.8G 776M 2.1G 5.6M 976M 2.6G
192.168.1.113 | CHANGED | rc=0 >>
Mem: 3.8G 572M 2.3G 4.6M 990M 2.8G
192.168.1.111 | CHANGED | rc=0 >>
Mem: 3.8G 839M 1.5G 4.1M 1.5G 2.7G
2、文件模块
copy
实现主控端向目标主机拷贝文件或目录,类似scp功能
|----------------|----------|------------------------------------------------------|
| 参数 | 选项/默认值 | 释义 |
| src | | 指定将本地管理主机的什么数据信息进行远程复制 |
| backup | no* yes | 默认数据复制到远程主机,会覆盖原有文件(yes 将源文件进行备份) |
| content | | 在文件中添加信息 |
| dest(required) | | 将数据复制到远程节点的路径信息 |
| group | | 文件数据复制到远程主机,设置文件属组用户信息 |
| mode | | 文件数据复制到远程主机,设置数据的权限 eg 0644 0755 |
| owner | | 文件数据复制到远程主机,设置文件属主用户信息 |
| remote_src | no* yes | 如果设置为yes,表示将远程主机上的数据进行移动操作如果设置为no, 表示将管理主机上的数据进行分发操作 |
备注:
required:为必须使用的参数
*:为默认参数
copy模块在复制数据时,如果数据为软链接文件,会将链接指定源文件进行复制
修改权限时候 需要加0 例如:chmod 0644 0755
[root@master ~]# ansible kubernetes -m copy -a "src=/root/1.txt dest=/root/1.txt"
# backup 如果源文件和目标位置文件的内容不一样,会进行备份,如果内容一样,就不会备份
ansible kubernetes -m copy -a "src=/root/1.txt dest=/tmp backup=yes"
[root@master ~]# ls /tmp/
1.txt 1.txt.60916.2022-07-19@00:20:55~ vmware-root
# owner设置文件属主信息
# group设置文件属组信息
# mode设置文件权限
ansible kubernetes -m copy -a "src=./1.txt dest=/root owner=www group=www mode=0644"
# content 在文件中添加信息 如果文件中有内容的话会被覆盖
ansible kubernetes -m copy -a "content=123 dest=/root/1.txt"
[root@master ~]# cat 1.txt
123[root@master ~]#
注:content添加内容不会添加回车符
fetch
从管理主机抓取文件
|---------------|--------------------------|
| 参数 | 释义 |
| src(required) | 要获取的远程系统上的文件,必须是文件,而不是目录 |
| dest | 用于保存文件的目录 |
# 将管理主机的hosts文件保存到自己的root下
[root@master ~]# ansible kubernetes -m fetch -a "src=/etc/hosts dest=/root/hosts"
file
实现创建/删除文件信息 对数据权限进行修改
|--------------------------|-----------|----------------------------------|
| 参数 | 选项/默认值 | 释义 |
| dest/path/name(required) | | 将数据复制到远程节点的路径信息 |
| group | | 文件数据复制到远程主机,设置文件属组用户信息 |
| mode | | 文件数据复制到远程主机,设置数据的权限 eg 0644 0755 |
| owner | | 文件数据复制到远程主机,设置文件属主用户信息 |
| src | | 指定将本地管理主机的什么数据信息进行远程复制 |
| state | absent | 将数据进行删除 |
| state | directory | 创建一个空目录信息 |
| state | file | 查看指定目录信息是否存在 |
| state | touch | 创建一个空文件信息 |
| state | hard/link | 创建链接文件 |
# 将目标主机的文件权限修改为777
ansible kubernetes -m file -a "path=/etc/hosts mode=777"
# 验证权限
[root@master ~]# ansible kubernetes -m shell -a "ls -ld /etc/hosts"
192.168.1.112 | CHANGED | rc=0 >>
-rwxrwxrwx 1 root root 220 Jun 10 13:53 /etc/hosts
192.168.1.114 | CHANGED | rc=0 >>
-rwxrwxrwx. 1 root root 158 Jun 7 2013 /etc/hosts
192.168.1.113 | CHANGED | rc=0 >>
-rwxrwxrwx 1 root root 220 Jun 10 13:53 /etc/hosts
192.168.1.111 | CHANGED | rc=0 >>
-rwxrwxrwx 1 root root 220 Jun 10 13:53 /etc/hosts
# 将目标主机上的/root/1.txt文件创建符号链接到/tmp下
ansible kubernetes -m file -a "src=/root/1.txt dest=/tmp/1.txt state=link"
# 验证
[root@master ~]# ansible kubernetes -m shell -a "ls -ld /tmp/1.txt"
192.168.1.114 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 11 Jul 21 10:25 /tmp/1.txt -> /root/1.txt
192.168.1.112 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 11 Jul 21 18:25 /tmp/1.txt -> /root/1.txt
192.168.1.113 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 11 Jul 21 18:25 /tmp/1.txt -> /root/1.txt
192.168.1.111 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 11 Jul 21 18:25 /tmp/1.txt -> /root/1.txt
# 在目标主机判断目录是否存在,不存在则创建
ansible kubernetes -m file -a "path=/root/dir state=directory"
# 验证
[root@master ~]# ansible kubernetes -m shell -a "ls -ld /root/dir"
192.168.1.114 | CHANGED | rc=0 >>
drwxr-xr-x 2 root root 6 Jul 21 10:31 /root/dir
192.168.1.112 | CHANGED | rc=0 >>
drwxr-xr-x 2 root root 6 Jul 21 18:31 /root/dir
192.168.1.113 | CHANGED | rc=0 >>
drwxr-xr-x 2 root root 6 Jul 21 18:31 /root/dir
192.168.1.111 | CHANGED | rc=0 >>
drwxr-xr-x 2 root root 6 Jul 21 18:31 /root/dir
# 在目标主机创建一个空文件
ansible kubernetes -m file -a "path=/root/test.txt state=touch"
# 验证
[root@master ~]# ansible kubernetes -m shell -a "ls /root/test.txt"
192.168.1.114 | CHANGED | rc=0 >>
/root/test.txt
192.168.1.113 | CHANGED | rc=0 >>
/root/test.txt
192.168.1.112 | CHANGED | rc=0 >>
/root/test.txt
192.168.1.111 | CHANGED | rc=0 >>
/root/test.txt
3、安装模块
yum
使用yum软件包管理器安装,升级,降级,删除和列出软件包和组。
|----------------|-------------------|--------------------|
| 参数 | 选项/默认值 | 释义 |
| name(required) | | 指定软件名称信息 |
| state | absent/removed | 将软件进行卸载(慎用) |
| state | present/installed | 将软件进行安装 |
| state | latest | 安装最新的软件 yum update |
# 在目标主机安装最新的httpd
ansible kubernetes -m yum -a "name=httpd state=latest"
# 验证
[root@master ~]# ansible kubernetes -m shell -a "rpm -qa | grep httpd"
192.168.1.112 | CHANGED | rc=0 >>
httpd-tools-2.4.6-97.el7.centos.5.x86_64
httpd-2.4.6-97.el7.centos.5.x86_64
192.168.1.113 | CHANGED | rc=0 >>
httpd-2.4.6-97.el7.centos.5.x86_64
httpd-tools-2.4.6-97.el7.centos.5.x86_64
192.168.1.114 | CHANGED | rc=0 >>
httpd-tools-2.4.6-97.el7.centos.5.x86_64
httpd-2.4.6-97.el7.centos.5.x86_64
192.168.1.111 | CHANGED | rc=0 >>
httpd-2.4.6-97.el7.centos.5.x86_64
httpd-tools-2.4.6-97.el7.centos.5.x86_64
4、服务模块
service
用于管理服务运行状态
|-----------------|------------|-------------------------------------|
| 参数 | 选项/默认值 | 释义 |
| enabled | no yes | 设置服务是否开机自启动 如果参数不指定,原有服务开机自启动状态进行保留 |
| name (required) | | 设置要启动/停止服务名称 |
| state= | reloaded | 平滑重启 |
| state= | restarted | 重启 |
| state= | started | 启动 |
| state= | stopped | 停止 |
# 启动httpd服务并设置为开机自启动
ansible kubernetes -m service -a "name=httpd enabled=yes state=started"
# 删除httpd服务
ansible kubernetes -m yum -a "name=httpd state=removed"
5、挂载模块
mount
用于批量管理主机进行挂载卸载操作
|--------|-----------|---------------------|
| 参数 | 选项/默认值 | 释义 |
| fstype | | |
| opts | | |
| path | | |
| src | | |
| state | absent | 会进行卸载,也会修改fstab文件信息 |
| state | unmounted | 会进行卸载,不会修改fstab文件 |
| state | present | 不会挂载,只会修改fstab文件 |
| state | mounted | 会进行挂载,会修改fstab文件 |
#只是在/etc/fstab文件中添加了配置信息,不会真正进行挂载(mount -a)
ansible kubernetes -m mount -a "src=172.16.1.31:/data/ path=/mnt fstype=nfs state=present"
# 在/etc/fstab文件中添加了配置信息,并且也会真正进行挂载
ansible kubernetes -m mount -a "src=172.16.1.31:/data/ path=/mnt fstype=nfs state=mounted"
6、定时任务模块
cron
定时任务模块
|-------------------------------|------------|-------------|
| 参数 | 选项/默认值 | 释义 |
| minute/hour/day/month/weekday | | 和设置时间信息相关参数 |
| job | | 和设置定时任务相关参数 |
| name(required) | | 设置定时任务注释信息 |
| state | absent | 删除指定定时任务 |
| disabled | yes | 将指定定时任务进行注释 |
| = | no | 取消注释 |
备注:时间参数不写时,默认为 *
# 每五分钟同步一下时间
ansible kubernetes -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' "
# 注释定时任务
注意:注释和取消注释时必须填写 job和时间 参数
ansible kubernetes -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' disabled=yes"
# 取消注释
ansible kubernetes -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' disabled=no"
7、用户模块
group
远程批量创建用户组信息
|--------|------------|-----------|
| 参数 | 选项/默认值 | 释义 |
| gid | | 指创建的组ID信息 |
| name | | 指创建组名称信息 |
| state | absent | 删除指定的用户组 |
| = | present | 创建指定的用户组 |
# 创建一个指定的用户组zhangsan gid=1055
ansible kubernetes -m group -a "name=zhangsan gid=1055"
# 删除一个指定的用户组 gid=1055
ansible kubernetes -m group -a "name=zhangsan state=absent"
删除成功的前提是不能有用户把被删除的组当成基本组。会报如下错误:
"msg": "groupdel: cannot remove the primary group of user 'zhangsan'\n",
user
远程批量创建用户信息
|------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------|
| 参数 | 选项/默认值 | 释义 |
| password | | 请输入密码信息 |
| name | | 指定用户名信息 |
| uid | | 指定用户uid信息 |
| group | | 指定用户主要属于哪个组 |
| groups | | 指定用户属于哪个附加组信息 |
| shell | /bin/bash;/sbin/nologin | 指定是否能够登录 |
| create_home | yes/no | 是否创建家目录信息 |
| home | | 指定家目录创建在什么路劲默认是/home |
| state | present | 表示用户需要存在 |
| state | absent | 表示删除用户 |
| remove | yes/no | 是否删除用户的家目录 |
| generate_ssh_key | yes/no | 表示为对应的用户生成 ssh 密钥对,默认在用户家目录的 ./ssh 目录中生成名为 id_rsa 的私钥和名为 id_rsa.pub 的公钥,如果同名的密钥已经存在与对应的目录中,原同名密钥并不会被覆盖(不做任何操作)。 |
备注:password设置密码时不能使用明文方式,只能使用密文方式
可以给用户设置密码 还可以给用户修改密码
root@master ~]# python
Python 2.7.5 (default, Apr 11 2018, 07:36:10)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import crypt
>>> crypt.crypt('123456')
'$6$QYPyripe94Z.Cu5a$oYEUFA4eDqJxGgb4VhypXoapt7ZQTTVB8LQbseF4xb.2P202tAoiQzK2kc.3XyJT7eiptjXoetAuftDcKh5WD1'
# 创建一个用户指定密码
[root@master ~]# ansible kubernetes -m user -a "name=zhangsan password='$6$QYPyripe94Z.Cu5a$oYEUFA4eDqJxGgb4VhypXoapt7ZQTTVB8LQbseF4xb.2P202tAoiQzK2kc.3XyJT7eiptjXoetAuftDcKh5WD1'"
# 删除用户及家目录
ansible kubernetes -m user -a "name=zhangsan remove=yes state=absent"
# 创建用户berry,登录shell为/sbin/nologin
ansible kubernetes -m user -a "name=berry shell=/sbin/nologin state=present"
# 删除刚才创建的用户berry及其宿主目录
ansible kubernetes -m user -a "name=berry remove=yes state=absent"
8、脚本模块
script
script只能执行脚本,不能调用其他指令,但是script执行的是存放在ansbile管理端上的脚本
管理端的脚步在目标端执行
ansible kubernetes -m script -a "/root/1.sh"
三、Ansible PlayBook
1、PlayBook概述
之前的模块都是使用Ad-hoc方式(Ad-hoc方式是一种可以快速输入的命令,而且不需要保存起来的命令)点对点命令执行,可以管理远程主机,但如果服务器数量比较多,配置信息也比较多,可以利用Ansible PlayBook编写剧本,以更加简便的方式实现任务处理的自动化和流程化。
playbook是Ansible的配置、部署和编排的语言。Playbook可以定制配置,他们可以按照你指定的操作步骤有序执行,支持同步和异步方式。形象点的说就是:如果ansible的各模块(能实现各种功能)是车间里的各工具;playbook就是指导手册,目标远程主机就是库存和原料对象。
playbook可作为一个适合部署复杂应用程序的基础。
PlayBook是由一个或多个"play"组成的列表,在play中的内容被我们称之为tasks,也叫任务,也就是说多个tasks组成了一个play,task调用Ansible的各种模块(module)。将多个play组织在一个playbook剧本中,组成一个完整的流程控制集合,完成一个复杂的工作。

说明:
playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。
hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组。
vars 执行对应任务时,携带的到远端主机的变量信息
remote_user则用于指定远程主机上的执行任务的用户。
play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
每个task都应该有其name,name 是我们对当前任务的说明,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则执行的模块名将用于输出。
定义task的action(动作)可以使用module_name:module_args"。
一个name只能包括一个task。
在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用"key=value"格式

注:
如果命令或脚本的退出码不为零,可以使用如下方式替代:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者使用ignore_errors来忽略错误信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
playbook是基于YAML语言格式配置,通过YAML格式来进行描述定义的,扩展名是yml或yaml。
总结:简单来说playbook就是一个用yaml语法把多个模块堆起来的一个文件而已,把不同的模块按照顺序编排在剧本中,ansible就会按照剧本一步一步的执行,最终达到我们的目的。
更多playbook官方说明参考:
http://docs.ansible.com/ansible/latest/playbooks_intro.html
Ansible中文学习手册
https://ansible-tran.readthedocs.io/en/latest/docs/playbooks.html
2、Yaml语言
Playbook采用YAML语言编写,每一个Ansible的Playbook都是一个YAML格式的文件,因此要学习编写剧本(playbook),我们先来了解YAML语法的基本用法。
Yaml语言规则
1、yaml文件以---开头,以表明这是一个yaml文件,就像xml文件在开头使用<?xml version="1.0" encoding="utf-8"?>宣称它是xml文件一样。但即使没有使用---开头,也不会有什么影响。
2、yaml中使用"#"作为注释符。
3、大小写敏感
4、使用缩进表示层级关系:YAML使用一个固定的缩进风格表示层级结构,同样的缩进代表同样的级别。缩进时不允许使用Tab键,只允许使用空格。
注:缩进的空格数目没有限制,但要求同一层级左对齐。判断是否是同一级别是通过缩进结合换行来实现的。
5、冒号,以冒号结尾的除外,其他所有冒号后面必须有空格。
6、短横线,表示列表项,使用一个短横杠加一个空格。多个项使用同样的缩进级别作为同一列表。
7、关于布尔值的书写格式,即true/false的表达方式。其实playbook中的布尔值类型非常灵活,可分为两种情况:
- 模块的参数:这时布尔值作为字符串被ansible解析。接受yes/on/1/true/no/off/0/false。例如上面示例中的update_cache=yes。
- 非模块的参数:这时布尔值被yaml解释器解析,完全遵循yaml语法。接受不区分大小写的true/yes/on/y/false/no/off/n。例如上面的gpgcheck=False和enabled=True。
建议遵循ansible的官方规范,模块的布尔参数采用yes/no,非模块的布尔参数采用True/False。
8、YAML文件扩展名通常为yml或yaml
对于Ansible, 每一个YAML文件都是从一个列表(列表list,又称为序列 sequence)开始。列表中的每一项都是一个键值对,通常它们被称为一个 "哈希" 或 "字典"或映射。所以, 我们需要知道如何在YAML中编写列表和字典。
- 列表中的所有成员都开始于相同的缩进级别, 并且使用一个 "- " 作为开头(一个减号和一个空格)。
- 具体在ansible playbook中,列表所描述的是局部环境,它不一定要有名称,只要使用"- ",它就表示圈定一个范围,范围内的项都属于该列表。例如:


- 一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格),它一般当作列表项的属性。
- n k/v的值可同行写也可换行写。同行使用:分隔
- n v可是个字符串,也可是另一个列表
- YAML列表与字典是可以自由组合在一起的,它们之间可以相互嵌套,通过非常灵活的组合,可以帮助我们描述更加复杂的对象属性。
- 此外, Ansible使用"{{ var }}"来引用变量.。如果一个值以 "{" 开头, YAML 将认为它是一个字典, 所以我们必须引用它, 像这样foo: "{{ var }}"。
PlayBook核心元素及常用参数
playbook核心元素包括:
target:定义playbook的远程主机组
variables:定义playbook使用的变量
tasks:定义远程主机上执行的任务列表
handlers:处理器,当某条件满足时,触发执行的操作,例如修改配置文件之后,启动跟 handlers任务重启相关联的服务
roles:角色,用于层次性,结构化的组织playbook。roles能够根据层次型结构自动装载 变量文件、tasks以及handlers等。
target常用参数
- hosts:运行指定任务的目标主机,可以是一个主机组、主机、多个主机,中间以冒号分隔,也可以用all参数表示所有主机。
- remote_user:指定远程主机上的执行任务的用户。
- gather_facks:获取远程主机facts基础信息
注:remote_user参数以前称为user。它在ansibe1.4中被重命名,以使其与用户模块(用于在远程系统上创建用户)区别。
注:gather_facts: True 表示在远程主机运行setup模块,获取远程主机的facts,facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等,会存在facts中的某个变量中,调用后返回很多对应主机的信息。
variable常用参数
- vars:在yaml文件中定义变量赋值。定义格式,变量名:变量值
- vars_files:指定变量文件,在文件中定义变量
tasks常用参数
- name:任务显示名称也是屏幕显示信息
- module_name: module_args: 需要使用的模块名字: 模块参数
hardler常用参数
- notify: "notify"这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。
- handler: 也是task的列表。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
3、PlayBook运行方式
1、ansible-playbook --check playbook.yaml #只检测可能会发生的改变,但不真执行操作
2、ansible-playbook --list-hosts playbook.yaml #列出运行任务的主机
3、ansible-playbook --syntax-check playbook.yaml #检查yaml文件的语法是否正确
4、ansible-playbook -t TAGS_NAME playbook.yaml #表示跳过标签前的步骤,直接从标签位置开始。-t选项执行指定的tag标签任务
注:通过tags参数给指定的任务定义一个调用标识。
格式:
- name: NAME
module: arguments
tags TAG_ID
例如:

ansible-playbook -C -t 'update config file' /ansible/test1.yaml
5、ansible-playbook playbook.yaml # 运行
四、通过PlayBook批量部署Lnmp环境
本案例是通过rpm包部署LNMP环境(基于aliyun和epel源),如果要通过源码包部署的话,可以编写shell脚本,通过script模块进行批量部署LNMP。
首先,我们可以在 ansible 服务器上安装 LNMP 环境,然后,再将配置文件通过 ansible 拷贝到远程主机上
1、安装lnmp
所以机器安装阿里源
# 首先安装阿里源
[root@localhost ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@localhost ~]# yum install -y epel-release
安装nginx
[root@localhost ~]# yum -y install nginx && systemctl start nginx && systemctl enable nginx
修改nginx.conf,支持php访问
[root@localhost ~]# vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
index index.php index.html;
include /etc/nginx/default.d/*.conf;
location / {
}
location ~ .*\.(php|php5)?$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
# 重启服务
[root@localhost ~]# systemctl restart nginx
安装mysql
[root@localhost ~]# yum -y install mariadb-server mariadb
创建数据保存目录
[root@localhost ~]# mkdir -p /data/mysql/data && chown -R mysql:mysql /data/mysql/
启动
[root@localhost ~]# systemctl start mariadb && systemctl enable mariadb
安装php
[root@localhost ~]# yum install -y php php-mysql php-fpm && systemctl start php-fpm && systemctl enable php-fpm
创建php的测试页面
[root@localhost ~]# vim /usr/share/nginx/html/index.php
<?php
phpinfo();
?>

2、roles角色
Roles相当于我们剧本当中的角色,每个角色都有不同的事情要做,也正是分工才体现出了每个角色不同的作用,当你需要做不同的事情时,只需要调用不同角色即可。
比如一个互联网公司,想要研发新的软件时,就需要找产品去设计软件,找开发去研发软件,找测试去测试软件,找运维去维护软件,每一个角色都会完成各自的功能,这就是Role的作用。
总结:
Roles 角色:以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;相当于函数的调用把各个事件切割成片段来执行。
relos目录结构
[root@ceph01 lnmp]# tree /ansible/lnmp/
/ansible/lnmp/
├── ansible.cfg # 整个项目的配置文件
├── hosts # 定义主机的配置文件
├── roles # 定义角色的名字(不能修改)
│ ├── mysql # 角色目录(名字可以修改)
│ │ ├── files
│ │ ├── handlers
│ │ ├── meta
│ │ ├── tasks
│ │ ├── templates
│ │ └── vars
│ ├── nginx # 角色目录(名字可以修改)
│ │ ├── files
│ │ ├── handlers
│ │ ├── meta
│ │ ├── tasks
│ │ ├── templates
│ │ └── vars
│ ├── php # 角色目录(名字可以修改)
│ │ ├── files
│ │ ├── handlers
│ │ ├── meta
│ │ ├── tasks
│ │ ├── templates
│ │ └── vars
│ └── prepare # 角色目录(名字可以修改)
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
├── site.yml # 整个项目的入口文件
└── webserver.yml # 分支的入口文件
注:这些目录、文件都需要自己创建
files/:存储由copy或script等模块调用的文件,例如存放需要同步到远程服务器的源码文件及配置文件等。
tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行"包含"调用;
handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行"包含"调用;例如当服务的配置文件发生变化时需要进行的操作,比如:重启服务,重新加载配置文件。
vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable(变量);其它的文件需要由main.yml进行"包含"调用;
templates/:存储由template模块调用的模板文本。如用于执行lnmp相关配置文件的模板文件。
meta/:角色定义,可留空。此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行"包含"调用;
3、配置PlayBook
1)创建相关的目录
[root@localhost roles]# mkdir -p /ansible/lnmp/roles/{prepare,nginx,mysql,php}/{tasks,files,templates,vars,meta,handlers}
[root@localhost roles]# touch /ansible/lnmp/ansible.cfg
[root@localhost roles]# touch /ansible/lnmp/hosts
[root@localhost roles]# touch /ansible/lnmp/site.yml
[root@localhost roles]# touch /ansible/lnmp/webserver.yml
2)配置管理主机
[root@localhost ~]# ssh-keygen
[root@ceph01 ~]# ssh-keygen
[root@ceph01 ~]# for i in 14 15; do ssh-copy-id root@192.168.1.$i ;done
# 添加主机清单
[root@localhost ~]# vim /ansible/lnmp/hosts
[nginx]
nginx01 ansible_ssh_host=192.168.1.14 ansible_ssh_port=22 ansible_ssh_user=root
nginx02 ansible_ssh_host=192.168.1.15 ansible_ssh_port=22 ansible_ssh_user=root
[mysql]
mysql01 ansible_ssh_host=192.168.1.14 ansible_ssh_port=22 ansible_ssh_user=root
[php]
php01 ansible_ssh_host=192.168.1.14 ansible_ssh_port=22 ansible_ssh_user=root
php02 ansible_ssh_host=192.168.1.15 ansible_ssh_port=22 ansible_ssh_user=root
[lnmp:children]
nginx
mysql
php
说明:
是不是突然发现了一个不一样的组[lnmp:children],它的意思是,lnmp组由别的组成,具体成员是其他组的组名,这样当调用lnmp组时就会调用其他组内的组员了,同时要注意,lnmp组里的组员,要在lnmp之前声明。
现在我们执行Ansible命令无法找到Lnmp组
因为我们默认是用的是/etc/ansible/hosts文件,这个文件中并没有定义lnmp组,我们的lnmp组存在于我们ansible项目根目录(/ansible/lnmp/)的hosts文件内,如果想使用/ansible/lnmp/路径下的hosts文件,需要修改ansible.cfg配置文件,修改成这样:
[root@localhost ~]# vim /ansible/lnmp/ansible.cfg
[defaults]
host_key_checking = True
inventory = ./hosts
ping 测试
[root@localhost ~]# cd /ansible/lnmp/
[root@localhost lnmp]# ansible lnmp -m ping
3)配置入口文件(site.yaml)
现在我们已经调整好了配置,设置好了主机,接下里就开始写Roles以及Playbook,我们site.yml文件是一切任务的入口文件,因此我们从site.yml开始写。
[root@localhost lnmp]# vim site.yml
---
- import_playbook: webserver.yml
Import_playbook意为包含webserver.yml这个文件,当执行到site.yml文件中的这一行时,就会跑去执行webserver.yml里面的内容,这样我们的项目将会更加模块化,利于管理。
4)配置角色分支的入口文件(webserver.yaml)
webserver.yml当中又要写些什么呢?webserver当中写的是要完成对应的模块功能需要的角色,也就是需要什么样的Role。
例如:我们要完成lnmp项目的第一个role,也就是prepare角色(prepare角色主要任务是:远程主机配置yum源,关闭防火墙,关闭selinux),webserver.yml文件内容如下:
[root@localhost lnmp]# vim webserver.yml
---
- hosts: all
gather_facts: True
remote_user: root
name: prepare system
roles:
- prepare
tags: prepare
说明:
all的意思是,让所有主机执行prepare这个role,如果想要针对于组执行roles,那么就将all换成组名,如果针对于某个主机执行,就写主机的别名或者IP
roles列表当中的prepare是指,我们要执行prepare这个Role,那么我们就需要在roles这个目录下创建一个叫做prepare的文件夹,保证我们的Role能够执行,我们roles选项下的名称就是我们在roles目录中文件夹的名称。

gather_facts: True开启收集主机静态信息,如版本号,操作系统内容等;
tags: prepare,对当前内容进行标记,也就是打标签,在执行时可以使用标签从指定位置开始向下执行,为测试节省时间;
prepare内容说明,存在两个目录,一个是tasks,执行对应任务的目录,一个是templates,进行模版文件复制的目录。

当执行到对应的Role时,Ansbile就会调用对应Role目下的Playbook,也就是调用我们的tasks,所以我们在对应的Role目录下都会存在一个叫做tasks的目录
tasks目录当中文件说明,main.yml,任务的入口文件,执行任务时从此文件开始执行,yum.yml、firewalld.yml、selinux.yml完成对应功能的目录
tasks/
├── firewalld.yml # 防火墙
├── main.yml # task的入口文件,帮助我们加载对应的功能(名字不可变)
├── selinux.yml # selinux
└── yum.yml # 配置yum源
# 创建对应的文件
[root@localhost lnmp]# cd /ansible/lnmp/roles/prepare/tasks/
[root@localhost tasks]# touch {firewalld,main,selinux,yum}.yml
编辑main文件
[root@localhost tasks]# vim main.yml
---
- import_tasks: yum.yml
- import_tasks: firewalld.yml
- import_tasks: selinux.yml
对于关键字段说明:
import_tasks字段,是在main.yml文件当中导入相关功能文件的内容,来执行相关文件name字段,相当于对执行任务的说明
编辑yum.yml
[root@localhost tasks]# vim yum.yml
---
- name: delete repo for system
shell: rm -fr /etc/yum.repos.d/*
- name: get repo centos6 for aliyun
get_url:
url: http://mirrors.aliyun.com/repo/Centos-6.repo
dest: /etc/yum.repos.d/CentOS-Base.repo
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6")
- name: get repo centos7 for aliyun
get_url:
url: http://mirrors.aliyun.com/repo/Centos-7.repo
dest: /etc/yum.repos.d/CentOS-Base.repo
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7")
- name: get epel repo centos6 for aliyun
get_url:
url: http://mirrors.aliyun.com/repo/epel-6.repo
dest: /etc/yum.repos.d/epel.repo
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6")
- name: get epel repo centos7 for aliyun
get_url:
url: http://mirrors.aliyun.com/repo/epel-7.repo
dest: /etc/yum.repos.d/epel.repo
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7")
编辑firewalld.yml
[root@localhost tasks]# vim firewalld.yml
---
- name: close firewalld
service: name=firewalld state=stopped enabled=no
编辑selinux.yml
[root@localhost tasks]# vim selinux.yml
---
- name: forever close selinux
template: src=config.j2 dest=/etc/selinux/config
- name: current close selinux
command: setenforce 0
ignore_errors: true # 忽略错误的意思
对于关键字段说明:
template字段,指定模版文件,该文件必须存在于prepare角色目录下的templates目录中,起名需要加上.j2结尾,将templates下的文件复制到对应主机的对应目录下,src指定源文件,dest指定目标目录及复制到目录后改成什么名字。
在webserver.yml文件将我们要干的事情,全部用角色的身份填写完毕,然后注释掉暂时不执行的内容,以便后续修改
[root@localhost lnmp]# vim webserver.yml
---
- hosts: all
gather_facts: True
remote_user: root
name: prepare system
roles:
- prepare
tags: prepare
#- hosts: nginx
# gather_facts: True
# remote_user: root
# name: Install and config nginx
# roles:
# - nginx
# tags: nginx
#
#- hosts: php
# gather_facts: True
# remote_user: root
# name: Install and config php
# roles:
# - php
# tags: php
#
#- hosts: mysql
# gather_facts: True
# remote_user: root
# name: Install and config mysql
# roles:
# - mysql
# tags: mysql
5)配置nginx相关角色
Nginx角色说明,在nginx目录中除了和prepare目录中一样,具备的tasks和templates以外,还多一个目录叫做handlers,该目录使用来执行notify,handler功能的,后续说明该功能。另外还会用到files和vars目录。
配置nginx的tasks
tasks,templates下目录内容和prepare一样,就不再详细说明,只看内容即可,tasks当中的内容查看。
[root@localhost ~]# cd /ansible/lnmp/roles/nginx/tasks
[root@localhost tasks]# touch {config,install,main,webpage}.yml
main.yml
[root@localhost tasks]# vim main.yml
---
- import_tasks: install.yml
- import_tasks: config.yml
- import_tasks: webpage.yml
install.yml
[root@localhost tasks]# vim install.yml
---
- name: install nginx
yum: name=nginx state=present
config.yml
[root@localhost tasks]# vim config.yml
---
- name: config nginx
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: start nginx
service: name=nginx enabled=yes state=started
说明:
Ansible的template模块。该模块和copy模块作用基本一样,都是把某个文件复制到远端主机上,但是区别在于template模块可以获取变量的值,而copy则是原封不动的把文件内容复制过去。
notify模块,在是在做消息通知,notify上面的内容如果执行成功,就会发出消息,通知notify下方的内容执行,如果上面的内容没有执行,就不会通知下面的内容,如何判断是否执行就看执行过程的返回结果,是changed还是ok,changed是执行了,ok是没执行。
webpage.yml
[root@localhost tasks]# vim webpage.yml
---
- name: provide web page
#copy: src=index.php dest=/usr/share/nginx/html
copy: src=/ansible/lnmp/roles/nginx/files/ dest=/usr/share/nginx/html
测试nginx组
准备远程的文件
[root@localhost tasks]# vim /ansible/lnmp/roles/nginx/files/testdb.php
<?php
$link=mysql_connect('192.168.1.14','zhangsan','123456');
if ($link)echo "connection success......";
mysql_close();
?>
[root@localhost tasks]# cp /usr/share/nginx/html/index.php /ansible/lnmp/roles/nginx/files/
[root@localhost tasks]# cp /etc/nginx/nginx.conf /ansible/lnmp/roles/nginx/templates/nginx.conf.j2
根据需要修改nginx的配置文件模板
[root@localhost tasks]# vim /ansible/lnmp/roles/nginx/templates/nginx.conf.j2
user nginx;
worker_processes {{ ansible_processor_vcpus}}; # 修改cpu进程核心数
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
-------------
server {
listen {{ ngxport }}; # 端口变量
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
index index.php index.html;
include /etc/nginx/default.d/*.conf;
构建nginx的handlers目录和vars/下的main.yml 文件
[root@localhost tasks]# vim /ansible/lnmp/roles/nginx/handlers/main.yml
---
- name: restart nginx
service: name=nginx state=restarted
[root@localhost tasks]# vim /ansible/lnmp/roles/nginx/vars/main.yml
---
ngxport: 80 # 变量的值
[root@localhost lnmp]# ansible-playbook site.yml -t nginx
PLAY [prepare system] *******************************************************************************************************************************************************************************************
PLAY [Install and config nginx] *********************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [nginx02]
ok: [nginx01]
TASK [install nginx] ********************************************************************************************************************************************************************************************
ok: [nginx01]
ok: [nginx02]
TASK [config nginx] *********************************************************************************************************************************************************************************************
changed: [nginx01]
changed: [nginx02]
TASK [start nginx] **********************************************************************************************************************************************************************************************
changed: [nginx01]
changed: [nginx02]
TASK [nginx : provide web page] *********************************************************************************************************************************************************************************
changed: [nginx02]
changed: [nginx01]
RUNNING HANDLER [restart nginx] *********************************************************************************************************************************************************************************
changed: [nginx01]
changed: [nginx02]
PLAY RECAP ******************************************************************************************************************************************************************************************************
nginx01 : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6)配置php相关角色
构建php任务,这里我们只用到了tasks,templates和handlers目录,tasks当中的内容查看。
[root@localhost lnmp]# cd /ansible/lnmp/roles/php/tasks/
[root@localhost tasks]# touch {config,install,main}.yml
main.yml
[root@localhost tasks]# vim main.yml
---
- import_tasks: install.yml
- import_tasks: config.yml
install.yml
[root@localhost tasks]# vim install.yml
---
- name: install php php-mysql php-fpm
yum: name={{ item }} state=latest
with_items:
- php
- php-mysql
- php-fpm
说明:
发现虽然同是安装应用,用的模块也是yum模块,但是安装名却发生变化,使用了{{ item }}变量,这种方式意味携带变量执行,{{ item }}当中大括号是在说明,我们当前的item是个变量,并不是实际安装的软件名,那么实际的软件名字在哪里,就在下面的with_items当中,每个减号开头字符,都是一个实际软件名,这条task会在执行yum模块时,循环执行,有多少个变量item就执行几回,直到将所有with_items当中的字符全部带入到yum模块中,执行一遍为止。
那么实际这个with_items方法不光能用在yum模块中,只要涉及到循环执行的内容都可以使用,其本质是python的列表,执行过程是遍历一个叫做item的列表,然后来执行其操作内容。
config.yml
[root@localhost tasks]# vim config.yml
---
- name: config php
template: src=php.ini.j2 dest=/etc/php.ini
notify: restart php-fpm
- name: config php-fpm
template: src={{ item.src }} dest={{ item.dest }}
with_items:
- { src: "php-fpm.conf.j2",dest: "/etc/php-fpm.conf",mode: "0644" }
- { src: "www.conf.j2",dest: "/etc/php-fpm.d/www.conf",mode: "0644" }
notify: restart php-fpm
- name: start php-fpm
service: name=php-fpm enabled=yes state=started
配置php的handlers目录下的main.yml文件
[root@localhost tasks]# vim /ansible/lnmp/roles/php/handlers/main.yml
---
- name: restart php-fpm
service: name=php-fpm state=restarted
测试php组
[root@localhost tasks]# cp /etc/php.ini /ansible/lnmp/roles/php/templates/php.ini.j2
[root@localhost tasks]# cp /etc/php-fpm.conf /ansible/lnmp/roles/php/templates/php-fpm.conf.j2
[root@localhost tasks]# cp /etc/php-fpm.d/www.conf /ansible/lnmp/roles/php/templates/www.conf.j2
打开php组的注释
[root@localhost tasks]# vim /ansible/lnmp/webserver.yml
---
- hosts: all
gather_facts: True
remote_user: root
name: prepare system
roles:
- prepare
tags: prepare
- hosts: nginx
gather_facts: True
remote_user: root
name: Install and config nginx
roles:
- nginx
tags: nginx
- hosts: php
gather_facts: True
remote_user: root
name: Install and config php
roles:
- php
tags: php
#- hosts: mysql
# gather_facts: True
# remote_user: root
# name: Install and config mysql
# roles:
# - mysql
# tags: mysql
[root@localhost tasks]# cd /ansible/lnmp/
[root@localhost lnmp]# ansible-playbook site.yml -C -t php # -C 测试结果不执行
警告不用理会
# 执行php组
[root@localhost lnmp]# ansible-playbook site.yml -t php
访问测试

7)配置mysql相关角色
构建mysql任务,这里我们只用到了tasks,templates和handlers目录,tasks当中的内容查看。
[root@localhost lnmp]# cd /ansible/lnmp/roles/mysql/tasks/
[root@localhost tasks]# touch {config,install,main}.yml
main.yml
[root@localhost tasks]# vim main.yml
---
- import_tasks: install.yml
- import_tasks: config.yml
install.yml
[root@localhost tasks]# vim install.yml
- name: Installed Mariadb Server
yum: name={{ packages }} state=present
vars:
packages:
- mariadb
- mariadb-server
- MySQL-python
说明:
我们发现在安装数据库的同时,安装了一个叫装MySQL-python的包,这个包是在我们即将配置mysql时使用的,因为我们在配置mysql时调用了Ansible的mysql模块,所以需要由这个包对我们的操作进行支持,没有这个包我们无法使用Ansible的mysql模块。
config.yml
[root@localhost tasks]# vim config.yml
---
- name: create data directory
file: path=/data/mysql/data state=directory owner=mysql group=mysql
- name: copy mysql config
template: src=my.cnf.j2 dest=/etc/my.cnf
notify: restart mysql
- name: start mysql
service: name=mariadb enabled=yes state=started
- name: set root password
shell: /usr/bin/mysqladmin -uroot password '1' | /bin/true
- name: create a database
mysql_db:
login_host: localhost
login_user: root
login_password: "1"
login_port: 3306
name: test
encoding: utf8
state: present
- name: create a user
mysql_user:
login_host: localhost
login_user: root
login_password: "1"
login_port: 3306
name: zhangsan
host: '192.168.1.%'
password: "123456"
priv: 'test.*:ALL'
state: present
说明:
其他模块在前面已经说明过了,不再进行赘述,主要介绍涉及的新模块,分别是mysql_db,mysql_user模块
mysql_db模块,对数据库当中的数据库进行操作,可以帮助我们完成create,drop,show等针对数据库的操作。
mysql_user模块,针对于数据库当中用户进行操作,可以帮助我们完成,create,delete,select,grant等对于用户的操作。
如果我们要操作数据库,那必不可少的过程是要登录数据库,对于这点,如果手动执行登录命令,复杂且不好管理,还好Ansible提供了数据库相关模块,对于数据库的操作,我们只需要调用相关模块即可
在调用mysql_db和mysql_user时,统一会用到的参数login_host,login_user,login_password,login_port都是在指定登录时相关信息。
对于mysql_db模块来说,name指定是数据库名,encoding指定创建数据库或操作数据库时使用的字符集,state是指对数据库进行什么样的操作,persent相当于创建数据库,import的是导入数据库,导入数据时使用的数据库文件由target指定,那么如果你想删除一个数据库,只需要将state由persent改成asbent。
在调用mysql_user模块时,我们除了使用了登录的参数外,还有几个额外的参数,name创建或者操作用户时指定用户名,password指定创建用户的密码,host指定创建的用户能在哪里登录,priv指定创建出来的用户具备什么样的权限,state当中作用就和数据库一样了,persent表示创建,absent表示删除
对mysql_user模块的priv书写方式为 "在哪个数据库上.对哪个表:有什么权限"的方式书写,举例:"*.*:all"表示,对所有数据库当中的所有表具备所有权限
构建mysql的handlers目录下的main.yml文件
[root@localhost tasks]# vim /ansible/lnmp/roles/mysql/handlers/main.yml
---
- name: restart mysql
service: name=mariadb state=restarted
测试mysql组
[root@localhost tasks]# cp /etc/my.cnf /ansible/lnmp/roles/mysql/templates/my.cnf.j2
[root@localhost tasks]# vim /ansible/lnmp/roles/mysql/templates/my.cnf.j2
[mysqld]
datadir=/data/mysql/data #修改此行,其他参数保持默认即可
打开mysql组的注释
[root@localhost tasks]# vim /ansible/lnmp/webserver.yml

# 执行
[root@localhost lnmp]# ansible-playbook site.yml -t mysql

看一下Python-mysql模块的结果
登录到对应的主机
[root@localhost ~]# mysql -uroot -p1
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
MariaDB [(none)]> select user,host from mysql.user where user="zhangsan";
+----------+-------------+
| user | host |
+----------+-------------+
| zhangsan | 192.168.1.% |
+----------+-------------+
1 row in set (0.00 sec)
MariaDB [(none)]> show grants for zhangsan@'192.168.1.%';
+-------------------------------------------------------------------------------------------------------------------+
| Grants for zhangsan@192.168.1.% |
+-------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'zhangsan'@'192.168.1.%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |
| GRANT ALL PRIVILEGES ON `test`.* TO 'zhangsan'@'192.168.1.%' |
+-------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)