Ansible介绍

2023-10-27

1.安装ansible

1.下载并安装ansible

# 所有节点安装依赖
yum install python -y
# 添加源
yum -y install epel-release
# 查看可安装的版本
yum list | grep ansible
# 下载安装
yum install ansible.noarch -y
# 查看ansible版本
ansible --version

2.配置hosts文件,添加被管控主机

# 路径:/etc/ansible/hosts
vim /etc/ansible/hosts

[host]
192.168.5.117
192.168.5.233

[ansible]
192.168.5.165

3.配置ansible主机和被管理主机机器互信(ssh免密登录)

# 需要实现ansible主机(192.168.5.165)向其他主机的单项ssh免密登录

# 下载sshpass工具
yum install sshpass -y
# 免交互
ssh-keygen -t dsa -f ~/.ssh/id_dsa -P ''
# 免交互分发密钥
sshpass -p{密码} ssh-copy-id -o StrictHostKeyChecking=no {主机ip}



# for循环多台分发密钥
for i in {165,233,117};do sshpass -pCloudEasy@2020 ssh-copy-id -o StrictHostKeyChecking=no 192.168.5.$i;done







# 讲解
为了使用ansible进行自动化运维,我们需要实现192.168.5.165向其他其他主机的单向ssh免密登录。为了实现此功能,我们需要在ansible服务器192.168.5.165上,生成密钥对(公钥id_rsa.pub,私钥id_rsa),然后将公钥追加到ansible管控端和被管控端的授权文件authorized_keys中
这里有个坑:
authorized_keys 这个文件的权限必须是600(,就算是644 也不行),否则无法由133免密登录到被管控端服务器上。

[root@test ~]# cd .ssh    //系统默认不带 .ssh文件
bash: cd: .ssh: No such file or directory
// 生成密钥对
[root@test ~]# ssh-keygen -t rsa        // 如果之前生成过密钥对,那可以直接用,不需要再生成
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.         // 自动生成 /root/.ssh 文件夹
Enter passphrase (empty for no passphrase):   // 直接回车,也可以设置密码
Enter same passphrase again:                  // 直接回车
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:uYpPQZBJkXb5uRw5Ugxs4GFG/qGuVALRZyecHqmwxJc root@test
The key's randomart image is:
+---[RSA 2048]----+
|o. +@X.+         |
|.+.E&o* o        |
|oo.*o*oo o       |
|... .+..*.       |
|  . o ooS+       |
|   +   .o.       |
|  . . . .        |
| . . o .         |
|  . ..o          |
+----[SHA256]-----+

然后到被管控主机上执行操作
mkdir -p /root/.ssh
cd /root/.ssh && touch authorized_keys
再将ansible主机上的公钥信息拷贝至被管控主机的authorized_keys文件中即可



# 最简单的方法
#1.生成私钥
ssh-keygen 
#2.向主机分发私钥
ssh-copy-id root@192.168.5.233
ssh-copy-id root@192.168.5.117
ssh-copy-id root@192.168.5.165
注意:若出现以下错误
-bash: ssh-copy-id: command not found
则安装一个包即可
yum -y install openssh-clientsansible

4.验证


# 查看所有主机列表
[root@g42k8snode-0002 ansible]# ansible all --list
  hosts (3):
    192.168.5.165
    192.168.5.117
    192.168.5.233

# 查看[host]组下的主机列表
[root@g42k8snode-0002 ansible]# ansible "host" --list
  hosts (2):
    192.168.5.117
    192.168.5.233

# 尝试访问所有ip
[root@g42k8snode-0002 ansible]# ansible all -m ping
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
192.168.5.165 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
192.168.5.233 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

2.配置文件

1.ansible配置文件

# 配置文件为 /etc/ansible/ansible.cfg 
# 以下为部分配置参数
	inventory = /etc/ansible/hosts		#这个参数表示资源清单inventory文件的位置
	library = /usr/share/ansible		#指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
	forks = 5		#并发连接数,默认为5
	sudo_user = root		#设置默认执行命令的用户
	remote_port = 22		#指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
	host_key_checking = False		#设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
	timeout = 60		#设置SSH连接的超时时间,单位为秒
	log_path = /var/log/ansible.log		#指定一个存储ansible日志的文件(默认不记录日志)

2.ansible配置文件查找顺序

1. 检查环境变量ANSIBLE_CONFIG指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg)2. ~/.ansible.cfg,检查当前目录下的ansible.cfg配置文件;
3. /etc/ansible.cfg检查etc目录的配置文件。

3.ansible常用模块

(1)command模块

此模块功能与shell模块类似,已逐渐被shell模块取代

# chdir	在执行命令前,前切换至该目录
[root@g42k8snode-0002 ansible]# ansible host -m command -a 'chdir=/data/ ls'
192.168.5.117 | CHANGED | rc=0 >>

192.168.5.233 | CHANGED | rc=0 >>
ca_download
config
database
docker
jenkins_home
job_logs
m2
nfs
registry
secretkey

·················································································

# creates	用于判断文件是否存在。若存在,则不执行后面的命令(若不存在,则执行后面的命令)
	# 存在
[root@g42k8snode-0002 ansible]# ansible ansible -m command -a 'creates=/etc/ansible/hosts ls /etc/ansible/'
192.168.5.165 | SUCCESS | rc=0 >>
skipped, since /etc/ansible/hosts exists

·······················································································

# removes	用于判断文件是否存在。若不存在,则不执行后面的命令(若存在,则执行后面的命令)
	# 不存在
[root@g42k8snode-0002 ansible]# ansible ansible -m command -a 'removes=/etc/ansible/a.txt ls /etc/ansible/'
192.168.5.165 | SUCCESS | rc=0 >>
skipped, since /etc/ansible/a.txt does not exist
	# 存在
[root@g42k8snode-0002 ansible]# ansible ansible -m command -a 'removes=/etc/ansible/hosts ls /etc/ansible/'
192.168.5.165 | CHANGED | rc=0 >>
ansible.cfg
hosts
roles

(2)copy模块

该模块用于将本机文件复制到远程主机,同时支持给定内容生成文件和修改权限等

# src	将ansible本地文件复制到远程主机上。本地文件的指定可以是绝对路径,也可以是相对路径,但远端主机的路径必须是绝对路径。如果路径是目录,则会递归复制
	$ 绝对路径
[root@g42k8snode-0002 ansible]# ansible host -m copy -a 'src=/etc/ansible/hosts dest=/root/test/'
192.168.5.117 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "c1920ad05c2daa80856bb3eae9b7b7d6b8a2c5e2",
    "dest": "/root/test/hosts",
    "gid": 0,
    "group": "root",
    "md5sum": "009c4e34fc719cc02d417be09af095ae",
    "mode": "0644",
    "owner": "root",
    "size": 1075,
    "src": "/root/.ansible/tmp/ansible-tmp-1614849313.77-27470-211102900060561/source",
    "state": "file",
    "uid": 0
}
192.168.5.233 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "c1920ad05c2daa80856bb3eae9b7b7d6b8a2c5e2",
    "dest": "/root/test/hosts",
    "gid": 0,
    "group": "root",
    "md5sum": "009c4e34fc719cc02d417be09af095ae",
    "mode": "0644",
    "owner": "root",
    "size": 1075,
    "src": "/root/.ansible/tmp/ansible-tmp-1614849313.78-27472-203988361199867/source",
    "state": "file",
    "uid": 0
}
	$ 相对路径
