Skip to content

一. Installation Guide

1.1 Installing Ansible on Ubuntu

1
2
3
4
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

1.2 Structure of configuration dir

1
2
3
4
/etc/ansible
├── ansible.cfg     #主配置文件,配置ansible工作特性(一般无需修改)
├── hosts       #主机清单(将被管理的主机放到此文件)
└── roles       #存放角色的目录

二. Introduction to Ansible

Ansible 是新出现的自动化运维工具,有以下特征: - 基于Python开发 - 集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点

- 实现了批量系统配置、批量程序部署、批量运行命令等功能。

- ansible是基于模块工作的,本身没有批量部署的能力。

- 真正具有批量部署的是ansible所运行的模块,ansible 只是提供一种框架。

​ ansible 框架主要包括: ​ 1. connection plugins 连接插件:负责和被监控端实现通信; ​ 2. host inventory:指定操作的主机,是一个配置文件里面定义监控的主机; ​ 3. 各种模块核心模块、command模块、自定义模块; ​ 4. 借助于插件完成记录日志邮件等功能; ​ 5. playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

ansible的架构:连接其他主机默认使用ssh协议

Ansible 主要组成部分: - ansible playbooks:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YML文件 - inventory:Ansible管理主机的清单 /etc/anaible/hosts - modules: Ansible执行命令的功能模块,多数为内置核心模块,也可自定义 - plugins: 模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用 - API: 供第三方程序调用的应用程序编程接口 - ansible: 组合INVENTORY、API、MODULES、PLUGINS的绿框,可以理解为是ansible命令工具,其为核心执行工具

ansible命令执行过程如下,也可以在命令中添加 -vvvvv参数查看执行过程。 1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg 2. 加载自己对应的模块文件,如command 3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件 4. 给文件+x执行 5. 执行并返回结果 6. 删除临时py文件,sleep 0退出

  1. 执行ansible的主机一般称为主控端,中控,master或堡垒机
  2. 主控端Python版本需要2.6或以上
  3. 被控端Python版本小于2.4需要安装python-simplejson
  4. 被控端如开启SELinux需要安装libselinux-python
  5. windows不能做为主控端
  6. ansible不是服务,不会一直启动,只是需要的时候启动

2.1 Quick start

2.1.1 连接集群节点

# 添加节点配置到 hosts 
sudo tee -a /etc/ansible/hosts << EOF
master ansible_host=192.168.1.180 ansible_user=moloom ansible_ssh_port=7777
node1 ansible_host=192.168.1.181 ansible_user=moloom ansible_ssh_port=7777
node2 ansible_host=192.168.1.182 ansible_user=moloom ansible_ssh_port=7777
EOF

# 校验配置文件编写是否正确
ansible-inventory /etc/ansible/hosts --list

# 测试各节点是否能联通
ansible node1 -m ping -k
ansible node2 -m ping -k

2.1.2 运行 playbook

编辑文件 first_playbook.yaml

1
2
3
4
5
6
7
8
- name: My first play
  hosts: mohosts
  tasks:
    - name: Ping my hosts
      ansible.builtin.ping:
    - name: Print message
      ansible.builtin.debug:
        msg: Hello world!
运行 playbook
ansible-playbook first_playbook.yaml -k

2.2 Inventory

Ansible 的主要功能在于批量的主机操作,inventory 就是存放要操作的主机节点的 IP 信息文件。为了方便结合环境,Ansible 还支持在 inventory 文件内对主机节点进行分组。 /etc/ansible/hosts 文件是 ansible 寻找 inventory 的默认文件。也可以通过 -i inventory.ini 命令行参数来指定 inventory 文件。 Ansible 的 inventory 支持两种文档格式 ==INI== 和 ==YAML== ,Ansible 的默认 inventory 文件就是 INI 格式。

inventory 的组名必须唯一,且区分大小写,最好不要有空格、连字符(-)以及用数字开头

2.2.1 INI 格式示例

[a_xxx]
master ansible_host=192.168.1.180
node1 ansible_host=192.168.1.181
node2 ansible_host=192.168.1.182

[a_xxx:vars]
ansible_user=moloom
ansible_ssh_port=7777
ansible_ssh_pass=mo
ansible_sudo_pass=mo
ansible_sudo_exec=/bin
ansible_ssh_private_key_file=~/.ssh/
ansible_shell_type=bash
ansible_connection=ssh
ansible_python_interpreter=/usr/bin/python3.10

