0
点赞
收藏
分享

微信扫一扫

Ansible笔记

一枚路过的程序猿 2024-11-18 阅读 9

原文链接:Ansible-总手册 | 严千屹博客

Ansible三机部署

关于

ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。   ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远 程主机通讯的。ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一。

主机分布

主机名

ip

系统

内存

硬盘

controller

192.168.48.100

Centos7.9

4G

100G

node01

192.168.48.101

Centos7.9

4G

100G

node02

192.168.48.102

Centos7.9

4G

100G

修改主机名

controlle

hostnamectl set-hostname controller && bash

node01

hostnamectl set-hostname node01 && bash

node02

hostnamectl set-hostname node02 && bash

三台机加入hosts

cat >> /etc/hosts << EOF
192.168.48.100 controller
192.168.48.101 node01
192.168.48.102 node02
EOF

设置阿里yum

mkdir repo.bak
mv /etc/yum.repos.d/* repo.bak/
wget -O /etc/yum.repos.d/CentOSase.repo https://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all && yum makecache
systemctl disable firewalld --now
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
yum update -y

安装python

已安装可以忽略。

确保python版本>=2.6

sudo yum install epel-release
sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
sudo yum install python27

[root@controller ~]# python --version
Python 2.7.5
#有显示说明python安装成功

安装Ansible

sudo yum install epel-release ansible openssh

[root@controller ~]# ansible --version
ansible 2.9.27
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Oct 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]

测试

测试主机是否存活

vim /etc/ansible/hosts

#在末尾添加ip
192.168.48.101
192.168.48.102
-----------------------

ansible 192.168.48.101 -m ping -k
ansible 192.168.48.102 -m ping -k

如果controller没有首次进行ssh至node01-02节点,则ansible会出错,如下图:

Ansible笔记_Ansible

Ansible笔记_Ansible_02

所以我们必须先ssh至各节点,让其生成缓存信息

[root@controller ~]# ssh 192.168.48.101
##输入密码

[root@node01 ~]# exit


[root@controller ~]# ssh 192.168.48.102
##输入密码

[root@node02 ~]# exit

这时我们在进行测试

Ansible笔记_Ansible_03

SSH免密配置

ssh-keygen   (一路回车,三次)
[root@controller ~]# ls -al ~/.ssh
total 12
drwx------  2 root root   57 Sep  6 00:43 .
dr-xr-x---. 8 root root  236 Sep  9 23:05 ..
-rw-------  1 root root 1675 Sep  6 00:42 id_rsa
-rw-r--r--  1 root root  397 Sep  6 00:42 id_rsa.pub
-rw-r--r--  1 root root  352 Sep  6 00:35 known_hosts
#有密钥文件了

#将密钥文件复制到node01-02节点,实现ssh免密登入
(先yes 然后输入密码即可)
ssh-copy-id root@192.168.48.101

ssh-copy-id root@192.168.48.102

最后我们在进行测试

Ansible笔记_Ansible_04

Ansible笔记_Ansible_05

Ansible配置及相关指令

ansible 程序结构

安装目录如下(yum安装):   配置文件目录:/etc/ansible/   执行文件目录:/usr/bin/   Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/   Help文档目录:/usr/share/doc/ansible-X.X.X/   Man文档目录:/usr/share/man/man1/

ansible配置文件查找顺序

ansible与我们其他的服务在这一点上有很大不同,这里的配置文件查找是从多个地方找的,顺序如下:

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

ansible配置文件

ansible 的配置文件为/etc/ansible/ansible.cfg,ansible 有许多参数,下面我们列出一些常见的参数:

[defaults]
 
#inventory      = /etc/ansible/hosts   //定义Inventory
#library        = /usr/share/my_modules/  //自定义lib库存放目录 
#remote_tmp     = ~/.ansible/tmp       //零时文件远程主机存放目录
#local_tmp      = ~/.ansible/tmp       //零时文件本地存放目录
#forks          = 5                    //默认开启的并发数
#poll_interval  = 15                   //默认轮询时间间隔
#sudo_user      = root                 //默认sudo用户
#ask_sudo_pass = True                  //是否需要sudo密码
#ask_pass      = True                  //是否需要密码
#host_key_checking = False             //首次连接是否检查key认证
#roles_path    = /etc/ansible/roles    //默认下载的Roles存放的目录
#log_path = /var/log/ansible.log       //执行日志存放目录
#module_name = command                 //默认执行的模块
#action_plugins     = /usr/share/ansible/plugins/action //action插件存放目录
#callback_plugins   = /usr/share/ansible/plugins/callback //callback插件存放目录
#connection_plugins = /usr/share/ansible/plugins/connection  //connection插件存放目录
#lookup_plugins     = /usr/share/ansible/plugins/lookup //lookup插件存放目录
#vars_plugins       = /usr/share/ansible/plugins/vars //vars插件存放目录
#filter_plugins     = /usr/share/ansible/plugins/filter //filter插件存放目录
#test_plugins       = /usr/share/ansible/plugins/test //test插件存放目录
#strategy_plugins   = /usr/share/ansible/plugins/strategy //strategy插件存放目录
#fact_caching = memory                 //getfact缓存的主机信息存放方式
#retry_files_enabled = False              
#retry_files_save_path = ~/.ansible-retry  //错误重启文件存放目录

配置文件的分类与优先级

Ansible只有一个配置文件ansible.cfg,但配置文件可以存在不同的位置,并且只有一个可用 (数字代表优先级,数字越小代表优先级越高) :

Ansible笔记_Ansible_06

配置文件选项

Ansible笔记_Ansible_07

Ansible笔记_Ansible_08

Ansible笔记_Ansible_09

官网配置参考网址

Ansible Configuration Settings — Ansible Documentation

Ansible笔记_Ansible_10

ansuble主机清单

1、 定义单独主机:
	## green.example.com#
	# blue.example.com#
	# 192.168.100.1
	# 192.168.100.10
2、 定义一个主机组[组名]把地址或主机名加进去
	[mysql_test]
	192.168.253.159
	192.168.253.160
	192.168.253.153

需要注意的是,这里的组成员可以使用通配符来匹配,这样对于一些标准化的管理来说就很轻松方便了。   我们可以根据实际情况来配置我们的主机列表,具体操作如下:

[root@server ~]# vim /etc/ansible/hosts
	[web]
	192.168.37.122
	192.168.37.133

3、 定义嵌套组
    [web-mysql]
       mysql_test
       web
4、 定义范围化ip
    172.16.[0:4].[2:254]

ansible 常用命令

/usr/bin/ansible  Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行 /usr/bin/ansible-doc  Ansible 模块功能查看工具 /usr/bin/ansible-galaxy  下载/上传优秀代码或Roles模块 的官网平台,基于网络的 /usr/bin/ansible-playbook  Ansible 定制自动化的任务集编排工具 /usr/bin/ansible-pull  Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高) /usr/bin/ansible-vault  Ansible 文件加密工具 /usr/bin/ansible-console  Ansible基于Linux Consoble界面可与用户交互的命令执行工具

其中,我们比较常用的是/usr/bin/ansible/usr/bin/ansible-playbook

ansible 命令详解

命令的具体格式如下:

ansible <host-pattern> [-f forks] [-m module_name] [-a args]

也可以通过ansible -h来查看帮助,下面我们列出一些比较常用的选项,并解释其含义:

-a MODULE_ARGS   #模块的参数,如果执行默认COMMAND的模块,即是命令参数,如: “date”,“pwd”等等 -k--ask-pass #ask for SSH password。登录密码,提示输入SSH密码而不是假设基于密钥的验证 --ask-su-pass #ask for su password。su切换密码 -K--ask-sudo-pass #ask for sudo password。提示密码使用sudo,sudo表示提权操作 --ask-vault-pass #ask for vault password。假设我们设定了加密的密码,则用该选项进行访问 -B SECONDS #后台运行超时时间 -C #模拟运行环境并进行预运行,可以进行查错测试 -c CONNECTION #连接类型使用 -f FORKS #并行任务数,默认为5 -i INVENTORY #指定主机清单的路径,默认为/etc/ansible/hosts --list-hosts #查看有哪些主机组 -m MODULE_NAME #执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数 -o #压缩输出,尝试将所有结果在一行输出,一般针对收集工具使用 -S #用 su 命令 -R SU_USER #指定 su 的用户,默认为 root 用户 -s #用 sudo 命令 -U SUDO_USER #指定 sudo 到哪个用户,默认为 root 用户 -T TIMEOUT #指定 ssh 默认超时时间,默认为10s,也可在配置文件中修改 -u REMOTE_USER #远程用户,默认为 root 用户 -v #查看详细信息,同时支持-vvv-vvvv可查看更详细信息

ansible 配置公私钥

上面我们已经提到过 ansible 是基于 ssh 协议实现的,所以其配置公私钥的方式与 ssh 协议的方式相同,具体操作步骤如下:

#1.生成私钥
[root@server ~]# ssh-keygen 
#2.向主机分发私钥
[root@server ~]# ssh-copy-id root@192.168.48.101
[root@server ~]# ssh-copy-id root@192.168.48.102

192.168.48.101为node01的ip地址

这样的话,就可以实现无密码登录,我们的实验过程也会顺畅很多。   注意,如果出现了一下报错:

-bash: ssh-copy-id: command not found

那么就证明我们需要安装一个包:

yum -y install openssh

把包安装上即可。

注意:先ssh 192.168.48.101和ssh 192.168.48.102各节点,生成缓存信息,才能进行主机连通性测试

ansible ping模块

主机连通性测试

我们使用ansible web -m ping命令来进行主机连通性测试,效果如下:

[root@server ~]# ansible web -m ping
192.168.48.101 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.48.102 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

这样就说明我们的主机是连通状态的。接下来的操作才可以正常进行。

用户级ansible环境构建

主机分布

主机名

ip

系统

内存

硬盘

controller

192.168.48.100

Centos7.9

4G

100G

node01

192.168.48.101

Centos7.9

4G

100G

node02

192.168.48.102

Centos7.9

4G

100G

创建student用户

三台机创建student用户

#创建student用户
useradd student
passwd student
123456

controller创建student用户工作目录

#切换student用户,创建工作目录,新建ansible.cfg配置文件,验证配置文件生效。
su student
cd 
#创建资产清单 
mkdir ansible
cat >> /home/student/ansible/inventory <<EOF
[servers]
192.168.48.101
192.168.48.102
EOF

controller编辑配置文件ansible.cfg

cd ansible
cat >> /home/student/ansible/ansible.cfg <<EOF
[defaults]
inventory=/home/student/ansible/inventory
remote_port=22
remote_user=root
#指定远程用户为root
ask_pass=True
EOF

验证清单主机存活(指定root)

验证清单主机存活 ,执行命令进行测试,可以看到在每次执行ansible时都会询问连接用户的密码(相 当于-K参数)

ansible all --list

[student@controller ansible]$ ansible all --list
SSH password:
  hosts (2):
    192.168.48.101
    192.168.48.102
[student@controller ansible]$
#成功

如果不想输入密码,那需要修改配置文件:

vi /home/student/ansible/ansible.cfg
······
ask_pass=False

Ansible笔记_Ansible_11

[student@controller ansible]$ ansible all --list
  hosts (2):
    192.168.48.101
    192.168.48.102
[student@controller ansible]$
#无输入密码选项

实例(指定student)

远程用户指定为普通用户(student)

[student@controller ansible]$ vim ansible.cfg
[defaults]
inventory=/home/student/ansible/inventory
remote_port=22
remote_user=student
#指定远程用户为student
ask_pass=False

这时候执行ping会报错

ansible all -m ping

Ansible笔记_Ansible_12

Ansible笔记_Ansible_13

这时候我们要配置免密登入(这里的密钥是student用户的,和root不一样,不会覆盖root用户的,这是在student用户下执行的命令)

[student@controller ansible]$ ssh-keygen
#回车三次
[student@controller ansible]$ ssh-copy-id student@192.168.48.101
#输入yes和node1的root密码

[student@controller ansible]$ ssh-copy-id student@192.168.48.102
#输入yes和node2的root密码

这是执行ping命令

ansible all -m ping

Ansible笔记_Ansible_14

测试提取文件

这个普通用户(student)并不能执行所有的操作,比如ansible以student身份登录,执行(ls /root)发普通用户没有权限,

ansible all -m shell -a "ls /root"

Ansible笔记_Ansible_15

解决这个问题就需要提权:sudo 提权

在受控主机(node01、node02)上执行visudo(配置 /etc/sudoers)

node01机子

[root@node01 ~]# visudo

Ansible笔记_Ansible_16

node02机子

[root@node02 ~]# visudo

Ansible笔记_Ansible_17

或者(node01和node02执行以下指令)

cat >>/etc/sudoers.d/student << EOF 
student          ALL=(ALL)        NOPASSWD: ALL
EOF

在控制主机(controller)上(student用户)修改ansible.cfg配置文件提权

[student@controller ansible]$ vim ansible.cfg
[defaults]
inventory=/home/student/ansible/inventory
remote_port=22
remote_user=student
ask_pass=False
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

Ansible笔记_Ansible_18

验证

ansible all -m shell -a "ls /root"

Ansible笔记_Ansible_19

#在控制节点的student经过sudo提权之后可以读取/root目录了

Ansible-常用模块

command模块

linux命令,不支持管道、重定向等,不建议使用

ansible all -m command -a "pwd"
ansible all -m command -a "ls"
ansible all -m command -a "cat /etc/passwd |grep student" #这个不能正常使用 ansible all -m command -a "echo bb >>/tmp/testansible"
ansible all -m command -a "cat /tmp/testansible"

#重定向也无法正常使用

课堂练习:

使用command命令查询各主机磁盘状态、查询内存状态

ansible all -m command -a "df -h"
ansible all -m command -a "free -m"

shell模块

支持管道、重定向等,常用模块

ansible all -m shell -a "cat /etc/passwd | grep student" #支持管道
ansible all -m shell -a "echo bb >>/tmp/testansible"
ansible all -m shell -a "cat /tmp/testansible"

\#支持重定向

课堂练习:

使用shell模块查看selinux状态

ansible all -m shell -a "getenforce"

通过shell模块批量关闭selinux

临时关闭:

ansible all -m shell -a "setenforce 0"

永久关闭:

ansible all -m shell -a "sed -ri 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config"

ansible all -m shell -a "reboot"

文件模块

copy模块

从主控端复制文件到远程主机

ansible-doc copy

常用参数

src:source源路径文件/目录。即要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是 相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制。

dest:destnation受管主机上的一个目标路径,即要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录(必须)

content:代替src,将本机指定内容传至远程主机并生成目标文件,相当于 echo 重定向内容到文件

mode:文件权限(chmod)

linux权限回顾

Ansible笔记_Ansible_20

owner:文件属主(chown) group:文件属组(chgrp) backup:在覆盖之前将原文件备份,备份文件包含时间信息。 directory_mode: 递归地设定目录的权限,默认为系统默认权限 force: 若目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标 主机的存放位置不存在该文件时,才复制。默认为yes

使用案例
  1. 复制dir1目录及其文件到受控主机/tmp/下(无斜杠-操作整个目录)

注:关于src目录加不加/的演示

#复制dir1目录及其文件到受控主机/tmp/下
su student
cd ~
ll
mkdir ansible
cd ansible/
mkdir dir1
echo "123" >dir1/file1
ansible 192.168.48.101 -m copy -a "src='dir1' dest=/tmp/"

Ansible笔记_Ansible_21

查看受控主机是否复制成功

Ansible笔记_Ansible_22

成功

2.仅复制dir1目录下的文件(有斜杠-操作目录下的文件,不复制目录)

ansible 192.168.48.101 -m copy -a"src='dir1/' dest=/tmp/"

Ansible笔记_Ansible_23

练习
  1. 将控制主机的copyfile文件复制到受管主机的 /tmp 目录

echo '123' > copyfile
ansible 192.168.48.101 -m copy -a 'src=copyfile dest=/tmp'

Ansible笔记_Ansible_24

  1. 直接在受管主机上生成一个指定内容的文件文件

ansible 192.168.48.101 -m copy -a "cnotallow='test copy\n' dest=/tmp/f1"

Ansible笔记_Ansible_25

  1. 在受管主机上生成指定属性和内容的文件

ansible 192.168.48.101 -m copy -a "cnotallow='test copy 2\n' dest=/tmp/f2 mode=0644 owner=student group=student"

Ansible笔记_Ansible_26

  1. 在文件覆盖前生成备份文件

ansible 192.168.48.101 -m copy -a "content='test copy 1\n' dest=/tmp/f1 backup=yes"

ansible 192.168.48.101 -m shell -a "ls -l /tmp/f1*"

Ansible笔记_Ansible_27

Ansible笔记_Ansible_28

script模块

在远程主机上运行ansible服务器上的脚本,优点是不需手动传送脚本至每个服务器。

其实是ansible自动传到远程主机、执行然后再删除脚本:copy+shell+delete

cat >> tesh.sh << EOF
#!/bin/bash 
echo hello
EOF
ansible all -m script -a tesh.sh

Ansible笔记_Ansible_29

执行结果显示了每台主机的执行情况。

CHANGED 表示执行过程中发生了变化,即脚本被成功执行。

rc 字段显示返回码为 0,表示执行成功。

stderr 字段显示了标准错误输出,其中包含了连接关闭的信息。

stdout 字段显示了标准输出,其中包含了脚本执行的结果,即 "hello"。

cat >>  ansible_ntp.sh << EOF
#!/bin/bash
systemctl status ntpd >/dev/null 2>&1
if [ \$? == 0 ]; then
	echo "ntp service has been installed"
	exit
fi
yum install -y ntp >/dev/null 2>&1
if [ \$? == 0 ]; then
	systemctl start ntpd
	systemctl enabled ntpd >/dev/null 2>&1
	sleep 5
	ntpq -p
else
	echo "ntp service install failed,check network or yum"
fi
EOF

这条命令的意思就是在后台执行这个程序,并将错误输出2重定向到标准输出1,然后将标准输出1全部放 到/dev/null文件,也就是清空.
所以可以看出" >/dev/null 2>&1 "常用来避免shell命令或者程序等运行中有内容输出。

chmod 777 ansible_ntp.sh

ansible all -m script -a "ansible_ntp.sh"

Ansible笔记_Ansible_30

fetch模块

从受管主机上,拉取文件到控制节点(目前不支持目录,可以先打包,再提取文件)

常见参数

dest:控制节点的保存路径

src:受管节点要拉取文件的路径(必须是文件,不能是目录)

flat:直接保存到目标指定位置,而不是在受管主机名下的文件路径中。

使用案例

  1. 从受管主机拉取指定文件

ansible 192.168.48.101 -m fetch -a "src=/etc/hosts dest=/home/student/ansible"

索取到本地目录下的文件会自动生成与目标主机的域名或IP地址的目录存放索取的文件

Ansible笔记_Ansible_31

  1. 直接拉取受管主机文件到控制节点指定位置

flat:直接保存到目标指定位置,而不是在受管主机名下的文件路径中。

ansible 192.168.48.101 -m fetch -a "src=/etc/hosts dest=/home/student/ansible/file1 flat=yes"

Ansible笔记_Ansible_32

  1. 打包目录并所有内容到控制节点指定位置

ansible 192.168.48.101 -m shell -a 'pwd'

ansible 192.168.48.101 -m shell -a 'tar cf test.tar.gz /var/log'
ansible 192.168.48.101 -m shell -a 'ls -l /home/student/'
ansible 192.168.48.101 -m fetch -a "src=/home/student/test.tar.gz dest=/home/student/ansible/ flat=yes"

Ansible笔记_Ansible_33

Ansible笔记_Ansible_34

file模块

file 模块可以帮助我们完成一些对文件的基本操作。比如,创建文件或目录、删除文件或目录、修改文 件权限等。

常用参数

mode: 定义文件/目录的权限,比如,如果想要将文件权限设置为"rw-r-x---",则可以使用mode=650进行 设置,或者使用mode=0650,效果也是相同的。 owner: 定义文件/目录的所有者,属主对应的用户必须在远程主机中存在,否则会报错。 group: 定义文件/目录的属组,属组对应的组必须在远程主机中存在,否则会报错。 path: 必选项,定义受管主机的文件/目录的路径 recurse: 递归地设置文件的属性,只对目录有效 src: 要被链接的源文件的路径,只应用于state=hard/link的情况 dest: 被链接到的路径,只应用于state=hard/link的情况。 state: 操作方法 directory:如果目录不存在,创建目录 file:即使文件不存在,也不会被创建(只能指定已存在的文件) touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 link:创建软链接 hard:创建硬链接 absent:删除目录、文件或者取消链接文件,相当于rm -rf force: 只应用于state=hard/link的情况,若需要在两种情况下强制创建软链接,一种是源文件不存在但 之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选 项:yes|no

使用案例

  1. 创建指定文件属性的空目录

ansible 192.168.48.101 -m file -a "path=/tmp/dir2 state=directory owner=student group=student mode=0755"

ansible 192.168.48.101 -m shell -a "ls -l /tmp/"

Ansible笔记_Ansible_35

  1. 创建指定文件属性的空文件

ansible 192.168.48.101 -m file -a "path=/tmp/file2 state=touch owner=student group=student mode=0755"
ansible 192.168.48.101 -m shell -a "ls -l /tmp/"

Ansible笔记_Ansible_36

注意:为何不能用state=file

file:即使文件不存在,也不会被创建(只能指定已存在的文件)

file3不存在

ansible 192.168.48.101 -m file -a "path=/tmp/file3 state=file owner=student group=student mode=0755"

Ansible笔记_Ansible_37

如果指定file1(已存在)呢(将root用户属组改成student)

ansible 192.168.48.101 -m file -a "path=/tmp/file1 state=file owner=student group=student mode=0755"

Ansible笔记_Ansible_38

  1. 删除目录、删除文件

ansible 192.168.48.101 -m file -a "path=/tmp/dir1 state=absent"
ansible 192.168.48.101 -m file -a "path=/tmp/file1 state=absent"
ansible 192.168.48.101 -m shell -a "ls -l /tmp/"

Ansible笔记_Ansible_39

  1. 创建链接文件

软链接:快捷方式 file2→file1(link)

生成file1(如果已存在就忽略这步)

ansible 192.168.48.101 -m copy -a "content='123 \n' dest=/tmp/file1"

Ansible笔记_Ansible_40

生成软链接

ansible 192.168.48.101 -m file -a "src=/tmp/file1 path=/tmp/file2 state=link force=true"

Ansible笔记_Ansible_41

取消软连接

ansible 192.168.48.101 -m file -a "path=/tmp/file2 state=absent"

Ansible笔记_Ansible_42

硬链接:指向同一个inode

file3→file1(hard)

file3不存在

ansible 192.168.48.101 -m file -a "src=/tmp/file1 path=/tmp/file3 state=hard"

Ansible笔记_Ansible_43

课堂练习

1、在/tmp/下创建目录ansiblefile,并在该文件夹下创建test.txt文件,指定属主student,赋予权限0700

ansible all -m shell -a "useradd student"	#创建一个用户与组
ansible 192.168.48.101 -m file -a 'path=/tmp/ansiblefile state=directory'
ansible 192.168.48.101 -m file -a 'path=/tmp/ansiblefile/test.txt state=touch owner=student mode=0700'

Ansible笔记_Ansible_44

2、删除远程机器上的指定文件或目录(删除远程主机上的文件:/tmp/ansiblefile/test.txt

ansible 192.168.48.101 -m file -a 'path=/tmp/ansiblefile/test.txt state=absent'

Ansible笔记_Ansible_45

lineinfile模块

增加或修改文件内容(以行为单位做流式处理),该模块在自动化运维中非常重要,他可以通过正则表达 式替换指定文本;例如开启一些配置选项等可以新加一行文本,或者是删除指定的行,本命令一定认真掌握 下来.

\常见参数\

path:必须参数,远端文件路径

line:必须参数,修改后的内容(按行写入),追加

regexp:(定位)匹配正则语句,与要过滤的关键字

state:文件修改状态(present 添加生效 / absent 删除)

replace:替换文件内容

create:当文件不存在时,是否创建对应文件

backup:若文件更新时创建备份副本

insertafter:在指定位置的下一行插入(定位)

insertbefore:在指定位置的上一行插入(定位)

使用案例

假设前提:将控制节点的/etc/selinux/config文件复制到受管主机192.168.48.101,另存为/tmp/selinux文件

ansible 192.168.48.101 -m copy -a "src=/etc/selinux/config dest=/tmp/selinux"
ansible 192.168.48.101 -m shell -a "cat /tmp/selinux"

Ansible笔记_Ansible_46

Ansible笔记_Ansible_47

  1. 修改文件内容:考虑两个问题,修改哪个部分,修改成什么内容

修改SELINUX开头的行,更新内容为:SELINUX=disabled

ansible 192.168.48.101 -m lineinfile -a "path=/tmp/selinux regexp='^SELINUX=' line='SELINUX=disabled' "
ansible 192.168.48.101 -m shell -a "cat /tmp/selinux"

Ansible笔记_Ansible_48

2.增加文件内容:考虑两个问题,增加什么内容,增加在哪个位置(上一行或下一行)

在SELINUX开头的行,在下一行加个注释,并且应用生效

ansible 192.168.48.101 -m lineinfile -a "path=/tmp/selinux insertafter='^SELINUX=' line='##Disabled SELINUX' "

Ansible笔记_Ansible_49

通过正则匹配查找/tmp/selinux文本,并在文本末尾插入一行##end

ansible 192.168.48.101 -m lineinfile -a 'path=/tmp/selinux regexp="EOF" line="#end"'

Ansible笔记_Ansible_50

3.删除文件内容:把刚才添加的“##disabled selinux”注释去掉(删除所在行)

ansible 192.168.48.101 -m lineinfile -a "path=/tmp/selinux regexp='^##Disa' state=absent"
ansible 192.168.48.101 -m shell -a "cat /tmp/selinux"

Ansible笔记_Ansible_51

Ansible笔记_Ansible_52

  1. 备份文件:在SELINUX开头的行,前一行加个注释,并且生效,生成备份文件

ansible 192.168.48.101 -m lineinfile -a "path=/tmp/selinux insertbefore='^SELINUX=' line='##Disabled SELINUX' backup=yes state=present"
ansible 192.168.48.101 -m shell -a "ls -l /tmp/selinux*"

Ansible笔记_Ansible_53

Ansible笔记_Ansible_54

课堂练习:

修改192.168.48.101主机的/etc/hosts文件,

1、增加内容192.168.48.102 node03,验证增加成功

ansible 192.168.48.101 -m lineinfile -a "path=/etc/hosts line='192.168.48.102 node03' "
ansible 192.168.48.101 -m shell -a "cat /etc/hosts"

Ansible笔记_Ansible_55

2、匹配以192开头的行,修改192.168.48.102 对应的 域名为node02,验证增加成功

ansible 192.168.48.101 -m lineinfile -a "path=/etc/hosts regexp='^192' line='192.168.48.102 node02' "

Ansible笔记_Ansible_56

3、匹配以192开头的行之前增加 192.168.48.101 node01 ,验证增加成功

ansible 192.168.48.101 -m lineinfile -a "path=/etc/hosts insertbefore='^192' line='192.168.48.101 node01' "

Ansible笔记_Ansible_57

4、在文档结尾增加 192.168.48.100 controller

ansible 192.168.48.101 -m lineinfile -a 'path=/etc/hosts regexp="EOF" line="192.168.48.100 controller"'

Ansible笔记_Ansible_58

5、删除步骤1-3加入的内容

ansible 192.168.48.101 -m lineinfile -a "path=/etc/hosts regexp='^192.' state=absent"
ansible 192.168.48.101 -m shell -a "cat /etc/hosts"

Ansible笔记_Ansible_59

软件包模块

yum模块

\常用参数\

name:软件包名称(必填)

state:

latest(更新到最新)

present(安装)

version(版本)

absent(卸载)

查看是否安装了某个服务 rpm -qa|grep httpd

\使用案例\

给node01安装httpd服务

ansible 192.168.48.101 -m yum -a 'name=httpd state=present'

Ansible笔记_Ansible_60

验证安装

ansible 192.168.48.101 -m shell -a 'rpm -qa|grep httpd'

卸载 state=absent

ansible 192.168.48.101 -m yum -a 'name=httpd state=absent'

更新软件state=latest

ansible 192.168.48.101 -m yum -a 'name='httpd' state=latest'

系统模块

user模块

常用参数

comment:注释信息
group:主要组
groups:附加组
state:present/absent
generate_ssh_key:生成SSH验证密钥
name:用户名
shell:Shell类型
uid:UID

使用案例

1、在node1上创建用户 test_user UID=1010

ansible 192.168.48.101 -m user -a "name=test_user  uid=1010 comment='ansible_test_user' shell=/bin/bash generate_ssh_key=yes  state=present"

ansible 192.168.48.101 -m shell -a 'id test_user'

Ansible笔记_Ansible_61

2、删除用户test_user(userdel test_user)

ansible 192.168.48.101 -m user -a "name=test_user  state=absent force=yes"
ansible 192.168.48.101 -m shell -a 'getent passwd |grep test_user'

Ansible笔记_Ansible_62

group组模块

1、创建组test_group (groupadd -g 1010 test_group)

ansible 192.168.48.101 -m group -a "name=test_group  gid=1010  state=present"
ansible 192.168.48.101 -m shell -a 'getent group|grep test_group'

Ansible笔记_Ansible_63

2、删除组test_group (groupdel test_group)

ansible 192.168.48.101 -m group -a "name=test_group   state=absent"
ansible 192.168.48.101 -m shell -a 'getent group|grep test_group'

Ansible笔记_Ansible_64

service模块

启用/启动/停止指定的服务

常用参数

name:服务名(确定服务存在)(必选项)
state:服务目标状态
	(state=started/stopped/restarted/...)(必选项)
enabled:是否开机启动(yes/no)

1、在node01上安装和启用httpd服务(相当于systemctl enable --now httpd)

安装

ansible 192.168.48.101 -m yum -a 'name=httpd state=present'

启用

ansible 192.168.48.101 -m service -a "name=httpd state=started  enabled=yes"

ansible 192.168.48.101 -m shell -a 'systemctl status httpd'

Ansible笔记_Ansible_65

Ansible笔记_Ansible_66

2、停止服务

ansible 192.168.48.101 -m service -a 'name=httpd state=stopped'

Ansible笔记_Ansible_67

3、重启服务

ansible 192.168.48.101 -m service -a 'name=httpd state=restarted'

Ansible笔记_Ansible_68

firewalld模块

常见参数

source:数据源(相当于--add-source)
interface:端口(相当于--add-port)
service:服务(相当于--add-service)
zone:关联区域(相当于--zone)
permanent:永久生效(相当于--permanent)
immediate:立即生效(相当于执行了firewall-cmd --reload)
state:防火墙规则状态(enabled | disabled)(必填项)
rich_rule:富规则(相当于--add-rich-rule='')

使用案例

1、添加基本规则

在node1中将http服务进行放行,并关联到public区域中,立即生效且永久生效

ansible 192.168.48.101 -m firewalld -a 'zone=public service=http permanent=yes immediate=yes state=enabled'

综合练习

(1)在node01上创建一个用户devops:

ansible node01 -m user -a "name=devops state=present"

Ansible笔记_Ansible_69

(2)在node01上创建一个目录 /devops,设置所属组、权限:

ansible node01 -m file -a "path=/devops state=directory owner=devops group=devops mode=0755"
 ansible node01 -m shell -a "ls -l /"

Ansible笔记_Ansible_70

(3)安装httpd服务,设定开机自启动,验证服务状态为启动:

ansible node01 -m yum -a "name=httpd state=present"
ansible node01 -m service -a "name=httpd state=started enabled=yes"

Ansible笔记_Ansible_71

Ansible笔记_Ansible_72

(4)创建一个文件 /devops/index.html 包含一行内容:DevOps:

ansible node01 -m copy -a "cnotallow='DevOps\n' dest=/devops/index.html"

Ansible笔记_Ansible_73

(5)创建软链接:/var/www/html/index.html 到 /devops/index.html:

ansible node01 -m file -a "src=/devops/index.html dest=/var/www/html/index.html state=link force=true"

Ansible笔记_Ansible_74

(6)验证软链接:

ansible node01 -m shell -a "ls -l  /var/www/html/index.html"

Ansible笔记_Ansible_75

(7)取消软链接,新建/var/www/html/index.html 文档,访问网页:

ansible node01 -m file -a "path=/var/www/html/index.html state=absent"
ansible node01 -m copy -a "content='Hello World' dest=/var/www/html/index.html"

Ansible笔记_Ansible_76

Ansible笔记_Ansible_77

使用浏览器访问http://192.168.48.101验证主页信息

Ansible-Playbook

介绍

playbook是由一个或多个"play"组成的列表 play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。 Task实际是调用ansible的一个module,将多个play组织在一个playbook中, 即可以让它们联合起来,按事先编排的机制执行预定义的动作 Playbook采用YAML语言编写

用户通过ansible命令直接调用yml语言写好的playbook,playbook由多条play组成
每条play都有一个任务(task)相对应的操作,然后调用模块modules,应用在主机清单上,通过ssh远程连接
从而控制远程主机或者网络设备

YAML语法

> 在单一档案中,可用连续三个连字号(---)区分多个档案。
  另外,还有选择性的连续三个点号( ... )用来表示档案结尾
> 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
> 使用#号注释代码
> 缩进必须是统一的,不能空格和tab混用,一般缩进2个空格
> 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
> YAML文件内容是区别大小写的,key/value的值均需大小写敏感
> 多个key/value可同行写也可换行写,同行使用:分隔,同一行使用 , 逗号分隔
> value可以是个字符串,也可是另一个列表[]
> 一个完整的代码块功能需最少元素需包括 name 和 task
> 一个name只能包括一个task
> YAML中不允许在双引号中出现转义符号,所以都是以单引号来避免转义符错误
> 使用 | 和 > 来分隔多行,实际上这只是一行。 
> YAML文件扩展名通常为yml或yaml

三种常见的数据交换格式

Ansible笔记_Ansible_78

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。
序列(Sequence)里的项用"-"来代表,Map里的键值对(字典)用":"分隔
示例
    name: John Smith
    age: 41
    gender: Male
    spouse:
      name: Jane Smith
      age: 37
      gender: Female
    children:
      - name: Jimmy Smith
        age: 17
        gender: Male
      - name: Jenny Smith
        age 13
        gender: Female

修改vim

vim ~/.vimrc
set nu       
set paste    
set cursorline 
set cursorcolumn 
autocmd FileType yaml setlocal ai et ts=2 sw=2 


set nu       #显示行号
set paste    #黏贴内容保留格式
set cursorline #行定位
set cursorcolumn #列定位
autocmd FileType yaml setlocal ai et ts=2 sw=2 
#FileType 代表文件类型,后边跟参数yaml,就是这个作用于yaml文件,编写其他文件时不起作用
#ts=2是tabstop=2的缩写,表示使用2个空格自动代替tab键
#et=expandtab 表示tab键的缩写
#sw=2 是shiftwidth=2的缩写,表示开启自动缩进对齐,缩进宽度为2个空格
#ai=auto indent   自动退格对齐\

将这段代码添加到 ~/.vimrc 文件中,以使 Vim 在启动时自动应用这些设置

playbook基础组件

一个简单的剧本模型(YAML语言)

1> 缩进:用两个空格缩进

2> 列表:用 -

3> 字典:key: value

--- 
- hosts: YYY          #待操作主机集,可以不写,执行时通过 -i 调用host文件
  remote_user: root  #在远端使用哪个用户执行
  tasks:              #任务集(必须)
  - name: task1       #只是一个文本提示,执行时会输出其中内容(例如输出Install httpd)
    module1:          #真正干活的部分,其实就是前面讲过的ansible各种模块
      argument1 : value1 
      argument2 : value2 
  - name: task2 
    module2:
      argument1 : value1 
      argument2 : value2 
...

解释:

Hosts:
    > playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。
      hosts用于指定要执行指定任务的主机,须事先定义在主机清单中

remote_user: 
    可用于Host和task中。
    也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;
    此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
    - hosts: all
      remote_user: root   (可省略,默认为root)  以root身份连接
      tasks:    指定任务
      - name: test connection
        ping:
          remote_user: magedu
          sudo: yes           默认sudo为root
          sudo_user:wang      sudo为wang

task列表和action
    任务列表task:由多个动作,多个任务组合起来的,每个任务都调用的模块,一个模块一个模块执行
    1> play的主体部分是task list,task list中的各任务按次序逐个在hosts中指定的所有主机上执行,
       即在所有主机上完成第一个任务后,再开始第二个任务

    2> task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。
   模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致

    3> 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。
   如果未提供name,则action的结果将用于输出

playbook书写风格

简单案例:

编写echo.yaml文件,内容如下

vim echo.yaml
---
- hosts: 192.168.48.102
  tasks:
  - name: 输出1
    shell: echo "1"
  - name: 输出2
    shell: echo "2"
...
#执行该剧本文件:
ansible-playbook echo.yaml

命令执行返回的结果:

第一行PLAY表示执行的主机或者主机组。 第二行TASK[Gathering Facts],在 Playbook 中并没有定义,这是Ansible自带的task 收集主机的信息,此功能非常实用,后面的任务中会详细讲解。这里仅需知晓task为Ansible自带的功能,可以通过Playbook中添加 gather_facts: no 进行关闭。 下面两个task是自行编辑的task,可以发现没有返回结果,但是当出现黄色的changed时代表执行或者修改成功。changed代表前后状态发生改变,例如使用copy模块,拷贝同一个东西,第一次执行成功的时候是changed状态,第二次再执行的时候就是ok状态。ok状态代表:Ansible检查了需要更改的内容发现前后没有变化,所以直接返回ok状态,实际上 Ansible并没有去执行该操作。最后代表状态,即 Playbook的执行结果。ok表示检查了但不需要操作的任务量。failed表示执行失败的数量,changRed代表状unreachable表示不可达的主机数态更改的数量,ok+changed 才代表执行完成的任务数量。

编写playbook

vim httpd.yaml
--- ##列出第一个play 
- name: Install httpd package and start httpd service ##标明 该play的用途 
  hosts: 192.168.142.101 ##指定对其运行play中任务的主机(必填项,指定多台主机可以使用分组,或者 , 分隔) 
  tasks: ##play的任务列表 
  - name: Install httpd package ##任务1的描述 
    yum: ##任务1调用yum模块,模块内容往下写 
      name: httpd ##参数1:yum模块需要使用的软件包 
      state: present ##参数2:安装软件包#以上任务等同于 ansible 192.168.142.101 -m yum -a "name=httpd state=present" 

  - name: Start httpd service ##任务2的描述 
    service: ##任务2调用服务模块 
      name: httpd ##参数1:service调用的服务名称 
      state: started ##参数2:service调用服务要达到的目标状态 
      enabled: yes ##参数3:调用的服务开机启动 
#以上任务等同于 ansible 192.168.142.101 -m service -a "name=httpd state=started enabled=yes"

Ansible笔记_Ansible_79

运行playbook

运行playbook的方式
    ansible-playbook <filename.yaml> ... [options]

常见选项
    --check -C       只检测可能会发生的改变,但不真正执行操作 
                     (只检查语法,如果执行过程中出现问题,-C无法检测出来)
                     (执行playbook生成的文件不存在,后面的程序如果依赖这些文件,也会导致检测失败)
    --list-hosts     列出运行任务的主机
    --list-tags      列出tag  (列出标签)
    --list-tasks     列出task (列出任务)
    --limit 主机列表 只针对主机列表中的主机执行
    -v -vv -vvv      显示过程

示例
    ansible-playbook hello.yaml --check 只检测
    ansible-playbook hello.yaml --list-hosts  显示运行任务的主机
    ansible-playbook hello.yaml --limit 192.168.142.101  限制主机
    ansible-playbook hello.yaml --list-tasks  显示运行任务的主机

1、在ansible工作目录运行 完整剧本:httpd.yaml

执行剧本
ansible-playbook playbooks/httpd.yaml
验证服务
ansible 192.168.142.101 -m shell -a 'rpm -qa |grep httpd'
ansible 192.168.142.101 -m shell -a 'netstat -ntulp |grep 80'

Ansible笔记_Ansible_80

2.提高输出的详细程度

Ansible笔记_Ansible_81

注:通常使用 ansible-playbook -v 即可。

Ansible笔记_Ansible_82

3.执行空运行(冒烟运行)

Ansible笔记_Ansible_83

Ansible笔记_Ansible_84

handlers+notify

Handlers 实际上就是一个触发器,是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作。任务都有状态changed或者ok,只有在任务执行状态为change时,才执行该任务调用的handler。

Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

示例1:

  1. 使用playbook安装httpd,并验证服务启动,查看httpd使用的端口

vim httpd3.yaml
---
- hosts: all
  remote_user: root

  tasks:
  - name: Install httpd
    yum:
      name: httpd
      state: present
  - name: ensure apache is running
    service:
      name: httpd
      state: started
      enabled: yes

ansible-playbook httpd3.yaml
ansible all -m shell -a 'systemctl status httpd'
ansible all -m shell -a 'netstat -tunlp|grep httpd'

  1. 在被控端(两台机)修改httpd的conf文件,监听端口改成8080

mkdir -p /root/ansible/files
cp /etc/httpd/conf/httpd.conf  /root/ansible/files
#如果前面httpd3运行成功,说明成功安装httpd,则httpd.conf会存在
vim /root/ansible/files/httpd.conf
#将Listen 80 修改为Listen 8080

  1. 修改剧本文件,增加拷贝配置文件的task,并重新执行剧本。

vim httpd4.yaml
---
- hosts: all
  remote_user: root
  tasks:   
  - name: Install httpd
    yum:
      name: httpd
      state: present
  - name: backup httpd.conf
    shell: cp /etc/httpd/conf/httpd.conf{,.bak}
  #备份原文件
  - name: copy configure file
    copy: 
      src: /root/ansible/files/httpd.conf 
      dest: /etc/httpd/conf/
      backup: yes
  #第二步修改了8080端口,将文件移回原处覆盖源文件
  - name: ensure apache is running
    service:
      name: httpd
      state: started
      enabled: yes

ansible-playbook httpd4.yaml
ansible all -m shell -a 'cat /etc/httpd/conf/httpd.conf|grep 8080'
ansible all -m shell -a 'systemctl status httpd'
ansible all -m shell -a 'netstat -tunlp|grep httpd'
#发现修改配置,但没有生效,因为没有重启httpd应用

  1. 增加handlers和notify

vim httpd4.yaml
---
- hosts: all
  remote_user: root
  tasks:   
  - name: Install httpd
    yum:
      name: httpd
      state: present
  - name: copy configure file
    copy: 
      src: /root/ansible/files/httpd.conf 
      dest: /etc/httpd/conf/
      backup: yes
    #调用触发列表里的 restart httpd任务,调用之后重启httpd,配置文件即刻生效
    notify: restart httpd
  - name: ensure apache is running
    service:
      name: httpd
      state: started
      enabled: yes
#触发器列表
  handlers:
  - name: restart httpd
    service: 
      name: httpd 
      state: restarted
        
        
ansible-playbook httpd4.yaml
ansible all -m shell -a 'netstat -tunlp|grep httpd'
发现端口是8080(即成功)

修改/root/ansible/files/httpd.conf ,将端口修改为8081,重新执行httpd4.yaml,并验证服务端口已经改变。

ansible-playbook httpd4.yaml
ansible all -m shell -a 'netstat -tunlp|grep httpd'

发现端口变成8081,说明只有在任务执行状态为change时,才执行该任务调用的handler。

TAGS

tage: 添加标签 可以指定某一个任务添加一个标签,添加标签以后,想执行某个动作可以做出挑选来执行,多个动作可以使用同一个标签

停止httpd服务

ansible all -m service -a 'name=httpd  state=stopped'
ansible all -m shell -a 'ss -tln |grep :8081'

[root@controller ~]# vi httpd5.yaml
---
- hosts: all
  remote_user: root
  tasks:
  - name: install httpd
    yum:
      name: httpd
      state: present
    tags: install #install标签
  - name: set listen8080
    shell: sed -i "s/Listen 80/Listen 8080/g" /etc/httpd/conf/httpd.conf
    tags: set8080 #设置8080标签
  - name: backup cofing
    copy:
      src: /etc/httpd/conf/httpd.conf
      dest: /etc/httpd/conf/httpd.conf
      backup: yes
    notify: restart httpd
    tags: backup #备份标签
  - name: 配置 httpd 服务
    service:
      name: httpd
      state: started
      enabled: yes
    tags: started #开启httpd服务标签
  handlers:
  - name: restart httpd
    service:
      name: httpd
      state: restarted
    tags: restart  #重启服务标签
...

ansible-playbook -tstarted httpd5.yaml   
#指定执行started 这个标签
ansible all -m shell -a 'ss -tln |grep :8080'
ansible-playbook -t install,conf httpd.yaml   
#指定执行install,backup 两个标签

管理变量

Ansible笔记_Ansible_85

变量定义:key=value 示例:http_port=80

变量调用方式: 1> 通过{{ variable_name }} 调用变量,且变量名前后必须有空格,有时用"{{ variable_name }}"才生效 (引号)

在playbook中定义

vars语句定义全局变量(该变量作用于整个Play)

vim test_vars.yaml

---
- name: test_var
  hosts: all
  vars:
    username: test_user1
  tasks:
  - name:  create user via a variable file
    user:
      name: "{{ username }}"    
      #冒号后面不能以{开头,不然会报语法错误,需要加上引号。
      state: present
#创建一个test_user1的用户
 
 ansible-playbook -v test_vars.yaml 
 
 ansible all -m shell -a 'getent passwd test_user1'

Ansible笔记_Ansible_86

执行结果:

Ansible笔记_Ansible_87

课堂练习

通过playbook中定义用户名和组名,实现变量引用,创建用户和组。

vim var.yaml
---
- hosts: all
  remote_user: root
  vars:
  - username: user1
  - groupname: group1
  tasks:
  - name: create group
    group: 
      name: "{{ groupname }}" 
      state: present
  - name: create user
    user: 
      name: "{{ username }}" 
      state: present

ansible-playbook -v var.yaml
ansible all -m shell -a 'getent passwd user1'
ansible all -m shell -a 'getent group group1'

开启防火墙
ansible all -m shell -a 'systemctl start firewalld'

vim firewall.yaml
---
- hosts: all
  remote_user: root
  vars:
  - http_port: 80
  tasks:
  - name: insert firewalld rule for httpd
    firewalld: 
      port: "{{ http_port }}/tcp" 
      permanent: true 
      state: enabled 
      immediate: yes
    
ansible-playbook -v firewall.yaml

ansible all -m shell -a 'systemctl stop firewalld'
ansible all -m shell -a 'firewall-cmd --query-port=80/tcp'

在独立的变量YAML文件中定义

当变量较多的时候,或者变量需要多个playbook重用的时候,可以把变量放到独立的文件中,通过关键字"var_files"把文件中定义的变量引用到playbook中。

vars_files 引用变量文件(只能所用于Play全局,不能在某个task中单独被引用)

vim var_file.yaml
username: test_user3

vim test_var_file.yaml
---
- name: test_var_file
  hosts: all
  vars_files:
  - /root/var_file.yaml
  tasks:
  - name:  create user via a variable file
    user:
      name: "{{ username }}"
      state: present
...
 
 ansible-playbook -v test_var_file.yaml
 
 ansible all -m shell -a 'getent passwd test_user3'

练习:将防火墙端口写入

将变量写进单独的配置文件中引用
test_var_file.yaml
---
- hosts: all
  remote_user: root
  vars_files:
  - /root/var_file.yaml
  tasks:
  - name: insert firewalld rule for httpd
    firewalld: 
      port: "{{ http_port }}/tcp" 
      permanent: true 
      state: enabled 
      immediate: yes
...
vim var_file.yaml
http_port: 78

ansible-playbook -v test_var_file.yaml
ansible all -m shell -a 'firewall-cmd --query-port=78/tcp'

远程主机上的系统变量(Facts事实)

ansible会通过setup模块来搜集主机的系统信息,这些搜集到的系统信息叫做Facts。

Ansible笔记_Ansible_88

每个playbook在执行前都会默认执行setup模块,所以这些facts信息是可以以变量的形式被使用。

查看Facts变量

ansible all -m setup 能查看到node节点的所有信息
ansible 192.168.48.101 -m setup |grep ansible_hostname
或者可以使用filter过滤信息
ansible all -m setup -a 'filter="ansible_hostname"'  查询主机名
ansible all -m setup -a 'filter="ansible_default_ipv4"'  查询ipv4地址
ansible all -m setup -a "filter=ansible_memory_mb"查询内存


其他常用信息列出如下:
ansible_all_ipv4_addresses:仅显示ipv4的信息。
ansible_devices:仅显示磁盘设备信息。
ansible_distribution:显示是什么系统,例:centos,suse等。
ansible_distribution_major_version:显示是系统主版本。
ansible_distribution_version:仅显示系统版本。
ansible_machine:显示系统类型,例:32位,还是64位。
ansible_eth0:仅显示eth0的信息。
ansible_hostname:仅显示主机名。
ansible_kernel:仅显示内核版本。
ansible_lvm:显示lvm相关信息。
ansible_memtotal_mb:显示系统总内存。
ansible_memfree_mb:显示可用系统内存。
ansible_memory_mb:详细显示内存情况。
ansible_swaptotal_mb:显示总的swap内存。
ansible_swapfree_mb:显示swap内存的可用内存。
ansible_mounts:显示系统磁盘挂载情况。
ansible_processor:显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus:显示cpu个数(只显示总的个数)。

使用Facts变量

vim var2.yaml
---
- hosts: all
  remote_user: root
  tasks:
  - name: create log file
    file: 
      name: /root/{{ ansible_hostname }} 
      state: touch

ansible-playbook var2.yaml

ansible all -m shell -a 'ls /root|grep node*'

复杂Facts变量的使用

Ansible笔记_Ansible_89

方式1:使用中括号

{{ ansible_date_time["date"] }}

方式2:使用点号(推荐)

{{ ansible_date_time.date }}

vim var2.yaml
---
- hosts: all
  remote_user: root
  tasks:
  - name: 22
    copy:
      content: "{{ ansible_date_time.date }}"
      dest: /tmp/f1

ansible-playbook var2.yaml

ansible all -m shell -a 'cat /tmp/f1'

关闭Facts

搜集facts会消耗额外时间,可以在剧本中设置是否开启和关闭facts搜集。

开启gather_facts:yes,关闭gather_facts:no

Ansible笔记_Ansible_90

在/etc/ansible/hosts(主机清单)中定义变量

普通变量:主机组中主机单独定义,优先级高于公共变量(单个主机 ) 公共(组)变量:针对主机组中所有主机定义统一变量(一组主机的同一类别)

可以是主机级别或者是主机组级别的

定义主机级别变量

vim  /etc/ansible/hosts
[all]
192.168.48.101 username=test_user3   #主机级别变量
192.168.48.102 username=test_user4

编辑剧本文件

vim test_vars2.yaml
---
- name: test inventory vars
  hosts: all
  tasks:
  - name:  create user via a variable file
    user:
      name: "{{ username }}"
      state: present

ansible-playbook -v test_vars2.yaml 
 
ansible all -m shell -a 'getent passwd test_user3'
ansible all -m shell -a 'getent passwd test_user4'

主机组级别定义变量(相对于主机级别定义的变量,优先级较低)

vim  /etc/ansible/hosts
[all]
192.168.142.101 username=test_user3   #主机级别变量
192.168.142.102   

[all:vars]
username=test_user5

ansible-playbook -v test_vars2.yaml 
发现第一台主机不变,第二台主机创建新的用户test_user5,证明主机组变量比主机变量优先级低

通过命令行指定变量

ansible-playbook -e 变量 剧本(优先级最高)

ansible-playbook -v -e username=test_user10 test_vars2.yaml

Ansible笔记_Ansible_91

安装httpd服务

示例:test_vars3.yaml 
---
- hosts: all
  remote_user: root
  tasks:
  - name: install package
    yum:
      name: "{{ pkname }}"
      state: present
  - name: start service
    service:
      name: "{{ pkname }}"
      state: started
      enabled: yes


ansible-playbook –e pkname=httpd test_vars3.yaml

示例:test_vars3.yaml 
---
- hosts: all
  remote_user: root
  tasks:
  - name: install package
    yum: 
      name: "{{ pkname1 }}" 
      state: present
  - name: install package
    yum: 
      name: "{{ pkname2 }}" 
      state: present
  
ansible-playbook -e 'pkname1=httpd pkname2=tree' -v test_vars3.yaml

复杂变量的使用

数组

如果我们定义变量,而这些值都属于同一类型的元素,那么我们必定要用数组。

例如:

vim test_com_var.yaml

---
- hosts: all
  vars:
    user_name:
    - test_user11
    - test_user12
    - test_user13
    - test_user14
  tasks:
  - name: create users
    user:
      name: "{{ user_name[1] }}"
      state: present

Ansible笔记_Ansible_92

验证:ansible-playbook -v test_com_var.yaml

Ansible笔记_Ansible_93

注意:在用user模块建用户的时候,只能调用数组中的某一个值,不能全部调用,否则报错“用户名不合法”

Ansible笔记_Ansible_94

Ansible笔记_Ansible_95

字典(dictionary)

如果我们的变量信息中具备多种不同的元素时,采用字典。

例如:

vim test_com_var.yaml

---
- name: test_dict
  hosts: all
  vars:
    user_info:
      test_user20:
        name: test_user20
        shell: /bin/bash
        comment: test_user20
      test_user21:
        name: test_user21
        shell: /bin/bash
        comment: test_user21
  tasks:
  - name: create users via dict
    user:
      name: "{{ user_info['test_user20']['name'] }}"
      shell: "{{ user_info['test_user20']['shell'] }}"
      state: present

Ansible笔记_Ansible_96

Ansible笔记_Ansible_97

变量引用的另一种写法:引用对象写法(python语法)

Ansible笔记_Ansible_98

注意:以点作为分隔(引用对象)这种方式,可能会和python本身的语义引起冲突,所以不建议使用这种方式

注册变量

注册变量是指将一个任务(task)的输出结果定义到一个变量中,这个变量就可以在随后的任务中像普通变量一样使用。 很多情况下,注册变量用来收集shell的执行结果,结果中包含标准输入和标准输出。接下来使用shell模块执行命令将命令结果传入名为var_echo 的变量并使用debug进行检测。 register 的使用形如 register: varname,即 register模块后直接加变量名即可,而register这一行仅仅需要写在需要收集输出的那一行下即可。

案例:

vim test_com_var.yaml

---
- name: test_dict
  hosts: all
  vars:
    user_info:
      test_user20:
        name: test_user20
        shell: /bin/bash
        comment: test_user20
      test_user21:
        name: test_user21
        shell: /bin/bash
        comment: test_user21
  tasks:
  - name: create users via dict
    user:
      name: "{{ user_info.test_user21.name }}"
      shell: "{{ user_info.test_user21.shell }}"
      state: present

ansible-playbook test_com_var.yaml

执行结果如下:

Ansible笔记_Ansible_99

修改剧本文件,加入debug模块

vim test_com_var.yaml

- name: test_dict
  hosts: all
  vars:
    user_info:
      test_user20:
        name: test_user20
        shell: /sbin/nologin
        comment: test_user20
      test_user21:
        name: test_user21
        shell: /sbin/nologin
        comment: test_user21
  tasks:
  - name: create users via dict
    user:
      name: "{{ user_info.test_user21.name }}"
      shell: "{{ user_info.test_user21.shell }}"
      state: present
    register: user_result

  - name: debug result of user creation
    debug:
      msg: "{{ user_result }}"

      
ansible-playbook test_com_var.yaml

运行结果:

Ansible笔记_Ansible_100

可以引用结果中的部分元素(user_result['uid'] / user_result.uid)

vim test_com_var.yaml

- name: test_dict
  hosts: all
  vars:
    user_info:
      test_user20:
        name: test_user20
        shell: /sbin/nologin
        comment: test_user20
      test_user21:
        name: test_user21
        shell: /sbin/nologin
        comment: test_user21
  tasks:
  - name: create users via dict
    user:
      name: "{{ user_info.test_user21.name }}"
      shell: "{{ user_info.test_user21.shell }}"
      state: present
    register: user_result

  - name: debug result of user creation
    debug:
      msg: "{{ user_result.uid }}"
      
  ansible-playbook test_com_var.yaml

运行结果:

Ansible笔记_Ansible_101

可以对输出结果进行迭代引用(用register存在多个变量中)

vim test_com_var.yaml
---
- name: test_dict
  hosts: all
  vars:
    user_info:
      test_user20:
        name: test_user20
        shell: /sbin/nologin
        comment: test_user20
      test_user21:
        name: test_user21
        shell: /sbin/nologin
        comment: test_user21
  tasks:
  - name: create users via dict
    user:
      name: "{{ user_info.test_user21.name }}"
      shell: "{{ user_info.test_user21.shell }}"
      state: present
    register: user_result

  - name: debug result of user creation
    debug:
      msg: "{{ user_result.uid }}"
    register: shell_result
  
  - name: debug result of shell
    debug:
      msg: "{{ shell_result }}"
      
  ansible-playbook test_com_var.yaml

Ansible笔记_Ansible_102

Ansible Vault(Ansible 保管箱)

作用:加密敏感的数据、密码等信息,通常情况下都是定义在变量内的敏感信息。

应用的情景:

1> 加密变量文件(敏感数据、密码信息等)

2> 加密证书

命令:ansible-vault

命令用法:

创建一个加密文件:

ansible-vault create sec.yaml

Ansible笔记_Ansible_103

使用vim sec.ym或者cat sec.yaml只能看到加密后的内容

Ansible笔记_Ansible_104

如何查看加密过的文件内容:

Ansible笔记_Ansible_105

如何在剧本中调用加密文件

vim test_vault.yaml

---
- name: Create users via vault
  hosts: all
  vars_files:
  - /root/sec.yaml
  tasks:
  - name: Create users
    user:
      name: "{{ username }}"
      state: present

执行剧本时报错

Ansible笔记_Ansible_106

解决方法:

方法一:ansible-playbook 命令时候添加--ask-vault-pass参数

ansible-playbook --ask-vault-pass test_vault.yaml

Ansible笔记_Ansible_107

方法二:ansible-playbook --vault-id @prompt test_vault.yaml(2.3之后使用,建议)

Ansible笔记_Ansible_108

方法三:ansible-playbook --vault-password-file=pass.yaml test_vault.yaml

(纯文本形式的密码存放在文件中,只能单行写一个密码,需要对该密码文件加强安全措施)

echo 123456 > pass.yaml

Ansible笔记_Ansible_109

解密

Ansible笔记_Ansible_110

加密一个已存在的文件

Ansible笔记_Ansible_111

重置加密文件的密码

Ansible笔记_Ansible_112

编辑已存在的加密文件

Ansible笔记_Ansible_113

Tips:如果我们使用加密文件保存变量、密码等敏感数据,最好采用隐藏文件来存放,增强安全性。

Ansible笔记_Ansible_114

Ansible笔记_Ansible_115

ansible-playbook --vault-password-file=.pass.yaml  test_vault.yaml

Ansible笔记_Ansible_116

综合实践

编辑剧本文件实现以下功能:

0、设置主机组 all

1、设置变量 定义nginx服务端口为8081

2、关闭facts

3、调用service模块,卸载受控端的httpd

4、调用SELinux模块,关闭selinux

5、调用yum模块安装epel源

6、调用yum模块安装nginx

7、调用lineinfile模块修改nginx配置文件中的监听端口,使用自定义的服务端口变量,并将结果注册到 port_result

8、调用service模块启动nginx,并设置为开机自启动

9、调用debug模块,msg信息为port_result

10、验证受控端服务及端口

---
- hosts: all
  gather_facts: no
  vars: 
    nginx_port: "8081"
  tasks:   
  - name: uninstall httpd
    yum:
      name: httpd
      state: absent
  - name: stop selinux
    selinux:
      state: disabled
  - name: install epel
    yum:
      name: epel-release
      state: present
  - name: 
    yum:
      name: nginx
      state: present
  - name: set nginx_port
    lineinfile:
      path: /etc/nginx/nginx.conf
      regexp: "        listen       80;"
      line: "        listen       {{ nginx_port }};"
    register: port_result   
  - name: start nginx
    service:
      name: nginx
      state: started
      enabled: yes
  - name: debug msg
    debug:
      msg: "{{ port_result }}"


ansible-playbook  install_nginx.yaml -C

ansible-playbook install_nginx.yaml  

ansible all -m shell -a  "ps aux |grep nginx "  

ansible all -m shell -a  "netstat -lntp |grep nginx "

Ansible笔记_Ansible_117

Ansible笔记_Ansible_118

Ansible-templates

JINJA2语法简要介绍

Jinja2语言,支持的数据类型:

字符串:使用单引号或双引号
    数字:整数,浮点数
    列表:[item1, item2, ...]
    元组:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布尔型:true/false

支持的运算及操作:

算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When

Playbook的进阶应用

使用when实现条件判断

条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试。剧本中不能使用if判断,需要使用when判断。

when语句:在task后添加when子句即可使用条件测试,可以使用facts或playbook中定义的变量,支持Jinja2表达式语法

示例:

tasks:
  - name: "shutdown RedHat flavored systems"
    command: /sbin/shutdown -h now
    when: ansible_os_family == "RedHat"  当系统属于红帽系列,执行command模块,注意:'所有变量'都可以直接在条件语句中使用,而无需使用双大括号

也可以使用多个when进行多条件判断,等效于and。

vim test_when.yml
---
- hosts: all
  tasks:
  - name: copy file
    copy:
      src: /etc/hosts
      dest: /root/hosts_when
    when: ansible_hostname is match "node1"		#when支持通配符

ansible all --list
ansible-playbook  test_when.yml
ansible all -m shell -a "ls -l /root/hosts_when"

使用with_items实现迭代

迭代:当有需要重复性执行的任务时,可以使用迭代机制 > 对迭代项的引用,固定变量名为"item"

要在task中使用with_items给定要迭代的元素列表, > 列表格式: 字符串 字典

示例:打印1、2、3

vim test_items.yml

---
- name: add serveral users
  gather_facts: no
  hosts: all
  tasks:
  - name: test loop
    debug: 
      msg: "name --- {{ item }}" #{{ item }} 系统自定义变量
    with_items:   ##with_items定义{{ item }} 的值和个数,      一般放到模块的末尾,与模块同一缩进级别    
    - one
    - two
    - three

示例:创建用户

vim test_items.yml

---
- name: add serveral users
  hosts: all
  tasks:
  - user:
      name: "{{ item  }}"  #{{ item }} 系统自定义变量
      state: present
    with_items:           ##with_items定义{{ item }} 的值和个数,一般放到模块的末尾,与模块同一缩进级别    
    - testuser1
    - testuser2

ansible all --list
ansible-playbook  test_items.yml
ansible all -m shell -a "getent passwd testuser1"

上面语句的功能等同于下面的语句:
- name: add user testuser1
  user: name=testuser1 state=present 
- name: add user testuser2
  user: name=testuser2 state=present

示例:拷贝多个文件

touch /root/1.txt /root/2.txt

vim test_items2.yml
---
- name: copy serveral files
  hosts: all
  tasks:
  - copy:
      src: /root/{{ item  }}
      dest: /etc/{{ item }}
    with_items:          
    - 1.txt
    - 2.txt

ansible-playbook  test_items2.yml
ansible all -m shell -a "ls -l /etc/*.txt"

示例:迭代字典

with_items中可以使用元素还可为hashes
示例:
vim test_items3.yml
---
- name: add several users
  gather_facts: no
  hosts: all
  tasks:
  - user:
      name: "{{ item.name }}"
      state: present
      groups: " {{ item.groups }}"
    with_items:
    - { name: 'testuser3', groups: 'wheel' }
    - { name: 'testuser4', groups: 'root' }


ansible-playbook  test_items3.yml
ansible all -m shell -a "getent passwd testuser3"
ansible all -m shell -a "id testuser3"
ansible all -m shell -a "getent passwd testuser4"
ansible all -m shell -a "id testuser4"

课堂作业:使用with—items拷贝多个文件

要求:item列表条目为字典类型,包含src、dest、mode3个键值对,使用with_items实现多个文件的拷贝,并赋予设定的权限。

touch /root/3.txt /root/4.txt
vim test_items4.yml
---
- name: copy several files
  hosts: all
  tasks:
  - copy:
      src: "{{ item.src }}"
      dest: "{{ item.dest }}"
      mode: "{{ item.mode }}"
    with_items:          
    - { src: "/root/3.txt", dest: "/root/", mode: "0644" }
    - { src: "/root/4.txt", dest: "/root/", mode: "0644" }

ansible-playbook  test_items4.yml
ansible all -m shell -a "ls -l /root/*.txt"

when和with items组合使用

当when和with_items一起使用的时候,每个项都会单独被when语句处理

vim test_when_items.yml
---
- hosts: all
  tasks:
  - command: echo {{ item }}
    with_items: [ 1,2,3,4,5,6,8,10]
    when: item > 5
         
 ansible-playbook test_when_items.yml

templates 模板

templates功能:根据模板文件动态生成对应的配置文件,命名必须以.j2结尾,支持jinja2语法。

在呈现 JINJA2模板时,文件中引用的变量和表达式被替换为对应的值。模板中使用的变量可以在 Playbook 的 vars 部分中指定。可以将受管主机的事实用作模板中的变量。

分隔符使用规范:

{% EXPR %}:用于表达式或逻辑(如循环、判断等)

{{ EXPR }}:用于向最终用户输出表达式或变量的结果。在呈现时将被替换为一个或多个值,对最终用户可见。

{# COMMENT #},用于注释,不会出现在最终文件中。

templates的使用场景

在实际的工作中由于每台服务器的环境配置都可能不同,但是往往很多服务的配置文件都需要根据服务器环境进行不同的配置,比如Nginx最大进程数、Redis最大内存等。

为了解决这个问题可以使用Ansible的template模块,该模块和copy模块作用基本一样,都是把管理端的文件复制到客户端主机上,但是区别在于template模块可以通过变量来获取配置值,支持多种判断、循环、逻辑运算等,而copy只能原封不动的把文件内容复制过去。

示例:httpd.conf的templates模板

创建并编辑httpd.conf.j2文件

yum -y install httpd
rpm -qa httpd
 
cp /etc/httpd/conf/httpd.conf /root/httpd.conf.j2
 
vim /root/httpd.conf.j2
 
---------42行----------
Listen {{port}}
 
----------95行---------
ServerName {{domain}}
 
vim /etc/ansible/hosts
 
[websrvs]
192.168.142.101 port=80 domain=www.node1.com
192.168.142.102 port=81 domain=www.node2.com

卸载受控机上的httpd服务

ansible websrvs -m shell -a 'yum remove -y httpd'
ansible websrvs -m shell -a 'yum remove -y nginx'

新建yaml文件

cd /root
vim a.yaml
---
- hosts: websrvs
  remote_user: root
  vars:
  - package: httpd
  - service: httpd
  tasks:
  - name: install service
    yum:
      name: "{{ package }}"
      state: latest

  - name: httpd.conf
    template:
      src: /root/httpd.conf.j2
      dest: /etc/httpd/conf/httpd.conf
    notify: restart service

  - name: start service
    service:
      name: "{{ service }}"
      state: started
      enabled: true
 
 handlers:
  - name: restart service
    service:
      name: "{{ service }}"
      state: restarted

执行yaml文件并验证

ansible-playbook a.yaml --syntax-check
ansible-playbook a.yaml
ansible websrvs -a 'systemctl status httpd'
ansible websrvs -m shell -a 'ss -ntl'
ansible websrvs -m shell -a 'netstat -ntlp |grep httpd'
ansible websrvs -m shell -a 'lsof -i:80'
ansible websrvs -m shell -a 'lsof -i:81'

tamplates-for(循环)

语法:

{% for 变量 in 列表 %}
{{ 文本内容调用变量 }}
{% endfor %}

示例:使用for循环遍历调用users列表变量的元素

{%  for user in users %}
{{  user }}
{% endfor %}

示例:yaml文件中变量的调用

编写yaml文件 jinja2_for.yml

vim jinja2_for.yml
---
- name: jinja2_for example
  hosts: all
  remote_user: root
  vars:
    users:
    - user1
    - user2
  tasks:
  - name: Copy template
    template: 
      src: /root/users.j2
      dest: /root/users

编写/root/users.j2文件

vim /root/users.j2
{% for user in users %}
username: {{ user }}
{% endfor %}

执行并验证

ansible-playbook jinjia2_for.yml --syntax-check
ansible-playbook jinjia2_for.yml
ansible all -m shell -a "cat /root/users"

扩展示例:

以下示例模板使用for语句逐一运行users变量中的所有值,将user替换为各个值,但值为root时除外。

vim users.j2

{# for statement #}
{% for user in users if not user =="root" %}
User number {{ loop.index }}- {{ user }}
{% endfor %}

loop.index变量扩展至循环当前所处的索引号。它在循环第一次执行时值为1,每一次迭代递增1.

ansible-playbook jinjia2_for.yml --syntax-check
ansible-playbook jinjia2_for.yml

ansible all -m shell -a "cat /root/users"

示例:事实变量的调用

编写yaml文件 jinja2_for2.yml

vim jinja2_for2.yml
---
- name: jinja2_for example2
  hosts: all
  remote_user: root
  vars:
    users:
    - user1
    - user2
  tasks:
  - name: Copy template
    template: 
      src: /root/host.j2
      dest: /root/hosts

编写/root/host.j2文件

vim /root/host.j2
{% for host in groups['websrvs'] %}
{{ ansible_facts.default_ipv4.address }}{{ ansible_facts.fqdn }}
{% endfor %}

执行并验证

ansible-playbook jinjia2_for2.yml --syntax-check
ansible-playbook jinjia2_for2.yml

ansible websrvs -m shell -a "cat /root/hosts"

tamplates-if(判断)

Jinja2使用 if 语句来提供条件控制。如果满足条件,允许在文件中添加一行内容。

语法:

{% if 条件 %}
{{ 语句 }}
{% endif %}

示例:

编写yaml文件 jinja2_if.yml

vim jinja2_if.yml
---
- name: jinja2_if example
  hosts: websrvs
  remote_user: root

  tasks:
  - name: Copy template
    template: 
      src: /root/host2.j2
      dest: /root/hosts2

编辑host2.j2文件

vim /root/host2.j2

{% if ansible_facts.default_ipv4.address =='192.168.142.101' %}
{{ ansible_facts.default_ipv4.address }}{{ ansible_facts.fqdn }}
{% endif %}

执行并验证

ansible-playbook jinja2_if.yml --syntax-check
ansible-playbook jinja2_if.yml
ansible all -m shell -a "cat /root/hosts2"

综合案例:nginx templates

0、编辑主机清单,组websrvs,包含2台受控主机

1、主控端安装ngxin、拷贝nginx配置文件为nginx.conf.j2模板文件。创建nginx首页模版,命名为html.j2,引用实事变量:主机名,文件内容格式如: Welcome to {{ 需要引用的实事变量 }}

2、编写test_template.yaml文件,要求tasks

1)安装epel源 2)安装nginx 3)拷贝nginx.conf.j2模板文件为受控主机的nginx配置文件4)拷贝html.j2模板文件为受控主机的nginx首页文件4)开启服务

3、校验playbook语法并执行,验证受控主机的nginx进程数\服务端口\首页

4、修改nginx.conf.j2模板文件,配置 worker_processes数量为实事变量:受控主机处理器vcpu个数的两倍,保存

5、修改test_template.yaml文件,添加notify和handlers,在配置文件变化时,重启nginx

6、校验playbook语法并执行,验证受控主机的nginx进程数

7、修改hosts文件为每台主机定义服务端口变量 第一台 8082,第二台8083

8、修改test_template.yaml文件,修改监听端口行,增加主机端口变量的引用

9、校验playbook语法并执行,验证受控主机的nginx服务端口

10、修改test_template.yaml,增加端口变量定义,端口88

11、校验playbook语法并执行,验证受控主机的nginx服务端口

1、主控端安装ngxin、拷贝nginx配置文件为nginx.conf.j2模板文件

yum install -y nginx
cp /etc/nginx/nginx.conf /root/nginx.conf.j2
echo "welcome to {{ ansible_hostname  }}" > html.j2

ansible all -m setup |grep hostname
ansible all -m setup |grep vcpu

2、创建nginx首页模版,命名为html.j2,引用实事变量:主机名

内容格式如: Welcome to {{ 需要引用的实事变量 }}

2、编写test_template.yaml文件

vim test_template.yaml
---
- hosts: websrvs
  remote_user: root
  tasks:
  - name: install epel
    yum:
      name: epel-release
  - name: install package
    yum:
      name: nginx
  - name: copy template
    template:
      src: /root/nginx.conf.j2
      dest: /etc/nginx/nginx.conf
  - name: copy template
    template:
      src: /root/html.j2
      dest: /usr/share/nginx/html
  - name: copy html
    template:
      src: /root/html.j2
      dest: /usr/share/nginx/html/index.html    
  - name: start service
    service:
      name: nginx
      state: started
      enabled: yes

执行并验证

ansible-playbook test_template.yaml  --syntax-check
ansible-playbook test_template.yaml  
ansible all -m shell -a 'systemctl status nginx'
ansible all -m shell -a 'ss -ntpl|grep nginx'
#可以查看到进程,每个cpu一个
ansible all -m shell -a 'ps aux|grep nginx'

3、修改template文件,修改进程数为cpu内核的2倍

ansible websrvs -m setup|grep "cpu"

vim nginx.conf.j2
修改第6行
worker_processes {{ ansible_processor_vcpus*2  }}    #worker_processes auto

修改test_template.yaml文件,添加notify和handlers,在配置文件变化时,重启nginx

vim test_template.yaml
---
- hosts: websrvs
  remote_user: root
  tasks:
  - name: install package
    yum:
      name: nginx
  - name: copy template
    template:
      src: /root/nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify:
    - restart service
  - name: copy html
    template:
      src: /root/html.j2
      dest: /usr/share/nginx/html/index.html    
  - name: start service
    service:
      name: nginx
      state: started
      enabled: yes
  handlers:
  - name: restart service
    service:
      name: nginx
      state: restarted

执行并验证

ansible-playbook test_template.yaml
#可以查看到进程,
ansible all -m shell -a 'ps aux|grep nginx' #查看nginx进程数为cpu核数的2倍

检验nginx配置文件是否存在语法错误

nginx -t

nginx和httpd服务,web服务保证只有一个运行。

4、使用主机变量,修改服务端口

修改hosts文件增加端口变量

#使用主机变量
#修改nginx对应的端口
vim /etc/ansible/hosts
[websrvs]
192.168.142.101 http_port=8083
192.168.142.102 http_port=8084

修改模板文件,增加端口引用

vim nginx.conf.j2
修改39、40行
server{
    listen   {{ http_port }} ;
    listen   [::]:{{  http_port  }} ;
}

执行并验证

ansible-playbook test_template.yaml
ansible websrvs -m shell -a 'ss -ntpl|grep nginx'

5、使用playbook变量

修改test_template.yaml,增加端口信息

vim test_template.yaml

---
- hosts: websrvs
  remote_user: root
  vars:
  - http_port: 88
  tasks:
  - name: install package
    yum:
      name: nginx
  - name: copy template
    template:
      src: /root/nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify:
    - restart service
  - name: copy html
    template:
      src: /root/html.j2
      dest: /usr/share/nginx/html/index.html   
  - name: start service
    service:
      name: nginx
      state: started
      enabled: yes
  handlers:
  - name: restart service
    service:
      name: nginx
      state: restarted

执行并验证

ansible-playbook test_template.yaml
ansible websrvs -m shell -a 'ss -ntpl|grep nginx'
#发现端口变成88

6、使用命令行变量

ansible-playbook -e "http_port=99"  test_template.yaml
ansible websrvs -m shell -a 'ss -ntpl|grep nginx'
#发现端口变成99

Roles

·由来: ansible自动化运行,基础由AD-Hoc命令来完成,在命令变多时,产生了playbook进行管理任务,简单任务使用playcook可以轻松处理,但是有复杂任务时单个playbook不可以胜任了,这时需要把多个playbook进行组合,少量用include将剧本中任务互相关联即可完成,但是playbook还在增多的情况时就不方便管理了,这时引入roles对playbook进行有效组织就十分必要了
· Roles:角色,是ansible自1.2版本开始引入的新特性
·目的:用于层次性,结构化地组织playbook, roles能够根据层次型结构自动装载变量、文件、任务、模块及触发器·方法: roles通过分别将放置于变量、文件、任务、模块及触发器单独的目录中,并可以便捷地include它们的一种机制·应用:角色一般用于基于主机构建服务的场景中、但也可以是用于构建守护进程等场景中

roles默认路径设置

/etc/ansible/ansible.cfg
roles_path= /etc/ansible/roles

Roles各目录结构及作用

每个角色,以特定的层级目录结构进行组织
roles目录结构:
playbook.yml  调用角色
roles/
  project/ (角色名称)
    tasks/
    files/
    vars/
    templates/
    handlers/
    default/ 不常用,设定默认变量时使用此目录中的main.yml文件
    meta/    不常用,定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件;其它文件需在此文件中通过include进行包含
各目录的作用:
/roles/project/ :项目名称,有以下子目录,project可以是mysql\httpd\nginx\memcached等
    files/ :存放由copy或script模块等调用的文件
    templates/:template模块查找所需要模板文件的目录
    tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件, 其定义了此角色的任务列表.
             在handler中使用include包含的其它的handler文件也应该位于此目录中;
    handlers/:至少应该包含一个名为main.yml的文件;用于定义此角色用到的各handler;
               其它的文件需要在此文件中通过include进行包含
    vars/:定义变量,至少应该包含一个名为main.yml的文件,;
           其它的文件需要在此文件中通过include进行包含
    meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,
           其它文件需在此文件中通过include进行包含, ansible1.3及其以后的版本才支持;
    defaults/:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件

创建role框架

您可以使用标准Linux命令创建新角色所需的所有子目录和文件。

cd /etc/ansible/roles/
mkdir  httpd
cd httpd
mkdir  tasks  handlers  vars  meta  defaults templates files

或者可以运行ansible-galaxy init来创建新角色的目录结构。指定角色的名称作为命令的参数,该命令在当前工作目录中为新角色创建子目录。

cd /etc/ansible/roles
ansible-galaxy init httpd
tree httpd
[root@controller roles]# tree httpd
httpd      #具体的⾓⾊项⽬名称,   ⽐如nginx、tomcat、php  (⾃由设置)
├── defaults  #⽤于为当前⾓⾊设定默认变量,  此⽬录应当包含⼀个main.yml⽂件
│   └── main.yml  #类似代码中的主函数,  进⾏统⼀管理
├── files      #⽤来存放由copy模块或script模块等模块调⽤的⽂件
├── handlers    #⽤于定义此⾓⾊中触发条件时执⾏的动作,  此⽬录应当包含⼀个main.yml⽂件
│   └── main.yml
├── meta      #⽤于定义此⾓⾊的特殊设定及其依赖关系,  此⽬录应当包含⼀个main.yml⽂件
│   └── main.yml
├── README.md   #说明⽂件
├── tasks       #⽤于定义当前⾓⾊的任务列表,  此⽬录应当包含⼀个main.yml⽂件
│   └── main.yml
├── templates  #⽤来存放jinjia2模板,template模块会⾃动在此⽬录中寻找jinjia2模板⽂件
├── tests   #⽤于存放测试role本⾝功能的playbook和主机定义⽂件,  在开发测试阶段⽐较常⽤ ,此⽬录应当包含⼀个main.yml⽂件和⾃⾝资源设定invetory
│   ├── inventory
│   └── test.yml
└── vars    #⽤于定义此⾓⾊⽤到的变量,  此⽬录应当包含⼀个main.yml⽂件
    └── main.yml

实验任务:安装httpd服务

原始的playbook版本

1、制作主页

echo hi > index.html

2、拷贝本机httpd的配置文件为httpd.conf.j2模版,并修改

cp /etc/httpd/conf/httpd.conf httpd.conf.j2

vim httpd.j2 #42行 修改为

{% if http_port is defined %}
Listen {{ ansible_facts.default_ipv4.address }}:{{ http_port }}
{% endif %}

3、编写playbook文件,

创建变量http_port: 8080

执行任务:

1)安装httpd

2)拷贝主页

3)拷贝配置(做触发器)

4)防火墙放通自定义的端口

- name: firewalld configuration
  firewalld:  
    port: "{{  http_port }}/tcp"
    permanent: yes 
    immediate: yes 
    state: enabled
  when: http_port is defined

5)开启服务

---                                                                                                                                                                           
- hosts: all 
  remote_user: root
  vars:
    http_port: 8080
  tasks:
  - name: install httpd package
    yum:
      name: httpd
      state: present
  - name: create a web content
    copy:
      src: index.html
      dest: /var/www/html/index.html
  - name: config file
    template:
      src: httpd.conf.j2
      dest: /etc/httpd/conf/httpd.conf
    notify: restart_httpd
    when: http_port is defined                                                                                                                                                
  - name: firewalld configuration
    firewalld:                                                                   
      port: "{{  http_port }}/tcp"
      permanent: yes 
      immediate: yes 
      state: enabled
    when: http_port is defined
  - name: start service
    service: 
      name: httpd 
      state: started 
      enabled: yes
  handlers:
  - name: restart_httpd
    service:
      name: httpd
      state: restarted

验证端口及主页

ansible all -m shell -a "ss -tunlp|grep httpd"

任务分析:

1.配置 httpd 的时候,可能存在配置文件,配置文件可能含有变量

2.必要变量的定义

3.源码文件的定义

创建httpd角色框架

ansible-galaxy init httpd

查看目录结构

[root@controller roles]# tree httpd
httpd
├── defaults
│  └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

部署完善httpd角色框架

cd roles/httpd/tasks/
   touch install.yml conf_template.yml service.yml index.yml   httpd_firewalld.yml

定义分任务(tasks/中存放)

vim install.yml
- name: install httpd package
  yum: 
    name: httpd
    state: present
     
vim conf_template.yml
- name: config file
  template: 
    src: httpd.conf.j2 
    dest: /etc/httpd/conf/httpd.conf 
  notify: restart_httpd
  when: http_port is defined
         
vim service.yml
- name: start service
  service: 
    name: httpd 
    state: started 
    enabled: yes
    
vim  index.yml
- name: create a web content
  copy:
    src: index.html
    dest: /var/www/html/index.html

vim httpd_firewalld.yml
- name: firewalld configuration
  firewalld:
    port: "{{  http_port }}/tcp"
    permanent: yes
    immediate: yes
    state: enabled
  when: http_port is defined

定义主任务(tasks/main.yml)

创建main.yml主控文件,调用以上单独的yml文件,main.yml定义了谁先执行谁后执行的顺序
vim main.yml
- include: install.yml
- include: index.yml
- include: conf_template.yml
- include: httpd_firewalld.yml
- include: service.yml

定义变量(vars/main.yml)

vim /etc/ansible/roles/httpd/vars/main.yml

---
#vars file for httpd
http_port: 8080

定义首页文件(files/index.html)

cd    /etc/ansible/roles/httpd/files/
vim index.html
<h1> welcome to wd home <\h1>

定义模板(templates/httpd.conf.j2 )

yum -y install httpd

cp /etc/httpd/conf/httpd.conf  /etc/ansible/roles/httpd/templates/httpd.conf.j2 

vim templates/httpd.conf.j2
将LISTEN 80 行修改为以下内容
{% if http_port is defined %}
Listen {{ ansible_facts.default_ipv4.address }}:{{ http_port }}
{% endif %}

定义角色处理程序(handlers/mail.yml)

vim /etc/ansible/roles/httpd/handlers/main.yml
- name: restart_httpd
  service: 
    name: httpd 
    state: restarted

调用角色,配置httpd服务(roles/role_httpd.yml)

cd /etc/ansidle/roles
vim role_httpd.yml
---
# httpd role
- name: httpd deployment
  hosts: websrvs
  remote_user: root    
  
  roles:       #调用角色
  - httpd

检查语法及冒烟运行

ansible-playbook role_httpd.yml -C

正式执行

ansible-playbook role_httpd.yml

验证服务

ansible all -m shell -a "ss -tunlp |grep httpd"
curl 192.168.142.101:8080

特别声明

千屹博客旗下的所有文章,是通过本人课堂学习和课外自学所精心整理的知识巨著
难免会有出错的地方
如果细心的你发现了小失误,可以在下方评论区告诉我,或者私信我!
非常感谢大家的热烈支持!

举报

相关推荐

0 条评论