Ansible

image-20241231212805028

一、什么是Ansible

Ansible是一个自动化统一配置管理工具,自动化主要体现在Ansible集成了丰富模块以及功能组件,可以通过一个命令完成一系列的操作,进而能减少重复性的工作和维护成本,可以提高工作效率。

同类型软件对比

1.puppet 学习难,安装ruby环境难,没有远程执行功能

2.ansible 轻量级,大规模环境下只通过ssh会很慢,串行的

3.saltstack 一般选择salt会使用 C/S 结构的模式, salt-master 和 salt-minion ,并行的,大规模批量操作的情况下,会比Ansible速度快一些,底层使用的是 zero-MQ 消协队列

Ansible架构

image-20241231211944872

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
posted @   Linux小菜鸟  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示