1. 闲不住的人首页
  2. Ansible

Ansible 学习笔记

Ansible是一个极其简单的IT自动化系统。它处理配置管理,应用程序部署,云配置,临时任务执行和多节点编排 – 包括通过负载平衡器轻松实现零停机滚动更新等操作。

1. 安装ansible

1、配置EPEL源作为yum安装源

# Centos7
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# Centos6
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo

2、安装

$ yum -y install ansible

2. ansible 配置文件

1、主配置文件

$ cat /etc/ansible/ansible.cfg

[defaults]:段常用参数说明
inventory      = /etc/ansible/hosts # 定义主机清单的文件
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 # 是否需要密码
roles_path - /etc/ansible/roles # 默认下载的roles存放的目录
log_path = /var/log/ansible.log # 执行日志存放目录

2、主机清单

$ cat /etc/ansible/hosts

# 定义格式
# "#" 开头的行表示为注释行

# 主机的定义可以直接为IP地址
192.168.1.142

# 主机定义也支持使用hostname的方式,后面跟冒号加数字表示端口号,默认22号端口
bj-1-142.enzhi.com:52113
bj-1-160.enzhi.com

# 中括号的内容表示一个分组开始,紧随其后的主机均属于该组成员,空行后的主机亦属于该组
[webservers]
192.168.1.142
web1.enzhi.com
web[10:20].enzhi.com # [10:20]表示10~20之间的所有数字(包括10,20),即表示web10.enzhi.com, web11.enzhi.com...web20.enzhi.com的所有主机

3. 主程序

1、ansible

使用格式:

ansible <host-pattern> [-m module_name] [-a args] [options]
    <host-pattern>:指明对哪台主机或主机组执行操作
    -m module_name:指定执行使用的模块
    -a args:指定模块参数

2、ansible playbook

ansible-playbook <filename.yml> ... [options]
[options]
--check:只检测可能会发生的改变,但不真正执行操作;
--list-hosts:列出运行任务的主机;

3、ansible-doc

ansible-doc [-M module_path] [-l] [-s] [module...]
-l:列出所有可用模块。
-s:显示模块用法

示例:

[root@Bj-1-141 ansible]# ansible-doc -s file
[root@Bj-1-141 ansible]# ansible-doc -s copy

4. ansible 常用模块

4.1 command模块

功用:在远程主机上运行命令,不支持使用管道

[root@Bj-1-141 ansible]# ansible dbservers -m command -a "date"
192.168.1.160 | SUCCESS | rc=0 >>
2017年 04月 01日 星期六 10:38:29 CST

4.2 shell模块

功用:在远程主机,在shell进程下运行命令,支持 shell 特性,如管道等。

[root@Bj-1-141 ansible]# ansible dbservers -m shell -a "useradd mysql"
192.168.1.160 | SUCCESS | rc=0 >>

# 使用command模块为用户设置密码无法实现,会把echo后面的全部当作字符串输出。
[root@Bj-1-141 ansible]# ansible dbservers -m command -a "echo mypass | passwd --stdin mysql"
192.168.1.160 | SUCCESS | rc=0 >>
mypass | passwd --stdin mysql

# 使用shell模块可以做到
[root@Bj-1-141 ansible]# ansible dbservers -m shell -a "echo mypass | passwd --stdin mysql"
192.168.1.160 | SUCCESS | rc=0 >>
更改用户 mysql 的密码 。
passwd: 所有的身份验证令牌已经成功更新。

4.3 copy 模块

功用:复制文件至远程主机某个位置;

用法:

backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
content:用于替代"src",可以直接设定指定文件的值
dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
directory_mode:递归的设定目录的权限,默认为系统默认权限match
force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
others:所有的file模块里的选项都可以在这里使用
src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。match
follow	yes/no	当拷贝的文件夹内有link存在的时候,那么拷贝过match去的也会有link
force	yes/no	默认为yes,会覆盖远程的内容不一样的文件(可能文件名一样)。如果是no,就不会拷贝文件,如果远程有这个文件
group	设定一个群组拥有拷贝到远程节点的文件权限
mode  等同于chmod,参数可以为“u+rwx or u=rw,g=r,o=r”
owner	设定一个用户拥有拷贝到远程节点的文件权限