[metagroup_name_s:children]
a_xxx
b_xxx
c_xxx

[metagroup_name_s2]
a_xxxx

[metagroup_name_m:children]
metagroup_name_s
metagroup_name_s2

2.2.2 YAML 格式示例

a_xxx:
    hosts:
        master:
            ansible_host: 192.168.1.180
        node1:
            ansible_host: 192.168.1.181
        node2:
            ansible_host: 192.168.1.182
    vars:   # 定义变量,可以把一些字段相同的值放到 vars 下
        ansible_user: moloom
        ansible_ssh_port: 7777
        ansible_ssh_pass: mo    #ssh连接时的密码
        ansible_sudo_pass: mo   #使用sudo连接用户时的密码
        ansible_sudo_exec: /bin #如果sudo命令不在默认路径,需要指定sudo命令路径
        ansible_ssh_private_key_file: ~/.ssh/   #秘钥文件路径,秘钥文件如果不想使用ssh-agent管理时可以使用此选项
        ansible_shell_type: bash    #目标系统的shell的类型,默认sh
        ansible_connection: ssh     #SSH 连接的类型:local,ssh,paramiko
        ansible_python_interpreter: /usr/bin/python3.10 # 指定 python 解释器版本,防止输出警告

metagroup_name_s:
    children:
        a_xxx:
        b_xxx:
        c_xxx:

metagroup_name_s2:
    hosts:
        a_xxxx:

metagroup_name_m: 
    children:
        metagroup_name_s:
        metagroup_name_s2:

2.3 Command line tools

Ansible 命令介绍。

1
2
3
4
5
6
7
/usr/bin/ansible          主程序,临时命令执行工具
/usr/bin/ansible-doc      查看配置文档,模块功能查看工具
/usr/bin/ansible-galaxy   下载/上传优秀代码或Roles模块的官网平台
/usr/bin/ansible-playbook 定制自动化任务,编排剧本工具
/usr/bin/ansible-pull     远程执行命令的工具,推送命令至远程主机
/usr/bin/ansible-vault    文件加密工具
/usr/bin/ansible-console  基于Console界面与用户交互的执行工具

ansible 命令中的 Host-pattern 支持正则表达式

- 通配符 "*"       例:ansible "*" -m ping 表示所有主机
- 逻辑或 ":"       ansible "websrvs:appsrvs" -m ping
- 逻辑与 ":&"      ansible "websrvs:&dbsrvs" –m ping 在websrvs组并且在dbsrvs组中的主机
- 逻辑非 ":!"      ansible 'websrvs:!dbsrvs' –m ping 在websrvs组,但不在dbsrvs组中的主机。注意:此处为单引号!!!
- 综合逻辑      ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' –m ping
- 正则        ansible "websrvs:&dbsrvs" –m ping , ansible "~(web|db).*\.magedu\.com" –m ping

2.3.1 Command ansible

ansible Host-pattern [options]
    -m --module #指定模块
    -a module-args  #指定模块参数,默认为 command
    -b --become #代替旧版的 sudo 切换
    -C --check  #执行但不会改变,有点类似 k8s 的 --dry-run
    -u --user   #指定远程连接的用户
    -f  #启动的并发线程数
    -K  --ask-become-pass   #提示输入 sudo 的口令
    -i  #指定 inventory 文件
    -T --timeout    #执行命令的超时时间,默认 10s
    -v  #打印详细信息,v越多,信息越详细,最多 5 个 v!!!! 
    --list-hosts    #不执行命令,只输出受影响的主机节点名
    --become-user   #指定执行操作的用户,默认是 root

2.3.2 Command ansible-inventory

操作 inventory 的命令。

ansible-inventory /etc/ansible/hosts --list #校验 inventory 文件格式

2.3.3 Command ansible-doc

这个命令相当于在查 ansible 的手册。

1
2
3
ansible-doc <moduleName> [options] [resourcesName]
    -l --list   #列出所有模块
    -s --snippet    #只显示 playbook 相关说明

2.3.4 Command ansible-galaxy

官网资源:https://galaxy.ansible.com/ui/

