1、简介

1.1 架构图

playbook主要是实现将多个ansible指令进行编排,让它们有顺序,有逻辑 的执行,采用yaml语言编写
3、playbook - 图1
playbook 剧本是由一个或多个“play”组成的列表
play 的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作

1.2 格式

playbook由YMAL语言编写

  • 1、文件的第一行应该以 “—-“ (三个连字符)开始,表明YMAL文件的开始。
  • 2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。
  • 3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
  • 4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
  • 5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以”:”分隔表示,“:”后面还要增加一个空格。 ```yaml

安装与运行mysql服务

  • hosts: node1 remote_user: root tasks:
    • name: install mysql-server package yum: name=mysql-server state=present
    • name: starting mysqld service service: name=mysql state=started

转换为json格式如下:

[ { “hosts”:”node1”, “remote_user”:”root”, “tasks”:[ { “name”:”install mysql-server package”, “yum”:”name=mysql-server state=present” }, { “name”:”starting mysqld service”, “service”:”name=mysql state=started” } ] } ]

  1. 使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言
  2. - 绿色代表执行成功,系统保持原样
  3. - 黄色代表系统代表系统状态发生改变
  4. - 红色代表执行失败,显示错误输出
  5.   执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果
  6. <a name="Y4Xjl"></a>
  7. # 2、核心元素
  8. | 核心元素 | 作用 |
  9. | --- | --- |
  10. | Hosts | 主机列表 |
  11. | Remoter_user,su sudo | 执行远程主机任务的用户 |
  12. | Tasks | 任务列表 |
  13. | Variables | 内置变量或自定义变量 |
  14. | Templates | 模板文本 |
  15. | Handlers,notify | 特定条件触发的操作,满足条件方才执行,否则不执行 |
  16. | Tag | 标记式运行 |
  17. <a name="xVcKa"></a>
  18. ## 2.1 hosts
  19. - 使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts
  20. - 可以使用通配符格式,如:- hosts: websrvs:appsrvs
  21. - Websrvs:dbsrvs # 或,两个组的并集
  22. - Websrvs:&dbsrvs # 与,两个组的交集
  23. - webservers:!dbsrvs # 非,在websrvs组,但不在dbsrvs组
  24. - 加上`-i`选项,指定清单的位置即
  25. <a name="o98rh"></a>
  26. ## 2.2 remote_user
  27. 可用于Hosttask中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
  28. ```yaml
  29. ---
  30. - hosts: websrvs
  31. remote_user: root
  32. tasks:
  33. - name: test connection
  34. ping:
  35. remote_user: magedu
  36. sudo: yes # 默认sudo为root
  37. sudo_user: wang # sudo为wang

2.3 tasks

play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。

---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd
    - name: start httpd
      service: name=httpd state=started enabled=yes

3、命令相关

3.1 基础命令

ansible-playbook <filename.yml> ... [options]

    -C --check          #只检测可能会发生的改变,但不真正执行操作
    --list-hosts        #列出运行任务的主机
    --list-tags         #列出tag
    --list-tasks        #列出task
    --limit 主机列表    #只针对主机列表中的主机执行
    -v -vv  -vvv        #显示过程

ansible-playbook yml_name --syntax-host        #检测语法错误

ansible-playbook yml_name --list-host            #列出运行任务的主机

ansible-playbook yml_name --list-task            #列出任务

ansible-playbook -t TAG_NAME PATH                  #运行playbook中指定的TAG

3.2 shell VS palybook

##### SHELL脚本实现 ##### 
#!/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实现 ##### 
---
- hosts: websrvs
  remote_user: root
  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

4、实战案例

4.1 新增用户

利用 playbook 创建 mysql 用户
---
- hosts: tx
  remote_user: root

  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

4.2 安装 nginx

---
- hosts: tx
  remote_user: root
  tasks:
    - name: add group nginx
      group: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: install nginx
      yum: name=nginx state=present
    - name: copy nginx.conf
      copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes
      notify: reload    #当nginx.conf发生改变时,通知给相应的handlers
      tags: reloadnginx   #打标签
    - name: start nginx service
      service: name=nginx state=started
      tags: startnginx   #打标签

  handlers:  #注意,前面没有-,是两个空格
    - name: reload
      service: name=nginx state=restarted  #为了在进程中能看出来
# 执行palybook
ansible-playbook nginx.yml
# 查看端口
ansible web -m shell -a 'ss -nutlp |grep nginx'
# 引用标签
ansible-playbook nginx.yml -t startnginx