示例:copy 本地 /etc/fstab 文件到 dbservers 组内主机的 /tmp 目录下名为 fstab,属主属组为 mysql,权限为 644

[root@Bj-1-141 ansible]# ansible dbservers -m copy -a "src=/etc/fstab dest=/tmp/fstab owner=mysql group=mysql mode=644"
192.168.1.160 | SUCCESS => {
    "changed": true,
    "checksum": "0cf45815fbdda9ff44910fe87e556984192c9414",
    "dest": "/tmp/fstab",
    "gid": 500,
    "group": "mysql",
    "md5sum": "3d18ffa0e04260589f1bbb43c4538c36",
    "mode": "0644",
    "owner": "mysql",
    "size": 501,
    "src": "/root/.ansible/tmp/ansible-tmp-1491015083.3-276514660679850/source",
    "state": "file",
    "uid": 500
}
# 查看结果
[root@Bj-1-141 ansible]# ansible dbservers -m shell -a "ls -l  /tmp/fstab"
192.168.1.160 | SUCCESS | rc=0 >>
-rw-r--r-- 1 mysql mysql 501 4月   1 10:51 /tmp/fstab

4.4 cron 模块

功用:管理远程主机的crontab任务计划;

用法:

backup:对远程主机上的原任务计划内容修改之前做备份 
cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划 
day:日(1-31,*,*/2,……) 
hour:小时(0-23,*,*/2,……)  
minute:分钟(0-59,*,*/2,……) 
month:月(1-12,*,*/2,……) 
weekday:周(0-7,*,……)
job:要执行的任务,依赖于state=present 
name:该任务的描述,必须指明一个name
special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly 
state:present or absent,确认该任务计划是创建还是删除,默认是创建任务 presents
user:以哪个用户的身份执行

示例:对 dbservers 组内主机添加一条时间同步任务计划,每个5分钟同步一次时间

[root@Bj-1-141 ~]# ansible dbservers -m cron -a "minute=*/5 hour=* day=* month=* weekday=* job='/usr/sbin/ntpdate 0.asia.pool.ntp.org &> /dev/null' name=Synctime "
192.168.1.160 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": [
        "Synctime"
    ]
}
[root@Bj-1-141 ~]# ansible dbservers -m shell -a "crontab -l"
192.168.1.160 | SUCCESS | rc=0 >>
#Ansible: Synctime
*/5 * * * * /usr/sbin/ntpdate 0.asia.pool.ntp.org &> /dev/null

删除任务:

root@k8s02-ops-bjqw:~ # ansible all -m cron -a "state=absent name=Synctime"
10.100.4.182 | CHANGED => {
    "changed": true,
    "envs": [],
    "jobs": []
}
10.100.4.183 | CHANGED => {
    "changed": true,
    "envs": [],
    "jobs": []
}

4.5 file 模块

功用:设定远程主机文件属性

用法:

force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no 
group:定义文件/目录的属组 
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归的设置文件的属性,只对目录有效
src:要被链接的源文件的路径,只应用于state=link的情况
dest:被链接到的路径,只应用于state=link的情况 
state:  
directory:如果目录不存在,创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件

示例1:创建软连接文件

[root@Bj-1-141 ~]# ansible dbservers -m file -a "src=/tmp/fstab path=/tmp/fstab.link state=link"
192.168.1.160 | SUCCESS => {
    "changed": true,
    "dest": "/tmp/fstab.link",
    "gid": 0,
    "group": "root",
    "mode": "0777",
    "owner": "root",
    "size": 10,
    "src": "/tmp/fstab",
    "state": "link",
    "uid": 0
}

示例2:修改文件属性