[root@g42k8snode-0002 ansible]# ansible host -m copy -a 'src=./hosts dest=/root/test/'
192.168.5.233 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "checksum": "c1920ad05c2daa80856bb3eae9b7b7d6b8a2c5e2",
    "dest": "/root/test/hosts",
    "gid": 0,
    "group": "root",
    "mode": "0644",
    "owner": "root",
    "path": "/root/test/hosts",
    "size": 1075,
    "state": "file",
    "uid": 0
}
192.168.5.117 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "c1920ad05c2daa80856bb3eae9b7b7d6b8a2c5e2",
    "dest": "/root/test/hosts",
    "gid": 0,
    "group": "root",
    "md5sum": "009c4e34fc719cc02d417be09af095ae",
    "mode": "0644",
    "owner": "root",
    "size": 1075,
    "src": "/root/.ansible/tmp/ansible-tmp-1614849406.71-29423-152125754614573/source",
    "state": "file",
    "uid": 0
}

················································································

# content	用于替换“src”,可以直接将给定内容生成文件,并制定权限
[root@g42k8snode-0002 ansible]# ansible host -m copy -a 'content="hello\n" dest=/root/test/a.txt mode=666'
[root@g42k8snode-0003 test]# ls
hosts
[root@g42k8snode-0003 test]# ls
a.txt  hosts
[root@g42k8snode-0003 test]# cat a.txt
hello
[root@g42k8snode-0003 test]# ll
total 8
-rw-rw-rw- 1 root root    6 Mar  4 17:29 a.txt
-rw-r--r-- 1 root root 1075 Mar  4 17:16 hosts


················································································

# 关于覆盖:buckup=yes	将源文件改名作为备份(源文件名称格式:oldname.xxxx.日期),新文件用源文件的名字
[root@g42k8snode-0002 ansible]# ansible host -m copy -a 'content="hellohellohellohelloooooooooooooooooooooooooo\n" backup=yes dest=/root/test/a.txt mode=666'
[root@g42k8snode-0003 test]# ll
total 12
-rw-rw-rw- 1 root root   46 Mar  4 17:37 a.txt
-rw-rw-rw- 1 root root   21 Mar  4 17:35 a.txt.5298.2021-03-04@17:37:56~
-rw-r--r-- 1 root root 1075 Mar  4 17:16 hosts

·················································································
# directory_mode	递归设定目录的权限,默认为系统默认权限
# force				当远程主机文件已存在,但里面的内容不同时,设为“force=yes”表示强制覆盖;设为“force=no”表示远程主机的目标位置不存在该文件才复制。默认为“yes”
# others			所有的 file 模块中的选项都可以在这里使用

(3)file模块

该模块主要用于设置文件的属性,比如创建文件、创建链接文件、删除文件等

force  #需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group  #定义文件/目录的属组。后面可以加上mode:定义文件/目录的权限
owner  #定义文件/目录的属主。后面必须跟上path:定义文件/目录的路径
recurse  #递归设置文件的属性,只对目录有效,后面跟上src:被链接的源文件路径,只应用于state=link的情况
dest  #被链接到的路径,只应用于state=link的情况

# 创建目录
[root@g42k8snode-0002 ansible]# ansible host -m file -a 'path=/root/test1 state=directory'
	# 注释:
		path	指定路径
		state	说明状态
	# state 有以下选项
		directory:如果目录不存在,就创建目录
		file:即使文件不存在,也不会被创建
		link:创建软链接
		hard:创建硬链接
		touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
		absent:删除目录、文件或者取消链接文件

··················································································

# 创建链接文件
[root@g42k8snode-0002 ansible]# ansible host -m file -a 'path=/root/test/a.tex src=/root/test1/b.txt state=link'
192.168.5.117 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "dest": "/root/test/a.tex",
    "gid": 0,
    "group": "root",
    "mode": "0777",
    "owner": "root",
    "size": 17,
    "src": "/root/test1/b.txt",
    "state": "link",
    "uid": 0
}

[root@g42k8snode-0003 test]# ll
total 12
lrwxrwxrwx 1 root root   17 Mar  4 18:01 a.tex -> /root/test1/b.txt
-rw-rw-rw- 1 root root   46 Mar  4 17:37 a.txt
-rw-rw-rw- 1 root root   21 Mar  4 17:35 a.txt.5298.2021-03-04@17:37:56~
-rw-r--r-- 1 root root 1075 Mar  4 17:16 hosts

·······················································································

# 删除文件
root@g42k8snode-0002 ansible]# ansible host -m file -a 'path=/root/test/a.txt state=absent'
[root@g42k8snode-0003 test]# ll
total 8
lrwxrwxrwx 1 root root   17 Mar  4 18:01 a.tex -> /root/test1/b.txt
-rw-rw-rw- 1 root root   21 Mar  4 17:35 a.txt.5298.2021-03-04@17:37:56~
-rw-r--r-- 1 root root 1075 Mar  4 17:16 hosts

(4)fetch模块

该模块用于从远程主机复制文件到ansible本地(注意:远程的目录结构同样会复制过来)

dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录

[root@g42k8snode-0002 ansible]# ansible host -m fetch -a 'src=/root/test1/b.txt dest=/etc/ansible'
192.168.5.117 | CHANGED => {
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/etc/ansible/192.168.5.117/root/test1/b.txt",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "remote_checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "remote_md5sum": null
}
[root@g42k8snode-0002 ansible]# ls
192.168.5.117  ansible.cfg  hosts  roles
[root@g42k8snode-0002 ansible]# cd 192.168.5.117/
[root@g42k8snode-0002 192.168.5.117]# ls
root
[root@g42k8snode-0002 192.168.5.117]# cd root/
[root@g42k8snode-0002 root]# ls
test1
[root@g42k8snode-0002 root]# cd test1/
[root@g42k8snode-0002 test1]# ls
b.txt

(5)cron模块

该模块适用于管理计划任务

day= #日应该运行的工作( 1-31, *, */2, )
hour= # 小时 ( 0-23, *, */2, )
minute= #分钟( 0-59, *, */2, )
month= # 月( 1-12, *, /2, )
weekday= # 周 ( 0-6 for Sunday-Saturday, )
job= #指明运行的命令是什么
name= #定时任务描述
reboot # 任务在重启时运行,不建议使用,建议使用special_time
special_time #特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state #指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
user # 以哪个用户的身份执行

