YAML使用三种节点类型表示任何本机数据结构:序列 - 有序的条目系列;映射 - 唯一键与值的无序关联;和标量 - 任何具有不透明结构的基准面,可表示为一系列 Unicode 字符。这些基元组合在一起,生成有向图结构。选择这些原语是因为它们既强大又熟悉:序列对应于Perl数组和Python列表,映射对应于Perl哈希表和Python字典。标量表示字符串、整数、日期和其他原子数据类型。
每个 YAML 节点除了其种类和内容外,还需要一个指定其数据类型的标记。类型说明符可以是全局 URI,也可以是单个应用程序的本地范围。例如,在 YAML 中,一个整数用标量加上全局标记“tag:yaml.org,2002:int”表示。同样,特定于给定组织的发票对象可以与本地标记“!invoice”一起表示为映射。这个简单的模型可以表示独立于编程语言的任何数据结构。
对于顺序访问媒体(如事件回调 API),YAML 表示形式必须序列化为有序树。由于在 YAML 表示形式中,映射键是无序的,并且节点可能被多次引用(具有多个传入的“箭头”),因此序列化过程需要对映射键施加排序,并将对给定节点的第二个和后续引用替换为称为别名的占位符.YAML 不指定如何选择这些序列化详细信息。YAML处理器可以提出人性化的键顺序和锚点名称,可能是在应用程序的帮助下。然后,可以遍历此过程的结果(YAML 序列化树),以生成一系列事件调用,以便对 YAML 数据进行一次性处理。
要使用串行 API 表示 YAML 表示形式,必须对映射键施加顺序,并使用别名节点来指示以前遇到的节点的后续出现。此过程的结果是一个序列化树,其中每个节点都有一组有序的子节点。对于基于事件的串行 API,可以遍历此树。从串行接口构造本机结构不应使用键序或锚点来保存重要数据。
从 YAML 流加载本机数据结构的过程有几个潜在的故障点。字符流可能格式不正确,别名可能未识别,未指定的标记可能无法解析,标记可能无法识别,内容可能无效,并且本机类型可能不可用.这些故障中的每一个都会导致不完整的加载。
部分表示不需要解析每个节点的标签,并且标量内容的规范形式也不需要可用。这种较弱的表示形式对于文档中使用的类型不完全了解的情况很有用。相反,完整表示指定每个节点的标记,并提供标量内容的规范形式,从而允许进行相等性测试。为了构造本机数据结构,需要完整的表示形式。
标量是最基本的不可在分的值,包含:
范例
#使用缩进的方式
martin:
name: Martin D'vloper
job: Developer
skill: Elite
#key对应value,字典列表
- martin:
name: Martin D'vloper
job: Developer
skills:
- python
- perl
- pascal
- tabitha:
name: Tabitha Bitumen
job: Developer
skills:
- lisp
- fortran
- erlang
#流集合
---
martin: {name: Martin D'vloper, job: Developer, skill: Elite}
fruits: ['Apple', 'Orange', 'Strawberry', 'Mango']
#几种形式指定布尔值(true/false)
create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
#使用yaml表示一个家庭
name: John Smith
age: 41
gender: Male
spouse: { name: Jane Smith, age: 37, gender: Female } # 写在一行里
name: Jane Smith #也可以写成多行
age: 37
gender: Female
children: [ {name: Jimmy Smith,age: 17, gender: Male}, {name: Jenny Smith, age:
13, gender: Female}, {name: hao Smith, age: 20, gender: Male } ] #写在一行
- name: Jimmy Smith #写在多行,更为推荐的写法
age: 17
gender: Male
- {name: Jenny Smith, age: 13, gender: Female}
- {name: hao Smith, age: 20, gender: Male }
一个playbook中由多个组件组成,其中所用到的常见组件类型如下:
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用 于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!dbsrvs #在websrvs组,但不在dbsrvs组
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可 用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
---
- hosts: websrvs
remote_user: root #指定任务执行默认用户
tasks:
- name: test connection
ping:
remote_user: xiang
sudo: yes #默认sudo为root
sudo_user:Test #sudo为Test
task列表和action组件
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主 机上执行,即在所有主机上完成第一个task后,再开始第二个task task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着 多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。 如果未提供name,则action的结果将用于输出
action: module arguments #示例: action: shell wall hello
module: arguments #建议使用 #示例: shell: wall hello
注意:
范例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
#shell 脚本实现安装httpd
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
#playbook实验安装httpd
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes
https://docs.ansible.com/ansible/2.9/user_guide/playbooks.html#working-with-playbooks
ansible-playbook <filename.yml> ... [options]
--syntax-check #语法检查,可缩写成--syntax, 相当于bash -n
-C --check #模拟执行,只检测可能会发生的改变,但不真正执行操作,dry run
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-i INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件
--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的
name
-v -vv -vvv #显示过程
范例
[root@ansible ansible]#cat hello.yml
---
- hosts: websrvs
tasks:
- name: hello
command: echo "hello ansible"
ansible-playbook file.yml --check #只检测语法
ansible-playbook file.yml #直接执行
ansible-playbook file.yml --limit websrvs 只执行存在webservs列表内的主机
#写法一
---
- hosts: webservs #指定hostsliet
remote_user: root #指定执行tasks的默认用户
gather_facts: no #关闭setup收集信息
tasks:
- name: "创建组,组名:mysql 系统组 gid为306"
group: name=mysql system=yes gid=306
- name: "创建用户 mysql,不可登录,不创建家目录,是系统用户加入mysql组"
user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_hoem=no
#写法二
---
- hosts: webservs #指定hostsliet
remote_user: root #指定执行tasks的默认用户
gather_facts: no #关闭setup收集信息
tasks:
- { name: create group,group: name=mysql system=yes gid=306 }
- { name: create user, user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no }
#环境清理
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: "删除nginx用户相关的组和目录"
user: name=nginx state=absent remove=yes
#写法一
---
- hosts: websers
remote_user: root
gather_facts: no
tasks:
- name: "创建挂载目录"
file: path=/mnt/cdrom state=directory mode=755
- name: "临时挂载cdrom"
mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present
- name: "创建nginx组"
group: name=nginx state=present gid=307 system=yes
- name: "创建nginx用户"
user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin
- name: "安装nginx"
yum: name=nginx state=present
- name: "拷贝网页文件"
copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html
- name: "启动服务"
service: name=nginx state=started enabled=yes
#写法二
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- { name: "创建挂载目录",file: path=/mnt/cdrom state=directory mode=755 }
- { name: "临时挂载cdrom",mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present }
- { name: "创建nginx组",group: name=nginx state=present gid=307 system=yes }
- { name: "创建nginx用户",user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin }
- { name: "安装nginx",yum: name=nginx state=present }
- { name: "拷贝网页文件",copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html }
- { name: "启动服务",service: name=nginx state=started enabled=yes }
#环境清理
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: "停止服务"
service: name=nginx state=stopped
- name: "删除nginx用户相关的组和目录"
user: name=nginx state=absent remove=yes
- name: "卸载目录"
mount: path=/mnt/cdrom state=unmounted
- name: "删除index文件"
file: path=/usr/share/nginx/html/index.html state=absent
#!/usr/bin/ansible-playbook
---
#This is playbook file
#install mysql 5.6
- hosts: dbservs
remote_user: root
gather_facts: yes
vars:
version: "mysql-5.6.46-linux-glibc2.12-x86_64"
suffix: "tar.gz"
pack_file: "{{version}}.{{suffix}}"
bash: mysql-5.6_install.sh
tasks:
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
- name: create mysql group
group: name=mysql system=yes gid=306
- name: create mysql user
user: name=mysql group=mysql uid=306 system=yes create_home=no shell=/sbin/nologin home=/data/mysql
- name: copy tar to remote host and file mode
unarchive: src=/data/ansible/files/{{file}} dest=/usr/local/ owner=root group=root
- name: create linkfile /usr/local/mysql
file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link
- name: create linkfile /usr/local/mysql
file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
tags: data
- name: config my.cnf
copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: enable service
shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on
tags: service
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
- name: secure script
script: /data/ansible/files/{{bash}}
tags: script
ignore_errors
功能
---
- hosts: websrvs
tasks:
- name: error
command: /bin/false #执行后默认值为1,即rc=1,$?=1
ignore_errors: yes #忽略错误
- name: continue
command: wall continue #广播 continue
handlers和notify
功能
Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质 上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在 每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完 成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作;
注意
范例
#复制httpd的配置文件到指定目录
cp -p /etc/httpd/conf/httpd.conf /root/files/
#生成playbook,对httpd.conf设置notify
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=/root/files/httpd.conf dest=/etc/httpd/conf/ #当httpd.conf文件发生改变时触发notify
notify:
- restart httpd
- wall
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
- name: wall
command: wall "The config file is changed"
#执行playbook,可以发现没有触发notify,因此HANDLER直接跳过了
[root@Ansible-Master Date14:04]#ansible-playbook install_httpd.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install httpd] *****************************************************************************************************************************************************************************************************
changed: [192.168.213.123]
changed: [192.168.213.122]
TASK [Install configure file] ********************************************************************************************************************************************************************************************
changed: [192.168.213.122]
changed: [192.168.213.123]
TASK [ensure apache is running] ******************************************************************************************************************************************************************************************
changed: [192.168.213.123]
changed: [192.168.213.122]
RUNNING HANDLER [restart httpd] ******************************************************************************************************************************************************************************************
changed: [192.168.213.123]
changed: [192.168.213.122]
RUNNING HANDLER [wall] ***************************************************************************************************************************************************************************************************
skipping: [192.168.213.122]
skipping: [192.168.213.123]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=4 changed=4 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.213.123 : ok=4 changed=4 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
#修改httpd.conf文档后在执行playbook
sed -ri '/Listen/s/80/8088/' /root/files/httpd.conf
#再次执行playbook,成功触发HANDLER
[root@Ansible-Master Date14:07]#ansible-playbook -C install_httpd.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install httpd] *****************************************************************************************************************************************************************************************************
^C [ERROR]: User interrupted execution
[root@Ansible-Master Date14:12]#ansible-playbook install_httpd.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install httpd] *****************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [Install configure file] ********************************************************************************************************************************************************************************************
changed: [192.168.213.123]
changed: [192.168.213.122]
TASK [ensure apache is running] ******************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
RUNNING HANDLER [restart httpd] ******************************************************************************************************************************************************************************************
changed: [192.168.213.123]
changed: [192.168.213.122]
RUNNING HANDLER [wall] ***************************************************************************************************************************************************************************************************
changed: [192.168.213.122]
changed: [192.168.213.123]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#强制触发HANDLER
---
- hosts: websers
remote_user: root
gather_facts: no
force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers
tasks:
- name: config file
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
notify:
- restart nginx
- name: install package
yum: name=no_exist_package
handlers:
- name: restart nginx
service: name=nginx state=restarted
- name: "wall"
command: wall "call handlers"
tags
官方文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
功能说明
范例
#对单个任务添加标签
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags:
- conf
- file
- name: start httpd service
tags: service
service: name=httpd state=started enabled=yes
#查看标签
[root@Ansible-Master Date16:44]#ansible-playbook --list-tags tag_Test-01.yaml
playbook: tag_Test-01.yaml
play #1 (webservs): webservs TAGS: []
TASK TAGS: [conf, file, service]
#运行单个标签
[root@Ansible-Master Date16:46]#ansible-playbook -t conf tag_Test-01.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install configure file] ********************************************************************************************************************************************************************************************
ok: [192.168.213.122]
ok: [192.168.213.123]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#跳过某个标签
[root@Ansible-Master Date16:46]#ansible-playbook -t conf tag_Test-01.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install configure file] ********************************************************************************************************************************************************************************************
ok: [192.168.213.122]
ok: [192.168.213.123]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@Ansible-Master Date16:46]#ansible-playbook --skip-tags conf tag_Test-01.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Install httpd] *****************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [start httpd service] ***********************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#对tasks打标签
- hosts: websevs
remote_user: root
tags: install
gather_facts: no
tasks:
- { name: "创建挂载目录",file: path=/mnt/cdrom state=directory mode=755 }
- { name: "临时挂载cdrom",mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present }
- { name: "创建nginx组",group: name=nginx state=present gid=307 system=yes }
- { name: "创建nginx用户",user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin }
- { name: "安装nginx",yum: name=nginx state=present }
- { name: "拷贝网页文件",copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html }
- { name: "启动服务",service: name=nginx state=started enabled=yes }
- hosts: webservs
remote_user: root
tags: clear
gather_facts: no
tasks:
- name: "停止服务"
service: name=nginx state=stopped
- name: "删除nginx用户相关的组和目录"
user: name=nginx state=absent remove=yes
- name: "卸载目录"
mount: path=/mnt/cdrom state=unmounted
- name: "删除index文件"
file: path=/usr/share/nginx/html/index.html state=absent
#查看标签
[root@Ansible-Master Date16:56]#ansible-playbook --list-tags tag_Test-02.yaml
playbook: tag_Test-02.yaml
play #1 (webservs): webservs TAGS: [install]
TASK TAGS: [install]
play #2 (webservs): webservs TAGS: [clear]
TASK TAGS: [clear]
#只运行clear标签
[root@Ansible-Master Date16:56]#ansible-playbook -t clear tag_Test-02.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [停止服务] **************************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [删除nginx用户相关的组和目录] **************************************************************************************************************************************************************************************************
ok: [192.168.213.122]
ok: [192.168.213.123]
TASK [卸载目录] **************************************************************************************************************************************************************************************************************
changed: [192.168.213.122]
changed: [192.168.213.123]
TASK [删除index文件] *********************************************************************************************************************************************************************************************************
changed: [192.168.213.122]
changed: [192.168.213.123]
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
vars
Playbook中同样也支持变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
variable=value
variable: value
ansible 的 setup facts 远程主机的所有变量都可直接调用
通过命令行指定变量,优先级最高
nsible-playbook -e varname=value test.yml
在playbook文件中定义
vars:
vars1: value1
vars2: value2
在独立的变量YAML文件中定义
- hosts: all
vars_files:
- vars.yml
在主机清单文件中定义
在项目中针对主机和主机组定义
在role中定义
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名
文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组
变量
facts
范例
#使用setup变量的方法
[root@Ansible-Master Date17:18]#ansible 192.168.213.122 -m setup -a 'filter="ansible_default_ipv4"'
192.168.213.122 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.168.40.182",
"alias": "eth0",
"broadcast": "192.168.40.255",
"gateway": "192.168.40.1",
"interface": "eth0",
"macaddress": "00:0c:29:af:fc:35",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.40.0",
"type": "ether"
},
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
#在playbook中调用setup变量
---
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: create log file
file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang
mode=600
范例
#命令行指定变量
#yaml主体
---
- hosts: websrvs
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }} state=present
#执行命令需-e 调用变量,多个变量可以用空格隔开
ansible-playbook -e pkname=httpd var2.yaml
#多个变量
#yaml主体
---
- hosts: websrvs
remote_user: root
vars:
username: user1
groupname: group1
tasks:
- name: create group {{ groupname }}
group: name={{ groupname }} state=present
- name: create user {{ username }}
user: name={{ username }} group={{ groupname }} state=present
#命令行调用
ansible-playbook -e username=Test groupname=Test var2.yaml
#命令行指定变量文件
#yaml主体
tee vars <pkname1: memcached
pkname2: vsftpd
---
- hosts: websrvs
remote_user: root
tasks:
- name: install package {{ pkname1 }
yum: name={{ pkname1 }} state=present
- name: install package {{ pkname2 }
yum: name={{ pkname2 }} state=present
#执行命令需-e ‘@变量文件路径与名称’调用变量文件
ansible-playbook -e '@vars' var2.yml
#变量之间的相互调用方法:文件内调用
---
- hosts: websrvs
vars:
suffix: "txt"
file: "{{ ansible_nodename }}.{{suffix}}"
tasks:
- name: test var
file: path="/data/{{file}}" state=touch
#变量之间的相互调用,文件内变量+文件外变量
#生成变量文件vars1
tee vars1 <pkweb: httpd
pkftp: vsftp
#playbook主体
---
- hosts: webservs
remote_user: root
gather_facts: no
vars:
- Username: Test-1
- Groupname: Test-group
- Dir: /home/{{ Username }}
tasks:
- name: "创建组{{ groupname }}"
group: name={{ Groupname }} system=no gid=3099
- name: "创建用户{{ username }}"
user: name={{ Username }} state=present system=no home={{ Dir }} uid=3099 shell=/sbin/nologin group={{ Groupname }}
- name: "下载对应包到指定目录"
yum: name={{ pkweb }} {{ pkftp }} download_dir={{ Dir }} download_only=yes
#执行playbook
[root@Ansible-Master Date10:38]#ansible-playbook -e '@vars1' vars1.yaml
#环境清理
ansible webservs -m user -a 'name=Test-1 state=absent remove=yes'
#变量之间的相互调用,playbook文件内调用变量文件;
#生成变量文件vars1
tee vars1.yml <---
pkweb: httpd
pkftp: vsftp
Username: Test-1
Groupname: Test-group
Dir: /home/{{ Username }}
EOF
#playbook主体
---
- hosts: webservs
remote_user: root
gather_facts: no
vars:
- vars1.yml
tasks:
- name: "创建组{{ groupname }}"
group: name={{ Groupname }} system=no gid=3099
- name: "创建用户{{ username }}"
user: name={{ Username }} state=present system=no home={{ Dir }} uid=3099 shell=/sbin/nologin group={{ Groupname }}
- name: "下载对应包到指定目录"
yum: name={{ pkweb }} {{ pkftp }} download_dir={{ Dir }} download_only=yes
#执行playbook
[root@Ansible-Master Date10:38]#ansible-playbook vars1.yaml
所有项目的主机变量
说明:
在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用
范例:
[websrvs]
www1.example.com http_port=80 maxRequestsPerChild=808
www2.example.com http_port=8080 maxRequestsPerChild=909
所有项目的组(公共)变量
说明:
在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是 同名,优先级低于主机变量
范例:
[websrvs:vars]
http_port=80
ntp_server=ntp.example.com
nfs_server=nfs.example.com
[all:vars]
# --------- Main Variables ---------------
# Cluster container-runtime supported: docker, containerd
CONTAINER_RUNTIME="docker"
# Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
CLUSTER_NETWORK="calico"
# Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
PROXY_MODE="ipvs"
# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="192.168.0.0/16"
# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="172.16.0.0/16"
# NodePort Range
NODE_PORT_RANGE="20000-60000"
# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="example.local."
针对当前项目的主机和主机组的变量
上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量
生产建议在项目目录中创建额外的两个变量目录,分别是host_vars和group_vars
host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义,格式:host_vars/hostname
group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义,格式: gorup_vars/groupname
group_vars/all文件内定义的变量对所有组都有效
范例:
[root@Ansible-Master ansible11:02]#tree /ansible/
/ansible/
├── 1.sh
├── 2.sh
├── 3.sh
├── groups_vars
│ ├── all
│ └── webservs
├── group_vars
│ ├── all
│ └── webservs
├── host_vars
│ ├── 192.168.213.122
│ └── 192.168.213.123
├── Test_var7.yaml
└── Test.yaml
3 directories, 11 files
[root@Ansible-Master ansible11:03]#cat group_vars/
all webservs
[root@Ansible-Master ansible11:03]#cat group_vars/webservs
name: slave
[root@Ansible-Master ansible11:03]#cat group_vars/all
domain: Slave
[root@Ansible-Master ansible11:03]#cat host_vars/192.168.213.122
id: 01
[root@Ansible-Master ansible11:04]#cat host_vars/192.168.213.123
id: 02
[root@Ansible-Master ansible11:04]#cat Test_var7.yaml
#!/usr/bin/ansible-playbook
---
# This is a playbook file
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: get variable
command: echo "{{name}}{{id}}.{{domain}}"
register: result
- name: print variable
debug:
msg: "{{result.stdout}}"
[root@Ansible-Master ansible11:05]#ansible-playbook Test_var7.yaml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [get variable] ******************************************************************************************************************************************************************************************************
changed: [192.168.213.122]
changed: [192.168.213.123]
TASK [print variable] ****************************************************************************************************************************************************************************************************
ok: [192.168.213.122] => {
"msg": "slave1.slave01"
}
ok: [192.168.213.123] => {
"msg": "slave2.slave02"
}
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
register
功能
范例:
#利用debug 模块输出变量
---
- hosts: dbsrvs
remote_user: root
gather_facts: no
tasks:
- name: get variable
shell: hostname
register: name
- name: "print variable"
debug:
msg: "{{ name }}" #输出register注册的name变量的全部信息,注意变量要加" "引起来
#msg: "{{ name.cmd }}" #显示命令
#msg: "{{ name.rc }}" #显示命令成功与否
#msg: "{{ name.stdout }}" #显示命令的输出结果为字符串形式
#msg: "{{ name.stdout_lines }}" #显示命令的输出结果为列表形式
#msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素
#msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式
#说明
第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到该
变量中。
第二给 task 中,使用了 debug 模块,并从变量name中获取数据。
#使用register注册变量创建文件
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: "获取主机名并注册变量"
shell: hostname
register: file_name
- name: ”创建文件“
file: dest=/tmp/{{ file_name }}.log state=touch
#register和debug一起使用
---
- hosts: webservs
remote_user: root
gather_facts: no
tasks:
- name: "出输出测试值给register注册"
shell: echo hello word
register: say
- name: "获取root用户名称,并注册为变量"
shell: "awk -F: 'NR==1{print $1}' /etc/passwd"
register: user
- name: "使用debug输出变量"
debug: var=say.stdout
- debug: var=user.stdout
#安装nginx并启动
---
- hosts: webservs
remote_user: root
gather_facts: yes
vars:
- pkname: nginx
tasks:
- name: "安装{{ pkname }}包"
yum: name={{ pkname }} state=present
- name: "启动{{ pkname }}服务"
service: name={{ pkname }} state=started enabled=yes
- name: "检查"
shell: ps aux |grep {{ pkname }}
register: check_value
- debug:
msg: "{{ check_value.stdout_lines }}"
#修改主机名
- hosts: webservs
remote_user: root
gather_facts: no
vars:
host: web
domin: slave
tasks:
- name: "注册变量"
shell: echo $RANDOM | md5sum | cut -c 1-8 #取8位随机数
register: get_random
- name: "打印变量"
debug:
msg: "{{ get_random.stdout }}"
- name: "修改主机名称"
hostname: name={{ host }}-{{ get_random.stdout }}.{{ domain }}
template组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNc2o7jc-1653902203437)(C:\Users\10163\AppData\Roaming\Typora\typora-user-images\image-20220524161245604.png)]
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使 用,并且提供了可选的沙箱模板执行环境保证安全:
http://docs.jinkan.org/docs/jinja2/
https://www.w3cschool.cn/yshfid/
字面量,如: 字符串:使用单引号或双引号,数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
+
:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接 它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2-
:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1/
:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5//
:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2%
:计算整数除法的余数。 {{ 11 % 7 }} 等于 4*
:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ * 80 }} 会打印 80 个等号的横条\**
:取左操作数的右操作数次幂; {{ 2**3 }} 会返回 8可以根据和参考模块文件,动态生成相类似的配置文件 template文件必须存放于templates目录下,且命名为 .j2 结尾
例如:
yaml/yml 文件需和templates目录平级,目录结构如下:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
范例:利用template同步nginx配置文件
#创建template目录
mkdir "/root/Date/templates"
#拷贝nginx配置文件
cp -p /etc/nginx/nginx.conf /root/Date/templates/nginx.conf.j2
#修改nginx.config.j2文件,这里使用的变量ansible_processor_vcpu是setup的主机变量(具体内容请看setup模块部分),故gather_facts必须为yes(也可以不写,该组件默认开启);
sed -ri "/^worker_processe/s/auto/{{ ansible_processor_vcpu+2 }}/" #这里是逻辑运算符的运用 /root/Date/templates/nginx.conf.j2
#!/usr/bin/ansible-playbook
---
# This is a playbook file
- hosts: webservs
remote_user: root
gather_facts: yes #因为使用了setup变量,所以一定要收集主机信息
tasks:
- name: create dir
file: path=/data state=directory
- name: templates
template: src=/root/Date/templates/nginx.conf.j2 dest=/data/for.conf
for循环和if判断
{% for i in EXPR %}
...
{% endfor %}
示例:
{% for i in range(1,10) %}
server_name web{{i}};
{% endfor %}
范例:
#playbook文件内容
#!/usr/bin/ansible-playbook
---
# This is a playbook file
- hosts: webservs
remote_user: root
gather_facts: yes
vars:
nginx_vhosts:
- 81
- 82
- 83
tasks:
- name: template config
template: src=Test_for-2.j2 dest=/root/nginx.conf
#template文件内容
{% for vhosts in vhost_list %}
server {
listen {{ vhosts }}
}
{% endfor %}
#执行命令
[root@Ansible-Master Date10:12]#ansible-playbook jinja_Template-2.yml --limit 192.168.213.122
#结果验证
[root@web-0aadc460 ~10:14]$cat nginx.conf
server {
linsten 100
}
server {
linsten 101
}
server {
linsten 102
}
#playbook内容
#!/sbin/bin/playbook
---
#This is playbook file
- hosts: webservs
remote_user: root
gather_facts: yes
vars:
vhosts_list:
- listen: 8080
server_name: "web1.slave.com"
path: "/data/www/nginx/web1"
- listen: 8081
server_name: "web2.slave.com"
path: "/data/www/nginx/web2"
- listen: 8082
server_name: "web3.slave.com"
path: "/data/www/nginx/web3"
tasks:
- name: "创建目录,并忽略错误"
file: name=/data/www/nginx/ state=directory
ignore_errors: yes
- name: "拷贝模板配置"
template: src=Test_for-3.j2 dest=/data/www/nginx/nginx—2.conf
#template文件内容
{% for vhost in vhosts_list %}
server{
linsten {{ vhost.listen }}
server_name {{ vhost.server_name }}
path {{ vhost.path }}
}
{% endfor %}
#执行命令
[root@Ansible-Master Date10:29]#ansible-playbook jinja_Template-3.yml --limit 192.168.213.123
#结果验证
[root@web-1654f449 nginx10:30]$cat nginx4.conf
server{
linsten 8080
server_name web1.slave.com
path: /data/www/nginx/web1
}
server{
linsten 8081
server_name web2.slave.com
path: /data/www/nginx/web2
}
server{
linsten 8082
server_name web3.slave.com
path: /data/www/nginx/web3
}
{% if i is exrp %}
...
{% endif %}
示例:
{% for i is defined %}
server_name web{{i}};
{% endif %}
范例:
#使用先前的playbook,增加if判断
#playbook内容
#!/sbin/bin/playbook
---
#This is playbook file
- hosts: webservs
remote_user: root
gather_facts: yes
vars:
vhosts_list:
#删除web1的servername
- listen: 8080
path: "/data/www/nginx/web1"
- listen: 8081
server_name: "web1.slave.com"
path: "/data/www/nginx/web2"
- listen: 8082
server_name: "web1.slave.com"
path: "/data/www/nginx/web3"
tasks:
- name: "创建目录,并忽略错误"
file: name=/data/www/nginx/ state=directory
ignore_errors: yes
- name: "拷贝模板配置"
template: src=Test_for-3.j2 dest=/data/www/nginx/nginx—3.conf
#template文件内容
{% for vhost in vhosts_list %}
server{
linsten {{ vhost.listen }}
{% if vhost.server_name is defined %} #判断是否存在该值,若存在则输出;
server_name {{ vhost.server_name }}
{% endif %}
path {{ vhost.path }}
}
{% endfor %}
#执行命令
[root@Ansible-Master Date10:29]#ansible-playbook jinja_Template-4.yml --limit 192.168.213.123
#结果验证
[root@web-1654f449 nginx10:49]$cat nginx5.conf
server{
linsten 8080
path: /data/www/nginx/web1
}
server{
linsten 8081
server_name web1.slave.com
path: /data/www/nginx/web2
}
server{
linsten 8082
server_name web1.slave.com
path: /data/www/nginx/web3
}
with_items
对迭代项的引用,固定内置变量名为"item"
要在task中使用with_items给定要迭代的元素列表
注意: ansible2.5版本后,可以用loop代替with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
列表元素格式
示例:
---
- hosts: websrvs
remote_user: root
gather_facts: yes
tasks:
- name: "创建用户"
user: name={{ item }} state=present groups=wheel
#生成循环列表
with_items:
- testuser1
- testuser2
- testuser3
#该with_items等价于 - user: name=testuser1 state=present groups=wheel;(重复3次)
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: copy file
copy: src={{ item }} dest=/tmp/{{ item }}
with_items:
- file1
- file2
- file3
范例:
#卸载mysql
- hosts: 192.168.213.124
remote_user: root
gather_facts: no
vars:
- versions: 5.6.46
- pkname: mysql-{{ versions }}-linux-glibc2.12-x86_64
- path: /usr/local
- config: my.cnf
tasks:
- name: "停止服务"
shell: /etc/init.d/mysqld stop
- name: "删除文件"
file: path={{ item }} state=absent
#生成列表
with_items:
- {{ path }}/mysql
- {{ path }}/{{ pkname }}
- /etc/{{ my.cnf }}
- /etc/init.d/mysqld
- /etc/profile.d/mysql.sh
- /data/mysql
- name: "删除用户与相关配置"
user: name=mysql state=absent remove=yes
#批量安装与卸载
#!/usr/bin/ansible-playbook
---
#This is playbook file
#remove mariadb server
- hosts: webservs
remote_user: root
gather_facts: yes
tags:install
tasks:
- name: mount sr0
shell: mount /dev/cdrom /mnt/cdrom
ignore_errors: yes
- name: yum mkcache
shell: yum makecache
- name: install some packages
yum: name={{ item }} state=present
loop:
- nginx
- memcached
- php-fpm
- hosts: webservs
remote_user: root
gather_facts: yes
tags: remove
tasks:
- name: remove some packages
yum: name={{ item }} state=absent
loop:
- nginx
- memcached
- php-fpm
范例:
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: copy file and rename and clear
- hosts: webservs
remote_user: root
gather_facts: no
tags: create
tasks:
- name: "拷贝文件并重命名"
copy: src=/data/{{ item.old }} dest=/tmp/{{ item.new }}
with_items:
- { old: 'file1', new: 'files_01' }
- { old: 'file2', new: 'files_02' }
- { old: 'file3', new: 'files_03' }
- name: "查看文件"
shell: ls /data/files_*;sleep 3;
- hosts: webservs
remote_user: root
gather_facts: no
tags: remove
tasks:
- name: "删除文件"
file: name=/tmp/{{ item }} state=absent
loop:
- files_01
- files_02
- files_03
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: create user and clear
- hosts: webservs
remote_user: root
gather_facts: yes
tags: useradd
vars:
shell_dir: /sbin/nologin
tasks:
- name: create group
group: name={{ item }} state=present
with_items:
- Test01
- Test02
- Test03
- name: create user
user: name={{ item.name }} group={{ item.gname }} uid={{ item.num }} home={{ item.dir }} create_home=no shell={{ item.shell }} state=present
loop:
- { name: 'Test01', gname: 'Test01', num: '9009', dir: '/data/Test01',shell: "{{ shell_dir }}" }
- { name: 'Test02', gname: 'Test02', num: '9010', dir: '/data/Test02',shell: "{{ shell_dir }}" }
- { name: 'Test03', gname: 'Test03', num: '9011', dir: '/data/Test03',shell: "{{ shell_dir }}" }
- hosts: webservs
remote_user: root
gather_facts: no
tags: deluser
tasks:
- name: delete user
user: name={{ item }} state=absent remove=yes
loop:
- Test01
- Test02
- Test03
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Changing User Passwords in Batches
- hosts: webservs
remote_user: root
gather_facts: no
vars:
- user1: mysql
- user2: xiang
tasks:
- name: change user password
user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always
loop:
- { name: "{{ user1 }}", chpass: 'redhat@2022' }
- { name: '{{ user2 }}', chpass: 'redhat' }
#循环列表注册变量
- shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
#返回值
{
"changed": true,
"msg": "All items completed",
"results": [
{
"changed": true,
"cmd": "echo \"one\" ",
"delta": "0:00:00.003110",
"end": "2013-12-19 12:00:05.187153",
"invocation": {
"module_args": "echo \"one\"",
"module_name": "shell"
},
"item": "one",
"rc": 0,
"start": "2013-12-19 12:00:05.184043",
"stderr": "",
"stdout": "one"
},
{
"changed": true,
"cmd": "echo \"two\" ",
"delta": "0:00:00.002920",
"end": "2013-12-19 12:00:05.245502",
"invocation": {
"module_args": "echo \"two\"",
"module_name": "shell"
},
"item": "two",
"rc": 0,
"start": "2013-12-19 12:00:05.242582",
"stderr": "",
"stdout": "two"
}
]
}
#通过已注册变量进行后续循环以检查结果可能如下所示
- name: Fail if return code is not 0
fail:
msg: "The command ({{ item.cmd }}) did not have a 0 return code"
when: item.rc != 0
loop: "{{ echo.results }}"
loop_control组件
label标签
:限制最终输出内容,只显示需要的值
##增加label标签限制输出值
#未增加时yaml
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Changing User Passwords in Batches
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: change user password
user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always
loop:
- { name: 'mysql', chpass: 'redhat@2022' }
- { name: 'xiang', chpass: 'redhat' }
# loop_control:
# label: "{{ item.name }}"
#为增加时的回显
[root@Ansible-Master Date16:03]#ansible-playbook -C loop_test-8.yml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [change user password] **********************************************************************************************************************************************************************************************
changed: [192.168.213.123] => (item={u'chpass': u'redhat@2022', u'name': u'mysql'})
changed: [192.168.213.122] => (item={u'chpass': u'redhat@2022', u'name': u'mysql'})
changed: [192.168.213.122] => (item={u'chpass': u'redhat', u'name': u'xiang'})
changed: [192.168.213.123] => (item={u'chpass': u'redhat', u'name': u'xiang'})
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#增加label后的回显
sed -ri "/^#.*loop|label/s/#//" loop_test-8.yml
#回显
[root@Ansible-Master Date16:18]#ansible-playbook -C loop_test-8.yml
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [change user password] **********************************************************************************************************************************************************************************************
changed: [192.168.213.123] => (item=mysql)
changed: [192.168.213.122] => (item=mysql)
changed: [192.168.213.122] => (item=xiang)
changed: [192.168.213.123] => (item=xiang)
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.213.123 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
pause:循环内执行间隔
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Changing User Passwords in Batches
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: change user password
user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always
loop:
- { name: 'mysql', chpass: 'redhat@2022' }
- { name: 'xiang', chpass: 'redhat' }
loop_control:
pause: 3 #默认单位为秒,每次执行完一次循环后等待3秒
index_var:循环进度追踪
#playbook组件
---
- hosts: webservs
tasks:
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
#回显
PLAY [webservs] **********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************************
ok: [192.168.213.123]
ok: [192.168.213.122]
TASK [count our fruit] ***************************************************************************************************************************************************************************************************
ok: [192.168.213.122] => (item=apple) => {
"msg": "apple with index 0"
}
ok: [192.168.213.122] => (item=banana) => {
"msg": "banana with index 1"
}
ok: [192.168.213.122] => (item=pear) => {
"msg": "pear with index 2"
}
ok: [192.168.213.123] => (item=apple) => {
"msg": "apple with index 0"
}
ok: [192.168.213.123] => (item=banana) => {
"msg": "banana with index 1"
}
ok: [192.168.213.123] => (item=pear) => {
"msg": "pear with index 2"
}
内嵌循环执行:loop_var
#playbook内容
[root@Ansible-Master Date17:00]#cat loop_test-10.yml
- hosts: 192.168.213.122
remote_user: root
gather_facts: no
tasks:
- include_tasks: inner.yml #引用外部任务
loop:
- 1
- 2
- 3
loop_control:
loop_var: outer_item
[root@Ansible-Master Date17:00]#cat inner.yml
- debug:
msg: "outer item={{ outer_item }} inner item={{ item }}"
loop:
- a
- b
- c
#回显
[root@Ansible-Master Date16:59]#ansible-playbook -C loop_test-10.yml
PLAY [192.168.213.122] ***************************************************************************************************************************************************************************************************
TASK [include_tasks] *****************************************************************************************************************************************************************************************************
included: /root/Date/inner.yml for 192.168.213.122
included: /root/Date/inner.yml for 192.168.213.122
included: /root/Date/inner.yml for 192.168.213.122
TASK [debug] *************************************************************************************************************************************************************************************************************
ok: [192.168.213.122] => (item=a) => {
"msg": "outer item=1 inner item=a"
}
ok: [192.168.213.122] => (item=b) => {
"msg": "outer item=1 inner item=b"
}
ok: [192.168.213.122] => (item=c) => {
"msg": "outer item=1 inner item=c"
}
TASK [debug] *************************************************************************************************************************************************************************************************************
ok: [192.168.213.122] => (item=a) => {
"msg": "outer item=2 inner item=a"
}
ok: [192.168.213.122] => (item=b) => {
"msg": "outer item=2 inner item=b"
}
ok: [192.168.213.122] => (item=c) => {
"msg": "outer item=2 inner item=c"
}
TASK [debug] *************************************************************************************************************************************************************************************************************
ok: [192.168.213.122] => (item=a) => {
"msg": "outer item=3 inner item=a"
}
ok: [192.168.213.122] => (item=b) => {
"msg": "outer item=3 inner item=b"
}
ok: [192.168.213.122] => (item=c) => {
"msg": "outer item=3 inner item=c"
}
PLAY RECAP ***************************************************************************************************************************************************************************************************************
192.168.213.122 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
until循环
范例:
- hosts: localhost
gather_facts: false
tasks:
- debug: msg="until"
until: false
retries: 3 #默认值即为3次
delay: 1 #一秒间隔
with_lines
范例:
- hosts: localhost
tasks:
- debug: msg={{ item }}
with_lines: ls -l /var #默认输出值到了item变量
#批量创建用户
#!/usr/bin/ansible-playbook
---
#This is playbook file
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: add several users
user: name={{ item[0] }} state=present group{{ item[1] }}
with_lines:
- cat /root/username_list.txt
- {while}
when
范例:
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: shutdown the RedHat system
- hsots: webservs
remote_user: root
gather_facts: yes
tags: redhat
tasks:
- name: shutdown system
command: /bin/shutdonw -h now
when: ansible_os_family == "RedHat"
# purpose: install sl package the Debian
- hosts: dbservs
remote_user: root
gather_facts: yes
tags: debian
tasks:
- name: install sl
apt: name=sl state=present
whne: ansible_os_family == "Debian"
#条件分组
- hsots: webservs
remote_user: root
gather_facts: yes
tags: redhat
tasks:
- name: shutdown system
command: /bin/shutdonw -h now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
#也可以写成列表的形式(逻辑为and)
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Checking the System Version is Centos 7 exec reboot
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: reboot Centos 7
command: /sbin/reboot
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "7"
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Check whether the service is started
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: check nginx service
conmand: systemctl is-active nginx
ignore_errors: yes #忽略错误
register: check_nginx #注册变量
- name: Service nginx started
service: name=nginx state=started
when: check_nginx.rc == 0 #判断conmand任务是否执行成功
#在循环中使用判断
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Prints a value greater than 3
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- command: echo {{ item }}
loop:
- [1,2,3,4,5]
when: item > 3
#判断执行状态
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Determine execution status
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- name: export true
command: /bin/true
register: result
ignore_errors: true
- debug: msg="failed"
when: result is failed
- debug: msg="succeeded"
when: result is succeeded
- debug: msg="skipped"
when: result is skipped
#字符串变量运算判断
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
- hosts: 192.168.213.122
remote_user: root
gather_facts: yes
tasks:
- shell: echo "only on Red Hat 6, derivatives, and later"
when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6
#使用default 筛选器来提供空迭代器,若列表为空则skipping
- hosts: 192.168.213.122
tasks:
- shell: echo {{ item }} >> /root/Test.txt
loop: "{{ [ 0,1,2,3,4,5,6,7,8 ]|default([]) }}"
when: item > 5
#在循环中使用字典
- command: echo {{ item.key }}
loop: "{{ query('dict', mydict|default({})) }}"
when: item.value > 5
#
- hosts: 192.168.213.122
tasks:
- shell: echo {{ item.key }} >> /root/Test.txt
loop: "{{ query('dict', { 'file': 7 }|default({})) }}"
when: item.value > 5
范例:
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test failed_when
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- command: echo failed
register: result
failed_when: "'failed' in result.stdout"
#failed_when: false 不满足条件,任务正常执行
#failed_when: true 满足条件,使用任务失败
- debug: msg="echo failed_when"
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test failed_when
- hosts: localhost
remote_user: root
gather_facts: yes
vars:
- web: httpd
tasks:
- name: Checking service Status
command: systemctl is-active {{ web }}
register: web_Status
failed_when: web_Status.rc != 0
- name: rc=0,restarted {{ web }}
service: name={{ web }} state=restarted
关闭changed状态:
当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的ahanged状态,可以通过changed_when:false关闭changed状态;
范例
使用changed_when之前
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test change_when
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- name: check sshd service
shell: ps aux | grep sshd
使用changed_when之后,使用后会取消掉修改的表示(黄色),请确认该操作的确未修改文件:
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test change_when
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- name: check sshd service
shell: ps aux | grep sshd
changed_when: false
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test change_when
- hosts: websrvs
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: config file
template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf"
notify: restart nginx
- name: check config
shell: /usr/sbin/nginx -t
register: check_nginx_config
changed_when:
- (check_nginx_config.stdout.find('successful')) #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
- false #nginx -t 每次成功执行是changed状态,关闭此changed状态
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted
block
范例
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test Block
- hosts: localhost
remote_user: root
gather_facts: yes
tasks:
- block:
- debug: msg="first"
- debug: msg="second"
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "7"
serial
管理节点过多导致的超时问题解决方法:
默认情况下,Ansible将尝试并行管理playbook中的所有主机,对于滚动执行更新用例,可以使用serial关键字
定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次执行的主机占总数的比例;
范例:
使用serial前
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test serial
- hosts: webservs
remote_user: root
gather_facts: yes
tasks:
- name: Test task 1
shell: wall "{{ ansible_nodename }} is running task 1"
- name: Test task 2
shell: wall "{{ ansible_nodename }} is running task 2"
使用后:
#!/usr/bin/ansible-playbook
---
# This is ansible-playbook files
# purpose: Test serial
- hosts: webservs
remote_user: root
gather_facts: yes
serial: 1
tasks:
- name: Test task 1
shell: wall "{{ ansible_nodename }} is running task 1"
- name: Test task 2
shell: wall "{{ ansible_nodename }} is running task 2"