Ansible PlayBook实践案例

一、PlayBook介绍

1.什么是playbook

playbook 顾名思义,即剧本,现实生活中演员按照剧本表演,在 ansible 中,由被控计算机表演,进行安装,部署应用,提供对外的服务等,以及组织计算机处理各种各样的事情。

playbook 是 ansible 用于配置,部署,和管理节点的剧本通过 playbook 的详细描述,执行其中的-些列 tasks,可以让远端的主机达到预期的状态。playbook 就像 ansible 控制器给被控节点列出的一系列 to-do-list,而且被控节点必须要完成。

2.Ansible playbook 使用场景

执行一些简单的任务,使用 ad-hoc 命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作的时候,执行的 ad-hoc 命令是不合适的,这时候最好使用 playbook。

就像执行 shell 命令与写 shell脚本一样,也可以理解为批处理任务,不过 playbook 有自己的语法格式使用 playbook 可以方便的重复使用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用 Ansible 的过程中,你也会发现,你所处理的大部分操作都是编写 playbook。可以把常见的应用都编写为 playbook,之后管理服务器会变得很简单。

二、Playbook的组成

Playbook 是由一个或多个"play"组成的列表,主要功能在于通过将 task 定义好的角色归并为组进行统一管理,也就是通过 Task 调用 Ansible 的模板将多个"play"组织在一个 Playbook 中运行。

Playbook 本身由以下几部分组成:

  • Tasks:任务,即调用模块完成的某操作;
  • Variables:变量;
  • Templates:模板;
  • Handlers:处理器,某条件满足时,触发执行的操作; ['hendla(r)]
  • Roles:角色。

下面是一个Playbook的简单实例:

复制代码
[root@ansible-node1 ~]# vim a.yaml

---
- hosts: web
  remote_user: root
  tasks:
    - name: create user
      user:
        name: zhangsan
        password: "{{ 'aptech' | password_hash('sha512') }}"
        state: present
      tags:
      - ccc

...
(1)执行playbook,进行语法检查
复制代码
[root@ansible-node1 ~]# ansible-playbook --syntax-check a.yaml 

playbook: a.yaml
(2)预测试
复制代码
[root@ansible-node1 ~]# ansible-playbook -C a.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [create user] *****************************************************************
changed: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
(3)列出主机
复制代码
[root@ansible-node1 ~]# ansible-playbook --list-hosts a.yaml 

playbook: a.yaml

  play #1 (web): web	TAGS: []
    pattern: [u'web']
    hosts (1):
      192.168.10.102
(4)列出任务
复制代码
[root@ansible-node1 ~]# ansible-playbook --list-tasks a.yaml 

playbook: a.yaml

  play #1 (web): web	TAGS: []
    tasks:
      create user	TAGS: [ccc]
(5)列出标签
复制代码
[root@ansible-node1 ~]# ansible-playbook --list-tags a.yaml 

playbook: a.yaml

  play #1 (web): web	TAGS: []
      TASK TAGS: [ccc]
(6)执行任务
复制代码
[root@ansible-node1 ~]# ansible-playbook a.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [create user] *****************************************************************
changed: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

1.Hosts 和Users 介绍

Playbook 的设计目的是为了让某个或某些主机以某个用户身份去执行完成相应的任务。其中用于指定要执行指定任务的主机用 hosts 定义,可以是一个也可以是由冒号分隔的多个主机组;用于指定被管理主机上执行任务的用户用 remote user 来定义,如下面示例中所示。

复制代码
- hosts: web
  remote_user: zhangsan

remote user 也可定义指定用户通过 sudo 的方法在被管理主机上运行指令,甚至可以在使用sudo 时用 sudo user 指定 sudo 切换的用户。

复制代码
[root@ansible-node1 ~]# vim b.yaml

---
- hosts: web
  remote_user: zhangsan
  tasks:
    - name: test connection
      ping:

...

[root@ansible-node1 ~]# ansible-playbook -C b.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [create user] *****************************************************************
changed: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@ansible-node1 ~]# ssh-copy-id zhangsan@192.168.10.102
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
zhangsan@192.168.10.102's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'zhangsan@192.168.10.102'"
and check to make sure that only the key(s) you wanted were added.