# 创建计划任务
[root@g42k8snode-0002 ansible]# ansible host -m cron -a 'name="a" month=*/5 job="ls /etc/ansible"'
192.168.5.117 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "ntpdate time",
        "a"
    ]
}
192.168.5.233 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "ntpdate time",
        "a"
    ]
}

[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'crontab -l'
192.168.5.117 | CHANGED | rc=0 >>
#Ansible: ntpdate time
0 1 * * * /usr/sbin/ntpdate ntp.myhuaweicloud.com > /dev/null 2>&1
#Ansible: a
* * * */5 * ls /etc/ansible
192.168.5.233 | CHANGED | rc=0 >>
#Ansible: ntpdate time
0 1 * * * /usr/sbin/ntpdate ntp.myhuaweicloud.com > /dev/null 2>&1
#Ansible: a
* * * */5 * ls /etc/ansible

····················································································

# 删除计划任务
[root@g42k8snode-0002 ansible]# ansible host -m cron -a 'name="a" month=*/5 job="ls /etc/ansible" state=absent'
192.168.5.117 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "ntpdate time"
    ]
}
192.168.5.233 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "envs": [],
    "jobs": [
        "ntpdate time"
    ]
}


[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'crontab -l'                                 192.168.5.117 | CHANGED | rc=0 >>
#Ansible: ntpdate time
0 1 * * * /usr/sbin/ntpdate ntp.myhuaweicloud.com > /dev/null 2>&1
192.168.5.233 | CHANGED | rc=0 >>
#Ansible: ntpdate time
0 1 * * * /usr/sbin/ntpdate ntp.myhuaweicloud.com > /dev/null 2>&1

(6)yum模块

该模块用于软件的安装、卸载

name=   #所安装的包的名称
state=   #present—>安装, latest—>安装最新的, absent—> 卸载软件。
update_cache   #强制更新yum的缓存
conf_file   #指定远程yum安装时所依赖的配置文件(安装本地已有的包)。
disable_pgp_check  #是否禁止GPG checking,只用于presentor latest
disablerepo   #临时禁止使用yum库。 只用于安装或更新时。
enablerepo   #临时使用的yum库。只用于安装或更新时。

# 下载安装
[root@g42k8snode-0002 ansible]# ansible host -m yum -a 'name=htop state=present' 


# 卸载
[root@g42k8snode-0002 ansible]# ansible host -m yum -a 'name=htop state=absent'

(7)service模块

该模块用于服务程序的管理

arguments #命令行提供额外的参数
enabled #设置开机启动。
name= #服务名称
runlevel #开机启动的级别,一般不用指定。
sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。(定义在剧本中。)
state #有四种状态,分别为:started—>启动服务, stopped—>停止服务, restarted—>重启服务, reloaded—>重载配置

# 开启nginx服务,并设置开机自启
[root@g42k8snode-0002 ansible]# ansible host -m service -a 'name=nginx state=started enabled=true'

# 关闭服务
[root@g42k8snode-0002 ansible]# ansible host -m service -a 'name=nginx state=stopped'

(8)user模块

该模块主要是用来管理用户账号

comment  # 用户的描述信息
createhome  # 是否创建家目录
force  # 在使用state=absent时, 行为与userdel –force一致.
group  # 指定基本组
groups  # 指定附加组,如果指定为(groups=)表示删除所有组
home  # 指定用户家目录
move_home  # 如果设置为home=时, 试图将用户主目录移动到指定的目录
name  # 指定用户名
non_unique  # 该选项允许改变非唯一的用户ID值
password  # 指定用户密码
remove  # 在使用state=absent时, 行为是与userdel –remove一致
shell  # 指定默认shell执行路径(如:shell=/sbin/nologin)
state  # 设置帐号状态,不指定为创建,指定值为absent表示删除
system  # 当创建一个用户,设置这个用户是系统用户:system=yes。这个设置不能更改现有用户
uid  # 指定用户的uid

# 添加一个用户并指定其uid
[root@g42k8snode-0002 ansible]# ansible host -m user -a 'name=mao uid=11111'
[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'cat /etc/passwd | grep mao'
192.168.5.117 | CHANGED | rc=0 >>
mao:x:11111:11111::/home/mao:/bin/bash
192.168.5.233 | CHANGED | rc=0 >>
mao:x:11111:11111::/home/mao:/bin/bash


# 删除用户
[root@g42k8snode-0002 ansible]# ansible host -m user -a 'name=mao state=absent'
root@g42k8snode-0002 ansible]# ansible host -m shell -a 'cat /etc/passwd | grep mao'
192.168.5.117 | FAILED | rc=1 >>
non-zero return code
192.168.5.233 | FAILED | rc=1 >>
non-zero return code

(9)group模块

该模块用于添加或删除组

gid=  #设置组的GID号
name=  #指定组的名称
state=  #指定组的状态,默认为创建,设置值为absent为删除
system=  #设置值为yes,表示创建为系统组

# 创建组并指定gid
[root@g42k8snode-0002 ansible]# ansible host -m group -a 'name=mao gid=122'
[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'cat /etc/group | grep 122'
192.168.5.117 | CHANGED | rc=0 >>
mao:x:122:
192.168.5.233 | CHANGED | rc=0 >>
mao:x:122:


# 删除组
[root@g42k8snode-0002 ansible]# ansible host -m group -a 'name=mao state=absent'
[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'cat /etc/group | grep mao'
192.168.5.117 | FAILED | rc=1 >>
non-zero return code
192.168.5.233 | FAILED | rc=1 >>
non-zero return code

(10)script模块

该模块用于将本机的脚本在被管理端的机器上运行

本地创建脚本
[root@g42k8snode-0002 ansible]# cat test.sh
#!/bin/bash
echo "hello !"
给脚本可执行权限
[root@g42k8snode-0002 ansible]# chmod +x test.sh
在被管理机器上运行该脚本
[root@g42k8snode-0002 ansible]# ansible host -m script -a '/etc/ansible/test.sh'
192.168.5.117 | CHANGED => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to 192.168.5.117 closed.\r\n",
    "stderr_lines": [
        "Shared connection to 192.168.5.117 closed."
    ],
    "stdout": "hello !\r\n",
    "stdout_lines": [
        "hello !"
    ]
}
192.168.5.233 | CHANGED => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to 192.168.5.233 closed.\r\n",
    "stderr_lines": [
        "Shared connection to 192.168.5.233 closed."
    ],
    "stdout": "hello !\r\n",
    "stdout_lines": [
        "hello !"
    ]
}

(11)setup模块

​ 该模块主要用于收集信息,是通过调用facts组件来实现的。
  facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。
  facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等。会存在facts中的某个变量中。调用后返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。

# 查看内存信息:直接使用命令获取变量的值
[root@g42k8snode-0002 ansible]# ansible host -m setup -a 'filter="*mem*"'
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 1879,
        "ansible_memory_mb": {
            "nocache": {
                "free": 5662,
                "used": 2158
            },
            "real": {
                "free": 1879,
                "total": 7820,
                "used": 5941
            },
            "swap": {
                "cached": 0,
                "free": 0,
                "total": 0,
                "used": 0
            }
        },
        "ansible_memtotal_mb": 7820,
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
192.168.5.233 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 985,
        "ansible_memory_mb": {
            "nocache": {
                "free": 12226,
                "used": 3657
            },
            "real": {
                "free": 985,
                "total": 15883,
                "used": 14898
            },
            "swap": {
                "cached": 0,
                "free": 0,
                "total": 0,
                "used": 0
            }
        },
        "ansible_memtotal_mb": 15883,
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": falses
}


