Ansible
一、什么是Ansible
Ansible是一个自动化统一配置管理工具,自动化主要体现在Ansible集成了丰富模块以及功能组件,可以通过一个命令完成一系列的操作,进而能减少重复性的工作和维护成本,可以提高工作效率。
同类型软件对比
1.puppet 学习难,安装ruby环境难,没有远程执行功能
2.ansible 轻量级,大规模环境下只通过ssh会很慢,串行的
3.saltstack 一般选择salt会使用 C/S 结构的模式, salt-master 和 salt-minion ,并行的,大规模批量操作的情况下,会比Ansible速度快一些,底层使用的是 zero-MQ 消协队列
Ansible架构
Ansible执行流程
1.Ansible读取playbook剧本,剧本中会记录对哪些主机执行哪些任务。
2.首先Ansible通过主机清单找到要执行的主机,然后调用具体的模块。
3.其次Ansible会通过连接插件连接对应的主机并推送对应的任务列表。
4.最后被管理的主机会将Ansible发送过来的任务解析为本地Shell命令执行。
二、安装Ansible
1.准备一台服务器61
[root@ansible ~]# yum -y install ansible
2.配置ansible
[root@ansible ~]# cat /etc/ansible/ansible.cfg
[defaults]
host_key_checking = False # 在进行
deprecation_warnings = False
interpreter_python = /usr/bin/python3
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
【1】、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日志
【2】、ansible查找配置文件顺序
- ansible配置文件查找顺序
-
首先检测ANSIBLE_CONFIG变量定义的配置文件
-
其次检查当前目录下的./ansible.cfg文件
-
再检查当前用户家目录下的ansible.cfg文件
-
最后检查/etc/ansible/ansible.cfg
-
ansible再进行管理的时候是通过ssh协议
-
三、Ansible Inventory
/etc/ansible/hosts
是ansible默认主机资产清单文件,用于定义被管理主机的认证信息, 例如ssh登录用户名、密码以及key相关信息。Inventory文件中填写需要被管理的主机与主机组信息。还可以自定义Inventory主机清单的位置,使用-i指定文件位置即可。
Ansible去和主机连接时是基于ssh协议进行的,连接方式主要是有两种
- 基于密码
- 基于密钥
【1】、编写主机清单
1、基于密码登录的主机清单
[root@ansible ~]# cat /etc/ansible/hosts
192.168.121.31 ansible_ssh_user=root ansible_ssh_port=22 ansible_ssh_pass="0207xrzh!"
192.168.121.41 ansible_ssh_user=root ansible_ssh_port=22 ansible_ssh_pass="0207xrzh!"
# ansible_ssh_user=root 基于什么用户进行远程登录
# ansible_ssh_port=22 基于什么端口进行远程登录
# ansible_ssh_pass="0207xrzh!" 密码是什么
# all 表示执行对象是主机清单中的所有主机
[root@ansible ~]# ansible all -m ping
192.168.121.31 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.121.41 | SUCCESS => {
"changed": false,
"ping": "pong"
}
[root@ansible ~]# ansible 192.168.121.31 -m ping
192.168.121.31 | SUCCESS => {
"changed": false,
"ping": "pong"
}
# 编写/etc/hosts本地解析,就可以通过域名去指定了
[root@ansible ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.121.31 nfs
192.168.121.41 backup
[root@ansible ~]# cat /etc/ansible/hosts
nfs ansible_ssh_user=root ansible_ssh_pass="0207xrzh!"
backup ansible_ssh_user=root ansible_ssh_pass="0207xrzh!"
[root@ansible ~]# ansible all -m ping
nfs | SUCCESS => {
"changed": false,
"ping": "pong"
}
backup | SUCCESS => {
"changed": false,
"ping": "pong"
}
2、基于密钥登录的主机清单
# 配置免密
[root@ansible ~]# ssh-keygen
[root@ansible ~]# ssh-copy-id backup
[root@ansible ~]# ssh-copy-id nfs
[root@ansible ~]# cat /etc/ansible/hosts
# 可以不写密码了
nfs
backup
[root@ansible ~]# ansible all -m ping
nfs | SUCCESS => {
"changed": false,
"ping": "pong"
}
backup | SUCCESS => {
"changed": false,
"ping": "pong"
}
【2】、定义主机组和子组
# 定义主机组
[webservers]
web01
web01
[back]
backup
[mysql]
mysql01
mysql02
# 定义子组
[lnmp:children]
webservers
back
mysql
【3】、测试
# 列出管理的主机
[root@ansible:192.168.121.66 ~/ansible]$ansible all --list-hosts
hosts (4):
nfs
web1
web2
db1
[root@ansible:192.168.121.66 ~/ansible]$ansible webservers --list-hosts
hosts (2):
web1
web2
# 批量执行ping命令,检测主机存活
[root@ansible ansible]# ansible all -m ping
db | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
web02 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
web01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
# ansible后面可以跟多个对象,用逗号隔开
[root@ansible:192.168.121.10 ~/ansible]$ansible web01,db -m ping
# 批量添加用户
[root@ansible ansible]# ansible all -a "useradd zhangsan"
db | CHANGED | rc=0 >>
web02 | CHANGED | rc=0 >>
web01 | CHANGED | rc=0 >>
# 批量创建目录
[root@ansible ansible]# ansible all -a "mkdir /tmp/demo"
web02 | CHANGED | rc=0 >>
db | CHANGED | rc=0 >>
web01 | CHANGED | rc=0 >>
四、Ansible-adhoc
ansible 主机或组列表 -m 模块 -a "参数" # -a是可选的
【1】、ping模块
测试ansible的master node能否连接各个被控节点
类似ping但是不完全等于ping
ansible无法连接被控端的情况
- 网络不通
- 没有设置ssh免密、也没有设置ansible变量
- hosts文件写错了
【2】、命令执行操作模块
1、command模块
这是ansible默认模块,如果执行ansible命令时,没有加模块,默认是command模块
[root@ansible ~]# ansible nfs -a "ls /etc/passwd"
nfs | CHANGED | rc=0 >>
/etc/passwd
[root@ansible ~]# ansible nfs -m command -a "ls /etc/passwd"
nfs | CHANGED | rc=0 >>
/etc/passwd
2、shell模块
在shell模块中执行命令支持shell特性
[root@ansible ~]# ansible nfs -m shell -a "ls /etc/ | wc -l"
nfs | CHANGED | rc=0 >>
236
3、script模块
如果要执行复杂的命令,可以写入脚本使用script模块可以执行脚本
在使用script模块执行脚本时,脚本可以没有x权限
# test脚本内容
#!/bin/bash
for user in user{6..8}
do
useradd $user
echo "123456" | passwd --stdin $user
done
#
[root@ansible:192.168.121.10 ~/ansible]$ansible all -m script -a "test.sh"
⚠️command、shell、script不建议使用
因为这三个模块没有幂等性
【3】、文件操作模块
1、file模块
可以创建文件、目录、链接等,还可以修改权限属性等
- 常用的选项
- path:指定文件路径
- owner:设置文件所有者,一定要是提前存在的
- group:设置文件所属组,一定要是提前存在的
- state:状态。
- touch表示创建文件
- directory表示创建目录
- link表示创建软连接
- absent表示删除
- mode:设置权限
- scr:source的缩写,源
- dest:目的路径
# 创建指定文件设置权限
[root@ansible ~]# ansible nfs -m file -a "path=/opt/aaa state=touch mode=0600"
nfs | CHANGED => {
"changed": true,
"dest": "/opt/aaa",
"gid": 0,
"group": "root",
"mode": "0600",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
[root@ansible ~]# ansible nfs -a "ls -l /opt/aaa"
nfs | CHANGED | rc=0 >>
-rw------- 1 root root 0 Dec 31 22:21 /opt/aaa
# 指定用户和用户组
[root@ansible ~]# ansible nfs -m file -a "path=/opt/bbb state=touch mode=0600 owner=xu group=xu"
nfs | CHANGED => {
"changed": true,
"dest": "/opt/bbb",
"gid": 1000,
"group": "xu",
"mode": "0600",
"owner": "xu",
"size": 0,
"state": "file",
"uid": 1000
}
[root@ansible ~]# ansible nfs -a "ls -l /opt/bbb"
nfs | CHANGED | rc=0 >>
-rw------- 1 xu xu 0 Dec 31 22:23 /opt/bbb
# 删除文件
[root@ansible ~]# ansible nfs -m file -a "path=/opt/aaa state=absent"
nfs | CHANGED => {
"changed": true,
"path": "/opt/aaa",
"state": "absent"
}
# 创建链接
[root@ansible ~]# ansible nfs -m file -a "src=/opt/bbb dest=/root/bbb state=link"
nfs | CHANGED => {
"changed": true,
"dest": "/root/bbb",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 8,
"src": "/opt/bbb",
"state": "link",
"uid": 0
}
[root@ansible ~]# ansible nfs -a "ls -l /root/bbb"
nfs | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 8 Dec 31 22:46 /root/bbb -> /opt/bbb
file模块幂等性的体现
在创建目录时,第一次创建是CHANGED,后面再创建相同的目录时就是SUCESS,不会报错
web01 | SUCCESS =>
在创建文件时不存在幂等性,因为虽然创建的文件是一样的,但是每一次touch时,文件的时间都会改变
web02 | CHANGED =>
2、copy模块
- 用于将文件从控制端拷贝到被控端
- 常用选项
- src:源,控制端文件路径
- dest:目的,被控端文件路径
- content:内容。需要写入文件中的内容,以覆盖的形式写入数据
# 复制文件
[root@ansible ~]# ansible nfs -m copy -a "src=/etc/hosts dest=/opt/hosts owner=root group=root mode=0644"
nfs | CHANGED => {
"changed": true,
"checksum": "89494912ef23eebe2419b2e81d6a1570c1ea3cba",
"dest": "/opt/hosts",
"gid": 0,
"group": "root",
"md5sum": "05bfe6fccbd704a3906397af2864a595",
"mode": "0644",
"owner": "root",
"size": 199,
"src": "/root/.ansible/tmp/ansible-tmp-1735656541.3716962-93076-40444820201851/source",
"state": "file",
"uid": 0
}
[root@ansible ~]# ansible nfs -a "ls /opt/hosts"
nfs | CHANGED | rc=0 >>
/opt/hosts
# 上传目录,不能上传空目录
[root@ansible ~]# mkdir abc
[root@ansible ~]# ansible nfs -m copy -a "src=/root/abc dest=/tmp/"
nfs | SUCCESS => {
"changed": false,
"dest": "/tmp/",
"src": "/root/abc"
}
[root@ansible ~]# echo 123 >abc/a.txt
[root@ansible ~]# ansible nfs -m copy -a "src=/root/abc dest=/tmp/"
nfs | CHANGED => {
"changed": true,
"checksum": "a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0",
"dest": "/tmp/abc/a.txt",
"gid": 0,
"group": "root",
"md5sum": "ba1f2511fc30423bdbb183fe33f3dd0f",
"mode": "0644",
"owner": "root",
"size": 4,
"src": "/root/.ansible/tmp/ansible-tmp-1735656695.835506-93791-170086591774854/source",
"state": "file",
"uid": 0
}
[root@ansible ~]# ansible nfs -a "ls -l /tmp/abc"
nfs | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 4 Dec 31 22:51 a.txt
# 我们可以使用copy模块直接在被控端主机上创建文件并写入内容,不需要再控制端创建好后在上传到被控端
[root@ansible ~]# ansible nfs -m file -a "path=/tmp/test.txt state=touch"
nfs | CHANGED => {
"changed": true,
"dest": "/tmp/test.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
[root@ansible ~]# ansible nfs -m copy -a "dest=/tmp/test.txt content='123'"
nfs | CHANGED => {
"changed": true,
"checksum": "40bd001563085fc35165329ea1ff5c5ecbdbbeef",
"dest": "/tmp/test.txt",
"gid": 0,
"group": "root",
"md5sum": "202cb962ac59075b964b07152d234b70",
"mode": "0644",
"owner": "root",
"size": 3,
"src": "/root/.ansible/tmp/ansible-tmp-1735656831.611952-94390-264532554114331/source",
"state": "file",
"uid": 0
}
[root@ansible ~]# ansible nfs -a "cat /tmp/test.txt"
nfs | CHANGED | rc=0 >>
123
【4】、用户相关模块
1、user模块
- 实现Linux的用户管理
- 常用选项
- name:创用户的名字
- uid:用户UID
- group:设置主组
- groups:设置附加组
- home:设置家目录
- password:设置用户密码
- state:状态。present表示创建,他是默认选项。absent表示删除
- remove:删除家目录、邮箱等。值为yes或true都行
- shell:指定解释器
# 直接创建用户
[root@ansible ~]# ansible nfs -m user -a "name=zhangsan uid=6666"
nfs | CHANGED => {
"changed": true,
"comment": "",
"create_home": true,
"group": 6666,
"home": "/home/zhangsan",
"name": "zhangsan",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 6666
}
[root@ansible ~]# ansible nfs -a "id zhangsan"
nfs | CHANGED | rc=0 >>
uid=6666(zhangsan) gid=6666(zhangsan) groups=6666(zhangsan)
# 指定条件创建用户
[root@ansible ~]# ansible nfs -m user -a "name=lisi uid=7777 groups=zhangsan shell=/bin/bash home=/home/lisi"
nfs | CHANGED => {
"changed": true,
"comment": "",
"create_home": true,
"group": 7777,
"groups": "zhangsan",
"home": "/home/lisi",
"name": "lisi",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 7777
}
[root@ansible ~]# ansible nfs -a "id lisi"
nfs | CHANGED | rc=0 >>
uid=7777(lisi) gid=7777(lisi) groups=7777(lisi),6666(zhangsan)
[root@ansible ~]# ansible nfs -a "ls -ld /home/lisi"
nfs | CHANGED | rc=0 >>
drwx------ 2 lisi lisi 76 Jan 1 09:11 /home/lisi
2、group模块
创建用户组
- name:带创建的组名
- gid:组的id号
- state:present表示创建,他是默认选项。absent表示删除
[root@ansible ~]# ansible nfs -m group -a "name=test gid=1234 state=present"
nfs | CHANGED => {
"changed": true,
"gid": 1234,
"name": "test",
"state": "present",
"system": false
}
[root@ansible ~]# ansible nfs -a "grep test /etc/group"
nfs | CHANGED | rc=0 >>
test:x:1234:
【5】、软件安装相关模块
1、yum模块
管理软件
常用选项
- name:包名
- state:状态
- present:表示安装,如果安装则忽略;
- latest表示安装或者升级到最新版本;
- absent表示卸载
- download_only:只下载不安装
- enablerepo:指定软件仓库
# 安装一个软件
[root@ansible:192.168.121.10 ~/ansible]$ansible webservers -m yum -a "name=tar state=present"
# 安装多个软件,软件之间使用逗号隔开
[root@ansible:192.168.121.10 ~/ansible]$ansible webservers -m yum -a "name=tar,wget state=present"
# 卸载软件
[root@ansible:192.168.121.10 ~/ansible]$ansible webservers -m yum -a "name=wget state=absent"
# 使用latest更新安装软件(软件版本以软件仓库中的为主)
[root@ansible:192.168.121.10 ~/ansible]$ansible webservers -m yum -a "name=nginx state=latest"
# 只下载不安装
[root@ansible ~]# ansible nfs -m yum -a "name=wget state=present download_only=true"
nfs | CHANGED => {
"ansible_facts": {
"pkg_mgr": "dnf"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Downloaded: wget-1.20.3-6.ky10.x86_64",
"Downloaded: libmetalink-0.1.3-8.ky10.x86_64"
]
}
2、yum_repository
- 用于配置yum
- 常用选项
- file:指定文件名
- name:软件仓库名
- description:描述名称
- 其他选项,请与文件内容对照
# 使用yum_repository模块进行配置
[root@ansible:192.168.121.10 ~/ansible]$ansible webservers -m yum_repository -a "file=myrepo name=MyApp description='My App' baseurl=file:///mnt/mydvd/AppStream enabled=yes gpgcheck=no "
# 如果在写一个相同文件名的repo文件,不会覆盖原有的repo文件,而是在源文件中追加
【6】、服务相关模块
1、systemd模块
- 常用选项
- name:服务名称
- state:对服务执行的操作。
- started启动
- stopped停止
- restarted重启服务
- reloaded重新加载服务
- enabled:是否开机自启。yes开机自启,no开机不自启
[root@ansible ~]# ansible nfs -m yum -a "name=nfs-utils state=present"
nfs | CHANGED => {
"ansible_facts": {
"pkg_mgr": "dnf"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: krb5-1.18.2-11.ky10.x86_64",
"Installed: nfs-utils-help-1:2.5.1-5.p03.ky10.x86_64",
"Installed: nfs-utils-1:2.5.1-5.p03.ky10.x86_64",
"Installed: gssproxy-0.8.3-1.ky10.x86_64"
]
}
[root@ansible ~]# ansible nfs -m systemd -a "name=nfs state=started enabled=yes"
[root@ansible ~]# ansible nfs -a "systemctl status nfs"
nfs | CHANGED | rc=0 >>
● nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
Active: active (exited) since Wed 2025-01-01 09:33:54 CST; 29s ago
Process: 105035 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Process: 105037 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
Main PID: 105037 (code=exited, status=0/SUCCESS)
Jan 01 09:33:54 nfs systemd[1]: Starting NFS server and services...
Jan 01 09:33:54 nfs systemd[1]: Started NFS server and services.
【7】、MySQL相关模块
1、mysql_db
mysql_db模块用于建立、删除、导入和导出数据库
建立数据库
state="present"
删除数据库
state="absent"
导出数据库
state="dump"
导入数据库
state="import"
2、mysql_user
mysql_user模块用来添加,删除用户以及设置用户权限
指定登录信息的方式
免密码登录方式
在用户下建立
.my.cnf
,实现免密码登录
[client] user=root password=mysql@123
在yml中使用如下选项指定信息
login_host login_user login_password login_port
创建mysql用户,当state='present'(默认),可用于指定或者更新数据库权限
当state='absent',删除用户
--- - name: create a user hosts: s.hi.com tasks: - name: create a user mysql_user: login_host: "127.0.0.1" login_user: "root" login_password: "mysql@123" login_port: "3305" name: "mezz" password: "mysql@123" host: "127.0.0.1" priv: "*.*:all" state: "present"
五、PlayBook
-
常用于复杂任务的管理,以及管理经常要完成的任务
-
playbook也是通过模块和它的参数,在特定的主机上执行任务
-
playbook是一个文件,该文件中需要通过yaml格式书写
-
一个剧本(即playbook),可以包含多个play
-
每个play用于在指定的主机上,通过模块和参数执行相应的任务
-
每个play可以包含多个任务
-
任务由模块和参数构成
【1】、yaml
YAML Ain‘t Markup Language
语法规范:
- yaml文件的文件名,一般以yml或yaml作为扩展名
- 文件以---作为第一行
- 键值对使用:表示,冒号后面必须有空格
- 数组使用-表示,-后面必须有空格
- 相同层级必须有相同的缩进。如果缩进不对,则有语法错误。每一级缩进,建议两个空格
- 全文不能使用tab,应该使用空格
【2】、配置vim适应yaml语法
# 文件位置和名字都是固定的,用于设置 vim的格式
[root@ansible:192.168.121.10 ~]$vim ~/.vimrc
1 set nu # 显示行号
2 set ai # 换行时自动缩进
3 set et # 让tab以空格的形式出现
4 set ts=2 # 按一次tab空两格
【3】、安装wget软件
[root@ansible ansible_test]# cat install_wget.yaml
---
- name: Install wget on nfs Server
hosts: nfs
tasks:
- name: install wget
yum:
name: wget
state: present
[root@ansible ansible_test]# ansible-playbook --syntax-check install_wget.yaml
playbook: install_wget.yaml
[root@ansible ansible_test]# ansible-playbook install_wget.yaml
PLAY [Install wget on nfs Server] ******************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************
ok: [nfs]
TASK [install wget] ********************************************************************************************************************************
ok: [nfs]
PLAY RECAP *****************************************************************************************************************************************
nfs : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible_test]# ansible nfs -a "rpm -qa wget"
nfs | CHANGED | rc=0 >>
wget-1.20.3-5.ky10.x86_64
【4】、重构LNMP架构
1、编写主机清单
[root@ansible ansible_test]# cat hosts
[webs]
web01
web02
[nfsserver]
nfs
[backupserver]
backup
[mysqlserver]
mysql
[root@ansible ansible_test]# ansible all --list-hosts
hosts (5):
web01
web02
nfs
backup
mysql
2、免密
[root@ansible ansible_test]# ssh-keygen
[root@ansible ansible_test]# ssh-copy-id web01
[root@ansible ansible_test]# ssh-copy-id web02
[root@ansible ansible_test]# ssh-copy-id mysql
[root@ansible ansible_test]# ssh-copy-id nfs
[root@ansible ansible_test]# ssh-copy-id backup
3、重构backup服务器
[root@ansible ansible_test]# cat set_backup_server.yaml
---
- name: set backup server
hosts: backup
tasks:
- name: Install rsync
yum:
name: rsync
state: present
- name: Configure file
copy:
src: /root/ansible_test/conf/rsyncd.conf
dest: /etc/
- name: create group
group:
name: www
gid: 666
- name: create user
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Configure secret file
copy:
content: rsync_backup:123456
dest: /etc/rsync.passwd
mode: 0600
- name: Create dir1
file:
path: /backup
state: directory
owner: www
group: www
- name: Create dir2
file:
path: /nfs
state: directory
owner: www
group: www
- name: start rsync server
systemd:
name: rsyncd
state: started
enabled: yes
[root@ansible ansible_test]# ansible-playbook --syntax-check set_backup_server.yaml
playbook: set_backup_server.yaml
# 测试
[root@ansible ansible_test]# rsync -avz /etc/hosts rsync_backup@backup::backup
Password:
sending incremental file list
hosts
sent 199 bytes received 43 bytes 53.78 bytes/sec
total size is 260 speedup is 1.07
4、重构nfs服务器
[root@ansible ansible_test]# cat set_nfs_server.yaml
---
- name: set NFS server
hosts: nfs
tasks:
- name: Install NFS
yum:
name: nfs-utils
state: present
- name: Configure nfs file
copy:
src: /root/ansible_test/conf/exports
dest: /etc/
- name: Create group
group:
name: www
gid: 666
- name: Create user
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Create Dir
file:
path: /wp
state: directory
owner: www
group: www
- name: start nfs
systemd:
name: nfs
state: started
enabled: yes
[root@ansible ansible_test]# ansible-playbook --syntax-check set_nfs_server.yaml
playbook: set_nfs_server.yaml
[root@ansible ansible_test]# ansible-playbook set_nfs_server.yaml
PLAY [set NFS server] ******************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************
ok: [nfs]
TASK [Install NFS] *********************************************************************************************************************************
ok: [nfs]
TASK [Configure nfs file] **************************************************************************************************************************
changed: [nfs]
TASK [Create group] ********************************************************************************************************************************
changed: [nfs]
TASK [Create user] *********************************************************************************************************************************
changed: [nfs]
TASK [Create Dir] **********************************************************************************************************************************
changed: [nfs]
TASK [start nfs] ***********************************************************************************************************************************
changed: [nfs]
PLAY RECAP *****************************************************************************************************************************************
nfs : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 测试
[root@web01 ~]# showmount -e 172.16.1.31
Export list for 172.16.1.31:
/wp 172.16.1.0/24
5、重构web服务器
[root@ansible ansible_test]# cat set_web_server.yaml
---
- name: Set Web Server
hosts: webs
tasks:
- name: Configure nginx repo file
yum_repository:
file: nginx
name: nginx_stable
description: nginx
baseurl: http://nginx.org/packages/centos/7/$basearch/
enabled: yes
gpgcheck: no
- name: Install Nginx
yum:
name: nginx
state: present
- name: Create group
group:
name: www
gid: 666
- name: Create User
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Configure nginx file
copy:
src: /root/ansible_test/conf/nginx.conf
dest: /etc/nginx/
- name: Configure web file
copy:
src: /root/ansible_test/conf/wp.conf
dest: /etc/nginx/conf.d/
- name: delete default nginx conf
file:
path: /etc/nginx/conf.d/default.conf
state: absent
- name: Create Dir
file:
path: /code/wp
state: directory
owner: www
group: www
- name: Install php
yum:
name: php,php-bcmath,php-cli,php-common,php-devel,php-embedded,php-fpm,php-gd,php-intl,php-mbstring,php-mysqlnd,php-opcache,php-pdo,php-process,php-xml,php-json
state: present
- name: Configure php file
copy:
src: /root/ansible_test/conf/www.conf
dest: /etc/php-fpm.d/
- name: start service
systemd:
name: "{{item}}"
state: started
enabled: yes
loop: [nginx,php-fpm]
- name: get website code
get_url:
url: https://cn.wordpress.org/wordpress-5.0.3-zh_CN.tar.gz
dest: /code/wp
- name: unarchive file
unarchive:
src: /code/wp/wordpress-5.0.3-zh_CN.tar.gz
dest: /code/wp/
remote_src: yes
[root@ansible ansible_test]# ansible-playbook --syntax-check set_web_server.yaml
playbook: set_web_server.yaml
6、重构mariadb服务器
[root@ansible ansible_test]# cat set_mysql_server.yaml
---
- name: Set mysql server
hosts: mysqlserver
tasks:
- name: Install mariadb
yum:
name: mariadb-server,python3-mysqlclient
state: present
- name: start mariadb
systemd:
name: mariadb
state: started
enabled: yes
- name: set mariadb root password
shell: mysqladmin password 'xu' | cat
- name: create database
mysql_db:
name: wp
state: present
login_user: root
login_password: xu
- name: create mariadb user
mysql_user:
login_user: root
login_password: xu
login_host: "localhost"
name: xu
password: xu
priv: '*.*:ALL'
host: "%"
state: present
- name: start mariadb
systemd:
name: mariadb
state: started
enabled: yes
[root@ansible ansible_test]# ansible-playbook --syntax-check set_mysql_server.yaml
playbook: set_mysql_server.yaml
7、重构负载均衡服务器
[root@ansible ansible_test]# cat set_load_balance_server.yaml
---
- name: set load balance server
hosts: load_balance
tasks:
- name: Configure nginx repo file
yum_repository:
file: nginx
name: nginx_stable
description: nginx
baseurl: http://nginx.org/packages/centos/7/$basearch/
enabled: yes
gpgcheck: no
- name: Install Nginx
yum:
name: nginx
state: present
- name: Create group
group:
name: www
gid: 666
- name: Create User
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Configure file
copy:
src: /root/ansible_test/conf/load_balance_wp.conf
dest: /etc/nginx/conf.d/
- name: delete default nginx conf
file:
path: /etc/nginx/conf.d/default.conf
state: absent
- name: Start nginx
systemd:
name: nginx
state: started
enabled: yes
- name: Install keepalived
yum:
name: keepalived
state: present
- name: send check_web shell
copy:
src: /root/ansible_test/conf/keepalived_nginx.sh
dest: /root/
mode: 0755
- name: Configure master keepalived
hosts: lb01
tasks:
- name: Configure keepalived file
copy:
src: /root/ansible_test/conf/keepalived_master/keepalived.conf
dest: /etc/keepalived/
- name: Configure slave keepalived
hosts: lb02
tasks:
- name: Configure keepalived file
copy:
src: /root/ansible_test/conf/keepalived_slave/keepalived.conf
dest: /etc/keepalived/
- name: Start keepalived
hosts: load_balance
tasks:
- name: Start
systemd:
name: keepalived
state: started
enabled: yes
[root@ansible ansible_test]# ansible-playbook --syntax-check set_load_balance_server.yaml
playbook: set_load_balance_server.yaml
8、结合shell脚本一键部署
[root@ansible ansible_test]# cat LNMP.sh
#!/bin/bash
ansible-playbook set_backup_server.yaml
ansible-playbook set_nfs_server.yaml
ansible-playbook set_web_server.yaml
ansible-playbook set_mysql_server.yaml
ansible-playbook set_load_balance_server.yaml
ssh web01 'chown -R www:www /code;mv /code/wp/wordpress/* /code/wp'
ssh web02 'chown -R www:www /code;mv /code/wp/wordpress/* /code/wp'
[root@ansible ansible_test]# chmod +x LNMP.sh
[root@ansible ansible_test]# ./LNMP.sh
六、变量
变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如 nginx-1.6.3 这个软件包的版本,在其它地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本。
【1】、变量定义方式
- 引入变量,可以方便playbook重用。比如装包的playbook,包名使用变量,多次执行playbook,只要改变变量名即可,不用重新编写playbook
- ansible支持10种以上的变量定义方式。常用变量来源如下:
- inventory变量。变量来自于主机清单
- facts变量。
- playbook变量。变量在playbook中定义。
- 变量文件。专门创建用于保存变量的文件。推荐变量写入单独的文件
1、在主机清单中定义变量
[root@ansible ansible_test]# cat hosts
[webs]
web01
web02
[nfsserver]
nfs
[backupserver]
backup
[mysqlserver]
db01
[load_balance]
lb01
lb02
[mysqlserver:vars]
user_name=zhaoliu
[backupserver:vars]
user_name=wangwu
[root@ansible ansible_test]# cat vars.yaml
---
- name: create user
hosts: backup,db01,lb01
tasks:
- name: create user
user:
name: "{{ user_name }}"
uid: 777
create_home: false
shell: /sbin/nologin
state: present
[root@ansible ansible_test]# ansible-playbook --syntax-check vars.yaml
playbook: vars.yaml
[root@backup ~]# id wangwu
uid=777(wangwu) gid=1000(wangwu) groups=1000(wangwu)
[root@db01 ~]# id zhaoliu
uid=777(zhaoliu) gid=1000(zhaoliu) groups=1000(zhaoliu)
2、在剧本中定义变量
[root@ansible ansible_test]# cat vars.yaml
---
- name: Install package
hosts: db01
vars:
- pk1: wget
- pk2: tree
tasks:
- name: Install package
yum:
name:
- "{{ pk1 }}"
- "{{ pk2 }}"
state: present
[root@ansible ansible_test]# ansible-playbook --syntax-check vars.yaml
playbook: vars.yaml
[root@ansible ansible_test]# cat vars.yaml
---
- name: Install package
hosts: db01
vars:
pk1:
- wget
- tree
tasks:
- name: Remove package
yum:
name: "{{ pk1 }}"
state: present
[root@ansible ansible_test]# ansible-playbook --syntax-check vars.yaml
playbook: vars.yaml
3、定义变量文件
[root@ansible ansible_test]# cat vars.yaml
pk1: wget
pk2: tree
[root@ansible ansible_test]# cat install_package.yaml
---
- name: Install wget on nfs Server
hosts: nfs
vars_files: vars.yaml
tasks:
- name: install wget
yum:
name:
- "{{ pk1 }}"
- "{{ pk2 }}"
state: absent
[root@ansible ansible_test]# ansible-playbook --syntax-check install_package.yaml
playbook: install_package.yaml
4、官方推荐定义方法
之前的几种变量定义都不是很好用,比较好用的是在Ansible项目目录下创建两个变量目录:
host_vars
group_vars
切记,目录名字一定要一致,不能做任何修改。
[root@ansible ansible_test]# mkdir host_vars group_vars
# 在nfs文件中定义的变量只能被nfs主机使用,而且文件名必须和主机清单中的名字一致
[root@ansible ansible_test]# cat host_vars/nfs
pk1: wget
[root@ansible ansible_test]# cat install_package.yaml
---
- name: Install wget on nfs Server
hosts: nfs
tasks:
- name: install wget
yum:
name:
- "{{ pk1 }}"
state: absent
[root@ansible ansible_test]# cat group_vars/webs
pk1: tree
[root@ansible ansible_test]# cat install_package.yaml
---
- name: Install wget on nfs Server
hosts: webs
tasks:
- name: install wget
yum:
name:
- "{{ pk1 }}"
state: absent
5、优先级
在上述的三个地方分别设置了:
1.命令行中:age=11
2.play文件中:age=12
3.Inventory中:age=13
那么,最终的age结果一定是11
命令行 > playbook文件 > Inventory文件
【2】、facts变量
- facts翻译过来就是事实
- facts变量是ansible自带的预定义变量,用于描述被控端软硬件信息(IP、memory等)
- facts变量通过setup模块
# 查看所有的ansible变量
[root@ansible ansible_test]# ansible db01 -m setup
# filter:过滤变量
[root@ansible ansible_test]# ansible db01 -m setup -a "filter=ansible_bios_version"
db01 | SUCCESS => {
"ansible_facts": {
"ansible_bios_version": "6.00"
},
"changed": false
}
常用的facts变量
- ansible_all_ipv4_addresses----所有的IP地址
- ansible_bios_version----BIOS版本信息
- ansible_memtotal_mb----总内存大小
- ansible_hostname---主机名
【3】、debug模块
用来打印变量
在输出时需要加上{{变量名}}
[root@ansible ansible_test]# cat debug.yaml
---
- name: db01
hosts: db01
tasks:
- name: display hostname and memory
debug:
msg: "hostname: {{ansible_hostname}}, mem {{ansible_memtotal_mb}}MB"
[root@ansible ansible_test]# ansible-playbook --syntax-check debug.yaml
playbook: debug.yaml
[root@ansible ansible_test]# ansible-playbook debug.yaml
PLAY [db01] *******************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [db01]
TASK [display hostname and memory] ********************************************************************************************************************************************************
ok: [db01] => {
"msg": "hostname: db01, mem 948MB"
}
PLAY RECAP ********************************************************************************************************************************************************************************
db01 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
【4】、执行剧本的顺序
在我们执行剧本时,在执行每一个play时系统会自己执行一个任务
TASK [Gathering Facts] ****************************************************************************************************************************************
ok: [web02]
ok: [web01]这个任务的作用是收集facts,只有通过setup模块收集了事实,才可以使用debug模块去输出
# 如果我们在adhoc中直接输出facts,会未定义的错误
[root@ansible ansible_test]# ansible db01 -m debug -a "msg='{{ ansible_hostname }}'"
db01 | FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'ansible_hostname' is undefined. 'ansible_hostname' is undefined"
}
# 如果我们将facts写入剧本中,在执行剧本时,剧本会自己生成一个task(通过setup去收集facts),这样你在后面如果要使用debug去输出facts就不会再报错了
【5】、ansible变量格式
ansible变量的格式类似于python中的字典,
我们在查询变量时,要严格遵循层层递进的关系去写
父.子的格式,中间使用”.“表示嵌套关系
[root@ansible ansible_test]# cat debug.yaml
---
- name: db01
hosts: db01
tasks:
- name: display hostname and memory
debug:
msg: "hostname: {{ansible_hostname}}, mem {{ansible_memtotal_mb}}MB, ip {{ ansible_ens33.ipv4.address}}"
[root@ansible ansible_test]# ansible-playbook debug.yaml
PLAY [db01] *******************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [db01]
TASK [display hostname and memory] ********************************************************************************************************************************************************
ok: [db01] => {
"msg": "hostname: db01, mem 948MB, ip 192.168.121.51"
}
PLAY RECAP ********************************************************************************************************************************************************************************
db01 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
【6】、register变量注册
当 absible 的模块在运行之后,其实都会返回一些 result 结果,就像是执行脚本,我们有的时候需要脚本给我们一些return 返回值,我们才知道,上一步是否可以执行成功,但是…默认情况下, ansible 的 result 并不会显示出来,所以,我们可以把这些返回值’存储’到变量中,这样我们就能通过’调用’对应的变量名,从而获取到这些 result ,这种将模块的返回值,写入到变量中的方法被称为变量注册
[root@ansible ansible_test]# cat reg.yaml
---
- name: list /root
hosts: db01
tasks:
- name: list
command: ls -l
[root@ansible ansible_test]# ansible-playbook reg.yaml
PLAY [list /root] *************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [db01]
TASK [list] *******************************************************************************************************************************************************************************
changed: [db01]
PLAY RECAP ********************************************************************************************************************************************************************************
db01 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 这样执行不会输出我们想看到的结果,我们会采用register来收集变量,通过debug模块输出
[root@ansible ansible_test]# cat reg.yaml
---
- name: list /root
hosts: db01
tasks:
- name: list
command: ls -l
register: info
- name: print info
debug:
msg: "{{ info }}"
[root@ansible ansible_test]# ansible-playbook reg.yaml
PLAY [list /root] *************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [db01]
TASK [list] *******************************************************************************************************************************************************************************
changed: [db01]
TASK [print info] *************************************************************************************************************************************************************************
ok: [db01] => {
"msg": {
"changed": true,
"cmd": [
"ls",
"-l"
],
"delta": "0:00:00.028652",
"end": "2025-01-07 10:59:09.275308",
"failed": false,
"msg": "",
"rc": 0,
"start": "2025-01-07 10:59:09.246656",
"stderr": "",
"stderr_lines": [],
"stdout": "total 0\n-rw-r--r-- 1 root root 0 Jan 7 10:58 1.txt\n-rw-r--r-- 1 root root 0 Jan 7 10:58 2.txt\n-rw-r--r-- 1 root root 0 Jan 7 10:58 3.txt",
"stdout_lines": [
"total 0",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 1.txt",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 2.txt",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 3.txt"
]
}
}
PLAY RECAP ********************************************************************************************************************************************************************************
db01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 如果输出的内容特别多,也可以取指定的内容
[root@ansible ansible_test]# cat reg.yaml
---
- name: list /root
hosts: db01
tasks:
- name: list
command: ls -l
register: info
- name: print info
debug:
msg: "{{ info.stdout_lines }}"
[root@ansible ansible_test]# ansible-playbook reg.yaml
PLAY [list /root] *************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [db01]
TASK [list] *******************************************************************************************************************************************************************************
changed: [db01]
TASK [print info] *************************************************************************************************************************************************************************
ok: [db01] => {
"msg": [
"total 0",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 1.txt",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 2.txt",
"-rw-r--r-- 1 root root 0 Jan 7 10:58 3.txt"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************
db01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
七、进阶语法
【1】、错误处理
当playbook中包含很多任务时,当某一个任务遇到错误,他将崩溃,终止执行
这个错误不包括语法错误
[root@ansible ansible_test]# cat ignore.yaml
---
- hosts: nfs
tasks:
- name: start mariadb
systemd:
name: mariadb
state: started
- name: create file
file:
path: /root/a.txt
state: touch
[root@ansible ansible_test]# ansible-playbook ignore.yaml
PLAY [nfs] ********************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [nfs]
TASK [start mariadb] **********************************************************************************************************************************************************************
fatal: [nfs]: FAILED! => {"changed": false, "msg": "Could not find the requested service mariadb: host"}
PLAY RECAP ********************************************************************************************************************************************************************************
nfs : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
# 由于主机上没有mysql,当执行ansible时他将崩溃,终止执行,就不会再去执行下一个任务了
# 我们可以加一个ignore_errors.参数来忽略错误,继续向下执行
[root@ansible ansible_test]# cat ignore.yaml
---
- hosts: nfs
tasks:
- name: start mariadb
systemd:
name: mariadb
state: started
ignore_errors: yes
- name: create file
file:
path: /root/a.txt
state: touch
[root@ansible ansible_test]# ansible-playbook ignore.yaml
PLAY [nfs] ********************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************
ok: [nfs]
TASK [start mariadb] **********************************************************************************************************************************************************************
fatal: [nfs]: FAILED! => {"changed": false, "msg": "Could not find the requested service mariadb: host"}
...ignoring
TASK [create file] ************************************************************************************************************************************************************************
changed: [nfs]
PLAY RECAP ********************************************************************************************************************************************************************************
nfs : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
【2】、触发执行
- 通过handlers定义触发执行的任务
- handlers中定义的任务,不是一定会执行的
- 在task中定义的任务,通过notify关键通知handlers中的哪个任务要执行
- 只有task中的任务状态是changed才会进行通知
[root@ansible ansible_test]# cat handlers.yaml
---
- name: Nginx Server
hosts: web02
tasks:
- name: Create Nginx repo file
yum_repository:
file: nginx
name: nginx_stable
description: nginx
baseurl: http://nginx.org/packages/centos/7/$basearch/
enabled: yes
gpgcheck: no
- name: Install Nginx
yum:
name: nginx
state: present
- name: Configure nginx file
copy:
src: /root/ansible_test/conf/nginx.conf
dest: /etc/nginx/
notify: restart nginx
# 当这个任务发生修改后,在执行handlers的任务,如果notify的任务没有执行,那就不会给handlers发送信号,handlers的任务也不会去执行
- name: Start Nginx
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: restart nginx
systemd:
name: nginx
state: restarted
【3】、when判断
---
- name: install mysql-server
hosts: db
tasks:
- name: mysql-server
yum:
name: mysql-server
state: present
when: ansible_memtotal_mb > 2048
# when后面的变量不需要加双大括号
TASK [mysql-server] *******************************************************************************************************************************************
skipping: [db]
# 如果不满足when的条件,则跳过,不执行
多条件判断
---
- name: whens
hosts: webservers
tasks:
- name: whens
copy:
src: ./motd
dest: /etc/motd
when: >
ansible_distribution == "Rocky"
and
ansible_distribution_major_version == "8"
【4】、loop循环
相当于是shell中的for循环
ansible中循环用到的变量名是固定的,叫item
# 启动多个服务
[root@ansible ansible_test]# cat loop.yaml
---
- name: Start Service
hosts: web01
tasks:
- name: start nginx and php-fpm
systemd:
name: "{{ item }}"
state: started
enabled: yes
loop:
- nginx
- php-fpm
[root@ansible ansible_test]# ansible-playbook --syntax-check loop.yaml
playbook: loop.yaml
# 创建多个文件
[root@ansible ansible_test]# cat loop.yaml
---
- name: Create files
hosts: web01
tasks:
- name: touch
file:
path: /root/{{ item }}
state: touch
loop:
- a.txt
- b.txt
[root@ansible ansible_test]# ansible-playbook --syntax-check loop.yaml
playbook: loop.yaml
# 进阶: 创建后的文件属主属组和权限都是不同的
[root@ansible ansible_test]# cat loop.yaml
---
- name: Create files
hosts: web01
tasks:
- name: touch
file:
path: /root/{{ item.name }}
owner: "{{ item.user }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
state: touch
loop:
- {name:a.txt, user:www, group:www, mode:0644}
- {name:b.txt, user:root, group:root, mode:0644}
[root@ansible ansible_test]# ansible-playbook --syntax-check loop.yaml
playbook: loop.yaml
【5】、ansible加解密文件
ansible加解密文件使用ansible-vault命令
# 文件加密
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault encrypt hello.txt
New Vault password:
Confirm New Vault password:
Encryption successful
# 文件解密
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault decrypt hello.txt
Vault password:
Decryption successful
# 在不解密的情况下查看文件内容
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault view hello.txt
Vault password:
在吗
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault view hello.txt > output
Vault password:
# 将密码写入文件中,通过文件进行加密和解密
[root@ansible:192.168.121.10 ~/ansible]$echo "aaa" > pass.txt#
[root@ansible:192.168.121.10 ~/ansible]$echo 'hello' > data.txt
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault encrypt --vault-id=pass.txt data.txt
Encryption successful
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault decrypt --vault-id=pass.txt data.txt
Decryption successful
# 先将剧本文件进行加密,在执行的时候输入密码
[root@ansible:192.168.121.10 ~/ansible]$ansible-vault encrypt loop2.yaml --vault-id=pass.txt
Encryption successful
[root@ansible:192.168.121.10 ~/ansible]$ansible-playbook loop2.yaml --ask-vault-pass # 交互式输入密码
Vault password:
[root@ansible:192.168.121.10 ~/ansible]$ansible-playbook loop2.yaml --vault-id=pass.txt # 非交互式
八、jinja2模板
使用Ansible的jinja2模板也就是使用template模块,该模块和copy模块一样,都是讲文件复制到远端主机上去,但是区别在于,template模块可以获取到文件中的变量,而copy则是原封不动的把文件内容复制过去。之前我们在推送rsync的backup脚本时,想把脚本中的变量名改成主机名,如果使用copy模块则推送过去的就是{{ ansible_fqdn }},不变,如果使用template,则会变成对应的主机名。
【1】、jinja2模板使用
{{ EXPR }}输出变量值,会输出自定义的变量值或facts
1)playbook文件使用template模块
2)模板文件里面变量使用{{名称}},比如{{PORT}}或使用facts
# 准备jinja2模板
[root@ansible ansible_test]# cat info.j2
Welcome to {{ ansible_fqdn }}
IP is {{ ansible_ens33.ipv4.address }}
This system total mem is : {{ ansible_memtotal_mb }} MB
This system free mem is: {{ ansible_memfree_mb }} MB
# 发送模板
[root@ansible ansible_test]# cat jinja2.yaml
---
- name: Send jinja2
hosts: web01
tasks:
- name: use template
template:
src: info.j2
dest: /root
[root@ansible ansible_test]# ansible-playbook jinja2.yaml
[root@web01 ~]# cat info.j2
Welcome to web01
IP is 192.168.121.7
This system total mem is : 948 MB
This system free mem is: 134 MB
【2】、jinja2结合条件判断
#循环表达式
{% for i in EXPR %}
{% endfor %}
#条件判断
{% if EXPR %}
{% elif EXPR %}
{% else %}
{% endif %}
#注释
{# COMMENT #}
九、Ansible Roles
roles 不管是Ansible还是saltstack,我在写一键部署的时候,都不可能把所有的步骤全部写入到一个’剧本’文件当中,我们肯定需要把不同的工作模块,拆分开来,解耦,那么说到解耦,我们就需要用到 roles 官方推荐,因为 roles 的目录结构层次更加清晰。
例如:我们之前推荐大家写一个 base.yml 里面写所有基础优化的项目,其实把所有东西摞进去也是很鸡肋的,不如我们把这些功能全部拆分开,谁需要使用,就调用即可。
建议:每个roles最好只使用一个tasks这样方便我们去调用,能够很好的做到解耦。(SOA)
在剧本中允许role和tasks同时存在
当一个剧本中既有role又有tasks时,不管书写的顺序如何,一定是role先执行,tasks后执行
【1】、创建roles
[root@ansible ansible_test]# ansible-galaxy init rsync
- Role rsync was created successfully
[root@ansible ansible_test]# ll rsync/
total 4
drwxr-xr-x 2 root root 22 Jan 7 23:10 defaults
drwxr-xr-x 2 root root 6 Jan 7 23:10 files
drwxr-xr-x 2 root root 22 Jan 7 23:10 handlers
drwxr-xr-x 2 root root 22 Jan 7 23:10 meta
-rw-r--r-- 1 root root 1328 Jan 7 23:10 README.md
drwxr-xr-x 2 root root 22 Jan 7 23:10 tasks
drwxr-xr-x 2 root root 6 Jan 7 23:10 templates
drwxr-xr-x 2 root root 39 Jan 7 23:10 tests
drwxr-xr-x 2 root root 22 Jan 7 23:10 vars
├── defaults #低优先级变量
├── files #存放文件
├── handlers #触发器文件
├── meta #依赖关系文件
├── tasks #工作任务文件
├── templates #jinja2模板文件
├── tests #测试文件
└── vars #变量文件
【2】、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的安装。
【3】、Ansible Roles 重构LNMP
1、创建用户、用户组的roles
# 创建角色
[root@ansible ansible_roles]# ansible-galaxy init create_user
[root@ansible ansible_roles]# ll create_user
total 4
drwxr-xr-x 2 root root 22 Jan 7 23:16 defaults
drwxr-xr-x 2 root root 6 Jan 7 23:16 files
drwxr-xr-x 2 root root 22 Jan 7 23:16 handlers
drwxr-xr-x 2 root root 22 Jan 7 23:16 meta
-rw-r--r-- 1 root root 1328 Jan 7 23:16 README.md
drwxr-xr-x 2 root root 22 Jan 7 23:46 tasks
drwxr-xr-x 2 root root 6 Jan 7 23:16 templates
drwxr-xr-x 2 root root 39 Jan 7 23:16 tests
drwxr-xr-x 2 root root 22 Jan 7 23:16 vars
[root@ansible ansible_roles]# cat create_user/tasks/main.yml
- name: Create Group
group:
name: "{{ name }}"
gid: "{{ name_id }}"
- name: Create User
user:
name: "{{ name }}"
uid: "{{ name_id }}"
create_home: false
shell: /sbin/nologin
gid: "{{ name_id }}"
[root@ansible ansible_roles]# cat create_user/vars/main.yml
name: www
name_id: 666
2、创建安装nginx的角色
[root@ansible ansible_roles]# ansible-galaxy init install_nginx
- Role install_nginx was created successfully
[root@ansible ansible_roles]# cat install_nginx/tasks/main.yml
- name: Create repo file
yum_repository:
file: nginx
name: nginx_stable
description: nginx
baseurl: http://nginx.org/packages/centos/7/$basearch/
enabled: yes
gpgcheck: no
- name: Install Nginx
yum:
name: nginx
state: presentls
3、重构backup剧本为角色
[root@ansible ansible_roles]# ansible-galaxy init backup_server
- Role backup_server was created
[root@ansible ansible_roles]# cat backup_server/tasks/main.yml
- name: Install rsync
yum:
name: rsync
state: present
- name: Configure file
copy:
src: rsyncd.conf
dest: /etc/
notify: Restart Rsync
- name: Configure secret file
copy:
content: rsync_backup:123456
dest: /etc/rsync.passwd
mode: 0600
- name: Create dir1
file:
path: /backup
state: directory
owner: www
group: www
- name: Create dir2
file:
path: /nfs
state: directory
owner: www
group: www
- name: start rsync server
systemd:
name: rsyncd
state: started
enabled: yes
[root@ansible ansible_roles]# cat backup_server/handlers/main.yml
- name: Restart Rsync
systemd:
name: rsyncd
state: restarted
[root@ansible ansible_roles]# cat backup_server/meta/main.yml
dependencies:
- { role: create_user }
[root@ansible ansible_roles]# cat rsync.yaml
- hosts: all
roles:
- role: backup_server
when: ansible_hostname == "backup"
4、重构nfs
[root@ansible ansible_roles]# ansible-galaxy init nfs_server
- Role nfs_server was created successfully
[root@ansible ansible_roles]# cat nfs_server/tasks/main.yml
- name: Install NFS
yum:
name: "{{ pk }}"
state: present
- name: Configure nfs file
copy:
src: "{{ item }}"
dest: /etc/
loop:
- lsyncd.conf
- exports
- name: configure secret file
copy:
dest: /etc/rsyncd.pwd
content: 123456
mode: 0600
- name: Create Dir
file:
path: /wp
state: directory
owner: www
group: www
- name: start nfs
systemd:
name: "{{ item }}"
state: started
enabled: yes
loop:
- nfs
- lsyncd
[root@ansible ansible_roles]# cat nfs_server/vars/main.yml
pk:
- nfs-utils
- lsyncd
[root@ansible ansible_roles]# ll nfs_server/files/
total 8
-rw-r--r-- 1 root root 63 Jan 8 11:11 exports
-rw-r--r-- 1 root root 429 Jan 8 11:12 lsyncd.conf
[root@ansible ansible_roles]# cat nfs.yaml
- hosts: all
roles:
- role: nfs_server
when: ansible_hostname == "nfs"
5、重构web服务器
[root@ansible ansible_roles]# ansible-galaxy init web_server
- Role web_server was created
[root@ansible ansible_roles]# cat web_server/tasks/main.yml
- name: Configure nginx file
copy:
src: /root/ansible_test/conf/nginx.conf
dest: /etc/nginx/
notify: Restart Nginx
- name: Configure web file
copy:
src: /root/ansible_test/conf/wp.conf
dest: /etc/nginx/conf.d/
- name: delete default nginx conf
file:
path: /etc/nginx/conf.d/default.conf
state: absent
- name: Create Dir
file:
path: /code/wp
state: directory
owner: www
group: www
- name: Install php
yum:
name: php,php-bcmath,php-cli,php-common,php-devel,php-embedded,php-fpm,php-gd,php-intl,php-mbstring,php-mysqlnd,php-opcache,php-pdo,php-process,php-xml,php-json
state: present
- name: Configure php file
copy:
src: /root/ansible_test/conf/www.conf
dest: /etc/php-fpm.d/
- name: start service
systemd:
name: "{{item}}"
state: started
enabled: yes
loop: [nginx,php-fpm]
- name: get website code
get_url:
url: https://cn.wordpress.org/wordpress-5.0.3-zh_CN.tar.gz
dest: /code/wp
- name: unarchive file
unarchive:
src: /code/wp/wordpress-5.0.3-zh_CN.tar.gz
dest: /code/wp/
remote_src: yes
[root@ansible ansible_roles]# ll web_server/files/
total 8
-rw-r--r-- 1 root root 646 Jan 8 11:33 nginx.conf
-rw-r--r-- 1 root root 247 Jan 8 11:32 wp.conf
[root@ansible ansible_roles]# cat web_server/meta/main.yml
dependencies:
- { role: create_user }
- { role: install_nginx }
6、重构mysql服务器
[root@ansible ansible_roles]# cat mysql_server/tasks/main.yml
- name: Install mariadb
yum:
name: mariadb-server,python3-mysqlclient
state: present
- name: start mariadb
systemd:
name: mariadb
state: started
enabled: yes
- name: set mariadb root password
shell: mysqladmin password 'xu' | cat
- name: create database
mysql_db:
name: wp
state: present
login_user: root
login_password: xu
- name: create mariadb user
mysql_user:
login_user: root
login_password: xu
login_host: "localhost"
name: xu
password: xu
priv: '*.*:ALL'
host: "%"
state: present
- name: start mariadb
systemd:
name: mariadb
state: started
enabled: yes
7、重构负载均衡服务器
# 配置keep alived
[root@ansible ansible_roles]# cat keepalived_server/tasks/main.yml
- name: Install keepalived
yum:
name: keepalived
state: present
- name: Configure master keepalived
template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
notify: Restart keepalived
- name: Start keepalived
systemd:
name: keepalived
state: started
enabled: yes
[root@ansible ansible_roles]# cat keepalived_server/templates/keepalived.conf.j2
! Configuration File for keepalived
global_defs {
router_id {{ ansible_hostname }}
}
vrrp_script check_web {
script "/root/keepalived_nginx.sh"
interval 5
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 50
{%if ansible_hostname == "lb01" %}
priority 150
{% else %}
priority 100
{% endif %}
nopreempt
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.121.50/24
}
track_script {
check_web
}
}
# 配置lb
[root@ansible ansible_roles]# cat load_balance_server/tasks/main.yml
- name: Configure file
copy:
src: /root/ansible_test/conf/load_balance_wp.conf
dest: /etc/nginx/conf.d/
notify: Restart Nginx
- name: delete default nginx conf
file:
path: /etc/nginx/conf.d/default.conf
state: absent
- name: Start nginx
systemd:
name: nginx
state: started
enabled: yes
- name: Install keepalived
yum:
name: keepalived
state: present
- name: send check_web shell
copy:
src: /root/ansible_test/conf/keepalived_nginx.sh
dest: /root/
mode: 0755
[root@ansible ansible_roles]# cat load_balance_server/meta/main.yml
dependencies:
- { role: create_user }
- { role: install_nginx }
- { role: keepalived_server }
[root@ansible ansible_roles]# ll load_balance_server/files/
total 8
-rw-r--r-- 1 root root 211 Jan 8 11:58 keepalived_nginx.sh
-rw-r--r-- 1 root root 217 Jan 8 11:58 load_balance_wp.conf
本文来自博客园,作者:Linux小菜鸟,转载请注明原文链接:https://www.cnblogs.com/xuruizhao/p/18689768
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?