1
2
3
4
ansible-galaxy [options] 
    - list  #列出安装了的 roles
    - install   #安装
    - remove    #删除

2.3.5 Command ansible-pull

推送命令至远程主机,效率无限提升。

2.3.6 Command ansible-playbook

1
2
3
4
5
6
7
ansible-playbook <filename.yml> ... [options]
    --check -C       只检测可能会发生的改变,但不真正执行操作;只检查语法,如果执行过程中出现问题,-C无法检测出来;执行playbook生成的文件不存在,后面的程序如果依赖这些文件,也会导致检测失败
    --list-hosts     列出运行任务的主机
    --list-tags      列出tag  (列出标签)
    --list-tasks     列出task (列出任务)
    --limit 主机列表 只针对主机列表中的主机执行
    -t              #指定执行打了某个标签的 play 片段

2.3.7 Command ansible-vault

管理加密解密yml文件

1
2
3
4
5
6
7
ansible-vault [options] [resourcesName]
    - encrypt   #加密
    - decrypt   #解密
    - view  #查看
    - edit  #编辑加密文件
    - rekey     #修改口令
    - create    #创建新文件

2.3.8 Command ansible-console

ansible-console [host-pattern] 

2.4. Ansible 常用模块

模块文档:https://docs.ansible.com/ansible/latest/module_plugin_guide/index.html

2.4.1 Command

Command 在远程主机执行命令,默认模块,可忽略-m选项。模块常用参数: - chdir 进入到被管理的主机 - creates 如果 creates 中的文件或文件夹存在,值则不执行后面的命令,若不存在则执行

1
2
3
4
5
6
7
8
# 示例

#查看 sshd 状态
ansible mohosts -a 'service sshd status'
#进入被管理主机某个目录,打印当前所在目录
ansible mohosts -a 'chdir=/tmp pwd'
#若 home 目录没有 calico,则打印 home 的所有文件
ansible mohosts -a 'creates=~/calico ls -l'

此命令不支持 $VARNAME < > | ; & 等!!!

2.4.2 Shell

Shell 在远程主机执行命令,与 Command 模块类似,但支持更复杂的命令。

1
2
3
4
5
# 修改用户密码
ansible mohosts -m shell -a 'echo moo | passwd --stdin moloom'

# 运行复杂命令,如 awk 处理文件内容,复杂命令可能会失败,推荐写入脚本后复制到远程主机执行,再将结果拉回执行机器。
ansible mohosts -m shell -a "cat /tmp/stanley.md | awk -F'|' '{print $1,$2}' &> /tmp/example.txt"

2.4.2.1 修改配置文件,使 Shell 作为默认模块

1
2
3
vim /etc/ansible/ansible.cfg
# 添加或修改以下内容
module_name = shell

2.4.3 Script

在远程主机上运行ansible服务器上的脚本

ansible mohosts -m script -a /data/test.sh

2.4.4 Copy

从主控端复制文件到远程主机。模块常用参数: - src 源文件,指定拷贝文件的本地路径 (如果有/ 则拷贝目录内容,比拷贝目录本身) - dest 目标路径 - owner 所有者 - group 所属组 - mode 设置权限 - backup 是否备份目的地的文件 - content 文件内容

1
2
3
4
# 如果目标存在,则备份要被覆盖的目的地文件
ansible mohosts -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=moloom mode=600 backup=yes"
# 指定内容,直接生成目标文件
ansible mohosts -m copy -a "content='test content\nxxx' dest=/tmp/test.txt"

2.4.5 Fetch

从远程主机提取文件至主控端,copy相反,目前不支持目录,可以先打包,再提取文件。

1
2
3
4
5
# 生成每个被管理主机不同编号的目录,不会发生文件名冲突
ansible mohosts -m fetch -a 'src=/root/test.sh dest=/data/scripts'
# 先压缩,在传到本机,注意压缩包名称不要重复
ansible all -m shell -a 'tar jxvf test.tar.gz /root/test.sh'
ansible all -m fetch -a 'src=/root/test.tar.gz dest=/data/'

2.4.6 File

设置文件属性。参数如下: - path 文件路径 - recurse 递归,一般在 state=directory 时用 - src 创建硬链接,软链接时,指定源目标,配合'state=link' 'state=hard' 设置软链接,硬链接 - state 状态,可选值:touch 创建文件、directory 创建文件夹、absent 删除作用、link 软连接、hard 硬连接。