## 测试notify
# 修改配置文件 
vim /tmp/nginx.conf  # 修改监听端口
# 重新加载
ansible-playbook nginx.yml -t reloadnginx
# 发现监听端口已改变

4.3 安装卸载 httpd

---
#install httpd
- hosts: tx
  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/
    - name: web html
      copy: src=files/index.html  dest=/var/www/html/
    - name: start service
      service: name=httpd state=started enabled=yes

ansible-playbook   install_httpd.yml --limit 42.193.0.74



#remove_httpd.yml
---
- hosts: tx
  remote_user: root

  tasks:
    - name: remove httpd package
      yum: name=httpd state=absent
    - name: remove apache user
      user: name=apache state=absent
    - name: remove config file
      file: name=/etc/httpd  state=absent
    - name: remove web html
      file: name=/var/www/html/index.html state=absent

4.4 安装 nfs

- hosts: 172.27.0.10
  tasks:
    - name: install nfs server
      yum: name=nfs-utils state=present

    - name: configure nfs server
      copy: src=./exports.j2 dest=/etc/exports

    - name: create directory for mount
      file: path=/nfs_server state=directory

    - name: create nfs group
      group: name=www gid=1021

    - name: create nfs user
      user: name=www uid=1021 group=www

    - name: start nfs server
      service: name=nfs.service enabled=yes state=started


- hosts: 172.27.0.11
  tasks:
    - name: create mount directory
      file:  path=/nfs_client state=directory

    - name: mount nfs_server
      mount: src=172.27.0.10:/nfs_server path=/nfs_client opts=defaults fstype=nfs state=present

#客户端验证
df -hP

5、变量

5.1 变量使用

变量名:仅能由字母、数字和下划线组成,且只能以字母开头。
通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用“{{ variable_name }}”才生效

5.2 变量定义

5.2.1 facts

ansible 的 setup facts 远程主机的所有变量都可直接调用