[root@Bj-1-141 ~]# ansible dbservers -m file -a "path=/tmp/fstab owner=nobody group=nobody mode=755"
192.168.1.160 | SUCCESS => {
    "changed": true,
    "gid": 99,
    "group": "nobody",
    "mode": "0755",
    "owner": "nobody",
    "path": "/tmp/fstab",
    "size": 501,
    "state": "file",
    "uid": 99
}

示例3:创建目录

[root@Bj-1-141 ~]# ansible dbservers -m file -a "path=/tmp/testdir state=directory"
192.168.1.160 | SUCCESS => {
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/testdir",
    "size": 4096,
    "state": "directory",
    "uid": 0
}

4.6 hostname 模块

功用:设定主机名

使用格式:

name=                  # Name of the host

示例:修改主机名

[root@Bj-1-141 ~]# ansible dbservers -m hostname -a "name=webdb-1-160.enzhi.com"
192.168.1.160 | SUCCESS => {
    "ansible_facts": {
        "ansible_domain": "enzhi.com",
        "ansible_fqdn": "webdb-1-160.enzhi.com",
        "ansible_hostname": "webdb-1-160",
        "ansible_nodename": "webdb-1-160.enzhi.com"
    },
    "changed": true,
    "name": "webdb-1-160.enzhi.com"
}
[root@Bj-1-141 ~]# ansible dbservers -m shell -a "hostname"
192.168.1.160 | SUCCESS | rc=0 >>
webdb-1-160.enzhi.com

4.7 yum模块

功用:管理程序包

用法:

config_file:yum的配置文件 
disable_gpg_check:关闭gpg_check 
disablerepo:不启用某个源 
enablerepo:启用某个源
name:要进行操作的软件包的名字,可以带版本号,也可以传递一个url或者一个本地的rpm包的路径 
state:状态,安装(present,latest)卸载包(absent)

示例:

[root@Bj-1-141 ~]# ansible dbservers -m yum -a "name=htop state=present"

4.8 service 模块

功用:管理服务启动或关闭

用法:

arguments:给命令行提供一些选项 

enabled:是否开机自动启动 yes|no
name:必选项,服务名称 
pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
runlevel:运行级别
sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟
state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)

示例:对远程主机安装nginx启动并设置为3级别开机自动启动

[root@Bj-1-141 ~]# ansible dbservers -m yum -a "name=nginx state=present"
[root@Bj-1-141 ~]# ansible dbservers -m shell -a "rpm -q nginx"
192.168.1.160 | SUCCESS | rc=0 >>
nginx-1.10.2-1.el6.x86_64

# 启动服务
[root@Bj-1-141 ~]# ansible dbservers -m service -a "name=nginx runlevel=3 enabled=yes state=started"
192.168.1.160 | SUCCESS => {
    "changed": true,
    "enabled": true,
    "name": "nginx",
    "state": "started"
}

4.9 user模块

功用:管理用户账户

用法:

home:指定用户的家目录,需要与 createhome 配合使用
groups:指定用户的属组
uid:指定用户的 uid
password:指定用户的密码
name:指定用户名
createhome:是否创建家目录 yes|no
system:是否为系统用户 yes|no
remove:当 state=absent 时,remove=yes 则表示连同家目录一起删除,等价于 userdel -r
state:是创建还是删除
shell:指定用户的shell环境

示例:

[root@Bj-1-141 ~]# ansible dbservers -m user -a "name=enzhi.wang"

4.10 setup模块

功用:获取主机的信息;

用法:

filter="":用于过滤出指定的变量的值;

示例1:查看dbservers组内所有主机的信息

[root@Bj-1-141 ~]# ansible dbservers -m setup

示例2:查看dbservers组内所有主机的内存总量信息;

[root@Bj-1-141 ~]# ansible dbservers -m setup -a "filter=ansible_memtotal_mb"
192.168.1.160 | SUCCESS => {
    "ansible_facts": {
        "ansible_memtotal_mb": 980 # 获取的内存总量信息;
    },
    "changed": false
}

4.11 template模块

功用:基于模版方式生成一个文件复制到远程主机