[root@ansible-node1 ~]# ansible-playbook b.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [test connection] *************************************************************
ok: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2.任务列表和 action 介绍

"Play"的主体是任务列表(Tasks list)。任务列表中的任务按照次序逐个在 hosts 中指定的所有主机上执行,在顺序执行这些任务时,如果发生错误会将所有已执行任务回滚。因此,需要在更正Playbook 中的错误后重新执行这些任务。

Task 的任务是按照指定的参数去执行模块。每个 task 使用 name 输出 Playbook 的运行结果,一般输出内容为描述该任务执行的步骤。如果没有提供将输出 action 的运行结果。

定义 task 的格式可以用"action:module options"或"module:options"都可,其中后者可以实现向后兼容。如果 action 的内容过多,可在行首使用空白字符进行换行。

复制代码
[root@ansible-node1 ~]# vim a.yaml 

---
- hosts: web
  remote_user: root
  tasks:
    - name: create user
      user:
        name: zhangsan
        password: "{{ 'aptech' | password_hash('sha512') }}"
        state: present
      tags:
      - ccc

- hosts: db
  remote_user: root
  tasks:
    - name: copy file to web
      copy: src=/etc/passwd dest=/opt
      tags:
      - ddd


...

[root@ansible-node1 ~]# ansible-playbook -C a.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [create user] *****************************************************************
changed: [192.168.10.102]

PLAY [db] **************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.103]

TASK [copy file to web] ************************************************************
changed: [192.168.10.103]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.10.103             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

[root@ansible-node1 ~]# ansible-playbook a.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [create user] *****************************************************************
changed: [192.168.10.102]

PLAY [db] **************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.103]

TASK [copy file to web] ************************************************************
changed: [192.168.10.103]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.10.103             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

如果多次去执行修改的 Playbook 时,涉及到一些没有变化的代码,可以使用 tages 让用户选择跳过没有变化代码,只运行 Playbook中发生变化的部分代码。可以在Playbook中为某个或某些任务定义"标签",在执行此Playbook 时通过ansible-playbook 命令的--tags 选项能实现仅运行指定的 tasks 而非所有的 tasks。

3.Handlers 介绍

Handlers 用于当关注的资源发生变化时所采取的操作。在 notify 中列出的操作便称为 handler,也就是 notify 中需要调用 handler 中定义的操作。 而 notify 这个动作用于在每个"play"的最后被触发,仅在所有的变化发生完成后一次性地执行指定操作。

示例:当拷贝模板文件为/etc/foo.conf 文件时,重新启动 memcached 和 apache 服务,如下所示。

简单示例如下所示。

(1)安装apache
复制代码
[root@ansible-node1 ~]# mkdir conf
[root@ansible-node1 ~]# yum -y install httpd
[root@ansible-node1 ~]# cp /etc/httpd/conf/httpd.conf conf
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 8080//修改端口号

[root@ansible-node1 ~]# vim a.yaml 

- hosts: web
  remote_user: root
  tasks:
    - name: install httpd package
      yum: name=httpd state=latest
    - name: install configuration file or httpd
      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
    - name: start httpd service
      service: enabled=true name=httpd state=started

[root@ansible-node1 ~]# ansible-playbook a.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [install httpd package] *******************************************************
changed: [192.168.10.102]

TASK [install configuration file or httpd] *****************************************
changed: [192.168.10.102]

TASK [start httpd service] *********************************************************
changed: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
(2)登录被管理主机 ansible-node2 进行查看执行结果。
复制代码
[root@ansible-node2 ~]# rpm -qa httpd
httpd-2.4.6-99.el7.centos.1.x86_64
[root@ansible-node2 ~]# grep "Listen" /etc/httpd/conf/httpd.conf | grep -v "#" 
Listen 8080
[root@ansible-node2 ~]# systemctl status httpd
(3)设置handlers

如果配置文件有改动,如:Apache 端口号改变,则需要定义 notify 和 handlers,关执行操作。

复制代码
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 808

[root@ansible-node1 ~]# vim b.yaml 

---
- hosts: web
  remote_user: root
  tasks:
    - name: change port
      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify:
        - restart httpd
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

...

[root@ansible-node1 ~]# ansible-playbook b.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [change port] *****************************************************************
ok: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