1
2
3
4
5
6
7
8
# 创建文件
ansible node1 -m file -a 'path=/app/test.txt state=touch'
# 创建目录
ansible node1 -m file -a "path=/data/testdir state=directory"
# 设置权限755
ansible node1 -m file -a "path=/root/test.sh owner=wang mode=755"
# 创建软链接
ansible node1 -m file -a 'src=/data/testfile dest=/data/testfile-link state=link' 

2.4.7 Unarchive

解包解压缩。常见参数: - copy deprecated! 默认 yes。值为 yes 会把压缩包传到远程主机后解压缩;若为 no,则会在远程主机上查找以 src 字段的值为文件 - src 源文件路径(可以是主控端/远程主机路径,远程路径需配合copy=no) - dest 解压目标路径(强制参数) - mode 设置解压后文件权限 - remote_src true 代表压缩包在远程主机上,false 代表压缩包在控制主机上

1
2
3
4
5
6
# 从主控端解压文件到远程主机(默认copy=yes)
ansible node1 -m unarchive -a 'src=foo.tgz dest=/var/lib/foo'
# 解压远程主机上的压缩包并设置权限777
ansible node1 -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
# 解压远程主机上的压缩包到远程主机
ansible node1 -m unarchive -a 'src=~/2/1.tar.gz remote_src=true dest=/home/moloom/2'

2.4.8 Archive

远程主机目录打包压缩。参数说明: - path 要打包的目录路径(强制) - dest 生成的压缩包路径(强制) - format 压缩格式(zip/tar/bz2/gz等) - owner 设置文件属主 - mode 设置文件权限

# 将/etc/sysconfig目录打包为bz2格式,并设置权限
ansible all -m archive -a 'path=/etc/sysconfig dest=/data/sysconfig.tar.bz2 format=bz2 owner=wang mode=0777'

2.4.9 Hostname

管理主机名。

1
2
3
4
# 批量修改主机组名称
ansible node1 -m hostname -a "name=app.adong.com"
# 修改单个主机名
ansible 192.168.38.103 -m hostname -a "name=app2.adong.com"

2.4.10 Cron

管理计划任务(增强版)。参数说明: - name 任务唯一标识(推荐) - job 要执行的命令(强制) - state absent表示删除任务 - disabled yes表示禁用任务(注释) - 时间参数:minute/hour/day/month/weekday

1
2
3
4
5
6
# 创建每5分钟时间同步任务
ansible mohosts -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.16.0.1 &>/dev/null' name=Synctime"
# 删除指定名称的任务
ansible mohosts -m cron -a 'state=absent name=Synctime'
# 创建被禁用的计划任务
ansible mohosts -m cron -a 'minute=*/10 job="/usr/sbin/ntpdate 172.30.0.100" name=synctime disabled=yes'

2.4.11 Service

服务管理。参数说明: - name 服务名称(强制) - state 服务状态:started/stopped/reloaded/restarted - enabled 是否开机自启

1
2
3
4
5
6
# 停止服务
ansible node1 -m service -a 'name=httpd state=stopped'
# 启动服务并设置开机自启
ansible node1 -m service -a 'name=httpd state=started enabled=yes'
# 重启服务
ansible node1 -m service -a 'name=httpd state=restarted'

2.4.12 User

用户管理。参数说明: - append 在加入多个组(非 primary 组)时,是否追加还是覆盖设置,默认 false 覆盖 - name 用户名(强制) - system 是否系统用户 - home 指定家目录 - group 主组 - shell 指定登录shell - password 设置密码,密码必须是加密的,用 openssl passwd -1 加密 - remove 删除用户时同时删除家目录 - state absent表示删除用户

1
2
3
4
5
6
7
8
# 创建测试用户
ansible mohosts -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
# 创建系统用户
ansible mohosts -m user -a 'name=sysuser1 system=yes home=/app/sysuser1'
# 彻底删除用户(包括家目录)
ansible mohosts -m user -a 'name=user1 state=absent remove=yes'
# 创建带密码的用户,密码必须是加密的
ansible mohosts -m user -a 'name=app uid=1188 system=yes home=/home/app groups=root shell=/sbin/nologin password="$6$randomsalt$IxDD3jeSOb5eB1CX5LBsqZFVkJdido3OUILO5Ifz5iwMuTS4XMS130MTSuDDl3aCI6WouIT9pzdK6cDmPw0vL0"' --become -K