用法

backup    yes/no   建立个包括timestamp在内的文件备份,以备不时之需.
dest            远程节点上的绝对路径,用于放置template文件。
group            设置远程节点上的的template文件的所属用户组
mode            设置远程节点上的template文件权限。类似Linux中chmod的用法
owner            设置远程节点上的template文件所属用户
src                本地Jinjia2模版的template文件位置。

4.12 systemd 模块

功能:CentOS7 版本以后改用 systemd 风格启动脚本,有些服务使用 service 模块无法启动。

enabled:是否加入开机自启动;
name:程序名称;
state:started(启动服务),stopped(停止服务),restarted(重启), reloaded(平滑重启)

4.13 stat 模块

stat 模块文档地址:https://docs.ansible.com/ansible/latest/modules/stat_module.html?highlight=stat#return-values

  • 功能:检索文件或文件系统状态,有点类似于 Linux 系统中的 stat 命令。
  • 应用场景:一般用来判断文件是否存在,是否为链接文件,目录是否存在。

常用参数:

path:必须给的参数,指定一个文件或对象的绝对路径

示例:直接在命令行执行查看返回结果

$ ansible webservers -m stat -a "path=/etc/fstab"

返回如下图:

ansible stat模块

应用案例:我在使用 ansible 部署 JDK 时用来判断 /usr/local/jdk 是否存在,如果存在就不执行安装操作,否则就安装 JDK。

- name: 检查 JDK 是否已经安装
  stat: path=/usr/local/jdk
  register: jdk_result

- name: 安装JDK
  shell: cd /usr/local/src/ && tar xf {{ version }} -C /usr/local/ && ln -sv /usr/local/{{ link }} /usr/local/jdk
  when: jdk_result.stat.exists == false

stat 模块的执行结果返回的是一个字典,常见的返回值,可以查看其模块文档内有详细说明。

4.14 debug 模块

功能:调试模块,用于在调试中输出信息。

常用参数:

msg:调试输出的消息。
var:将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出。
verbosity:debug的级别(默认是0级,全部显示)。

示例:

- hosts: webservers
  remote_user: root
  tasks:
  - name: show date time
    shell: date
    register: result
  - name: Show debug info
    debug: var=result verbosity=0

执行结果如下:

ansible debug

5、Playbook 的用法

1、playbook的核心元素

Hosts:
Tasks:
Variables
Templates:包含了模版语法的文本文件;
Handlers:由特定条件触发的任务;

5.1 playbook 的基础组件

hosts:运行指定任务的目标主机;
remote_user:在远程主机上执行任务的用户;

tasks:任务列表
	模块,模块参数:
	定义格式:
		(1) action:module arguments
		(2) module:arguments
	# 注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
(1)某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers;
(2)任务可以通过"tags"打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
假如已经安装了httpd服务,而后我们修改了配置文件,在此执行playbook时会把所有任务全都执行一遍,如果希望仅执行指定的任务就需要给指定任务打标签;

示例:

# vim webservice.yml
- hosts: webservers # 指明在webservers组内所有主机上执行任务
  remote_user: root # 指明远程执行任务的用户为root
  tasks: # 任务列表
  - name: install httpd package    # name:可以写多个,声明此任务的作用
    yum: name=httpd state=present # 使用yum模块安装httpd
  - name: install config file  # 声明这个任务是提供配置文件
    copy: src=files/httpd.conf dest=/etc/httpd/conf/ # 使用copy模块将配置文件复制到远程主机
  - name: start httpd service # 声明启动httpd服务
    service: name=httpd state=started

注意:copy 模块 src=files/ 这里使用的相对路径,是相对于此 playbook 文件所在的目录;

5.2 playbook 的运行方式

# 测试
ansible-playbook --check <filename.yml>  
    只检测可能会发生的改变,但不真正执行操作;
ansible-playbook --list-hosts <filename.yml>
    列出运行任务的主机;

# 运行
ansible-playbook <filename.yml>
ansible-playbook [-t tags_name] <filename.yml>