[root@g42k8snode-0002 ansible]# ansible host -m shell -a 'free -m'
192.168.5.117 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:           7820        1861        1884          81        4074        5578
Swap:             0           0           0
192.168.5.233 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:          15883        2937         990         776       11956       11839
Swap:             0           0           0


···················································································

# 保存信息:--tree 保存路径				(setup模块还有一个很好用的功能就是可以保存我们所筛选的信息至我们的主机上,同时,文件名为我们被管制的主机的IP,这样方便我们知道是哪台机器出的问题)
[root@g42k8snode-0002 ansible]# ansible host -m setup -a 'filter="*mem*"' --tree /etc/ansible/
192.168.5.117 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 1881,
        "ansible_memory_mb": {
            "nocache": {
                "free": 5664,
                "used": 2156
            },
            "real": {
                "free": 1881,
                "total": 7820,
                "used": 5939
            },
            "swap": {
                "cached": 0,
                "free": 0,
                "total": 0,
                "used": 0
            }
        },
        "ansible_memtotal_mb": 7820,
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
192.168.5.233 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 984,
        "ansible_memory_mb": {
            "nocache": {
                "free": 12225,
                "used": 3658
            },
            "real": {
                "free": 984,
                "total": 15883,
                "used": 14899
            },
            "swap": {
                "cached": 0,
                "free": 0,
                "total": 0,
                "used": 0
            }
        },
        "ansible_memtotal_mb": 15883,
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
[root@g42k8snode-0002 ansible]# ls
192.168.5.117  192.168.5.233  ansible.cfg  hosts  roles  test.sh

(12)template模块

​ 在实际应用中,我们的配置文件有些地方可能会根据远程主机的配置的不同而有稍许的不同,template可以使用变量来接收远程主机上setup收集到的facts信息,针对不同配置的主机,定制配置文件。用法大致与copy模块相同

src 源模板文件路径

dest 目标文件路径

force 是否强制覆盖,默认为yes

backup 如果原目标文件存在,则先备份目标文件

group 目标文件或目录的所属组

owner 目标文件或目录的所属主

mode 目标文件的权限

# 资产文件:
cat /etc/ansible/hosts
[webservers]
192.168.200.136 httpd_port=8088

# 配置文件:
grep ^Listen httpd.conf
Listen {{ httpd_port }}

# palybook文件:
cat httpd02.yml
---
- hosts: 192.168.200.136
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd state=present
    - name: install configure file
      template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd service
    - name: start httpd service
      service: name=httpd state=started
  handlers:
    - name: restart httpd servcie
      service: name=httpd state=restarted

(13)authorized_key模块

为远程服务器添加authorized_keys文件内容

#  新增公钥内容到服务器用户家目录的.ssh目录的authorized_keys文件 没有则创建authorized_keys文件 state: (1) present 添加 (2) absent 删除
---
- hosts: test
  gather_facts: false
  tasks:
  - name: deliver authorized_keys
    authorized_key:
        user: root
        key: "{{ lookup('file', '/etc/ansible/roles/authorized_keys') }}"  # 从本地authorized_keys文件读取公钥内容
        state: present
        exclusive: no
        
-----------------------------------------------------------------

# 实际可以直接指定公钥文件,如

- name: add user softadm
  user:
    name: softadm

- name: Set authorized key taken from file
  authorized_key:
    user: softadm
    state: present
    key: "{{ lookup('file', '/etc/ansible/roles/init/files/softadm_id_rsa.pub') }}"

- name: Set authorized key taken from file
  authorized_key:
    user: root
    state: present
    key: "{{ lookup('file', '/etc/ansible/roles/init/files/root_id_rsa.pub') }}"

(14)unarchive模块

该模块用于解压缩

copy 在解压缩之前,是否将文件复制到远程主机。默认为yes,若为no,则要求远端主机上压缩包必须存在

src 如果copyyes,则需要指定压缩文件的源路径

dest 远程主机上的一个路径,即文件解压的路径

mode 解压后文件的权限(默认权限:500)

owner 解压后文件或目录的属主

group 解压后文件或目录的属组

creates 指定一个文件名,当该文件存在时,则解压指令不执行

list_files 如果为yes,则会列出压缩包里的文件;默认为no(2.0版本新增的选项)

- unarchive: src=foo.tgz dest=/var/lib/foo  
- unarchive: src=/tmp/foo.zip dest=/usr/local/bin copy=no  
- unarchive: src=https://example.com/example.zip dest=/usr/local/bin copy=no

(15)wait_for模块

该模块用于设置等待时间,例如等待数据库启动、web 容器启动等等

port 等待端指定口号必须启动

path 等待某文件必须创建

host 默认是127.0.0.1,为了满足等待其他远程服务器的场景

timeout 等待时间,单位是“秒”

state 默认是started

4.ansible-playbook

1.介绍

playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务

2.核心元素

  • Hosts 执行的远程主机列表
  • Tasks 任务集
  • Varniables 内置变量或自定义变量在playbook中调用
  • Templates 模板,即使用模板语法的文件,比如配置文件等
  • Handlers 和notity结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签,指定某条任务执行,用于选择运行playbook中的部分代码

3.playbook语法

  • 在单一一个playbook文件中,可以连续三个连子号(---)区分多个play。还有选择性的连续三个点(...)好用来表示play的结尾,也可省略。
  • 次行开始正常写playbook的内容,一般都会写上描述该playbook的功能。
  • 使用#号注释代码。
  • 缩进必须统一,不能空格和tab混用。
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行实现的。
  • YAML文件内容和Linux系统大小写判断方式保持一致,是区分大小写的,k/v的值均需大小写敏感
  • k/v的值可同行写也可以换行写。同行使用:分隔。
  • v可以是个字符串,也可以是一个列表
  • 一个完整的代码块功能需要最少元素包括 name: task

4.playbook中元素属性

(1)主机与用户

在一个playbook开始时,最先定义的一定是要操作的主机和用户

---
- hosts: 192.168.5.117
  remote_user: root

除了上面的定义外,还可以在某一个 tasks 中定义要执行该任务的远程用户

tasks:
  - name: run "df -h"
    remote_user: root
    shell: name=df -h

还可以定义使用 sudo 授权用户执行该任务

tasks:
  - name: run "df -h"
    sudo_user: root
    sudo: yes
    shell: name=df -h

(2)tasks任务列表