2.4.13 Group

用户组管理,参数说明 - gid 指定组的gid - name 组名 - state 添加 present、删除 absent 用户组 - non_unique 是否允许 gid 不唯一,默认 false - force 是否强制执行用户组的修改操作,默认 false - local 是否只在本地创建组(即不使用集中认证系统),默认 false - system 是否是系统组,默认 false

用户组管理。

1
2
3
4
# 创建系统组
ansible srv -m group -a "name=testgroup system=yes"
# 删除用户组
ansible srv -m group -a "name=testgroup state=absent"

2.4.14 Lineinfile

Ansible 在使用 sed 进行替换时,经常会遇到需要转移的问题,而且 Ansible 在遇到特殊符号进行替换时,存在问题,无法正常进行替换。Ansible 提供了两个模块: Lineinfile 和 Replace 模块用于进行替换功能。

1
2
3
4
5
6
#把 master 解析的行更改成 222
ansible mohosts -m lineinfile -a "path=/etc/hosts regexp='master$' line='222'" --become -K
#更改回来
ansible mohosts -m lineinfile -a "path=/etc/hosts regexp='222' line='192.168.1.180 master'" --become -K
#删除 222 这行
ansible mohosts -m lineinfile -a "path=/etc/fstab regexp='222' state=absent" --become -K

2.4.15 Replace

类似 sed 命令,也支持正则。

#把挂载的 swap 行给取消注释
ansible mohosts -m replace -a "path=/etc/fstab regexp='^#(/swap.*)' replace='\1'" --become -K

2.4.16 Setup

用于收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是主机较多时性能有点差,可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息。

1
2
3
4
#收集 node1 的所有信息
ansible node1 -m setup
#获取指定的某个 key 信息
ansible node1 -m setup -a 'filter=ansible_processor'

2.5 Playbook

playbook 用于部署和配置托管节点,通过编写 playbook 来实现程序的自动化部署。

2.5.1 Playbook 核心元素

  • Hosts 执行的远程主机列表(应用在哪些主机上)
  • Tasks 任务集
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates模板 可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags标签 指定某条任务执行,用于选择运行playbook中的部分代码。 ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断 ansible-playbook -t tagsname useradd.yml

2.5.2 示例

2.5.3 notfy 和 handlers

notify 会在当前 task 结束时被触发,执行所指向的 handlers 中命令。

示例如下。

- name: test notify and handlers
  hosts: mohosts
  gather_facts: no  #取消收集信息
  tasks:
    - name: print 1
      shell: echo 1 > 1.txt
      notify: restarted cron
    - name: print 2
      shell: pwd >> 1.txt
    - name: print service cron info
      shell: service cron status >> 1.txt
    - name: restart service cron
      service: name=cron state=restarted 
    - name: print seperate
      shell: echo "\nservice cron has restarted!\n" >> 1.txt

  handlers:
    - name: restarted cron
      service: name=cron state=restarted
    - name: Check cron process
      shell: killall -0 cron >> 1.txt

2.5.4 tags

tags 用于在 play 中添加标签,这样可以在 ansible-playbook 命令中添加参数 --tags mo 来指定执行某个 play 片段

示例:只会执行 print 2 ansible-playbook AnsibleProjects/playbook/test_notify_handlers.yaml --limit master -t mo,qq

- name: test notify and handlers
  hosts: mohosts
  gather_facts: no  #取消收集信息
  tasks:
    - name: print 1
      shell: echo 1 > 1.txt
    - name: print 2
      shell: pwd >> 1.txt
      tags: mo
    - name: print 3
      shell: echo 3 >> 1.txt
      tags: qq

2.5.5 playbook 中的变量

变量命名:变量名仅能由字母、数字和下划线组成,且只能以字母开头。

2.5.5.1 变量来源

  1. setup,可以通过 setup 模块获取被控主机信息,这些信息都是变量,可以被引用。
  2. ansible 默认的 inventory 文件中定义的变量也可以被引用。
  3. 通过命令行指定变量,优先级是最高! ansible-playbook –e varname=value
  4. 在 playbook 中定义。
  5. 在独立的变量 YAML 文件中定义。
  6. 在 role 中定义。