示例:运行上面示例创建的 webservice.yml 文件

[root@Bj-1-141 working]# ansible-playbook webservice.yml

5.3 notify 与 handlers

notify 用来指明触发事件后执行哪个任务;handlers 接收到其它任务的通知时执行操作;

注意:notify指定的名称必须要与handlers中定义的name名称完全一样;

格式:

- hosts: webservers
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=present
  - name: install config file
    copy: src=files/httpd.conf dest=/etc/httpd/conf/
    notify: restart httpd # 指明当src指明的文件发生变化时就触发restart httpd这个任务
  - name: start httpd service
    service: name=httpd state=started
  handlers:  
    - name: restart httpd  # 定义restart httpd具体的操作
      service: name=httpd state=restarted

5.4 tags

默认情况下每次执行 playbook 文件都会从头开始全部执行一遍任务,当需要指明从某个具体的任务开始向下执行时就需要使用tags来指明从此任务开始向下执行。

假如已经安装了 httpd 服务,而后我们修改了配置文件,在此执行 playbook 时会把所有任务全都执行一遍,如果希望从提供配置文件任务开始执行就需要给指定任务打标签;

示例:

- hosts: webservers
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=present
  - name: install config file
    copy: src=files/httpd.conf dest=/etc/httpd/conf/
    tags: instconf # 给install configure file任务打一个标签叫instconf名称自定义;
    notify: restart httpd
  - name: start httpd service
    service: name=httpd state=started
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

注意:定义 tags 名称时不要加空格,同一个 tasks 下的任务可以为每个任务打一个标签,并且标签的名字可以相同。

使用 ansible-playbook -t <tag> 选项来指定从哪个 tag 开始向下执行。

运行:

[root@Bj-1-141 working]# ansible-playbook -t instconf --check webservice.yml

PLAY [webservers] **************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.142]
ok: [192.168.1.143]

TASK [install config file] *****************************************************
changed: [192.168.1.142]
changed: [192.168.1.143]

RUNNING HANDLER [restart httpd] ************************************************
changed: [192.168.1.143]
changed: [192.168.1.142]

PLAY RECAP *********************************************************************
192.168.1.142              : ok=3    changed=2    unreachable=0    failed=0
192.168.1.143              : ok=3    changed=2    unreachable=0    failed=0

观察上面运行测试结果可以看到并没有运行install httpd package任务

5.5 获取命令的输出 Register

https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html?highlight=register#register-variables

在刚开始使用 ansible-playbook 做应用程序部署的时候,因为在部署的过程中有使用到 command 或 shell 模块执行一些自定义的脚本,而且这些脚本都会有输出,用来表示是否执行正常或失败。如果像之前自己写脚本做应用程序部署的,这很好实现。但现在是用 Ansible 做,那么要怎么样做可以获取到 ansible playbook 中 command 模块的输出呢? Ansible 也提供的解决办法,这时我们就可以通过使用 register 关键字来实现,register 关键字可以存储指定命令的输出结果到一个自定义的变量中,我们通过访问这个自定义变量就可以获取到命令的输出结果。Register 的使用很方便,只需要在 task 声明 register 关键字,并自定义一个变量名就可以。如下:

- name: 检查 JAVA_HOME 是否存在
  shell: cat /root/.bashrc
  register: bashrc_result

- name: 引用环境变量
  shell: source /etc/profile 
  when: bashrc_result.stdout.find('JAVA_HOME') == -1

这里第 1 个 task 是执行了一个 cat 命令,register 关键字将 cat 命令的输出存储到 bashrc_result 变量名。第 2 个 task 对输出进行分析,并使用 when 对关键字对分析后的进行判断,如果 barshrc_result 变量中找不到 ‘JAVA_HOME’ 这个字符串返回 -1,则执行这个 task,不匹配就不执行。这里要重点说下的,因为 register 获取到的输出内容都是字符串,而 ansible 又是 python 写的,你可以使用 python 字符串的方法对其做处理,比如本文中使用的 find,还可以使用 split 方法。个人觉得,真是非常灵活方便