注意:

node2 上要关闭 selinux,否则,同步配置会出错,

(4)登录被管理主机 ansible-node2 进行查看。
复制代码
[root@ansible-node2 ~]# netstat -anpt | grep httpd

4.Templates 介绍

Jinia 是基于 Pvthon 的模板引擎。Template 类似 Jinia 的另一个重要组件,可以看作是一个编译过的模板文件。用来产生目标文本,传递 Python 的变量给模板去替换模板中的标记。

(1)创建模板文件
复制代码
[root@ansible-node1 ~]# mkdir templates
[root@ansible-node1 ~]# cp conf/httpd.conf templates/httpd.conf.j2
[root@ansible-node1 ~]# vim templates/httpd.conf.j2
Listen {{ http_port }}
ServerName {{ ansible_fqdn }}
(2)为远程主机添加变量
复制代码
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[web]
192.168.10.102 http_port=8888
[db]
192.168.10.103
(3)编写playbook文件
复制代码
[root@ansible-node1 ~]# vim apache.yaml

- hosts: web
  remote_user: root
  vars:
  - package: httpd
  - service: httpd
  tasks:
  - name: install httpd
    yum: name={{ package }} state=latest
  - name: install configuration file for httpd
    template: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart httpd
  - name: start httpd service
    service: enabled=true name={{ service }} state=started
  handlers:
  - name: restart httpd
    service: name={{ service }} state=restarted

[root@ansible-node1 ~]# ansible-playbook apache.yaml 

PLAY [web] *************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.102]

TASK [install httpd] ***************************************************************
ok: [192.168.10.102]

TASK [install configuration file for httpd] ****************************************
changed: [192.168.10.102]

TASK [start httpd service] *********************************************************
changed: [192.168.10.102]

RUNNING HANDLER [restart httpd] ****************************************************
changed: [192.168.10.102]

PLAY RECAP *************************************************************************
192.168.10.102             : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
(4)登录被管理主机 ansible-node2,执行查看命令
复制代码
[root@ansible-node2 ~]# grep -i listen /etc/httpd/conf/httpd.conf | grep -v "#"
Listen 8888
[root@ansible-node2 ~]# grep -i servername /etc/httpd/conf/httpd.conf | grep -v "#"
ServerName ansible-node2

三、Roles 介绍

1.什么是 Roles

Ansible 为了层次化、结构化地组织 Playbook,使用了角色(roles),可以根据层次结构自动装载变量文件、tasks 以及 handlers 等。只需要在 Playbook 中使用 include 指令便可使用 roles。简单来讲, roles 就是分别将变量、文件、任务、模块及处理器设置于单独的目录中,便捷地使用它们。

2.案例--利用 Roles 部署 mariadb

(1)被管理主机配置 yum 源

(2)配置数据库角色

复制代码
[root@ansible-node1 ~]# cd /etc/ansible/
[root@ansible-node1 ansible]# ls
ansible.cfg  hosts  roles
[root@ansible-node1 ansible]# cd roles/
[root@ansible-node1 roles]# ls
[root@ansible-node1 roles]# mkdir mariadb
[root@ansible-node1 roles]# ls
mariadb
[root@ansible-node1 roles]# cd mariadb/
[root@ansible-node1 mariadb]# mkdir files
[root@ansible-node1 mariadb]# mkdir tasks
[root@ansible-node1 mariadb]# mkdir handlers
(3)编写主文件
复制代码
[root@ansible-node1 tasks]# vim main.yaml 

---
- name: install mariadb
  yum: name=mariadb-server state=present
- name:install MySQL-python
  yum: name=MySQL-python state=present
- name: bak config file
  shell: "[ -e /etc/my.cnf ] && mv /etc/my.cnf /etc/my.cnf.bak"
- name: copy new config file
  copy: src=my.cnf dest=/etc/my.cnf
- name: restart mariadb
  shell: systemctl restart mariadb
- name: init mysql
  shell: mysql -u root -e "create database testdb;grant all on testdb.* to test@'%' identified by 'pwd123';flush privileges;"
  notify:
  - restart mariadb
...
(4)编写触发器文件
复制代码
[root@ansible-node1 mariadb]# cd handlers/
[root@ansible-node1 handlers]# vim main.yaml