[root@hchost ~]# ansible hw10 -m setup -a filter="ansible_default_ipv4"
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
124.71.193.36 | SUCCESS => {
    "ansible_facts": {
        "ansible_default_ipv4": {
            "address": "192.168.0.10", 
            "alias": "eth0", 
            "broadcast": "192.168.0.255", 
            "gateway": "192.168.0.1", 
            "interface": "eth0", 
            "macaddress": "fa:16:3e:c4:61:11", 
            "mtu": 1500, 
            "netmask": "255.255.255.0", 
            "network": "192.168.0.0", 
            "type": "ether"
        }, 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

# yml 格式如下
- hosts: hw10
  remote_user: root
  tasks:
  - name: look up internal variable
      #注意括号与变量名中间的空格
    copy: content={{ ansible_default_ipv4  }} dest=/tmp/ansible.variable

5.2.2 命令行指定变量

通过命令行指定变量,优先级最高
使用-e VARS,--extra-vars=VARS来指定,使用key:value格式指定
ansible-playbook -e varname=value

[root@hchost ~]# vim install_package.yaml
- hosts: hw10
  remote_user: root
  tasks:
  - name: install {{ package_name }}
    yum: name={{ package_name }} state=installed

# package_name 会替换为nginx
[root@hchost ~]# ansible-playbook  -e package_name=nginx  install_package.yaml

5.2.3 playbook中自定义变量

1. 在playbook文件中定义
   vars:
     - var1: value1
     - var2: value2

2. 在独立的变量YAML文件中定义
   - hosts: all
     vars_files:
       - vars.yml

[root@hchost ~]# vim pb_var.yaml
- hosts: hw10
  remote_user: root
  vars:     #定义变量
  #变量是同一类元素,用列表,表示方法,key:value
  - pb: palybook variable
  tasks:
  - name: palybook variable
    copy: content={{ pb }} dest=/tmp/pb.var

[root@hchost ~]# ansible hw10 -m shell -a 'cat /tmp/pb.var'  #查看变量名称是否正确
192.168.0.10 | CHANGED | rc=0 >>
palybook variable

5.2.4 Host Inventory

通过主机清单定义变量

  1. Inventory参数,用于定义 ansible 连接远程主机时使用的参数
  2. 主机清单自定义变量
    | Inventory参数 | 作用 | | —- | —- | | ansible_ssh_host | 定义远程连接的主机 | | ansible_ssh_port | 远程连接的主机的端口 | | ansible_ssh_user | 远程连接登录的用户 | | ansible_ssh_pass | 远程连接登录的密码 | | ansible_sudo_pass | 远程连接提权密码 |

  3. 主机(普通)变量:主机组中主机单独定义,优先级高于公共变量

  4. 组(公共)变量:针对主机组中所有主机定义统一变量 ```yaml

    向不同的主机传递不同的变量

    IP/HOSTNAME varaiable=value var2=value2

向组中的主机传递相同的变量:

[groupname:vars]   variable=value

```yaml
vim /etc/ansible/hosts
[web_server]
192.168.10.12 ipaddr=192.168.10.12    #ipaddr为主机清单自定义变量
192.168.10.13 ipaddr=192.168.10.13
[web_server]
domain=abc.com    #自定义组变量
#将变量存在目标主机
[root@hchost ~]# ansible all -m copy -a 'content={{ ipaddr }} dest=/tmp/host.var'
#查看变量内容
[root@hchost ~]# ansible all -m shell -a 'cat /tmp/host.var'
192.168.10.13 | CHANGED | rc=0 >>
192.168.10.13
192.168.10.12 | CHANGED | rc=0 >>
192.168.10.12

6、模板

6.1 模板介绍

模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套 jinja 语法。
Jinja2:Jinja2是python的一种模板语言,以Django的模板语言为原本。
模板支持:

  字符串:使用单引号或双引号;   数字:整数,浮点数;   列表:[item1, item2, …]   元组:(item1, item2, …)   字典:{key1:value1, key2:value2, …}   布尔型:true/false   算术运算:     +, -, , /, //, %, *   比较操作:     ==, !=, >, >=, <, <=   逻辑运算:     and, or, not

通常来说,模板都是通过引用变量来运用的。

  • template 功能:可以根据和参考模块文件,动态生成相类似的配置文件
  • template 文件必须存放于templates目录下,且命名为 .j2 结尾
  • yaml/yml 文件需和templates目录平级,目录结构如下示例:

./
├── temnginx.yml
└── templates
└── nginx.conf.j2

6.2 同步nginx配置文件

#准备templates/nginx.conf.j2文件
vim tem_nginx.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

ansible-playbook tem_nginx.yml



#修改文件nginx.conf.j2
mkdir templates
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};

vim tem_nginx2.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    - name: start service
      service: name=nginx state=started enable=yes

ansible-playbook tem_nginx2.yml



# template算术运算

[root@ansible ansible]#vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
# worker_processes {{ ansible_processor_vcpus+2 }}; 
[root@ansible ansible]#cat templnginx.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: restart nginx
    - name: start service
      service: name=nginx state=started enabled=yes

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

ansible-playbook  templnginx.yml --limit 192.168.0.10

6.3 流程控制 for 和 if

#templnginx5.yml
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.magedu.com"
        root: "/var/www/nginx/web3/"
  tasks:
    - name: template config to
      template: src=nginx.conf5.j2 dest=/data/nginx5.conf

#templates/nginx.conf5.j2
{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   {% if vhost.server_name is defined %}  # 决定是否生成相关的配置信息
server_name {{ vhost.server_name }}
   {% endif %}
root  {{ vhost.root }}
}
{% endfor %}


ansible-playbook  templnginx5.yml --limit 192.168.0.10


#生成的结果
server {
   listen 8080
   root  /var/www/nginx/web1/
}
server {
   listen 8080
   server_name web2.magedu.com
   root  /var/www/nginx/web2/
}
server {
   listen 8080
   server_name web3.magedu.com
   root  /var/www/nginx/web3/
}

6.4 when 和 循环 with_items

when语句,可以实现条件测试。

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

#需求:当系统是Centos7安装mariadb,Centos6安装mysql
# 1.使用ansible setup模块获取版本信息
"ansible_distribution_major_version": "7"

# 2.编写playbook
    - hosts: all
      remote_user: root
      tasks:
      - name: install mariadb
        yum: name=mariadb state=installed
        when: ansible_distribution_major_version == "7"   #测试当前系统版本信息

      - name: install mysql
        yum: name=mysql state=installed
        when: ansible_distribution_major_version == "6"

使用迭代 with_items

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

  • 字符串
  • 字典
cat with_item1.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add several users
      user: name={{ item }} state=present groups=wheel
      with_items:
        - testuser1
        - testuser2
#上面语句的功能等同于下面的语句
    - name: add user testuser1
      user: name=testuser1 state=present groups=wheel
    - name: add user testuser2
      user: name=testuser2 state=present groups=wheel



cat with_item2.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - g1
        - g2
        - g3
    - name: add some users
      user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present
      with_items:
        - { name: 'user1', group: 'g1', home: '/data/user1' }
        - { name: 'user2', group: 'g2', home: '/data/user2' }
        - { name: 'user3', group: 'g3', home: '/data/user3' }