特意使用 Python 测试了一下字符串的方法如下图:

测试1

加上 JAVA_HOME 字符串在使用 find 方法:

测试2

6. variables 变量

6.1、变量的定义

1、通过setup模块结果直接调用其内部变量

2、ansible-playbook命令行中的自定义变量

-e VARS, --extra-vars=VARS

# 示例
root@k8s05-ops-bjqw:~/working # cat forth.yml
- hosts: webservers
  remote_user: root
  tasks:
  - name: install pkg
    yum: name={{ pkname}} state=present # name定义变量引用
    
# 命令行传递一个变量 pkname=memcached
root@k8s05-ops-bjqw:~/working # ansible-playbook -e pkname=memcached  forth.yml

3、通过 roles 传递变量

4、Host Inventory 中定义变量

(1) 向不同的主机传递不同的变量
	IP/HOSTNAME variables=value var2=value2
	示例:
	[webservers]
	192.168.1.142 http_port=80
	
(2) 向组中的主机传递相同的变量
      [groupname:vars]
      variable=value
	示例:
      [webservers]
      192.168.1.142
      
      [webservers:vars] # 向webservers组内传递变量
      http_port=80

注意:inventory 参数:

用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量;
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansible_sudo_pass

5、在playbook文件中定义变量

定义方式:

vars:
- var1: value1
- var2: value2

示例:

- hosts: webservers
  remote_user: root
  vars: # 声明变量定义
  - http_port: 80 # http_port的值为80
  tasks:
  - name: install httpd package
    yum: name=httpd state=present
  - name: install config file
    template: src=files/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    tags: instconf
    notify: restart httpd
  - name: start httpd service
    service: name=httpd state=started
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

6.2 调用变量

调用方式:在模版文件中使用{{ 变量名 }}来调用指定变量;

{{ variable }}

# 例如,nginx 进程数设置为远程主机的CPU核心数
user nginx;
worker_processes {{ ansible_processor_count }};

# 变量中还可进行算数运算等操作例如,CPU 的核心数加1
worker_processes {{ ansible_processor_count + 1 }};

注意:被调用的模版文件后缀必须以.j2结尾

示例:httpd.conf 配置文件中 Listen 调用变量 http_port

# 修改httpd.conf文件
Listen {{ http_port }}

# playbook文件
- hosts: webservers
  remote_user: root
  vars: # 声明变量定义
  - http_port: 80 # http_port的值为80
  tasks:
  - name: install httpd package
    yum: name=httpd state=present
  - name: install config file
    template: src=files/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    tags: instconf
    notify: restart httpd
  - name: start httpd service
    service: name=httpd state=started
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

7. 条件测试

when语句:在 task 中使用,jinja2 的语法格式;

示例:

task:
- name: install conf file to centos7
    template: stc=files/nginx.conf.c7.j2
    when: ansible_distribution_major_version == "7" # 当远程主机版本为centos7提供centos7的nginx配置文件
- name: install conf file to centos6
    template: stc=files/nginx.conf.c6.j2
    when: ansible_distribution_major_version == "6" # 当远程主机版本为centos6提供centos6的nginx配置文件

when 语句中也可以使用 jinja2 中的语法,例如 and、not 等

- hosts: webservers
  remote_user: root
  tasks:
  - name: install nginx
    yum: name=nginx state=latest
  - name: inst nginx config centos7
    template: src=files/nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
    # 两个条件必须同时满足
    when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"
    tags: instconf
    notify: restart nginx
  - name: inst nginx config centos6
    template: src=files/nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
    when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6"
    tags: instconf
  - name: start nginx
    systemd: name=nginx state=started enabled=yes
  handlers:
  - name: restart nginx
    systemd: name=nginx state=reloade

8. 循环

功用:迭代需要重复的任务;

格式:

# 对迭代项引用,固定变量名为"item";而后要在task中使用 `loop` 给定要迭代的元素列表;在低版本的 ansible 中使用 with_items;