​ 每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很清楚的辨别是属于哪一个task的,如果没有定义 nameaction的值将会用作输出信息中标记特定的task
​ 每一个playbook中可以包含一个或者多个tasks任务列表,每一个tasks完成具体的一件事,(任务模块)比如创建一个用户或者安装一个软件等,在hosts中定义的主机或者主机组都将会执行这个被定义的tasks

tasks:
  - name: create new file
    file: path=/tmp/test01.txt state=touch
  - name: create new user
    user: name=test001 state=present

(3)handlers 与 notify

​ 很多时候当我们某一个配置发生改变,我们需要重启服务,(比如httpd配置文件文件发生改变了)这时候就可以用到handlersnotify了;
​ (当发生改动时)notify actions会在playbook的每一个task结束时被触发,而且即使有多个不同task通知改动的发生,notify actions知会被触发一次;比如多个resources指出因为一个配置文件被改动,所以apache需要重启,但是重新启动的操作只会被执行一次。

[root@ansible ~]# cat httpd.yml 
#用于安装httpd并配置启动
---
- hosts: 192.168.1.31
  remote_user: root

  tasks:
  - name: install httpd
    yum: name=httpd state=installed
  - name: config httpd
    template: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
      - restart httpd
  - name: start httpd
    service: name=httpd state=started

  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

#这里只要对httpd.conf配置文件作出了修改,修改后需要重启生效,在tasks中定义了restart httpd这个action,然后在handlers中引用上面tasks中定义的notify。

(4)playbook中变量的使用(5种方式)

环境说明:在 hosts 文件中定义两个组:apache、nginx

[root@ansible PlayBook]# cat /etc/ansible/hosts
[apache]
192.168.1.36
192.168.1.33

[nginx]
192.168.1.3[1:2]

a. 命令行指定变量

​ 执行playbook时候通过参数-e传入变量,这样传入的变量在整个playbook中都可以被调用,属于全局变量

[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: install pkg
      yum: name={{ pkg }}

#执行playbook 指定pkg
[root@ansible PlayBook]# ansible-playbook -e "pkg=httpd" variables.yml

b. hosts 文件中定义变量

​ 在/etc/ansible/hosts文件中定义变量,可以针对每个主机定义不同的变量,也可以定义一个组的变量,然后直接在playbook中直接调用。注意,组中定义的变量没有单个主机中的优先级高。

# 编辑hosts文件定义变量
[root@ansible PlayBook]# vim /etc/ansible/hosts
[apache]
192.168.1.36 webdir=/opt/test     #定义单个主机的变量
192.168.1.33
[apache:vars]      #定义整个组的统一变量
webdir=/web/test

[nginx]
192.168.1.3[1:2]
[nginx:vars]
webdir=/opt/web


# 编辑playbook文件
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: create webdir
      file: name={{ webdir }} state=directory   #引用变量


# 执行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

c. palybook 文件中定义变量

​ 编写playbook时,直接在里面定义变量,然后直接引用,可以定义多个变量;注意:如果在执行playbook时,又通过-e参数指定变量的值,那么会以-e参数指定的为准

# 编辑playbook
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root
  vars:                #定义变量
    pkg: nginx         #变量1
    dir: /tmp/test1    #变量2

  tasks:
    - name: install pkg
      yum: name={{ pkg }} state=installed    #引用变量
    - name: create new dir
      file: name={{ dir }} state=directory   #引用变量


# 执行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

# 如果执行时候又重新指定了变量的值,那么会已重新指定的为准
[root@ansible PlayBook]# ansible-playbook -e "dir=/tmp/test2" variables.yml

d. 调用setup模块获取变量

setup模块默认是获取主机信息的,有时候在playbook中需要用到,所以可以直接调用。常用的参数

# 编辑playbook文件
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: create file
      file: name={{ ansible_fqdn }}.log state=touch   #引用setup中的ansible_fqdn(主机的域名)


# 执行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

e. 独立的变量 yaml 文件中定义

​ 为了方便管理将所有的变量统一放在一个独立的变量YAML文件中,laybook文件直接引用文件调用变量即可

# 定义存放变量的文件
[root@ansible PlayBook]# cat var.yml 
var1: vsftpd
var2: httpd

# 编写playbook
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root
  vars_files:    #引用变量文件
    - ./var.yml   #指定变量文件的path(这里可以是绝对路径,也可以是相对路径)

  tasks:
    - name: install package
      yum: name={{ var1 }}   #引用变量
    - name: create file
      file: name=/tmp/{{ var2 }}.log state=touch   #引用变量


# 执行playbook
[root@ansible PlayBook]# ansible-playbook  variables.yml

(5)playbook中标签的使用

​ 一个playbook文件中,执行时如果想执行某一个任务,那么可以给每个任务集进行打标签,这样在执行的时候可以通过-t选择指定标签执行,还可以通过--skip-tags选择除了某个标签外全部执行等

# 编辑playbook
[root@ansible PlayBook]# cat httpd.yml 
---
- hosts: 192.168.1.31
  remote_user: root

  tasks:
    - name: install httpd
      yum: name=httpd state=installed
      tags: inhttpd

    - name: start httpd
      service: name=httpd state=started
      tags: sthttpd

    - name: restart httpd
      service: name=httpd state=restarted
      tags: 
        - rshttpd
        - rs_httpd

# 正常执行的结果
[root@ansible PlayBook]# ansible-playbook httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************
ok: [192.168.1.31]

TASK [install httpd] *************************************************************************************************************************
ok: [192.168.1.31]

TASK [start httpd] ***************************************************************************************************************************
ok: [192.168.1.31]

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

PLAY RECAP ***********************************************************************************************************************************
192.168.1.31               : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 通过-t选项指定tags进行执行
# 通过-t指定tags名称,多个tags用逗号隔开
[root@ansible PlayBook]# ansible-playbook -t rshttpd httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************
ok: [192.168.1.31]

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

PLAY RECAP ***********************************************************************************************************************************
192.168.1.31               : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 通过--skip-tags选项排除不执行的tags
[root@ansible PlayBook]# ansible-playbook --skip-tags inhttpd httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************
ok: [192.168.1.31]

TASK [start httpd] ***************************************************************************************************************************
ok: [192.168.1.31]

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

PLAY RECAP ***********************************************************************************************************************************
192.168.1.31               : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

(6)playbook中模板的使用

template模板为我们提供了动态配置服务,使用jinja2语言,里面支持多种条件判断、循环、逻辑运算、比较操作等。其实说白了也就是一个文件,和之前配置文件使用copy一样,只是当使用copy时,不能根据服务器配置不一样进行不同动态的配置。这样就不利于管理。
说明:
1、多数情况下都将template文件放在和playbook文件同级的templates目录下(手动创建),这样playbook文件中可以直接引用,会自动去找这个文件。如果放在别的地方,也可以通过绝对路径去指定。
2、模板文件后缀名为.j2

循环参考

template

示例1:通过 template 安装 httpd

1)playbook文件编写