---
- name: restart mariadb
  service: name=mariadb state=restarted
...
(5)编写角色文件
复制代码
[root@nodel tasks]# cd /etc/ansible/roles/mariadb/files
[root@node1 files]# ls
my.cnf    ##将编辑好的 my.cnf 文件拷贝在此处

[root@ansible-node1 ansible]# vim mariadb.yaml

---
- hosts: db
  remote_user: root
  roles:
  - mariadb
...
(6)测试角色文件
复制代码
[root@ansible-node1 ansible]# ansible-playbook --syntax-check mariadb.yaml 

playbook: mariadb.yaml
(7)执行yml文件
复制代码
[root@ansible-node1 ansible]# ansible-playbook mariadb.yaml 

PLAY [db] **************************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.10.103]

TASK [install mariadb] *************************************************************
changed: [192.168.10.103]

TASK [mariadb : install MySQL-python] **********************************************
changed: [192.168.10.103]

TASK [mariadb : bak config file] ***************************************************
changed: [192.168.10.103]

TASK [mariadb : copy new config file] **********************************************
changed: [192.168.10.103]

TASK [restart mariadb] *************************************************************
changed: [192.168.10.103]

TASK [mariadb : init mysql] ********************************************************
changed: [192.168.10.103]

RUNNING HANDLER [restart mariadb] **************************************************
changed: [192.168.10.103]

PLAY RECAP *************************************************************************
192.168.10.103             : ok=8    changed=7    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
(8)检查远程服务器上数据库

查看数据库信息,看看有没有创建制定的数据库

四、利用 Ansible 管理数据库

1.用 ansible 查看数据库

复制代码
[root@ansible-node1 ansible]# ansible db -m shell -a 'mysql -u root -e "show databases;"'
192.168.10.103 | CHANGED | rc=0 >>
Database
information_schema
mysql
performance_schema
test
testdb

2.创建账户并授权

复制代码
[root@ansible-node1 ansible]# ansible db -m yum -a "name=MySQL-python state=present" 
192.168.10.103 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "MySQL-python-1.2.5-1.el7.x86_64 providing MySQL-python is already installed"
    ]
}

[root@ansible-node1 ansible]# ansible db -m mysql_user -a "name==zhangsan password=pwd123 host=192.168.10.% priv=*.*:ALL"
[WARNING]: Module did not set no_log for update_password
192.168.10.103 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "msg": "User added", 
    "user": "=zhangsan"
}

[root@ansible-node1 ansible]# ansible db -m mysql_user -a "name=lisi password=pwd123 priv=*.*:ALL"
[WARNING]: Module did not set no_log for update_password
192.168.10.103 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "msg": "User added", 
    "user": "lisi"
}

注意:

张三能够远程登录,但李四不能

要想使用 mysql user 模块,需要在客户端安装MySQL-python,安装时注意大小写

3.为老用户授权(语法和创建用户并授权的语法是相同的)

复制代码
[root@ansible-node1 ansible]# ansible db -m mysql_user -a "name=root password=pwd123 host=192.168.10.% priv=*.*:ALL"
[WARNING]: Module did not set no_log for update_password
192.168.10.103 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "msg": "User added", 
    "user": "root"
}
相关推荐
lbb 小魔仙2 天前
【Linux】Ansible 自动化运维实战:2000+ 节点配置标准化教程
linux·运维·ansible
扑火的小飞蛾4 天前
【Ansible学习笔记01】 批量执行 shell 命令
笔记·学习·ansible
oMcLin4 天前
如何在 Red Hat Linux 服务器上使用 Ansible 自动化部署并管理多节点 Hadoop 集群?
linux·服务器·ansible
linux修理工7 天前
vagrant ubuntu 22.04 ansible 配置
ubuntu·ansible·vagrant
biubiubiu07068 天前
Ansible自动化
运维·自动化·ansible
秋4279 天前
ansible配置与模块介绍
ansible
秋4279 天前
ansible剧本
linux·服务器·ansible
码农101号10 天前
Ansible - Role介绍 和 使用playbook部署wordPress
android·ansible
2301_8000509912 天前
Ansible
运维·ansible
阎*水14 天前
Ansible 核心要点总结
ansible