列表方法:
    字符串
    字典

示例:

- name: install some packages
  yum: name= {{ item }} state=present
  loop: # 一次迭代一个元素,第一次item为nginx,第二次item为memcached,第三次item为php-fpm
  - nginx
  - memcached
  - php-fpm
- name: add some groups # 循环创建三个组
  group: name={{ item }} state=present
  loop:
  - group11
  - group12
  - group13
- name: add some users # 循环创建三个用户,并且同时给组引用变量;
  user: name={{ item.name }} group={{ item.group }} state=present
  loop:
  - { name: 'user1',group: 'group11' }
  - { name: 'user2',group: 'group12' }
  - { name: 'user3',group: 'group13' }

完整示例:

[root@Bj-1-141 working]# cat users.yml
- hosts: webservers
  remote_user: root
  tasks:
  - name: add some groups
    group: name={{ item }} state=present
    loop:
    - group11
    - group12
    - group13
  - name: add some users
    user: name={{ item.name }} group={{ item.group }} state=present
    loop:
    - { name: 'user1',group: 'group11' }
    - { name: 'user2',group: 'group12' }
    - { name: 'user3',group: 'group13' }

9. 角色(roles)

使用 roles 可以让我们按照功能角色为基准来划分。

默认 ansible 角色(roles)的存放位置在 /etc/ansible/roles 目录内,可以通过修改 ansible 配置文件进行修改:

# additional paths to search for roles in, colon separated
#roles_path    = /etc/ansible/roles

以下是一个参考示例,我们就是按照功能进行划分,每个应用在roles下面都是一个独立的子目录;

roles/
    mysql/
    nginx/
    httpd/
    tomcat/
    memcached/

每个角色,以特定的层级目录结构进行组织;例如:

mysql/
    files/:存放由copy或script模块等调用的文件;
    templates/:template模块查找所需的模版文件目录;
    tasks/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
    handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
    vars/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
    meta/:至少应该包含一个名为main.yml的文件;定义当前角色的特殊设定及其依赖关系;其它的文件需要在此文件中通过include进行包含;
    default/:设定默认变量时使用此目录中的main.yml文件;

上面这些目录并不是必须创建,用到哪个就创建哪个就可以。

9.1 角色调用方法

在 playbook中调用角色的方法1:

- hosts: webservers
  remote_user: root
  roles:
  - mysql
  - memcached
  - nginx

在playbook中调用角色的方法2:传递变量给角色

- hosts: webservers
  remote_user: root
  roles:
  - { role: nginx,username: nginx }
  键role用于指定角色名称;后续的username: nginx用于传递变量给角色;

  还可以基于条件测试实现角色调用:
  roles:
  - { role: nginx, when: ansible_distribution_major_version == '7' }
  当系统版本为centos7时才执行nginx这个角色

10. Ansible template 模块遇到特殊字符处理问题

注意:如果推送的配置文件里含有特殊字符,如:”;” “#”等,是不能用Template模块直接推送的,因为这些不能被解析会报错,如下:

ansible template模块报错

解决方法

使用jinja2的Escaping,把这些特殊字符转义,语法:“ … ”,参考:http://jinja.pocoo.org/docs/2.9/templates/#escaping

sed -i '/^;/s/^;/{% raw %};/g' www.conf.j2
sed -i '/^{% raw %}/s/$/{% endraw %}\n/g' www.conf.j2

Jinja2转义符:

#被raw包含起来的部分被转义,不会被解析
{% raw %}
;aaa
#bbb
{% endraw %}

执行成功后配置文件内容不变如下

原创文章,作者:恩志,如若转载,请注明出处:https://www.xbzdr.com/121.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论列表(2条)

  • 1
    1 2019年4月5日 21:07

    师承何处?

    • 不悔
      恩志 回复 1 2019年4月5日 22:18

      师承多处,曾看过多个国内知名培训老师的视频教程。

联系我们

在线咨询:点击这里给我发消息

邮件:510749025@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code