[root@ansible PlayBook]# cat testtmp.yml 
#模板示例
---
- hosts: all
  remote_user: root
  vars:
    - listen_port: 88    #定义变量

  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Config Httpd
      template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf    #使用模板
      notify: Restart Httpd
    - name: Start Httpd
      service: name=httpd state=started
      
  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

2)模板文件准备,http的配置文件准备(这里配置文件端口使用了变量)

[root@ansible PlayBook]# cat templates/httpd.conf.j2 |grep ^Listen
Listen {{ listen_port }}

3)查看目录结构

# 目录结构
[root@ansible PlayBook]# tree .
.
├── templates
│   └── httpd.conf.j2
└── testtmp.yml

1 directory, 2 files

4)执行playbook【由于192.168.1.36那台机器是6的系统,模板文件里面的配置文件是7上面默认的httpd配置文件,httpd版本不一样(6默认版本为2.2.15,7默认版本为2.4.6),所以拷贝过去后启动报错】

[root@ansible PlayBook]# ansible-playbook testtmp.yml 

PLAY [all] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.31]

TASK [Install Httpd] ********************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.33]
ok: [192.168.1.32]
ok: [192.168.1.31]

TASK [Config Httpd] *********************************************************************************
changed: [192.168.1.31]
changed: [192.168.1.33]
changed: [192.168.1.32]
changed: [192.168.1.36]

TASK [Start Httpd] **********************************************************************************
fatal: [192.168.1.36]: FAILED! => {"changed": false, "msg": "httpd: Syntax error on line 56 of /etc/httpd/conf/httpd.conf: Include directory '/etc/httpd/conf.modules.d' not found\n"}
changed: [192.168.1.32]
changed: [192.168.1.33]
changed: [192.168.1.31]

RUNNING HANDLER [Restart Httpd] *********************************************************************
changed: [192.168.1.31]
changed: [192.168.1.32]
changed: [192.168.1.33]

PLAY RECAP ******************************************************************************************
192.168.1.31               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.32               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.33               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.36               : ok=3    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
template之when

when语句参考

条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句执行,在task中使用jinja2的语法格式、
when语句:
task后添加when子句即可使用条件测试;when语句支持jinja2表达式语法

类似这样:

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True
  - command: /bin/something
    when: result|failed
  - command: /bin/something_else
    when: result|success
  - command: /bin/still/something_else
    when: result|skipped

示例2:通过 when 语句完善上面的 httpd 配置

1)准备两个配置文件,一个centos6系统httpd配置文件,一个centos7系统httpd配置文件

[root@ansible PlayBook]# tree templates/
templates/
├── httpd6.conf.j2     #6系统2.2.15版本httpd配置文件
└── httpd7.conf.j2     #7系统2.4.6版本httpd配置文件

0 directories, 2 files

2)修改playbook文件,通过setup模块获取系统版本去判断

[root@ansible PlayBook]# cat testtmp.yml 
#when示例
---
- hosts: all
  remote_user: root
  vars:
    - listen_port: 88

  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Config System6 Httpd
      template: src=httpd6.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "6"   #判断系统版本,为6便执行上面的template配置6的配置文件
      notify: Restart Httpd
    - name: Config System7 Httpd
      template: src=httpd7.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "7"   #判断系统版本,为7便执行上面的template配置7的配置文件
      notify: Restart Httpd
    - name: Start Httpd
      service: name=httpd state=started

  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

3)执行playbook

[root@ansible PlayBook]# ansible-playbook testtmp.yml

PLAY [all] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [192.168.1.31]
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.36]

TASK [Install Httpd] ********************************************************************************
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.31]
ok: [192.168.1.36]

TASK [Config System6 Httpd] *************************************************************************
skipping: [192.168.1.33]
skipping: [192.168.1.31]
skipping: [192.168.1.32]
changed: [192.168.1.36]

TASK [Config System7 Httpd] *************************************************************************
skipping: [192.168.1.36]
changed: [192.168.1.33]
changed: [192.168.1.31]
changed: [192.168.1.32]

TASK [Start Httpd] **********************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.31]
ok: [192.168.1.32]
ok: [192.168.1.33]

RUNNING HANDLER [Restart Httpd] *********************************************************************
changed: [192.168.1.33]
changed: [192.168.1.31]
changed: [192.168.1.32]
changed: [192.168.1.36]

PLAY RECAP ******************************************************************************************
192.168.1.31               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.32               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.33               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.36               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
template之with_items

with_items迭代,当有需要重复性执行的任务时,可以使用迭代机制。
​ 对迭代项的引用,固定变量名为“item”,要在task中使用with_items给定要迭代的元素列表。
列表格式:
  字符串
  字典

示例3:通过with_items安装多个不同软件

1)编写playbook

[root@ansible PlayBook]# cat testwith.yml 
# 示例with_items
---
- hosts: all
  remote_user: root

  tasks:
    - name: Install Package
      yum: name={{ item }} state=installed   #引用item获取值
      with_items:     #定义with_items
        - httpd
        - vsftpd
        - nginx

上面 tasks 写法等同于:

---
- hosts: all
  remote_user: root
  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Install Vsftpd
      yum: name=vsftpd state=installed
    - name: Install Nginx
      yum: name=nginx state=installed

示例4:通过嵌套子变量创建用户并加入不同的组

1)编写playbook

[root@ansible PlayBook]# cat testwith01.yml 
# 示例with_items嵌套子变量
---
- hosts: all
  remote_user: root

  tasks:
    - name: Create New Group
      group: name={{ item }} state=present
      with_items: 
        - group1
        - group2
        - group3 

    - name: Create New User
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - { name: 'user1', group: 'group1' } 
        - { name: 'user2', group: 'group2' } 
        - { name: 'user3', group: 'group3' }

2)执行playbook并验证

# 执行playbook
[root@ansible PlayBook]# ansible-playbook testwith01.yml

# 验证是否成功创建用户及组
[root@ansible PlayBook]# ansible all -m shell -a 'tail -3 /etc/passwd'
192.168.1.36 | CHANGED | rc=0 >>
user1:x:500:500::/home/user1:/bin/bash
user2:x:501:501::/home/user2:/bin/bash
user3:x:502:502::/home/user3:/bin/bash

192.168.1.32 | CHANGED | rc=0 >>
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
user3:x:1003:1003::/home/user3:/bin/bash

192.168.1.31 | CHANGED | rc=0 >>
user1:x:1002:1003::/home/user1:/bin/bash
user2:x:1003:1004::/home/user2:/bin/bash
user3:x:1004:1005::/home/user3:/bin/bash

192.168.1.33 | CHANGED | rc=0 >>
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
user3:x:1003:1003::/home/user3:/bin/bash
template之for if

​ 通过使用forif可以更加灵活的生成配置文件等需求,还可以在里面根据各种条件进行判断,然后生成不同的配置文件、或者服务器配置相关等

示例 5:

1)编写playbook

