一:Ansible介绍及安装
一:Ansible基本概述
1.1 什么是ansible
Ansible是一个自动化统一配置管理工具,自动化主要体现在Ansible集成了丰富模块以及功能组件,可以通过一个命令完成一系列的操作,进而能减少重复性的工作和维护成本,可以提高工作效率。
1.2 同类型管理工具对比
1.puppet 学习难,安装ruby环境难,没有远程执行功能
2.ansible 轻量级,大规模环境下只通过ssh会很慢,串行的
3.saltstack 一般选择salt会使用C/S结构的模式,salt-master和salt-minion,并行的,大规模批量操作的情况下,会比Ansible速度快一些,底层使用的是zero-MQ消协队列
1.3 应用:
优势:
1.4 ansible 功能及优点:
1.远程执行(看100台服务器的内存信息)
批量执行远程命令,可以对多台主机进行远程操作
2.配置管理(管理机安装playbook,统一管理主机配置文件,批量下发)
批量配置软件服务,可以进行自动化方式配置,服务的统一配置管理,和启停
3.事件驱动
通过Ansible的模块,对服务进行不同的事件驱动
比如:
1)修改配置后重启
2)只修改配置文件,不重启
3)修改配置文件后,重新加载
4)远程启停服务管理
4.管理公有云
通过API接口的方式管理公有云,不过这方面做的不如saltstack.
saltstack本身可以通过saltcloud管理各大云厂商的云平台。
5.二次开发
因为语法是Python,所以便于运维进行二次开发。
6.任务编排
可以通过playbook的方式来统一管理服务,并且可以使用一条命令,实现一套架构的部署
7.跨平台,跨系统
几乎不受到平台和系统的限制,比如安装apache和启动服务
在Ubuntu上安装apache服务名字叫apache2
在CentOS上安装apache服务名字叫httpd
在CentOS6上启动服务器使用命令:/etc/init.d/nginx start
在CentOS7上启动服务器使用命令:systemctl start nginx
1.5 ansible执行流程
1.Ansible读取playbook剧本,剧本中会记录对哪些主机执行哪些任务。
2.首先Ansible通过主机清单找到要执行的主机,然后调用具体的模块。
3.其次Ansible会通过连接插件连接对应的主机并推送对应的任务列表。
4.最后被管理的主机会将Ansible发送过来的任务解析为本地Shell命令执行。
二:Ansible安装
环境准备:
主机名 | wanIP | lanIP | 角色 |
---|---|---|---|
m01 | 10.0.0.61 | 172.16.1.61 | Ansible控制端 |
web01 | 10.0.0.7 | 172.16.1.7 | Ansible被控端 |
web02 | 10.0.0.8 | 172.16.1.8 | Ansible被控端 |
2.1 安装ansible
#1.安装epel源
[root@m01 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
#2.安装Ansible
[root@m01 ~]# yum install -y ansible
# ansible <host-pattern> [options]
--version #ansible版本信息
-v #显示详细信息
-i #主机清单文件路径,默认是在/etc/ansible/hosts
-m #使用的模块名称,默认使用command模块
-a #使用的模块参数,模块的具体动作
-k #提示输入ssh密码,而不使用基于ssh的密钥认证
-C #模拟执行测试,但不会真的执行
-T #执行命令的超时
#3.查看Ansible版本及模块路径
[root@m01 ~]# ansible --version
ansible 2.7.1
#配置文件路径
config file = /etc/ansible/ansible.cfg
#模块路径
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
2.2 ansible配置文件读取顺序
[root@m01 ~]# rpm -ql ansible
[root@m01 ~]# zcat /usr/share/man/man1/ansible-config.1.gz
#要查看完整列表,请访问https://docs.ansibe.com/或使用ansibe-config命令。
For a full list check \fI\%https://docs.ansible.com/\fP\&. or use the \fIansible\-config\fP command.
#/etc/ansible/ansible.cfg 配置文件,如果存在则使用
/etc/ansible/ansible.cfg \-\- Config file, used if present
#~/.ansible.cfg 用户配置文件,覆盖默认配置(如果存在)
~/.ansible.cfg \-\- User config file, overrides the default config if present
#\&/ansible.cfg 本地配置文件(在当前工作目录中)假定为(aqproject-specific)(aq,如果存在,则重写其余文件)。
\&./ansible.cfg \-\- Local config file (in current working directory) assumed to be \(aqproject specific\(aq and overrides the rest if present.
#如上所述,ANSIBLE_CONFIG环境变量将覆盖所有其他环境变量。
As mentioned above, the ANSIBLE_CONFIG environment variable will override all others.
正常读取顺序:
ansible.cfg-----~/.ansible.cfg------&/ansible.cfg(工作目录)如果上述都没有就会找环境变量ANSIBLE_CONFIG添加
但是:
~/.ansible.cfg的内容会覆盖ansible.cfg,就是如果配置冲突的情况下,以~/.ansible.cfg为准。
企业中,有时候改完ansible.cfg配置文件,但没有生效,因为可能有其他配置文件存在,会覆盖ansible.cfg,企业中一旦没有生效,需要找到是否有其他配置文件存在。
优先级:
1、$ANSIBLE_CONFIG
2、./ansible.cfg
3、~/.ansible.cfg
4、/etc/ansible/ansible.cfg
2.3 ansible 配置文件详解:
[root@m01 ~]# cat /etc/ansible/ansible.cfg
#inventory = /etc/ansible/hosts #主机列表配置文件
#library = /usr/share/my_modules/ #库文件存放目录
#remote_tmp = ~/.ansible/tmp #临时py文件存放在远程主机目录
#local_tmp = ~/.ansible/tmp #本机的临时执行目录
#forks = 5 #默认并发数
#sudo_user = root #默认sudo用户
#ask_sudo_pass = True #每次执行是否询问sudo的ssh密码
#ask_pass = True #每次执行是否询问ssh密码
#remote_port = 22 #远程主机端口
host_key_checking = False #跳过检查主机指纹
log_path = /var/log/ansible.log #ansible日志
#普通用户提权操作
[privilege_escalation]
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False
打开:host_key_checking = False #跳过检查主机指纹
目的:跳过下图的yes/no认证。直接进入系统
三:Ansible Inventory(主机清单)
/etc/ansible/hosts是ansible默认主机资产清单文件,用于定义被管理主机的认证信息, 例如ssh登录用户名、密码以及key相关信息。Inventory文件中填写需要被管理的主机与主机组信息。还可以自定义Inventory主机清单的位置,使用-i指定文件位置即可。
3.1 基于密码连接
#方式一:
[root@m01 ~]# vim /etc/ansible/hosts
[web_group]
10.0.0.7 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='1'
10.0.0.8 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='1'
#第一条命令
[root@m01 ~]# ansible web_group -m ping
#方式二:
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
web0[1:3] ansible_ssh_pass='1'
[root@m01 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.7 web01
10.0.0.8 web02
10.0.0.9 web03
#方式三、主机+端口+密码
[webs]
web0[1:3]
[webs:vars]
ansible_ssh_pass='1'
ansible_ssh_port=22
[root@m01 ~]# ansible webs -m ping -i ./hosts
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.7 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
3.2 基于密钥连接,分发公钥私钥
场景一:
#创建秘钥对
[root@m01 ~]# ssh-keygen
#推送公钥
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
10.0.0.7
10.0.0.8
10.0.0.9
场景二:
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
web03 ansible_ssh_host=10.0.0.9
#查看主机组中分别有哪些机器
[root@m01 ~]# ansible web_group --list-host
3.3 分组
[root@m01 ~]# vim /etc/ansible/hosts
[lnmp:children]
web_group
db_group
二:Ansible常用模块
一:Ansible命令模块
1.1 command
# 默认模块, 执行命令 [root@m01 ~]# ansible web_group -a "hostname"
1.2 shell
# 如果需要一些管道操作,则使用shell [root@m01 ~]# ansible web_group -m shell -a "ps -ef|grep nginx" -f 50
注意:command不识别管道符之类的操作
1.3 script
# 编写脚本
[root@m01 ~]# vim /root/yum.sh
#!/usr/bin/bash
yum install -y vsftpd
#在本地运行模块,等同于在远程执行,不需要将脚本文件进行推送目标主机执行
[root@m01 ~]# ansible web_group -m script -a "/root/yum.sh"
二:Ansible 软件管理模块
2.1 yum
#查看使用方法
[root@m01 ~]# ansible-doc yum
state:
present 安装软件包 默认是present,可以不写
absent 移除软件包
latest 安装最新软件包
name
(包名httpd) #本地yum源
file:// #指定本地安装路径(yum localinstall 本地rpm包)
http:// #指定yum源(从远程仓库获取rpm包)
[root@m01 ~]# ansible web_group -m yum -a "name=httpd state=present"
2.2 cron:定时任务
ansible web_group -m cron -a 'name="aaaaaaa" minute=0 hour=5,2 day=2 month=1 weekday=1-7 state=present job="/bin/sh /root/a.sh > /dev/null"'
name:注释
state:
present
absent
job:crontab要执行的命令
删除:
ansible web_group -m cron -a 'name="aaaaaaa state=absent"
分时日月周不写就直接*号
2.3 yum_repository:建YUM仓
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx description='zls_nginx' baseurl=http://nginx.org/packages/centos/7/$basearch/"
name: 指定repo文件名
description:描述(repo文件中name的值)
baseurl: 指定yum源
file:如果定义了file那么文件名以file为准,如果没有定义file文件名以name为准
state:
present #创建(默认)
absent #删除
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx_new file='zls_nginx_new' description='zls_nginx' baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=no"
#删除
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx state=absent"
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx_new file=zls_nginx_new state=absent"
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx123 file=zls_nginx_new state=absent"
# 在已有的仓库文件中添加一个仓库
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx123 file='zls_nginx_new' description='zls_nginx' baseurl=http://download.driverzeng.com gpgcheck=no"
三:Ansible文件管理模块
3.1 file
[root@m01 ~]# ansible web_group -m file -a 'path=/tmp/zls state=directory owner=root group=root mode=0644'
path: 指定创建的路径
state:
touch:创建文件
directory:创建目录
file:修改文件属性(默认)
link:软连接
absent:删除指定的文件或目录
owner:指定属主
group:指定属组
mode:指定权限
3.2 get_url:下载
[root@m01 ~]# ansible web01 -m get_url -a 'url=https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-agent-4.4.0-1.el7.x86_64.rpm dest=/tmp mode=0644'
[root@m01 ~]# ansible web01 -m get_url -a 'url=http://test.driverzeng.com/Zabbix_File/percona-release-0.1-3.noarch.rpm dest=/tmp mode=0644 checksum=md5:ea13c36cf79e131bded48bac4f7e88c2'
url:指定软件包地址
dest:指定下载的路径
mode:指定文件的权限
checksum:
md5:
sha256:
3.3 unarchive:解压缩
[root@m01 ~]# ansible web02 -m unarchive -a 'src=/root/wordpress-5.0.3-zh_CN.tar.gz dest=/tmp'
src:指定压缩包的路径
dest:指定解压的位置
remote_src:
yes:
no:(默认)
四:Ansible服务管理模块
systemd
[root@m01 ~]# ansible web01 -m systemd -a 'name=nginx state=started'
name:指定服务名
state:
started
stopped
restarted
reloaded
enabled:
true
false
五:Ansible用户管理模块
user
group
[root@m01 ~]# ansible web_group -m group -a 'name=qls state=present gid=250'
name:指定组名
state:
present:创建
absent:删除
gid:指定组的id
六:Ansible磁盘挂载模块
mount:挂载
[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs state=mounted'
path:挂载的路径
src:挂载点
fstype:挂载类型
state:
present # 开机挂载,仅将挂载配置写入/etc/fstab
absent # 卸载,并清除/etc/fstab
mounted # 挂载并写入/etc/fstab
unmounted # 卸载,不清除 /etc/fstab
七:Ansible主机信息模块
setup
八:Ansible防火墙模块
selinux
[root@m01 ~]# ansible web01 -m selinux -a 'state=disabled'
firewalld
[root@m01 ~]# ansible web01 -m firewalld -a 'port=80/tcp state=enabled'
九:Ansible 数据库模块
9.1 mysql_db:创建数据库
- name: Create a new database with name 'jiangwei'
mysql_db:
name: jiangwei
state: present
此时,遇到一个问题,playbook建库时,需要先登陆到数据库,登陆到数据库这个动作必须要自动完成,此时引入:
- login_host
Host running the database.
[Default: localhost]
type: str
- login_password
The password used to authenticate with.
[Default: (null)]
type: str
- login_port
Port of the MySQL server. Requires `login_host' be defined as
other than localhost if login_port is used.
[Default: 3306]
type: int
- login_user
The username used to authenticate with.
[Default: (null)]
type: str
EX:
- name: Create a new database with name 'jiangwei'
mysql_db:
login_user: root
login_password: '123'
login_host: localhost
name: jiangwei
state: present
9.2 mysql_user:创建数据库用户
- name: Create database user with password and all database privileges =
mysql_user:
name: bob
password: 12345
priv: '*.*:ALL'
state: present
EX:
- name: Create MySQL User
mysql_user:
name: wordpress
password: '123456'
priv: '*.*:ALL'
host: '%'
state: present
三:Ansible变量
一:变量概述
变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3
这个软件包的版本,在其它地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本。
1.1 定义变量的方式
1.通过命令行进行变量定义
[root@m01 ~]# vim test.yml
- hosts: web_group
tasks:
- name: Install httpd Server
yum:
name: "{{ web_server }}"
#定义阶段
[root@m01 ~]# ansible-playbook test.yml -e "web_server=vsftpd"
2.在play文件中进行变量定义
- name: ensure a list of packages installed
yum:
name: "{{ packages }}"
vars:
packages:
- httpd
- httpd-tools
#方法一
- hosts: web_group
vars:
packages:
- samba
- vsftpd
tasks:
- name: Install httpd mariadb php Server
yum:
name: "{{ packages }}"
#方法二
- hosts: web_group
vars:
- web_server: lsof
- db_server: htop
- php_server: iftop,sysstat #这边注意多个软件包的写法
tasks:
- name: Install httpd mariadb php Server
yum:
name:
- "{{ web_server }}"
- "{{ db_server }}"
- "{{ php_server }}"
3.通过Inventory主机信息文件中进行变量定义(不推荐使用,容易使环境混乱)
#定义阶段
[root@m01 ~]# vim /etc/ansible/hosts
[web_group]
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
[web_group:vars]
web_server=httpd
index_file=index.html
#调用阶段
- hosts: web_group
tasks:
- name: Install httpd Server
yum:
name: "{{ web_server }}"
- name: Create Index File
file:
path: /tmp/{{ index_file }}
state: touch
4.在一个模板文件中定义变量
EX1:
#定义变量
[root@m01 ~]#vim vars_file.yml
filename: vars_file
#调用变量
[root@m01 bianliang]# vim file.yml
- hosts: web_group
vars_files: ./vars_file.yml
tasks:
- name: Create {{ filename }} DIR
file:
path: /root/{{ filename }}
state: directory
EX2:
#定义变量
[root@m01 ~]# vim vars_file.yml
mysql_ip: localhost
mysql_user: root
mysql_password: '123'
#调用变量
- hosts: db01
vars_files: ./vars_file1.yml
tasks:
- name: Create a new database with name 'jiangwei'
mysql_db:
login_user: {{ mysql_user }}
login_password: {{ mysql_password }}
login_host: {{ mysql_ip }}
name: jiangwei
state: present
此变量目的:以后创建用户只需要在vars_file1.yml文件中修改即可,无须修改配置文件
#获取Ansible内置变量(利用setup模块)
- hosts: web_group
tasks:
- name: Touch IP File
file:
path: /root/{{ ansible_default_ipv4['address'] }}
state: touch
- name: Touch Hostname File
file:
path: /root/{{ ansible_fqdn }}
state: touch
#创建分别以地址和主机名命令的文件
[root@web01 ~]# ll
total 48
-rw-r--r-- 1 root root 0 Nov 19 21:03 10.0.0.7
-rw-r--r-- 1 root root 0 Nov 19 21:03 web01
5.官方推荐变量定义
之前的几种变量定义都不是很好用,比较好用的是在Ansible项目目录下创建两个变量目录:
host_vars
group_vars
切记,目录名字一定要一致,不能做任何修改。
注意:playbook创建在哪里,这两个文件就创建在哪里。
EX1:
#创建出组变量目录和主机变量目录
[root@m01 bianliang]# mkdir host_vars
#想给哪个主机定义变量,就在host_vars目录下创建该主机的名字文件
例如:web01
[root@m01 bianliang]# vim host_vars/web01 #注意web01必须和主机名对应,
web_server: nginx
[root@m01 bianliang]# vim host_vars/web02
web_server: samba
- hosts: web_group
tasks:
- name: Install
yum:
name: "{{ web_server }}"
此变量目的:当需求为web01只安装nginx,web02只安装samba时。
EX2:
#定义阶段
[root@m01 ~]# mkdir group_vars
#切记定义变量的文件必须以组名为文件名
[root@m01 ~]# vim /root/group_vars/web_group
web_server: httpd
#调用阶段
- hosts: web_group
tasks:
- name: Install httpd Server
yum:
name: "{{ web_server }}"
1.2 变量的优先级
1.命令行
2.vars_files
3.vars
4.host_vars
5.group_vars
#官方推荐
host_vars
group_vars
二:变量注册
当absible
的模块在运行之后,其实都会返回一些result
结果,就像是执行脚本,我们有的时候需要脚本给我们一些return
返回值,我们才知道,上一步是否可以执行成功,但是默认情况下,ansible
的result
并不会显示出来,所以,我们可以把这些返回值'存储'到变量中,这样我们就能通过'调用'对应的变量名,从而获取到这些result
,这种将模块的返回值,写入到变量中的方法被称为变量注册
如下一个playbook示例:
#编辑剧本
[root@m01 ~]# vim register.yml
- hosts: web_group
tasks:
- name: Test Register Vars
shell: "ls -l /"
#查看执行结果
[root@m01 ~]# ansible-playbook register.yml
PLAY [web_group] *****************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [web02]
ok: [web01]
TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
web01 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web02 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如上执行结果可见,当我们使用shell模块执行ls -l /时,ansible给我们返回的只有changed我们无法看到执行之后的结果,所以此时我们需要使用到变量注册
playbook如下:
#编辑playbook
[root@m01 ~]# vim register.yml
- hosts: web_group
tasks:
- name: Test Register Vars
shell: "ls -l /"
register: list_dir ####
- name: Return Result
debug:
msg: "{{ list_dir }}"
#查看执行结果
[root@m01 ~]# ansible-playbook register.yml
PLAY [web_group] *****************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [web01]
ok: [web02]
TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]
TASK [Return Result] *************************************************************************************************************************************************************************************************************************
ok: [web01] => {
"msg": {
"changed": true,
"cmd": "ls -l /",
"delta": "0:00:00.005536",
"end": "2019-09-16 11:52:16.492946",
"failed": false,
"rc": 0,
"start": "2019-09-16 11:52:16.487410",
"stderr": "",
"stderr_lines": [],
"stdout": "总用量 28\nlrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin\ndr-xr-xr-x. 5 root root 4096 3月 9 2019 boot\ndrwxr-xr-x. 20 root root 3280 9月 8 12:25 dev\ndrwxr-xr-x. 80 root root 8192 9月 10 20:52 etc\ndrwxr-xr-x. 5 root root 41 9月 8 16:22 home\nlrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib\nlrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64\ndrwxr-xr-x. 2 root root 6 4月 11 2018 media\ndrwxr-xr-x. 2 root root 6 4月 11 2018 mnt\ndrwxr-xr-x. 2 www www 6 9月 10 15:31 opt\ndr-xr-xr-x. 128 root root 0 9月 8 12:25 proc\ndr-xr-x---. 9 root root 4096 9月 10 21:16 root\ndrwxr-xr-x. 25 root root 740 9月 10 20:52 run\nlrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin\ndrwxr-xr-x. 2 root root 6 4月 11 2018 srv\ndr-xr-xr-x. 13 root root 0 9月 8 12:25 sys\ndrwxrwxrwt. 15 root root 4096 9月 16 11:52 tmp\ndrwxr-xr-x. 13 root root 155 3月 9 2019 usr\ndrwxr-xr-x. 21 root root 4096 9月 10 20:52 var",
"stdout_lines": [
"总用量 28",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin",
"dr-xr-xr-x. 5 root root 4096 3月 9 2019 boot",
"drwxr-xr-x. 20 root root 3280 9月 8 12:25 dev",
"drwxr-xr-x. 80 root root 8192 9月 10 20:52 etc",
"drwxr-xr-x. 5 root root 41 9月 8 16:22 home",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib",
"lrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64",
"drwxr-xr-x. 2 root root 6 4月 11 2018 media",
"drwxr-xr-x. 2 root root 6 4月 11 2018 mnt",
"drwxr-xr-x. 2 www www 6 9月 10 15:31 opt",
"dr-xr-xr-x. 128 root root 0 9月 8 12:25 proc",
"dr-xr-x---. 9 root root 4096 9月 10 21:16 root",
"drwxr-xr-x. 25 root root 740 9月 10 20:52 run",
"lrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin",
"drwxr-xr-x. 2 root root 6 4月 11 2018 srv",
"dr-xr-xr-x. 13 root root 0 9月 8 12:25 sys",
"drwxrwxrwt. 15 root root 4096 9月 16 11:52 tmp",
"drwxr-xr-x. 13 root root 155 3月 9 2019 usr",
"drwxr-xr-x. 21 root root 4096 9月 10 20:52 var"
]
}
}
ok: [web02] => {
"msg": {
"changed": true,
"cmd": "ls -l /",
"delta": "0:00:00.005813",
"end": "2019-09-16 11:52:16.495422",
"failed": false,
"rc": 0,
"start": "2019-09-16 11:52:16.489609",
"stderr": "",
"stderr_lines": [],
"stdout": "总用量 24\nlrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin\ndr-xr-xr-x. 5 root root 4096 3月 9 2019 boot\ndrwxr-xr-x. 20 root root 3260 9月 10 09:47 dev\ndrwxr-xr-x. 80 root root 8192 9月 10 20:52 etc\ndrwxr-xr-x. 5 root root 41 9月 8 16:22 home\nlrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib\nlrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64\ndrwxr-xr-x. 2 root root 6 4月 11 2018 media\ndrwxr-xr-x. 2 root root 6 4月 11 2018 mnt\ndrwxr-xr-x. 2 www www 6 9月 10 15:31 opt\ndr-xr-xr-x. 128 root root 0 8月 15 15:10 proc\ndr-xr-x---. 6 root root 180 9月 10 21:16 root\ndrwxr-xr-x. 25 root root 740 9月 10 20:52 run\nlrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin\ndrwxr-xr-x. 2 root root 6 4月 11 2018 srv\ndr-xr-xr-x. 13 root root 0 8月 15 15:10 sys\ndrwxrwxrwt. 14 root root 4096 9月 16 11:52 tmp\ndrwxr-xr-x. 13 root root 155 3月 9 2019 usr\ndrwxr-xr-x. 21 root root 4096 9月 10 20:52 var",
"stdout_lines": [
"总用量 24",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin",
"dr-xr-xr-x. 5 root root 4096 3月 9 2019 boot",
"drwxr-xr-x. 20 root root 3260 9月 10 09:47 dev",
"drwxr-xr-x. 80 root root 8192 9月 10 20:52 etc",
"drwxr-xr-x. 5 root root 41 9月 8 16:22 home",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib",
"lrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64",
"drwxr-xr-x. 2 root root 6 4月 11 2018 media",
"drwxr-xr-x. 2 root root 6 4月 11 2018 mnt",
"drwxr-xr-x. 2 www www 6 9月 10 15:31 opt",
"dr-xr-xr-x. 128 root root 0 8月 15 15:10 proc",
"dr-xr-x---. 6 root root 180 9月 10 21:16 root",
"drwxr-xr-x. 25 root root 740 9月 10 20:52 run",
"lrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin",
"drwxr-xr-x. 2 root root 6 4月 11 2018 srv",
"dr-xr-xr-x. 13 root root 0 8月 15 15:10 sys",
"drwxrwxrwt. 14 root root 4096 9月 16 11:52 tmp",
"drwxr-xr-x. 13 root root 155 3月 9 2019 usr",
"drwxr-xr-x. 21 root root 4096 9月 10 20:52 var"
]
}
}
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
web01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web02 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#只输出自己想要的内容
[root@m01 ~]# vim register.yml
- hosts: web_group
tasks:
- name: Test Register Vars
shell: "ls -l /"
register: list_dir
- name: Return Result
debug:
msg: "{{ list_dir.stdout_lines }}"
#查看结果
[root@m01 ~]# ansible-playbook register.yml
PLAY [web_group] *****************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [web02]
ok: [web01]
TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]
TASK [Return Result] *************************************************************************************************************************************************************************************************************************
ok: [web01] => {
"msg": [
"总用量 28",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin",
"dr-xr-xr-x. 5 root root 4096 3月 9 2019 boot",
"drwxr-xr-x. 20 root root 3280 9月 8 12:25 dev",
"drwxr-xr-x. 80 root root 8192 9月 10 20:52 etc",
"drwxr-xr-x. 5 root root 41 9月 8 16:22 home",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib",
"lrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64",
"drwxr-xr-x. 2 root root 6 4月 11 2018 media",
"drwxr-xr-x. 2 root root 6 4月 11 2018 mnt",
"drwxr-xr-x. 2 www www 6 9月 10 15:31 opt",
"dr-xr-xr-x. 128 root root 0 9月 8 12:25 proc",
"dr-xr-x---. 9 root root 4096 9月 10 21:16 root",
"drwxr-xr-x. 25 root root 740 9月 10 20:52 run",
"lrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin",
"drwxr-xr-x. 2 root root 6 4月 11 2018 srv",
"dr-xr-xr-x. 13 root root 0 9月 8 12:25 sys",
"drwxrwxrwt. 15 root root 4096 9月 16 11:54 tmp",
"drwxr-xr-x. 13 root root 155 3月 9 2019 usr",
"drwxr-xr-x. 21 root root 4096 9月 10 20:52 var"
]
}
ok: [web02] => {
"msg": [
"总用量 24",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 bin -> usr/bin",
"dr-xr-xr-x. 5 root root 4096 3月 9 2019 boot",
"drwxr-xr-x. 20 root root 3260 9月 10 09:47 dev",
"drwxr-xr-x. 80 root root 8192 9月 10 20:52 etc",
"drwxr-xr-x. 5 root root 41 9月 8 16:22 home",
"lrwxrwxrwx. 1 root root 7 3月 9 2019 lib -> usr/lib",
"lrwxrwxrwx. 1 root root 9 3月 9 2019 lib64 -> usr/lib64",
"drwxr-xr-x. 2 root root 6 4月 11 2018 media",
"drwxr-xr-x. 2 root root 6 4月 11 2018 mnt",
"drwxr-xr-x. 2 www www 6 9月 10 15:31 opt",
"dr-xr-xr-x. 128 root root 0 8月 15 15:10 proc",
"dr-xr-x---. 6 root root 180 9月 10 21:16 root",
"drwxr-xr-x. 25 root root 740 9月 10 20:52 run",
"lrwxrwxrwx. 1 root root 8 3月 9 2019 sbin -> usr/sbin",
"drwxr-xr-x. 2 root root 6 4月 11 2018 srv",
"dr-xr-xr-x. 13 root root 0 8月 15 15:10 sys",
"drwxrwxrwt. 14 root root 4096 9月 16 11:54 tmp",
"drwxr-xr-x. 13 root root 155 3月 9 2019 usr",
"drwxr-xr-x. 21 root root 4096 9月 10 20:52 var"
]
}
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
web01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web02 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#debug模块常用参数
msg: #调试输出的消息
var: #将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出
verbosity: #debug的级别(默认是0级,全部显示)
四:Ansible流程控制
一:playbook条件语句---when判断
1.1 根据不同的操作系统安装nginx
#官方示例:
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "Debian"
# note that all variables can be used directly in conditionals without double curly braces
- hosts: web_group
tasks:
- name: Install CentOS nginx
yum:
name: nginx
state: present
#官方
when: ansible_facts['os_family'] == "CentOS"
#非官方
when: ansible_distribution == "CentOS"
- name: Install Ubuntu nginx
yum:
name: apache2
state: present
when: ansible_facts['os_family'] == "Ubuntu"
1.2 使用括号对条件分组
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
1.3 指定多条件为列表
tasks:
- name: "shut down CentOS 6 systems"
command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"
案例:rsync推送配置文件
#服务端:
[root@m01 ~]# cat rsyncd/rsyncd.yml
- hosts: rsync_server
tasks:
- name: Install Rsyncd Server
yum:
name: rsync
state: present
- name: Create www Group
group:
name: www
gid: 666
- name: Create www User
user:
name: www
group: www
uid: 666
create_home: false
shell: /sbin/nologin
- name: Scp Rsync Config
copy:
src: ./rsyncd.j2
dest: /etc/rsyncd.conf
owner: root
group: root
mode: 0644
when: ansible_hostname == "backup"
#ansible_fqdn == "backup"
- name: Create Passwd File
copy:
content: 'rsync_backup:123'
dest: /etc/rsync.passwd
owner: root
group: root
mode: 0600
when: ansible_hostname == "backup"
- name: Create backup Directory
file:
path: /backup
state: directory
mode: 0755
owner: www
group: www
recurse: yes
when: ansible_hostname == "backup"
- name: Start Rsyncd Server
systemd:
name: rsyncd
state: started
when: ansible_hostname == "backup"
#客户端
[root@m01 ~]# vim rsync.yml
- hosts: rsync_server
tasks:
- name: SCP Backup Shell
copy:
src: ./backup.sh
dest: /root/backup.sh
when: ansible_hostname is match "web*"
注意点:1.when需要和模块对齐
2.如果用正则需要用“is match”来匹配
3.正常情况下判断是“==” 如果不等于“!=”
1.4 通过register将命令执行结果保存至变量,然后通过when语句进行判断
- hosts: web_group
tasks:
- name: Check Httpd Server
command: systemctl is-active httpd
ignore_errors: yes #忽略错误,方便下一步继续执行
register: check_httpd
- name: Httpd Restart
service:
name: httpd
state: started
when: check_httpd.rc != 0
说明:
1.systemctl is-active httpd 查看httpd是否启动,没有启动会报错rc=3(0为正常)
2.register设置变量check_httpd
3.when判断check_httpd.rc是否等于0
4.如果不等于0,将开启nginx服务
二:playbook循环语句
如:同时启动多个服务或同时创建多个mysql用户
2.1 定义变量循环
EX1:启动多个服务
- hosts: web_group
tasks:
- name: start service
systemd:
name: "{{ item }}"
state: started
with_items:
- httpd
- php-fpm
- mariadb
EX2:安装多个服务
- hosts: web_group
tasks:
- name: ensure a list of packages installed
yum: name= "{{ item }}" state=present
with_items:
- httpd
- httpd-tools
2.2 字典循环
EX1:创建多个用户
[root@m01 ~]# cat loop.yml
- hosts: web_group
tasks:
- name: Add Users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
state: present
with_items:
- { name: 'zls', groups: 'linux' }
- { name: 'egon', groups: 'python' }
EX2:拷贝多个文件
- hosts: web_group
tasks:
- name: Configure Nginx Websit PHP Conf
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
with_items:
- {src: './nginx.j2',dest: '/etc/nginx/nginx.conf',mode: '0644'}
- {src: './php.drz.com.j2',dest: '/etc/nginx/conf.d/php.drz.com.conf',mode: '0755'}
- {src: './php.j2',dest: '/etc/php-fpm.d/www.conf',mode: '0000'}
三:playbook handlers
handler
用来执行某些条件下的任务,比如当配置文件发生变化的时候,通过notify触发handler去重启服务。
在saltstack中也有类似的触发器,写法相对Ansible简单,只需要watch,配置文件即可。
案例
[root@m01 ~]# cat handler.yml
- hosts: web_group
vars:
- http_port: 8080
tasks:
- name: Install Http Server
yum:
name: httpd
state: present
- name: config httpd server
template:
src: ./httpd.j2
dest: /etc/httpd/conf
notify:
- Restart Httpd Server
- Restart PHP Server
- name: start httpd server
service:
name:httpd
state: started
enabled: yes
handlers:
- name: Restart Httpd Server
systemd:
name: httpd
state: restarted
- name: Restart PHP Server
systemd:
name: php-fpm
state: restarted
注意:
1.无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。
2.Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。
3.Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如: -meta: flush_handlers。
4.如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的--force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。
5.不能使用handlers替代tasks
五:Ansible Roles
一:Ansible Roles目录结构
1.1 官方推荐最佳实践目录结构定义方式
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
#不常用
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
library/ # roles can also include custom modules
module_utils/ # roles can also include custom module_utils
lookup_plugins/ # or other types of plugins, like lookup in this case
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
1.2 roles目录结构使用galaxy创建
[root@m01 ~]# cd /etc/ansible/roles/
[root@m01 roles]# tree wordpress/
nfs/ #项目名称
├── defaults #低优先级变量
├── files #存放文件
├── handlers #触发器文件
├── meta #依赖关系文件
├── tasks #工作任务文件
├── templates #jinja2模板文件
├── tests #测试文件
└── vars #变量文件
备注:只需要这些目录,ansible的roles会自动识别里面的main.yml
二:Ansible Roles依赖关系
roles
允许你在使用roles时自动引入其他的roles。role依赖关系存储在roles目录中meta/main.yml文件中。
例如:推送wordpress并解压,前提条件,必须要安装nginx和php,把服务跑起来,才能运行wordpress的页面,此时我们就可以在wordpress的roles中定义依赖nginx和php的roles
[root@m01 roles]# vim /etc/ansible/roles/wordpress/meta/main.yml
dependencies:
- { role: nginx }
- { role: php }
如果编写了meta目录下的main.yml文件,那么Ansible会自动先执行meta目录中main.yml文件中的dependencies文件,如上所示,就会先执行nginx和php的安装。
如果安装wordpress,main.yml里有nginx和php
流程:
1.当你执行worepress的playbook,会先在meta的main.yml里找nginx
2.找到后,会在roles目录里找nginx,再去nginx目录的meta找依赖,如果无,会在tasks目录里找到安装、配置、启动等
3.装完nginx后再同理执行php
4.最后再执行wordpress的tasks
三:Ansible Roles创建目录
ansible-galaxy init 服务名 roles
[root@m01 ~]# cd /etc/ansible/roles/
[root@m01 /etc/ansible/roles]# ansible-galaxy init rsync roles
- rsync was created successfully
[root@m01 /etc/ansible/roles]# tree
.
└── rsync
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
9 directories, 8 files