Ansible自动化管理工具
一、Ansible 基础
1.Ansible基础概述
1.1 什么是Ansible
Ansible是一个IT自动化的配置管理工具,自动化主要体现在Ansible集成了丰富模块,丰富的功能组件,可以
通过一个命令行完成一系列的操作。进而能减少我们重复性的工作和维护成本,以提高工作的效率。
1.2 Ansible可以完成哪些功能呢
1)批量执行远程命令,可以对N多台主机同时进行命令的执行
2)批量配置软件服务,可以进行自动化的方式配置和管理服务。
3)实现软件开发功能,jumpserver底层使用ansble来实现的自动化管理0
4)编排高级的IT任务,Ansible的playbook是一门编程语言,可以用来描绘一套IT架构。
1.3 Ansible的特点
1.容易学习,无代理模式,不像saltstack既要学服务端又要学习客户端,还要学习服务端与客户端之间的通讯协议
2.操作灵活,体现在Ansible有较多的模块,提供了丰富的功能,playbook则提供了类似于编程语言的复杂功能
3.简单易用,体现在Ansible —个命令可以完成很多事情
4.安全可靠,因为Ansible使用了SSH协议进行通汛,既稳定又安全
5.可移植性高,可以将写好的playbook拷贝至任意机器进行执行
4.Ansible架构中的控制节点、被控制节点、inventroy, ad-hoc、playbook、连接协议是什么?
2.Ansible的安全配置
2.1.Ansible安装
外网地址 | 内网地址 | 角色 |
---|---|---|
10.0.0.61 | 172.16.1.61 | Ansible控制端 |
10.0.0.7 | 172.16.1.7 | Ansible被控端 |
10.0.0.8 | 172.16.1.8 | Ansible被控端 |
1.先安装epel源(提供最新的ansible)
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
2.安装Ansible
yum install ansible -y
查看ansible的版本
[root@m01 ~]# ansible --version
ansible 2.7.7
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)]
3.Ansible的配置文件,配置文件可以随意放,但有查找顺序
$ANSIBLE_CONFIG
ansible.cfg #当前目录下面查找
.ansible.cfg #当前用户的家目录下查找
/etc/ansible/ansible.cfg
[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
二、Ineventory主机清单
1.场景一、基于密码连接
[root@oldboy.com ~]# cat /etc/ansible/hosts
#方式一、主机+端口+密码
[webservers]
172.16.1.7 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123456'
172.16.1.8 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123456'
#方式二、主机+端口+密码
[webservers]
web[1:2].oldboy.com ansible_ssh_pass='123456'
#方式三、主机+端口+密码
[webservers]
web[1:2].oldboy.com
[webservers:vars]
ansible_ssh_pass='123456'
2.场景二、基于密钥连接,需要先创建公钥和私钥,并下发公钥至被控端
[root@m01 ~]# ssh-keygen
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.1.7
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.1.8
-----------------------------------------------------------
[root@m01 ~]# cat hosts
#方式一、主机+端口+密钥
[webservers]
172.16.1.7
172.16.1.8
[root@m01 ~]# ansible webservers -m ping -i ./hosts
172.16.1.8 | SUCCESS => {
"changed": false,
"ping": "pong"
}
172.16.1.7 | SUCCESS => {
"changed": false,
"ping": "pong"
}
-----------------------------------------------------------
[root@m01 ~]# cat hosts
#方式二、别名+主机+端口+密钥
[webservers]
web01 ansible_ssh_host=172.16.1.7 ansible_ssh_port=22
web02 ansible_ssh_host=172.16.1.8
[root@m01 ~]# ansible webservers -m ping -i ./hosts
web02 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
3.场景三、主机组使用方式
#1.定义两个组
[lbservers]
172.16.1.5
172.16.1.6
[webservers]
172.16.1.7
172.16.1.8
#2.servers组包括两个子组[lbservers,webserver]
[servers:children]
[lbservers]
[webserver]
#列出当前某个组有多少台主机
[root@m01 ~]# ansible lbservers -m ping -i ./hosts --list-hosts
hosts (1):
web01
[root@m01 ~]# ansible webservers -m ping -i ./hosts --list-hosts
hosts (1):
web02
[root@m01 ~]# ansible servers -m ping -i ./hosts --list-hosts
hosts (2):
web01
web02
[root@m01 ~]# ansible all -m ping -i ./hosts --list-hosts
hosts (3):
web03
web02
web01
注意:
如果控制端和被控制端第一次通讯,需要先添加指纹信息,那如果机器特别多少的情况下怎么办?
仅需开启ansible中的 host_key_checking = False
三、Ad-Hoc
1.常用模块
command 执行shell命令(不支持管道等特殊字符)
shell 执行shell命令
scripts 执行shell脚本
yum_repository 配置yum仓库
get_url 联网下载
yum 安装
copy 配置
service、systemd 启动
user、group 创建用户与组
file 授权
crond 定时任务
mount 挂载
firewalld firewall
selinux selinux
2..使用过程中需要先了解ansible-doc帮助手册
[root@m01 ~]# ansible-doc -l # 查看所有模块说明
[root@m01 ~]# ansible-doc copy # 表示指定模块方法
[root@m01 ~]# ansible-doc -s copy # 表示指定模块参数
3..command默认执行bash命令模块,模块不支持重定向或管道
[root@m01 ~]# ansible oldboy -a "hostname"
4..shell模块,如果需要一些管道操作,则使用shell
[root@m01 ~]# ansible oldboy -m shell -a "ifconfig|grep eth0" -f 50
5..script脚本模块
[root@m01 ~]# cat yum.sh
#!/usr/bin/bash
yum install -y iftop
#在本地运行模块,等同于在远程执行,不需要将脚本文件进行推送目标主机执行
[root@m01 ~]# ansible oldboy -m script -a "/server/scripts/yum.sh"
6..yum安装软件模块
[root@m01 ~]# ansible oldboy -m yum -a "name=httpd state=installed"
name
httpd #指定要安装的软件包名称
file:// #指定从本地哪个目录安装rpm
http:// #指定从哪个网站安装rpm包
state #指定使用yum的方法
present #安装软件包
absent #移除软件包
latest #安装最新软件包
list=ansible #列出当前仓库可用的软件包
disablerepo="epel,ol7_latest" #安装软件时,不从哪些仓库获取
download_only=true #仅下载软件包,不安装
7.copy文件拷贝模块
#1.拷贝文件文件至被控节点
[root@m01 ~]# ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/test.txt"
#2.对远端已有文件进行备份,按照时间信息备份
[root@m01 ~]# ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/test.txt backup=yes"
#3.向被控端主机写入数据,并且会覆盖远端文件内原有数据信息
[root@m01 ~]# ansible oldboy -m copy -a "content='bgx' dest=/tmp/oldboy"
src #推送数据的源文件信息
dest #推送数据的目标路径
backup #对推送传输过去的文件,进行备份
content #直接批量在被管理端文件中添加内容
group #将本地文件推送到远端,指定文件属组信息
owner #将本地文件推送到远端,指定文件属主信息
mode #将本地文件推送到远端,指定文件权限信息
8..file文件创建模块
1.直接修改被控端的权限
[root@m01 ~]# ansible web01 -m file -a "path=/opt mode=0400" -i ./hosts
2.在被控端创建目录
[root@m01 ~]# ansible oldboy -m file -a "path=/tmp/oldboy state=directory"
3.在被控端创建文件
[root@m01 ~]# ansible oldboy -m file -a "path=/tmp/tt state=touch mode=555 owner=root group=root"
4.递归授权目录权限
[root@m01 ~]# ansible oldboy -m file -a "path=/data owner=bgx group=bgx recurse=yes"
path #指定远程主机目录或文件
recurse #递归授权
state #状态
directory #在远端创建目录
touch #在远端创建文件
link #创建链接文件
absent #表示删除文件或目录
mode #设置文件或目录权限
owner #设置文件或目录属主
group #设置文件或目录属组
9..get_url文件下载模块
1.通过get_url下载文件或者软件
[root@m01 ~]# ansible webservers -m get_url -a "url=http,https dest=/opt mode=0777" -i ./hosts
2.下载一个文件前先进行md5校验,通过则下载,不通过则失败
ansible webservers -m get_url -a "url=http,https dest=/opt mode=0777 checksum=md5:76eb3af80ffd" -i ./hosts
url #文件在网络上的具体位置
dest #下载到被控端的哪个目录下
checksum #校验(md5 sha256)
10.ansible管理服务的启动与停止,使用service、systemd
#1.启动crond服务,并加入开机自启
[root@m01 ~]# ansible webservers -m service -a "name=crond state=started enabled=yes"
#2.停止crond服务,并删除开机自启
[root@m01 ~]# ansible webservers -m service -a "name=crond state=stopped enabled=no"
#3.重启crond服务
[root@m01 ~]# ansible webservers -m service -a "name=crond state=restarted"
#4.重载crond服务
[root@m01 ~]# ansible webservers -m service -a "name=crond state=reloaded"
name # 定义要启动服务的名称
state # 指定服务状态
started #启动服务
stopped #停止服务
restarted #重启服务
reloaded #重载服务
enabled #开机自启
11.group组模块
[root@m01 ~]# ansible webservers -m group -a "name=oldgirl gid=888"
name #指定创建的组名
gid #指定组的gid
state
absent #移除远端主机的组
present #创建远端主机的组(默认)
12.user模块
1.创建用户指定uid和gid,不创建家目录也不允许登陆
[root@m01 ~]# ansible oldboy -m user -a "name=oldgirl uid=888 group=888 shell=/sbin/nologin create_home=no"
2.删除用户
[root@m01 ~]# ansible webservers -m user -a "name=tmd state=absent" -i ./hosts
3.给新创建的用户生成ssh密钥对
[root@m01 ~]# ansible webservers -m user -a "name=oo uid=6677 group=adm generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa" -i ./hosts
4.将明文密码进行hash加密,然后进行用户创建
[root@m01 ~]# ansible localhost -m debug -a "msg={{ '123456' | password_hash('sha512', 'salt') }}"
localhost | SUCCESS => {
"msg": "$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w.igcOo1R7vBYR65JquIQ/7siC7VRpmteKvZmfSkNc69."
}
[root@m01 ~]# ansible webservers -m user -a 'name=xlw password=$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w.igcOo1R7vBYR65JquIQ/7siC7VRpmteKvZmfSkNc69. create_home=yes shell=/bin/bash' -i ./hosts
uid #指定用户的uid
group #指定用户组名称
groups #指定附加组名称
password #给用户添加密码(记得单引号)
shell #指定用户登录shell
create_home #是否创建家目录
13.crond定时任务模块
# 正常使用crond服务(默认没写的时间都算*表示)
[root@m01 ~]# crontab -l
* * * * * /bin/sh /server/scripts/yum.sh
# 使用ansible添加一条定时任务
[root@m01 ~]# ansible webservers -m cron -a "minute=* hour=* day=* month=* weekday=* job='/bin/sh test.sh'"
[root@m01 ~]# ansible webservers -m cron -a "job='/bin/sh /server/scripts/test.sh'"
# 设置定时任务注释信息,防止重复,name设定
[root@m01 ~]# ansible webservers -m cron -a "name='cron01' job='/bin/sh /server/scripts/test.sh'"
# 删除相应定时任务
[root@m01 ~]# ansible webservers -m cron -a "name='ansible cron02' minute=0 hour=0 job='/bin/sh test.sh' state=absent"
# 注释相应定时任务,使定时任务失效
[root@m01 scripts]# ansible oldboy -m cron -a "name='ansible cron01' minute=0 hour=0 job='/bin/sh test.sh' disabled=yes"
14..mount挂载模块7 nfs 8客户端挂载
[root@m01 ~]# ansible web01 -m yum -a 'name=nfs-utils state=present' -i ./hosts
[root@m01 ~]# ansible web01 -m file -a 'path=/data state=directory' -i ./hosts
[root@m01 ~]# ansible web01 -m copy -a 'content="/data 172.16.1.0/24(rw,sync,no_all_squash)" dest=/etc/exports' -i ./hosts
[root@m01 ~]# ansible web01 -m systemd -a "name=nfs state=started enabled=yes" -i ./hosts
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=present"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=mounted"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=unmounted"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=absent"
present # 开机挂载,仅将挂载配置写入/etc/fstab
mounted # 挂载设备,并将配置写入/etc/fstab
unmounted # 卸载设备,不会清除/etc/fstab写入的配置
absent # 卸载设备,会清理/etc/fstab写入的配置
15.防火墙管理模块
Selinux模块
[root@m01 ~]# ansible webservers -m selinux -a "state=disabled" -i ./hosts
firewalld模块
[root@m01 ~]# ansible webservers -m systemd -a "name=firewalld state=started" -i ./hosts
[root@m01 ~]# ansible webservers -m firewalld -a "service=http immediate=yes permanent=yes state=enabled" -i ./hosts
[root@m01 ~]# ansible webservers -m firewalld -a "port=8080-8090/tcp immediate=yes permanent=yes state=enabled" -i ./hosts
service #指定开放或关闭的服务名称
port #指定开放或关闭的端口
masquerade #开启地址伪装
immediate #临时生效
permanent #是否添加永久生效
state #开启或是关闭
zone #指定配置某个区域
rich_rule #配置富规则
source #指定来源IP
四、Playbook
1.Ansible Playbook基本概述
1.什么是playbook,playbook翻译过来就是“剧本' 那么playbook组成如下
playbook:定义一个文本文件,以yml为后缀结尾(翻译:我有一个剧本)
play:定义的是主机的角色(翻译:找哪个大腕明星)
task:定义的是具体执行的任务(翻译:大腕每一集拍什么)
总结:playbook是由一个或多个play组成,一个play可以包含多个task任务。
可以理解为:使用不同的模块来共同完成一件事情。
2.Ansible playbook与AD-Hoc的关系
- playbook是对AD-Hoc的一种编排方式。
- playbook可以持久运行,而Ad-Hoc只能临时运行。
- playbook适合复杂的任务,而Ad-Hoc适合做快速简单的任务。
- playbook能控制任务执行的先后顺序,以及互相依赖的关系。
3.Ansible Playbook书写格式
playbook是由yml语法书写,结构清晰,可读性强,所以必须掌握yml基础语法
语法 | 描述 |
---|---|
缩进 | YAML使用固定的缩进风格表示层级结构,每个缩进由两个空格组成,不能使用Tab |
冒号 | 以冒号结尾的除外,其他所有冒号后面所有必须有空格。 |
短横线 | 表示列表项,使用一个短横杠加一个空格。多个项使用同样的缩进级别作为同一列表。 |
3.1.下面我们一起来编写一个playbook文件,playbook起步
host:对哪些主机进行操作
remote_user:我要使用什么用户执行
tasks: 具体执行什么任务
[root@m01 ~]# cat f1.yml
#play
- hosts: webservers
tasks:
- name: Installed Httpd Server
yum:
name: httpd
state: present
- name: Start Httpd Server
systemd:
name: httpd
state: started
enabled: yes
2.检查语法,只检查是否是yaml语法格式。并不做逻辑校验。
[root@m01 project1]# ansible-playbook --syntax-check p1.yml
playbook: p1.yml
3.模拟执行(不是真的执行)
[root@m01 project1]# ansible-playbook -C p1.yml
4.真实的描述状态(被控端的状态必须与控制端描述的状态一致)
[root@m01 project1]# ansible-playbook p1.yml
3.2.多paly语法示例
ansible安装并配置httpd服务,根据不同的主机配置不同的网站。(多个play的使用方式,但不是生产推荐,了解项,生产推荐使用循环方式)
[root@m01 project1]# cat p1.yml
---
#play
- hosts: webservers
tasks:
- name: Installed Httpd Server
yum: name=httpd state=present
- name: Start Httpd Server
systemd: name=httpd state=started enabled=yes
- name: Start Firewalld Server
systemd: name=firewalld state=started enabled=yes
- name: Configure Firewalld Server
firewalld: service=http immediate=yes permanent=yes state=enabled
- hosts: web01
tasks:
- name: Configure web01 Website
copy: content='This is Web01' dest=/var/www/html/index.html
- hosts: web02
tasks:
- name: Cofnigure webi-2 weisite
copy: content='This is Web02' dest=/var/www/html/index.html
3.3.安装nfs服务
1.安装
2.配置
用户
/data
3.启动
#记得重启你的nfs
[root@m01 project1]# cat nfs.yml
- hosts: web01
tasks:
- name: Install NFS-utils Server
yum: name=nfs-utils state=present
- name: Configure Nfs-utils Server
copy: src=./exports.j2 dest=/etc/exports owner=root group=root mode=0644
- name: Create NFS Group
group: name=www gid=666
- name: Create NFS User
user: name=www uid=666 group=www create_home=no shell=/sbin/nologin
- name: Create Data Directory
file: path=/data state=directory owner=www group=www mode=0755 recurse=yes
- name: Start NFS Server
systemd: name=nfs state=started enabled=yes
- hosts: web02
tasks:
- name: Mount NFS Server
mount: path=/opt src=172.16.1.7:/data fstype=nfs opts=defaults state=mounted
3.4.使用AnsiblePlaybook方式构建LAMP架构,具体操作步骤如下:
1.使用yum安装 httpd、php、php-mysql、mariadb、firewalld等
2.启动httpd、firewalld、mariadb等服务
3.添加防火墙规则,放行http的流量,并永久生效
4.使用get_url下载 http://fj.xuliangwei.com/public/index.php 文件
[root@m01 project1]# cat lamp.yml
#- hosts: webservers
- hosts: otherservers
tasks:
- name: Installed Web Packages
yum: name=httpd,mariadb-server,php,php-mysql,php-pdo state=present
- name: Start Web Serivce
service: name=httpd state=started
- name: Start Mariadb Service
service: name=mariadb state=started
- name: Get Wordpress
unarchive: src=./wordpress-5.0.3-zh_CN.tar.gz dest=/var/www/html/ copy=yes mode=0755
# - name: Copy Index.php
# copy: src=./index.php.j2 dest=/var/www/html/index.php
# - name: Get Url index.php
# get_url: url="http://fj.xuliangwei.com/public/index.php" dest=/var/www/html/index.php
4.Ansible Playbook变量解析
1 .变量概述
变量提供了便捷的方式来管理ansible项目中的动态值。比女Ozabbix-3.4.15,可能后期会反复的使用到这个版本的值,那么如果将此值设置扫变量,后续使用和修改都将变得非常方便。这样可以简化项目的创建和维护
定义变量分为如下三种方式
1)通过命令行进行变量定义
2)在play文件中进行定义变量
3)通过inventory在主机组或单个主机中设置变量
如果定义的变量出现重复,且造成冲突,优先级如下:
1.命令行定义的变量-高于->play文件定义的变量-高于->inventory文件定义的变量。
2.变量的定义
2.1.playbook变量可以通过多种方式进行定义,最简单的方式就是在playbook的开头通过vars进行定义
#安装两个软件包使用变量方式
[root@m01 project1]# cat p2.yml
- hosts: webservers
vars:
- web_package: httpd
- ftp_package: vsftpd
tasks:
- name: Installed Packages
yum:
name:
- "{{ web_package }}"
- "{{ ftp_package }}"
state: present
2.2.也可以在playbook中使用vars_files指定文件作为变量文件,好处就是其他的playbook也可以调
[root@m01 project1]# cat vars.yml
web_package: httpd
ftp_package: vsftpd
[root@m01 project1]# cat p2.yml
- hosts: webservers
vars_files: ./vars.yml
tasks:
- name: Installed Packages
yum:
name:
- "{{ web_package }}"
- "{{ ftp_package }}"
state: present
2.3.在inventory中定义变量,主机变量优先级高于主机组变量(不推荐,容易将环境弄的特别乱)
[root@m01 project1]# vim /etc/ansible/hosts
[webservers]
web01 ansible_ssh_host=172.16.1.7
web02 ansible_ssh_host=172.16.1.8
[webservers:vars]
filename=group_vars
[root@m01 project1]# cat p3.yml
- hosts: webservers
tasks:
- name: Create File
file: path=/tmp/{{ filename }} state=touch
2.4.更好的方式是在ansible的项目目录中创建额外的两个变量目录,分别是host_vars和group_vars
group_vars目录下必须存放和inventory清单文件中定义的组名一致,如下
[root@m01 project1]# cat /etc/ansible/hosts
[webservers]
web01 ansible_ssh_host=172.16.1.7
web02 ansible_ssh_host=172.16.1.8
[root@m01 project1]# cat group_vars/webservers
web_package: httpd
ftp_package: vsftpd
注意:系统提供了特殊的组,all,也就说在group_vars目录下创建一个all文件,定义变量对所有的主机都生效
[root@m01 project1]# cat host_vars/web01
web_package: zlib-static
ftp_package: zmap
[root@m01 project1]# cat group_vars/webservers
web_package: httpd
ftp_package: vsftpd
[root@m01 project1]# cat p4.yml
- hosts: webservers
#- hosts: otherservers
tasks:
- name: Installed Packages
yum:
name:
- "{{ web_package }}"
- "{{ ftp_package }}"
state: present
[root@m01 project1]# ansible-playbook p4.yml
PLAY [webservers] ********************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************
ok: [web02]
ok: [web01]
TASK [Installed Packages] ************************************************************************************************
ok: [web02]
changed: [web01]
PLAY RECAP ***************************************************************************************************************
web01 : ok=2 changed=1 unreachable=0 failed=0
web02 : ok=2 changed=0 unreachable=0 failed=0
2.5.通过命令行覆盖变量,inventory的变量会被playbook文件中覆盖,这两种方式的变量都会被命
令行直接指定变量所覆盖。使用--extra-vars或-e设定变量。
[root@m01 project1]# ansible-playbook p4.yml -e "web_package=zarafa-devel" -e "ftp_package=zarafa-utils"
2.6.变量优先级测试
命令行变量--->play中的vars_files--->play中的vars变量-->host_vars中定义的变量--->group_vars/组--->group_vars/all
[root@m01 project1]# cat p5.yml
- hosts: webservers
# vars:
# filename: play_vars
# vars_files:
# - ./vars.yml
tasks:
- name: Create
shell: mkdir -pv /tmp/{{ filename }}
register: mk_test
- name: debug
debug: msg={{ mk_test }}
2.7.变量注册register
- hosts: webservers
tasks:
- name: Get Network Port Status
shell: netstat -lntp
register: net_port
- name: OutPut Network Port Status
debug:
msg: "{{ net_port.stdout_lines }}"
2.8.变量也支持层级定义,使用"."可能会有问题,建议使用"[]"代替。
[root@m01 project1]# cat vars1.yml
rainbow:
web:
web_package: httpd
db_package: mariadb
code:
web:
filename: code_web_filename
[root@m01 project1]# cat p8.yml
- hosts: webservers
vars_files: ./vars1.yml
tasks:
- name: Install Package
yum: name= "{{ rainbow['web']['web_package'] }}"
- name: create filename
file:
path: /tmp/{{ code.web.filename }}
state: touch
2.9.facts变量 (setup模块)
Ansible facts是在被管理主机上通过ansible自动采集发现的变量。facts包含每台特定的主机信息。比如:被控端主机的主机名、IP地址、系统版本、CPU数量、内存状态、磁盘状态等等。
facts使用场景
1.通过facts检查CPU,来生成对应的Nginx配置文件
2.通过facts检查主机名信息,来生成不同的Zabbix配置文件
3.通过fact检索的内存情况来自定义mysql的配置文件
1.facts基本用法,比如获取被控端的主机名与IP地址
[root@m01 〜]# cat facts.yml
-hosts: web
tasks:
-name: Output variables ansible facts
debug:
msg: >
this default IPv4 address "{{ ansible_fqdn}}" is "{{ ansible_default_ipv4.address}}"
2.使用facts模拟批量修改zabbix配置文件,template和copy用法差不多,但template支持解析变量
[root@m01 project1]# cat p10.yml
- hosts: webservers
#gather_facts: no 关闭facts采集
vars:
- zabbix_server: 172.16.1.71
tasks:
- name: Copy Zabbix Agent Configure
template: src=./zabbix_agentd.conf dest=/tmp/zabbix_agent.conf
- facts开启后会影响Ansible主机的性能,如果没有采集被控端主机需求可选择关闭
[root@m01 project1]# cat p10.yml
- hosts: webservers
#gather_facts: no 关闭facts采集
vars:
- zabbix_server: 172.16.1.71
tasks:
- name: Copy Zabbix Agent Configure
template: src=./zabbix_agentd.conf dest=/tmp/zabbix_agent.conf
4.使用setup模块获取采集的值
ansible web01 -m setup -i ./hosts
5.playbook安装一个memcached,利用了facts变量
[root@m01 project1]# cat memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb //2 }}"
OPTIONS=""
[root@m01 project1]# cat p11.yml
- hosts: webservers
tasks:
- name: Installed Memcached
yum: name=memcached state=present
- name: Configure Memcached
template: src=./memcached.j2 dest=/etc/sysconfig/memcached
- name: Start Memcached
service: name=memcached state=started enabled=yes
2.10.批量修改主机名
解法一、web_随机数的解法
[root@m01 ~]# cat te.yaml
- hosts: all
tasks:
- name: 打印facts变量的内容
debug: msg={{ ansible_default_ipv4.address }}
- name: 使用hostname模块将主机名修改为web_ip
hostname: name=web_{{ ansible_default_ipv4.address }}
解法二、web_随机数的解法
[root@m01 ~]# cat te_2.yaml
- hosts: all
tasks:
- name: 定义一个随机数,设定为变量,然后后续调用
shell: echo $((RANDOM%200))
register: System_SJ
- name: 使用debug输出变量结果,这样好知道需要提取的关键值
debug: msg={{ System_SJ }}
- name: 使用hostname模块将主机名修改为web_随机数
hostname: name=web_{{ System_SJ.stdout }}
解法三、随机数+时间戳的解法
[root@m01 project1]# cat vars_14.yml
- hosts: oldboy
tasks:
- name: SHell
shell: echo $RANDOM|md5sum |cut -c 5-10
register: get_random
- name: Get Facts
debug:
msg: "{{ ansible_date_time.epoch }}"
- name: Hostname
hostname: name={{ get_random.stdout }}_{{ ansible_date_time.epoch }}
5.Playbook条件语句
判断在Ansible任务中_吏用频率非常高。比如yum模块可以检测软件包是否已被安装,而在这个过程中我们不用做太多的人工干预。
但是也有部分任务需要进行判断,比如:web服务器角色都需要安装nginx仓库,但其他的服务器角色并不需要,此时就会用到when判断。
比如:Centos与Ubuntu系统都需要安装httpd服务,那么就需要使用when判断主机系统,然后调用不同的模块执行。
实践案例一、根据不同操作系统,安装相同的软件包
Centos:httpd
Ubuntu:httpd2
[root@m01 project2]# cat when.yml
- hosts: webservers
tasks:
- name: Install httpd Server
yum: name=httpd state=present
when: ansible_distribution == "CentOS"
- name: Install httpd Server
apt: name=httpd2 state=present
when: ansible_distribution == "Ubuntu"
实践案例二、所有为web主机名的添加nginx仓库,其余的都跳过添加
1.如何添加yum仓库
2.如何判断,判断什么内容
---
- hosts: all
tasks:
- name: Add Nginx Repos
yum_repository:
name: nginx_tet
description: Nginx YUM repo
baseurl: http://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
when: (ansible_hostname is match ("web*")) or (ansible_hostname is match ("lb*"))
1.通过register将命令执行结果保存至变量,然后通过when语句进行判断
- hosts: webservers
tasks:
- name: Check Httpd Server
command: systemctl is-active httpd
ignore_errors: yes
register: check_httpd
#- name: debug outprint #仅仅只是输出结果
# debug: var=check_httpd
- name: Httpd Restart
service: name=httpd state=restarted
when: check_httpd.rc == 0
6.Playbook循环语句
有时候我们写playbook的时候发现了很多task都要重复引用某个模块,比如一次启动10个服务,或者一次拷贝10个文件,如果按照传统的写法最少要写10次,这样会显得playbook很臃肿。如果使用循环的方式来编写playbook,这样可以减少重复使用某个模块。
实践案例一、使用循环启动多个服务
[root@m01 project2]# cat with.yml
- hosts: webservers
tasks:
- name: Start httpd mariadb
systemd: name={{ item }} state=started
with_items:
- httpd
- mariadb
案例二、使用定义变量方式循环安装软件包。
- hosts: webservers
tasks:
- name: ensure a list of packages installed
yum: name= "{{ packages }}" state=present
vars:
packages:
- httpd
- httpd-tools
#弃用的方式
- hosts: webservers
tasks:
- name: ensure a list of packages installed
yum: name= "{{ item }}" state=present
with_items:
- httpd
- httpd-tools
实践案例三、使用字典循环方式创建用户和批量拷贝文件
1.批量创建用户,使用字典的key value的方式
[root@manager ~]# cat loop-user.yml
- hosts: webservers
tasks:
- name: Add Users
user: name={{ item.name }} groups={{ item.groups }} state=present
with_items:
- { name: 'testuser1', groups: 'bin' }
- { name: 'testuser2', groups: 'root' }
2.使用字典循环批量拷贝文件
[root@m01 project2]# cat with4.yml
- hosts: webservers
tasks:
- name: Copy Rsync configure and Rsync passwd
copy: src={{ item.src }} dest={{ item.dest }} mode={{ item.mode }}
with_items:
- { src: "./rsyncd.conf", dest: "/etc/rsyncd.conf", mode: "0644" }
- { src: "./rsync.passwd", dest: "/tmp/rsync.passwd", mode: "0600" }
7.handlers触发器
1.当配置发生改变,重启服务
[root@m01 project2]# cat han.yml
- hosts: webservers
vars:
- http_port: 8083
tasks:
- name: Install Http Server
yum: name=httpd state=present
- name: configure httpd server
template: src=./httpd.conf.j2 dest=/etc/httpd/conf/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
2.handlers注意事项
- 1.无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。
- 2.只有task发生改变了才会通知handlers,没有改变则不会触发handlers
- 3.不能使用handlers替代tasks
8.Playbook tag标记(用于调试的场景下)
默认情况下,Ansible在执行一个playbook时,会执行playbook中定义的所有任务。Ansible的标签(Tags)功能可以给单独任务甚至整个playbook打上标签,然后利用这些标签来指定要运行playbook中的个别任务,或不执行指定的任务。
1.打标签的方式有几种,比如:
对一个task打一个标签、对一个task打多个标签、对多个task打一个标签
2、对task打完标签应该如何使用
-t:执行指定的tag标签任务
-skip-tags:执行-skip-tags之外的标签任务
[root@m01 project2]# cat tag.yml
- hosts: webservers
vars:
- http_port: 8083
tasks:
- name: Install Http Server
yum: name=httpd state=present
tags:
- install_httpd
- httpd_server
- name: configure httpd server
template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: Restart Httpd Server
tags:
- confiure_httpd
- httpd_server
- name: start httpd server
service: name=httpd state=started enabled=yes
tags: service_httpd
handlers:
- name: Restart Httpd Server
systemd: name=httpd state=restarted
[root@m01 project2]# ansible-playbook tag.yml --list-tags #查看所有标签
[root@m01 project2]# ansible-playbook tag.yml -t httpd_server #运行指定的标签
[root@m01 project2]# ansible-playbook tag.yml -t install_httpd,confiure_httpd #运行指定的多个标签
[root@m01 project2]# ansible-playbook tag.yml --skip-tags httpd_server #跳过指定的标签
9.Playbook 文件复用(include)
include用来动态的包含tasks任务列表include_tasks新版/include老版
include包含
include(import_playbook)此为包含完整的文件
include_tasks 此为包含任务
#主入口文件
[root@m01 project2]# cat task.yml
- hosts: webservers
vars:
- http_port: 801
tasks:
- include_tasks: task_install.yml
- include_tasks: task_configure.yml
- include_tasks: task_start.yml
handlers:
- name: Restart Httpd Server
systemd: name=httpd state=restarted
#任务文件
[root@m01 project2]# cat task_install.yml
- name: Install Http Server
yum: name=httpd state=present
[root@m01 project2]# cat task_configure.yml
- name: configure httpd server
template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: Restart Httpd Server
[root@m01 project2]# cat task_start.yml
- name: start httpd server
service: name=httpd state=started enabled=yes
10.Playbook忽略错误(ignore_errors)
默认Playbook会偷asks执行的返囪状态,如遇到锗误则会立即终止playbook的后续的tasks执行。然而有些时候palybook即使执行锗误了也要让其继续执行
加入参数:ignore_errors: yes忽略错误
编写playbook,当有task执行失败则会立即终止后续task运行
[root@manager ~]# cat f9.yml
---
- hosts: webservers
tasks:
- name: Ignore False
command: /bin/false
ignore_errors: yes
- name: touch new file
file: path=/tmp/bgx_ignore state=touch
11.Playbook异常处理
通常情况下,当task失败后,play将会终止,任何在前面已经被tasks notify的handlers都不会被执行。如果你在play中设置了force_handlers: yes参数,被通知的handlers就会被强制执行。(有些特殊场景可能会使用到)
force_handlers: yes 强制调用handlers (写到play里)
changed_when: false 被管理主机没有发生变化,可以使用参数将change状态改为ok
changed_when: httpd_check.stdout.find('OK') #查看变量中的某个字符串
[root@m01 project2]# cat changed_when.yml
- hosts: webservers
vars:
- http_port: 8083
tasks:
- name: configure httpd server
template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: Restart Httpd Server
- name: Check HTTPD
shell: /usr/sbin/httpd -t
register: httpd_check
changed_when:
- httpd_check.stdout.find('OK')
- false
- name: start httpd server
service: name=httpd state=started enabled=yes
handlers:
- name: Restart Httpd Server
systemd: name=httpd state=restarted
failed_when
命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 failed 字符串,则判定为失败。示例如下:
- name: this command prints FAILED when it fails
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
五、Ansible加密模块
1.Ansible Vault 概述
Ansible Vault作为ansible的一项新功能可将例如passwords,keys等感数据文件逬行加密,而非存放在明文的playbooks或roles中。
2.Ansible Vault实践
ansible加密使用的是ansible-vault命令进行加密,语法示例
[root@m01 project2]# ansible-vault --help
Usage: ansible-vault [create|decrypt(解密)|edit|encrypt(加密)|encrypt_string|rekey(修改密码)|view(查看)] [options] [vaultfile.yml]
加密一个文件
ansible-vault encrypt include.yml
查看一个文件
[root@m01 project2]# ansible-vault view include.yml
Vault password:
- import_playbook: han.yml
- import_playbook: when2.yml
修改加密的文件内容
[root@m01 project2]# ansible-vault edit include.yml
rekey 修改密码
[root@m01 project2]# ansible-vault rekey include.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
执行加密的playbook
echo "1" >pass
chmod 600 pass
ansible-playbook include.yml --vault-password-file=pass
六、jinja模板
1.Ansible Jinja2模板概述
1.1.什么是Jinja2
Jinja2是Python的全功能模板引擎
1.2.Jinja2横板与Anslble有什么关系
Ansible通常会使用Jinja2模板来修改被管理主机的配置文件。例如给10台远程主机都装上httpd服务,但是要求每个服务器的端口不一样,如何解决?
1.3.Anslble如何使用Jinja2模板
使用ansible的jinja2模板,也就是template模板。该模块和copy模块一样,都是将文件复制到远端主机上去,但是区别在于template模板可以获取要复制的文件中变量的值,而copy则是原封不动的把文件内容复制过去,比如:针对不同的主机定义不同的变量, template会在将配置文件分发出去前读取变量到iinja2模板.然后分发到不同的被管理主机上。
Ansible 使用Jinja2模板注意事项:
Ansible允许Jinja2模板中使用条件判断和循环.但是不允许在playbook中使用。
注悤:不是每个管理员都需要这个特性,但屋有些时候jinja2模板能大大提高效率。
2.Ansible Jinja2的基本使用
2.1.jinja模板基本语法
{{EXPR}}输出变量的值(会输出自定义变量的值或fact}
1)playbook文件使用template 参数
2)模板文件里面变量使用{{名称}},比如{{PORT}}或使用facts.
2.2.Jinja模板逻辑关系
{% for i in EXPR %}...{% endfor%}作为循环表达式
{% if EXPR %}...{% elif EXPR %}...{% endif%}作为条件判断
{# COMMENT #}表示注释
2.3.jinja模板使用示例,使用fact变量的示例
1)使用Playbook推送文件
[root@m01 playbook ]# cat jinja2.yml
- hosts: web
tasks:
- name: Copy Template File /etc/motd
template: src=./motd.j2 dest=/etc.motd
2)准备motd.j2文件
[root@m01 playbook]# cat motd.j2
Welcome to {{ ansible_hostname }}
This system total Memory is: {{ ansible_memtotal_mb }} MB
This system free Memory is: {{ ansible_memfree_mb }} MB
3)执行Playbook
[root@m01 playbook]# ansible-playbook -i hosts jinja2.yml
3.Ansible Jinja2管理Nginx
ansible 使用jinja2的for循环表达式渲染出nginx负载均衡的配置文件
1)使用Playbook推送nginx配置文件
[root@m01 project2]# cat jinja_nginx.yml
- hosts: webservers
vars:
- http_port: 80
- server_name: www.oldboyedu.com
tasks:
- name: Copy Nginx COnfigure
template: src=./oldboyedu.conf.j2 dest=/etc/nginx/conf.d/oldboyedu_proxy.conf
2)准备proxy.conf.j2配置文件
[root@m01 project2]# cat proxy.conf.j2
upstream {{ server_name }} {
{% for i in range(1,20) %}
server 172.16.1.{{i}}:{{http_port}};
{%endfor%}
}
server {
listen {{ http_port }};
server_name {{ server_name }};
location / {
proxy_pass http://{{ server_name }};
proxy_set_header Host $http_host;
}
}
循环的高级用法:
读取主机清单中的组(inventory)
upstream {{ server_name }} {
{% for i in groups['webserver'] %}
server {{i}}:{{http_port}} weight=2;
{% endfor %}
4.Ansible Jinja2管理Keepalived
ansible 使用jinja2的if判断表达式渲染出Keepalived高可用配置文件,并推送到lb组
1)使用Playbook推送Keepalived配置文件
[root@m01 project2]# cat jinja_keepalived.yml
- hosts: webservers
tasks:
- name: Copy Keepalived Configure
template: src=./kee.conf.j2 dest=/tmp/keepalived.conf
2)准备kee.conf.j2 配置文件
[root@m01 project2]# cat kee.conf.j2
global_defs {
router_id {{ ansible_hostname }}
}
vrrp_instance VI_1 {
{%if ansible_hostname =="web01" %}
state MASTER
priority 150
{%elif ansible_hostname == "web02" %}
state BACKUP
priority 100
{%endif%}
interface eth0
virtual_router_id 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}
5.Ansible Jinja2 IF 管理mysql
1)使用Playbook推送mysql配置文件
[root@m01 project2]# cat jinja_mysql.yml
- hosts: webservers
gather_facts: no
vars:
PORT: 13306
# PORT: false #相当于开关
tasks:
- name: Copy MySQL Configure
template: src=./my.cnf.j2 dest=/tmp/my.cnf
2)准备my.cnf.j2 配置文件
[root@m01 project2]# cat my.cnf.j2
{% if PORT %}
bind-address=0.0.0.0:{{ PORT }}
{% else %}
bind-address=0.0.0.0:3306
{%endif%}
七、Ansible Rose角色
1.Ansible Rose基本概述
前面已经学过tasks和handles,那怎样组织playbook才是最好的方式呢?简单的回答就是:使用Roles! Roles基于一个已知的文件结构,去自动的加载某些vars_files, tasks以及handlers。
以便pkaybook更好的调用。相比playbook, roles的结构更加的清晰有层次。
例如:我们无论安装什么软件都会安装时间同步服务,那么每个playbook都要编写时间同步服务的task。此时我们可以将时间同步服务task写好,等到用的时候再调用就行了。
Ansible注意事项:在编写roles的时候,最好能够将一个task拆分为一个文件,方便后续复用。(彻底的打散)
2.Ansible Rose目录结构
1.rose官方目录的结构,必须那么定义
[root@m01 ~]# cd /etc/ansible/roles/
[root@m01 roles]# mkdir -p {nfs,rsync,web}/{vars,tasks,templates,handlers,files,meta}
[root@m01 roles]# tree
.
├── nfs
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
├── rsync
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
└── web
├── files
├── handlers
├── meta
├── tasks
├── templates
└── vars
21 directories, 0 files
3.Ansible Rose依赖关系
roles允许您在使用role时自动引入其他role。role依赖关系存储在role目录中meta/main.yml文件中。
例如:安装wordpress需要先确保nginx与php都能正常运行,此时可以在wordpress的role中定义,依赖nginx与php-fpm的roles
[root@m01 playbook]# cat /root/roles/wordpress/meta/main.yml
---
dependencies:
- { role: nginx }
- { role: php-fpm }
此时wordpress的role会先执行nginx的role,然后再执行php-fpm的role,最后再执行wordpress本身的role。
4.Ansible Rose案例实战
Roles小技巧:
1.创建role 目录结构,手动或使用ansible-galaxy init test roles
2.编写role功能内容。
3.在playbook中引用
案例一、Ansible Roles重构NFS服务
1.安装nfs的task任务
[root@m01 roles]# cat nfs/tasks/install.yml
- name: Install NFS-utils Server
yum: name=nfs-utils state=present
2.配置nfs的task任务
[root@m01 roles]# cat nfs/tasks/config.yml
- name: Configure Nfs-utils Server
template: src=./exports.j2 dest=/etc/exports owner=root group=root mode=0644
notify: Restart NFS Server
3.启动fs的task任务
[root@m01 roles]# cat nfs/tasks/start.yml
- name: Start NFS Server
systemd: name=nfs state=started enabled=yes
4.包含nfs的安装、配置、启动的task任务
[root@m01 roles]# cat nfs/tasks/main.yml
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml
5.客户端挂载nfs的task任务
[root@m01 roles]# cat nfs-client/tasks/main.yml
- name: Mount NFS Server
mount: path=/opt src=172.16.1.7:/data fstype=nfs opts=defaults state=mounted
6.执行所有tasks的roles主配置文件
[root@m01 roles]# cat site.yml
- hosts: web01
roles:
- nfs
- hosts: web02
roles:
- nfs-client
5.Ansible Galaxy
Galaxy是一个免费网站,类似于github网站,网站上基本都是共享的roles角色。从Galaxy下载roles角色是快速启动自动化项目方式之一。galaxy官网
Ansible提供了一个ansible-galaxy 命令行工具,可以用来init(初始化)、search(查找)、install(安装)、remove(移除)等操作。
1.如何使用ansible-galaxy 搜索一个项目
2.查看详细信息
3.客户端搜索项目,直接安装