2.5.5.2 定义变量

2.5.5.2.1 在 playbook 中定义
1
2
3
4
5
6
7
8
- name: define the vars
  hosts: mohosts
  vars:
    - var1: value1
    - var2: value2
  tasks:
    - name: print 1
      shell: echo {{ var1 }} > 1.txt
2.5.5.2.2 单独变量 yaml 文件

1
2
3
#文件名 vars.yaml
var1: value11
var2: value22
1
2
3
4
5
6
7
# playbook.yaml
- name: test
  vars_files:
    - /home/moloom/vars.yaml
  tasks:
    - name: print 1
      shell: echo {{ var1 }} > 1.txt

2.5.5.2.3 在 INI 类型的 inventory 文件中定义变量

1
2
3
4
5
6
[mohosts]
master ansible_host=192.168.1.180   #注意:在这定义的只有操作 master 时才能使用

[mohosts:vars]  #在这定义的在操作 mohosts 组时都能用
ansible_user=moloom
ansible_ssh_port=7777
使用变量
ansible master -a 'echo {{ ansible_host }} >> 1.txt'

2.5.5.2.4 在命令行定义临时变量
ansible master -e 'ansible_host=192.168.1.181' -a 'echo {{ ansible_host }} >> 1.txt'

2.5.5.3 调用变量

通过{{ variable_name }} 调用变量,且变量名前后必须有空格,有时用“{{ variable_name }}”才生效。

2.5.6 Template 模版

template 有点类似编程语言一样,有数组、运算符、逻辑控制(for、if、when),根据 template 模块文件动态生成对应的配置文件,使用 jinja2 语法格式。

template文件必须存放于templates目录下,且以 .j2 结尾.

1
2
3
├── temnginx.yml
     └── templates
        └── nginx.conf.j2

2.5.6.1 基本语法

Jinja2语言,使用字面量,有下面形式
    字符串:使用单引号或双引号
    数字:整数,浮点数
    列表:[item1, item2, ...]
    元组:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When

2.5.6.2 示例

#示例:利用template 同步nginx配置文件
#vim temnginx.yml
- hosts: master
  remote_user: root
  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

# templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpu+2 }}

2.5.6.3 when 分支结构

需要将某个执行结果作为判断条件时使用。

# 注意:在 when 语句后面取值不需要用双花括号 {{}} 。
- name: test when
  hosts: master
  gather_facts: no  # 取消收集信息
  tasks:
    - name: Run /bin/false
      command: /bin/false
      register: result
      ignore_errors: True
    #第一个 task 执行失败时执行
    - name: Run /bin/something if previous task failed
      command: /bin/pwd
      when: result is failed
    #第一个 task 执行成功时执行
    - name: Run /bin/something_else if previous task succeeded
      command: /bin/something_else
      when: result is succeeded
    #第一个 task 被跳过时执行
    - name: Run /bin/still/something_else if previous task was skipped
      command: /bin/still/something_else
      when: result is skipped

2.5.6.4 with_items

用于重复性执行任务。对迭代项的引用,固定变量名为"item"。

# 注意:在 when 语句后面取值不需要用双花括号 {{}} 。
- name: test when
  hosts: master
  gather_facts: no  # 取消收集信息
  tasks:
    - name: Run /bin/false
      command: /bin/false
      register: result
      ignore_errors: True
    #第一个 task 执行失败时执行
    - name: Run /bin/something if previous task failed
      command: /bin/pwd
      when: result is failed
    #第一个 task 执行成功时执行
    - name: Run /bin/something_else if previous task succeeded
      command: /bin/something_else
      when: result is succeeded
    #第一个 task 被跳过时执行
    - name: Run /bin/still/something_else if previous task was skipped
      command: /bin/still/something_else
      when: result is skipped

    #with_items 还可以嵌套子变量
    - name: add several users
      user: name={{ item.name }} state=present groups={{ item.groups }}
      with_items:
        - { name: 'testuser1', groups: 'wheel' }
        - { name: 'testuser2', groups: 'root' }

2.5.6.5 条件分支语法 for 、if

示例