[root@ansible PlayBook]# cat testfor01.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhost_port:
      - 81
      - 82
      - 83

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_test.conf

2)编写模板文件

# 循环playbook文件中定义的变量,依次赋值给port
[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for port in nginx_vhost_port %}
server{
     listen: {{ port }};
     server_name: localhost;
}
{% endfor %}

3)执行playbook并查看结果

[root@ansible PlayBook]# ansible-playbook testfor01.yml

# 去到一个节点看下生成的结果发现自动生成了三个虚拟主机
[root@linux ~]# cat /tmp/nginx_test.conf 
server{
     listen: 81;
     server_name: localhost;
}
server{
     listen: 82;
     server_name: localhost;
}
server{
     listen: 83;
     server_name: localhost;
}

img

示例6:

1)编写playbook

[root@ansible PlayBook]# cat testfor02.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8081
        server_name: "web1.example.com"
        root: "/var/www/nginx/web1"
      - web2:
        listen: 8082
        server_name: "web2.example.com"
        root: "/var/www/nginx/web2"
      - web3:
        listen: 8083
        server_name: "web3.example.com"
        root: "/var/www/nginx/web3"

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_vhost.conf

2)编写模板文件

[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
server{
     listen:    {{ vhost.listen }};
     server_name:    {{ vhost.server_name }};
     root:   {{ vhost.root }}; 
}
{% endfor %}

3)执行playbook并查看生成结果

[root@ansible PlayBook]# ansible-playbook testfor02.yml

# 去到一个节点看下生成的结果发现自动生成了三个虚拟主机
[root@linux ~]# cat /tmp/nginx_vhost.conf 
server{
     listen:    8081;
     server_name:    web1.example.com;
     root:   /var/www/nginx/web1; 
}
server{
     listen:    8082;
     server_name:    web2.example.com;
     root:   /var/www/nginx/web2; 
}
server{
     listen:    8083;
     server_name:    web3.example.com;
     root:   /var/www/nginx/web3; 
}

img

示例7:

​ 在for循环中再嵌套if判断,让生成的配置文件更加灵活

1)编写playbook

[root@ansible PlayBook]# cat testfor03.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8081
        root: "/var/www/nginx/web1"
      - web2:
        server_name: "web2.example.com"
        root: "/var/www/nginx/web2"
      - web3:
        listen: 8083
        server_name: "web3.example.com"
        root: "/var/www/nginx/web3"

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_vhost.conf

2)编写模板文件

# 说明:这里添加了判断,如果listen没有定义的话,默认端口使用8888,如果server_name有定义,那么生成的配置文件中才有这一项。
[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
server{
     {% if vhost.listen is defined %}
     listen:    {{ vhost.listen }};
     {% else %}
     listen: 8888;
     {% endif %}
     {% if vhost.server_name is defined %}
     server_name:    {{ vhost.server_name }};
     {% endif %}
     root:   {{ vhost.root }}; 
}
{% endfor %}

3)执行playbook并查看结果

[root@ansible PlayBook]# ansible-playbook testfor03.yml

# 去到一个节点看下生成的结果发现自动生成了三个虚拟主机
[root@linux ~]# cat /tmp/nginx_vhost.conf 
server{
          listen:    8081;
          root:   /var/www/nginx/web1; 
}
server{
          listen: 8888;
          server_name:    web2.example.com;
          root:   /var/www/nginx/web2; 
}
server{
          listen:    8083;
          server_name:    web3.example.com;
          root:   /var/www/nginx/web3; 
}

img

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ansible介绍 的相关文章

  • 在 Mac OS X 上构建 Linux 内核

    我正在做一个修改Linux内核的项目 我有一台桌面 Linux 机器 在上面构建内核没有问题 不过 我要去旅行 我想在途中工作 我只有一台 MacBook 当我尝试构建 Linux 内核时 它抱怨说elf h was not found 我
  • 从 PL/SQL 调用 shell 脚本,但 shell 以 grid 用户而非 oracle 身份执行

    我正在尝试使用 Runtime getRuntime exec 从 Oracle 数据库内部执行 shell 脚本 在 Red Hat 5 5 上运行的 Oracle 11 2 0 4 EE CREATE OR REPLACE proced
  • 创建 jar 文件 - 保留文件权限

    我想知道如何创建一个保留其内容的文件权限的 jar 文件 我将源代码和可执行文件打包在一个 jar 文件中 该文件将在使用前提取 人们应该能够通过运行批处理 shell 脚本文件立即运行示例和演示 然后他们应该能够修改源代码并重新编译所有内
  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • 通过特定分隔符删除字符串

    我的文件中有几列 其中第二列有 分隔符 我想删除第二列中的第一个 第三个和第四个字符串 并将第二个字符串留在该列中 但我有正常的分隔符空间 所以我不知道 input 22 16050075 A G 16050075 A G 22 16050
  • 应用程序无缘无故地被杀死。怀疑 BSS 高。如何调试呢?

    我已经在CentOs6 6中成功运行我的应用程序 最近 硬件 主板和内存 更新了 我的应用程序现在毫无理由地被杀死 root localhost PktBlaster PktBlaster Killed 文件和 ldd 输出 root lo
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • 如何查明CONFIG_FANOTIFY_ACCESS_PERMISSIONS是否启用?

    我想利用fanotify 7 http man7 org linux man pages man7 fanotify 7 html我遇到的问题是在某些内核上CONFIG FANOTIFY ACCESS PERMISSIONS不起作用 虽然C
  • 为什么内核需要虚拟寻址?

    在Linux中 每个进程都有其虚拟地址空间 例如 32位系统为4GB 其中3GB为进程保留 1GB为内核保留 这种虚拟寻址机制有助于隔离每个进程的地址空间 对于流程来说这是可以理解的 因为有很多流程 但既然我们只有 1 个内核 那么为什么我
  • 无法从 jenkins 作为后台进程运行 nohup 命令

    更新 根据下面的讨论 我编辑了我的答案以获得更准确的描述 我正在尝试从詹金斯运行 nohup 命令 完整的命令是 nohup java jar home jar server process 0 35 jar prod gt gt var
  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • 如何有效截断文件头?

    大家都知道truncate file size 函数 通过截断文件尾部将文件大小更改为给定大小 但是如何做同样的事情 只截断文件的尾部和头部呢 通常 您必须重写整个文件 最简单的方法是跳过前几个字节 将其他所有内容复制到临时文件中 并在完成
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 如何在 Linux shell 中将十六进制转换为 ASCII 字符?

    假设我有一个字符串5a 这是 ASCII 字母的十六进制表示Z 我需要找到一个 Linux shell 命令 它将接受一个十六进制字符串并输出该十六进制字符串代表的 ASCII 字符 所以如果我这样做 echo 5a command im
  • 如何将目录及其子目录中的所有 PDF 文件复制到一个位置?

    如何全部复制PDF文件从目录及其子目录到单个目录 实际上还有更多的文件 并且深度有些任意 假设四个目录的最大深度是公平的 我想这些文件需要重命名 如果a pdf例如 位于多个目录中 因为我会adding https ebooks stack
  • Linux 内核标识符中前导和尾随下划线的含义是什么?

    我不断遇到一些小约定 比如 KERNEL Are the 在这种情况下 是内核开发人员使用的命名约定 还是以这种方式命名宏的语法特定原因 整个代码中有很多这样的例子 例如 某些函数和变量以 甚至 这有什么具体原因吗 它似乎被广泛使用 我只需
  • NPTL 和 POSIX 线程有什么区别?

    NPTL 和 POSIX 线程之间的基本区别是什么 这两者是如何演变的 POSIX 线程 pthread 不是一个实现 它是几个函数的 API 规范 纸上的标准 英文 其名称以pthread 以及定义在
  • os.Mkdir 和 os.MkdirAll 权限

    我正在尝试在程序开始时创建一个日志文件 我需要检查是否 log如果不创建目录 则目录存在 然后继续创建日志文件 好吧 我尝试使用os Mkdir 也os MkdirAll 但无论我在第二个参数中输入什么值 我都会得到一个没有权限的锁定文件夹
  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 安装J语言的JQt IDE,出现错误

    我一直按照这里的说明进行操作 http code jsoftware com wiki System Installation Linux http code jsoftware com wiki System Installation L

随机推荐

  • 修复dubbo注册中心警告bug

    1 dubbo注册中心服务提供者界面显示警告 点击提示不同服务名注册了相同服务 这是界面显示逻辑bug 源码文件位置 dubbo admin src main webapp WEB INF templates governance scre
  • EGE-UNet, 轻量化U-Net

    随着transform 的出现 现在语义分割网路结构越来越复杂 轻量化网路也较少了 有些轻量化也只是名义上的轻量化 今天我看到一篇很好的论文 上海交大发表在 MICCAI 2023 的最新研究工作 一个称为Efficient Group E
  • 干式真空泵原理_如何安装干式墙锚在墙壁上悬挂重物

    干式真空泵原理 If you ever plan to mount something to the wall that s even remotely heavy you ll need to use drywall anchors if
  • 干货分享——产品经理必备的技能:专业技能和软技能。

    TOP1 沟通 作为一种软技能 沟通不是多种语言或激动人心的演讲 善于沟通的人能够根据听众的不同 调整自己的语气和风格 理解并有效地执行指示 向同事和客户解释复杂的问题 沟通也是领导力的一个重要方面 因为领导者必须能够清晰而全面地授权 TO
  • RISC-V学习笔记【系统设计】

    蜂鸟E200系列处理器简介 特色 开源 免费 高能效比 针对IoT领域设计 支持RV32I E A M C F D等指令子集和机器模式 2级流水线 功耗和性能均优于主流商用的ARM Cortex M处理器 提供完整的配套SoC 包括中断控制
  • C++使用curl实现https、http通信

    curl实现https http通信 curl实现https http通信 代码实现 依赖库和实现类文件 添加Body curl实现https http通信 代码实现 post http int CHttpClient Post const
  • GIt 上传

    自从使用github以来 一直都是在github网站在线上传文件到仓库中 但是有时因为网络或者电脑的原因上传失败 最重要的原因是我习惯本地编辑 完成以后再一起上传github 看过了几个教程 总结出最适合自己的比较简单的方法 两种方法上传本
  • 微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    原文地址 http skaka me blog 2016 04 21 springcloud1 不同于单一架构应用 Monolith 分布式环境下 进行事务操作将变得困难 因为分布式环境通常会有多个数据源 只用本地数据库事务难以保证多个数据
  • 14:00面试,14:06就出来了,问的问题有点变态。。。

    从小厂出来 没想到在另一家公司又寄了 到这家公司开始上班 加班是每天必不可少的 看在钱给的比较多的份上 就不太计较了 没想到5月一纸通知 所有人不准加班 加班费不仅没有了 薪资还要降40 这下搞的饭都吃不起了 还在有个朋友内推我去了一家互联
  • eclipse环境问题-java版本不兼容

    https www cnblogs com hellowhy p 9651559 html
  • 离线地图显示连接服务器未打开,如何在uwp中使用OSM离线地图?没有可用的互联网连接时出现问题...

    在脱机映射运行良好的情况下 OSM的所有位图都来自同一台计算机上的localhost服务器 一切正常 可以看到我的所有地图 但是 如果wifi未连接到互联网 则该地图将完全停止工作 并显示黑屏 wifi关闭时 我已经测试了服务器 并且似乎在
  • 编程离软件工程有多远?

    原文地址 http kb cnblogs com page 160717 作者 周爱民 来源 VeDa原型 发布时间 2012 10 19 11 31 阅读 5135 次 原文链接 全屏阅读 收藏 语言只是工具 我曾经是非常执著的开发人员
  • vue-element-ui 中使用 el-form 报错 “TypeError: this.$refs[formName] is undefined“

    情况说明 使用了 element ui 里面
  • 【Java】 关于解决 错误: 找不到或无法加载主类 原因: java.lang.ClassNotFoundException 的方法

    哭了 泪目 出现 java lang ClassNotFoundException 的原因 当Java的版本高于10的时候不需要配置CLASSPATH 环境变量 只需要配置JAVA HOME和PATH即可
  • Springboot集成logback

    一 logback的介绍 Logback是由log4j创始人设计的另一个开源日志组件 官方网站 http logback qos ch 它当前分为下面下个模块 logback core 其它两个模块的基础模块 logback classic
  • 朱自清《春》加薪版

    为什么80 的码农都做不了架构师 gt gt gt 盼望着 盼望着 文件来了 加薪的脚步近了 一切都像刚睡醒的样子 欣欣然张开了眼 物价涨起来了 房价涨起来了 职工的工资也要涨了 大家都高兴的欢呼起来了 标准悄悄地从官员口里漏出来 嫩嫩 的
  • 虚拟化技术及实时虚拟化概述

    版权声明 本文为本文为博主原创文章 未经本人同意 禁止转载 如有问题 欢迎指正 博客地址 https www cnblogs com wsg1100 文章目录 一 前言 二 分时系统 三 虚拟化介绍 四 虚拟化实现方式及分类 模拟器 Typ
  • linux下载安装jdk

    1 从官网下载jdk 如下是jdk下载地址 直接点击即可 Java Downloads Oracle 下载自己需要的jdk即可 建议下载jdk8 2 将jdk传入linux服务器 2 1 首先在linux中创建文件夹并且进入 mkdir o
  • jdbc autoReconnect=true 参数设置导致 slow log 爆表。

    1 过程 同事按照文档上配置了下面的jdbc url jdbc mysql ip port db autoReconnect true useUnicode true characterEncoding utf 8 结果导致了 mysql
  • Ansible介绍

    1 安装ansible 1 下载并安装ansible 所有节点安装依赖 yum install python y 添加源 yum y install epel release 查看可安装的版本 yum list grep ansible 下