# temnginx.yml
---
- hosts: testweb
  remote_user: root
  vars:      # 调用变量
    nginx_vhosts:
      - listen: 8080  #列表 键值对
      - server_name: 127.0.0.1

# templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}  
server {
  listen {{ vhost.listen }}
  {% if vhost.server_name is defined %}
  server_name {{ vhost.server_name }}
  {% endif %}
}
{% endfor %}

#生成的结果
server {
  listen 8080
}

2.6 Roles

roles 是 1.2 版本引入的新特性,用于层次性、结构化地组织 playbook。roles 能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。roles 就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地 include 它们的一种机制,类似于 docker compose 的编排技术。

2.6.1 通过 Roles 传递参数

当给一个主机应用角色的时候可以传递变量,然后在角色内使用这些变量。

1
2
3
4
5
- hosts: master
  roles:
    - common    #调用第一个 role
    # 调用 foo_app_instance ,后面的 dir 和 port 是给 role 传参
    - { role: foo_app_instance, dir: '/web/htdocs/a.com', port: 8080 }

2.6.2 条件使用 Roles

角色也可以条件调用。

1
2
3
4
- hosts: master
  roles:
    # 当 when 后面的条件成立,才会调用 some_role
    - { role: some_role, when: "ansible_os_family == 'RedHat'" }

2.6.3 Roles 目录结构

roles/
└── projectName/        # 项目名称,以下每个目录必须至少有一个 main.yaml 文件!!!!
    ├── tasks/             # 定义 task, role 的基本元素
       └── main.yaml
    ├── files/             # 存放由 copy 或 script 模块等调用的文件
       └── main.yaml
    ├── vars/              # 定义变量
       └── main.yaml
    ├── templates/         # template 模块查找所需要模板文件的目录
       └── main.yaml
    ├── handlers/          # 其它的文件需要在此文件中通过 include 进行包含
       └── main.yaml
    ├── default/           # 不常用,设定默认变量时使用此目录中的 main.yml 文件
       └── main.yaml
    └── meta/     # 用于定义此角色的特殊设定及其依赖关系;ansible 1.3 及其以后的版本才支持
        └── main.yaml

2.6.4 示例

在 ubuntu 上安装 nginx。

2.6.4.1 目录结构

├── playbook.yaml
└── roles
    ├── nginx
       ├── files
          └── index.html
       ├── handlers
          └── main.yml
       ├── tasks
          └── main.yml
       └── templates
           └── nginx.conf.j2
    └── nginx_uninstall
        ├── files
        └── tasks
            └── main.yml

2.6.4.2 创建 playbook.yml

1
2
3
4
5
- hosts: master
  become: yes
  roles:
    #- nginx #安装 nginx
    - nginx_uninstall #卸载 nginx

2.6.4.3 roles/nginx/tasks/main.yml

- name: Ensure Nginx is installed
  apt:
    name: nginx
    state: present
    update_cache: yes

- name: Copy Nginx configuration template
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Restart Nginx

- name: Copy index.html to default site
  copy:
    src: index.html
    dest: /var/www/html/index.html

- name: Ensure Nginx is enabled and running
  service:
    name: nginx
    state: started
    enabled: yes

2.6.4.4 roles/nginx/files/index.html

<!DOCTYPE html>
<html>
<head>
    <title>Welcome to Nginx!</title>
</head>
<body>
    <h1>Hello, World!</h1>
    <p>This is the default page for Nginx on Ubuntu.</p>
</body>
    </html>

2.6.4.5 roles/nginx/handlers/main.yml

1
2
3
4
- name: Restart Nginx
  service:
    name: nginx
    state: restarted

2.6.4.6 roles/nginx/templates/nginx.conf.j2

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;
        index index.html;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

2.6.4.7 roles/nginx_uninstall/tasks/main.yml

- name: Stop Nginx service
  service:
    name: nginx
    state: stopped
    enabled: no

- name: Remove Nginx package
  apt:
    name: nginx
    state: absent
    purge: yes  # 彻底删除配置文件
    autoremove: yes  # 自动删除不再需要的依赖包

- name: Remove Nginx log files
  file:
    path: /var/log/nginx
    state: absent

- name: Remove Nginx configuration files
  file:
    path: /etc/nginx
    state: absent

- name: Remove Nginx web root directory
  file:
    path: /var/www/html
    state: absent