实验前准备:各主机之间实现ssh相互登录,关闭防火墙,SELinux,同步时间

PlaybookYAML(可读性高,用来表达数据序列的格式)格式,任务(task

可以用YAML脚本批量执行计划好的命令,从而实现运维自动化,避免重复运维配置等工作

基本数据结构:标量、数组、关联数组

Playbook的核心元素:

  • Hosts:主机

  • Tasks:任务列表

  • Variables

  • Templates:包含了模板语法的文本文件;

  • Handlers:由特定条件触发的任务;

    Roles(非核心)

 

playbook的基础组件

- Hosts:运行指定任务的目标主机;

  remoute_user: 在远程主机上执行任务的用户;

  sudo_user

  - tasks:任务列表

  模块,模块参数;

  格式:(1) action: module arguments

            (2) module: arguments

先把官网的简单几个语法给说明下。

#这个是你选择的主机

- hosts: webservers

#这个是变量

  vars:

  - http_port: 80

  - max_clients: 200

#远端的执行权限

  remote_user: root

  tasks:

#利用yum模块来操作

  - name: ensure apache is at the latest version

    yum: pkg=httpd state=latest

  - name: write the apache config file

    template: src=/srv/httpd.j2 dest=/etc/httpd.conf

#触发重启服务器

    notify: restart apache

  - name: ensure apache is running

    service: name=httpd state=started

#这里的restart apache 和上面的触发是配对的。这就是handlers的作用。相当于tag

  handlers:

    - name: restart apache

      service: name=httpd state=restarted

可以继续定义主机

- hosts: webs

  remote_user: root

  …

  …

\注意:shellcommand模块后面直接跟命令,而非key=value类的参数列表;

(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers

(2) 任务可以通过tags打标签,而后可在ansible-playbook后使用-t进行调用,且多个任务可使用同一个标签,一个任务也可用多个标签;

(3)一定要注意yaml格式,前面的空格要对齐,不然总会出错,创建好playbook先进行语法,playbook文件一般是以.yaml或者.yml结尾,不以这两个结尾也可以识别

playbook的使用方法:

(1) 测试

  • ansible-playbook      --check   -C file.yml   只检测可能会发生的改变,但不真正执行操作;

  • ansible-playbook      --list-hosts file.yaml  查看任务主机

  • ansible-playbook      --list-tasks file.yaml   查看所有任务

  • ansible-playbook      --syntax-check file.yml  检查配置文件语法是否有错

(2) 运行 ansible-playbook file.yaml 

 

标签tags

ansibleplaybook的朋友可能会发现,当配置工作很多时,如果在中间过程出错了,修改后想重新执行,前面的一大堆步骤让人感觉很烦躁。虽然提供了“retry”文件,但是却只是根据host来判断重新执行,仍然不够方便;又或者,中间的某些步骤特别耗时,比如下载一个很大的数据包,每次执行特别浪费时间,想要特别的跳过。怎么办?我猜你就是把不需要的部分给注释掉了。有没有更好的办法呢?

        ansibleplaybool中有一个关键字,叫做tagstags是什么?就是打标签。tags可以和一个play(就是很多个task)或者一个task进行捆绑。然后,ansible-playbook提供了“--skip-tags”和“--tags 来指明是跳过特定的tags还是执行特定的tags

        下面请看例子。

有时候只想用这个文件中的复制配置文件的功能,而不想再每一项都检查,虽然也没什么问题。

      - hosts: wserver

        remote_user: root

        tasks:

        - name: install httpd redhat

          yum: name=httpd state=present

        - name: copy httpd configuration

          copy: src=/root/httpd dest=/etc/

          tags: config                         #加了一个tags.

        - name: start httpd

          service: name=httpd state=started

        - name: boot httpd start

          service: name=httpd enabled=yes

       当执行  ansible-playbook httpd.yml --tags="config"  ,则只会执行 copy命令。

wKioL1a8l2rxtZffAABmdXa4rmo705.png

那么复制完配置文件以后应该重载配置文件才对。可是就算再添加一个任务,因为我们指定了标签也不会执行。那么就可以用handlers啦。

handlers

也只有其关注的条件满足时,才会被触发执行。这里的条件其实就是发生修改。

如果我们复制配置文件和远程主机上的一样,那就不会触发了。

Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别。

Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行。

不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次。

Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了。

- hosts: wserver

  remote_user: root

  tasks:

  - name: install httpd redhat

    yum: name=httpd state=present

  - name: start httpd

    service: name=httpd state=started

  - name: copy httpd configuration

    copy: src=/root/httpd dest=/etc/

    notify: 

    - reload httpd #添加了一行这个。用以触发名称为reload httpd handlers

    tags: config

  - name: boot httpd start

    service: name=httpd enabled=yes

  handlers: reload httpd  \或者reload httpd换行修改为- name: reload httpd

    service: name=httpd state=reloaded

notify: 条件式触发,只要配置文件改变了,就会通知给handlers

tags: chfredis  配置文件改变了,要重新复制配置文件到远程主机,给这个任务增加一个标签
notify: restartredis 
条件式触发,只要配置文件改变了,就会通知给handlers

[root@node1 ~]$ ansible-playbook --list-tags file.yml  查看添加的标签

[root@node1 ~]$ ansible-playbook  file.yml   ---执行操作

 

ansible-playbook httpd.yml --tags="config" 或者

 wKioL1a8l42T9gdXAACNBDeWXYE133.png

注:可以定义多个notify

- name: template configuration file

  template: src=template.j2 dest=/etc/foo.conf

  notify: restart memcached

- name: copy httpd configuration

  copy: src=/root/httpd dest=/etc/

  notify: reload httpd

handlers:

- name: restart memcached

  service: name=memcached state=restarted

- name: relad httpd

  service: name=apache state=restarted

 

variables(变量)

(1) facts:可直接调用;

注意:可使用setup模块直接获取目标主机的facters

示例:

[root@node1 ~]$ ansible dbs -m setup -a "filter=ansible_*_mb"

172.18.253.32 | SUCCESS => {

    "ansible_facts": {

        "ansible_memfree_mb": 1336变量---

 

备注:常用的内建变量
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep vcpu
        "ansible_processor_vcpus": 4,   ---cpu
核心数
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep fqdn
        "ansible_fqdn": "node4.magedu.com",   ---
主机名
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep memtotal
        "ansible_memtotal_mb": 1823,   ---
系统的总内存
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep version
        "ansible_bios_version": "6.00", 
        "ansible_distribution_major_version": "7",   ---
系统版本
        "ansible_distribution_version": "7.4", 
[root@node1 ~]#ansible 172.18.21.7 -m setup|grep -A 2 "default_ipv4"
        "ansible_default_ipv4": {
            "address": "172.18.21.7",    ---
使用的ip地址
            "alias": "ens38",

(2) 用户自定义变量:

    (a) playbook中定义变量的方法:

      vars:

        - var1: value1

        - var2: value2

      vars_fies:

         - /path-to-file.yml

变量引用:{{  variable  }}

示例:

通过vars关键字定义:

- hosts: dbs

  remote_user: root

  vars:

  - packname: mariadb

  tasks:

  - name: install package {{ packname }}

    yum: name={{ packname }}  state=latest

通过vars_files关键字引入变量文件:

- hosts: all

  remote_user: root

  vars:

    favcolor: blue

  vars_files:

    - /vars/nginx_vars.yml

 

/vars/nginx_vars.yml示例:

http_port: 80

server_name: localhost

cert_file: /etc/nginx/ssl/nginx.crt

key_file: /etc/nginx/ssh/nginx.key

conf_file: /etc/nginx/conf/default.conf

 

会发现安装mariadb 

   (b) ansible-playbook命令的命令行中的   -e VARS(如,“packname=tree”), --extra-vars=VARS  

[root@node1 ~]$ ansible-playbook -e "packname=tree" -C var.yaml

干跑会发现不是安装mariadb了,而是tree

(3) 通过roles传递变量;

(4) Host Inventory

(a) 用户自定义变量

(i) 向不同的主机传递不同的变量;IP/HOSTNAME varaiable=value var2=value2

(ii) 向组中的主机传递相同的变量;[groupname:vars] variable=value/etc/ansible/hosts的主机定义组变量

示例:

[root@node1 ~]$ vim /etc/ansible/hosts  ---在主机清单中定义变量
[websrvs]
172.18.21.100 p
ackname=memcached  不同的主机设置不同的变量
172.18.21.200 p
ackname=haproxy
[root@node1 ~]$ ansible-playbook -C pkg.yaml ---在这里要将剧本中的变量vars定义去掉,否则不会生效,说明剧本中的变量优先于主机清单中的变量

或者

[root@node1 ~]$ vim /etc/ansible/hosts ---也可以这样定义在同一个组内的主机定义相同的变量
[
dbs]
172.18.21.100 
172.18.21.200 
[
dbs:vars]
p
ackname=memcached
[root@node1 ~]$ ansible-playbook -C pkg.yaml ---测试

 

总结:

自定义变量有三种方式:分别是在playbook中、命令行和主机清单配置文件中定义,在命令行中定义的变量优先于在playbook中定义的变量,在playbook中定义的变量优先于在主机清单中定义的变量,调用变量要使用双大括号,并且大括号前后都要有空格,以上定义的变量都是自定义变量

注意变量名里面不能使用-,否则会报错,下划线可以使用,注意空格使用

调用变量有两种方式:roles调用变量和setupsetup模块直接获取目标主机的facters后面介绍

(6主机变量 (此处着重了解)

以下是Hosts部分中经常用到的变量部分:

ansible_ssh_host     #用于指定被管理的主机的真实IP

ansible_ssh_port     #用于指定连接到被管理主机的ssh端口号,默认是22

ansible_ssh_user     #ssh连接时默认使用的用户名

ansible_ssh_pass     #ssh连接时的密码

ansible_sudo_pass     #使用sudo连接用户时的密码

ansible_sudo_exec     #如果sudo命令不在默认路径,需要指定sudo命令路径

ansible_ssh_private_key_file #秘钥文件路径,秘钥文件如果不想使用ssh-agent管理时可以使用此选项

ansible_shell_type     #目标系统的shell的类型,默认sh

ansible_connection     #SSH 连接的类型: local , ssh , paramiko,在 ansible 1.2 之前默认是paramiko ,后来智能选择,优先使用基于 ControlPersist  ssh (支持的前提)

ansible_python_interpreter     #用来指定python解释器的路径,默认为/usr/bin/python 同样可以指定ruby perl 的路径

ansible_*_interpreter    #其他解释器路径,用法与ansible_python_interpreter类似,这里"*"可以是ruby或才perl等其他语言

示例如下:

[test]

192.168.1.1 ansible_ssh_user=root ansible_ssh_pass='P@ssw0rd'

192.168.1.2 ansible_ssh_user=breeze ansible_ssh_pass='123456'

192.168.1.3 ansible_ssh_user=bernie ansible_ssh_port=3055 ansible_ssh_pass='456789'

上面的示例中指定了三台主机,三台主机的用密码分别是P@ssw0rd12345645789,指定的ssh连接的用户名分别为rootbreezeberniessh 端口分别为22223055 ,这样在ansible命令执行的时候就不用再指令用户和密码等了。这样不安全,一般不这样使用

 

template模块:

基于模板方式生成一个文件复制到远程主机,将模板的文件中变量值转换成对应的主机指定关键字符串的确定值,并将模板文件复制过去

  • *src= 

  • *dest=

  • owner=

  • group=

  • mode=

*必须有此参数

模板:templates为文本文件,嵌套有脚本(使用模板编程语言Jinja2编写)

模块示例:

模板配置文件nginx.conf.j2 

Worker_porcesses {{ ansible_precossor_vcpus }}

#注意空格哦。替换Worker_porcesses的值;

此变量执行ansible all -m setup  (收集到的远程主机的变量即可查看到

Worker_porcesses {{ ansible_precossor_vcpus +1 }}

此表达式也可。此处只为表示可支持算数运算。

 

         Jinja2 语言:

                   字面量:

                            字符串:使用单引号或双引号;

                            数字:整数,浮点数

                            列表:[item1,item2 ..]

                            元组:(item1item2,)

                            字典:{key1valuekey2value.}

                                     布尔型: true/filase

                            算数运算:

                                     +,- , * , / , // , % **

                            比较操作:

                                     == != , >=  ,<=

                            逻辑运算:

                                     andor not

                            流表达式

                                     ForIFwhen

                        

示例: (用ansible-playbook调用此文件,ansible不能直接用templates调用)

[root@node1 ~]$ ansible 172.18.251.90 -m setup |grep processor

或者使用

[root@node1 ~]$ ansible 172.18.251.90 -m setup -a "filter=*_processor_*"

        "ansible_processor": [

        "ansible_processor_cores": 2,

        "ansible_processor_count": 2,

        "ansible_processor_threads_per_core": 1,

        "ansible_processor_vcpus": 4,

[root@node1 ~]$ cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.jj2

[root@node1 ~]$ vim /etc/nginx/nginx.conf.jj2      模板配置文件nginx.conf.jj2

   worker_processes {{ ansible_processor_cores }}  这行修改为:调用这个内建变量

[root@node1 ~]$ vim ng.yml

  1 - hosts: dbs

  2   remote_user: root

  3   tasks:

  4   - name: install nginx

  5     yum: name=nginx state=present

  6   - name: install conf file

  7     template: src=/etc/nginx/nginx.conf.jj2 dest=/etc/nginx/nginx.conf

  8   - name: start nginx

  9     service: name=nginx state=started

注:

template模块核心是模板,copy就是简单复制的意思.template模块首先使用变量渲染jinja2模板文件成普通文件,然后再复制过去.copy模块不支持

条件测试:复杂环境的批量判断操作

示例:

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

   - hosts: dbs

     remote_user: root

     tasks: 
     - name: install conf file to centos7
     template: src=files/nginx.conf.c7.jj2   dest=/etc/nginx/nginx.conf
     when: ansible_distribution_major_version == "7"
     - name: install conf file to centos6
     template: src=files/nginx.conf.c6.jj2   dest=/etc/nginx/nginx.conf
     when: ansible_distribution_major_version == "6"   

 

循环:迭代,需要重复执行的任务

对迭代项的引用,固定变量名为”item,而后,要在task中使用with_items给定要迭代的元素列表;例:

  - hosts: webs
    remote_user: root

    tasks:   

- name: install some packages
  yum: name={{ item }} state=present
  with_items:
  - nginx
  - memcached
  - php-fpm   
- name: add some groups
  group: name={{ item }} state=present
  with_items:
  - group11
  - group12
  - group13
- name: add some users
  user: name={{ item.name }} group={{ item.group }}  state=present  

  with_items:
  - { name: 'user11', group: 'group11' }   
  - { name: 'user12', group: 'group12' }
  - { name: 'user13', group: 'group13' }

就是利用itemwith_items相当与一个数组,一次完成多个重复的、属性相同指令,加版本号的方法也类似

如下:实现将tomcat的两个不同的配置文件拷贝到远程主机

- hosts: webs
  remote_user: root
  vars:
  - jdk_version: 1.8.0
  tasks:
  - name : install {{ item }} package
    yum : name= {{ item }} state =installed
    with_items:
    - nginx
    - java-{{ jdk_version }}-openjdk
    - tomcat
    - tomcat-webapps
    - tomcat-docs_webapp
    - tomcat-admin-webapps
  - name : config tomcat
    copy : src ={{ item.file }}  dest={{ item.conf }}
    with_items:
    - { file: 
'/data/tomcat-users.xml', conf:  '/etc/tomcat-user.xml' }
    - { file: 
'/data/server.xml', conf:  '/etc/server.xml' } 

 

角色(roles):分类组织调用各个应用各个模块

roles 用于层次性、结构化地组织playbookroles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及触发处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

角色集合

/etc/ansible/roles/下可有多个按应用分类的角色,如:

  • mysql/

  • httpd/

  • nginx/

  • memcached/

目录层级结构

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

       Files/     #存放有copyscript模块等调用的文件;’

       Tepmlates/ #template模块查找所需要模板文件目录;

       Tasks/     #定义任务;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。

       Handlers/  #定义触发器;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。

       Vars/     #定义变量;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。

       Meta/      #定义变量;至少应该包含一个名为main.yml的文件;定义当前角色的特殊设定及其依赖关系;其他的文件需要在此文件中通过include进行包含。

       Default/   #设定默认变量时使用此目录中的main.yml文件。

调用角色

playbook调用角色方法1

- hosts: webservers

  remote_user: root

  roles:

  - mysql

  - memcached

  - nginx

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

- hosts:

  remote_user:

  roles:

  - { role: nginx, username: nginx等变量 }

role用于指定角色名称;后续的k/v用于传递变量给角色;

还可以基于条件测试实现角色调用

roles:

- { role: nginx, when: "ansible_distribution_major_version == '7' " }

层级结构展示

wKioL1iNvDigfDsaAAAfQx5IoMw285.png

示例1:利用ansible角色安装nginx

[root@centos7 ~]# mkdir /etc/ansible/roles/nginx/{files,tasks,templates,handlers,vars,default,mata} pv

#创建固定目录结构

[root@centos7 ~]# tree  /etc/ansible/roles/nginx/

/etc/ansible/roles/nginx/

├── default

├── files

├── handlers

├── mata

├── tasks

├── templates

└── vars

[root@centos7 ~]# cd /etc/ansible/roles/nginx/

[root@centos7 nginx]# vim tasks/main.yml  #创建任务

- name: install nginx package

  yum: name=nginx state=present

- name: install conf file

  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 

 #此处源文件可不写绝对路径,系统自查找。

- name: start nginx

  service: name=nginx state=started

[root@centos7 ~]# cp /etc/nginx/nginx.conf.j2 ./templates/nginx.conf.j2 

#将配置文件拷贝至templates目录内。

[root@centos7 ~]# cd /apps/yaml/

[root@centos7 yaml]# cat roles.yml #创建调用文件

- hosts: web

   remote_user: root

   roles:

  - nginx

[root@centos7 yaml]#ansible-playbook roles.yml  #利用ansible-playbook执行。

示例2:变量调用

利用定义变量使远程主机的nginx服务运行用户变更为daemon

[root@centos7 ~]# vim /etc/ansible/roles/nginx/vars/main.yml

username: daemon

[root@centos7 ~]# vim /etc/ansible/roles/nginx/templates/nginx.conf.j2

user {{ username }};  #  将此处原有用户修改为变量

[root@centos7 ~]# cd /apps/yaml/

[root@centos7 yaml]#ansible-playbook roles.yml

[root@centos7 yaml]#ansible-playbook -e"username=adm"  roles.yml

#也可以直接利用命令行传递变量参数给剧本文件。

示例3:在playbook调用角色方法:传递变量给角色

不在vars下定义,role下传递

[root@centos7 yaml]vim roles.yml

 - hostsweb

    remote_user:root

    roles:

    - {role: nigix, username: nginx } 

  #在调用nginx角色是使用变量username:nginx时服务运行用户为nginx

   role:用于指定角色名称;后续的键值对用户传递变量给角色

[root@centos7 yaml]# ansible-playbook roles.yml

   还可以基于条件测试实现角色调用;

[root@centos7 yaml]vim roles.yml

- hostsweb

  remote_user: root

  roles:

 {role: nigix, username: nginx ,when: “ansible_distribution_major_version ==’7’”}

#基于条件测试调用变量赋予nginx

[root@centos7 yaml]#ansible-playbook -t instconf  roles.yml

 

示例5:角色安装

[root@centos7 ~]# mkdir /etc/ansible/roles/memcached/tasks -pv

[root@centos7 ~]# vim /etc/ansible/roles/memcached/tasks/main.yml

- name: install package

 yum: name=memcached state=present

- name: start memecached

 service: name=memcached state=started

    

[root@centos7 ~]# cd/apps/yaml/

[root@centos7 yaml]# cat mem.yml

- hosts: web

  remote_user: root

  roles:

  - { role: nginx, when: ansible_distribution_version == '7' }  

  #系统为centos7时调用执行nginx

  - { role: memcached, when: ansible_distribution_version == '6' }  

  #系统为centos7时调用执行memcached

 

示例6:角色变量调整memcached内存大小

利用变量使远程主机上的Memcahed的缓存大小占用系统内存大小的三分之一。

[root@centos7 ~]# cd /etc/ansible/roles/memcached/

[root@centos7 memcached]#ls

handlers/  tasks/    templates/

[root@centos7 memcached]#cat tasks/main.yml

- name: install package

  yum: name=memcached state=present

- name: start memecached

  service: name=memcached state=started

- name: install conf file

  template: src=memcached.j2 dest=/etc/sysconfig/memcached

     notify: restart memcached

  tags: restart

[root@centos7 memcached]# scp 172.16.254.216:/etc/sysconfig/memcached

    ./templates/memcached.j2

[root@centos7 memcached]#vim templates/memcached.j2

PORT="11211"

USER="memcached"

MAXCONN="1024"

CACHESIZE="{{ ansible_memtotal_mb//3 }}"

 #变量设置内存的3分之一  此变量为远程主机的总内存//3 指除3取商

  便为远程主机的三分之一

[root@centos7 memcached]#vim handlers/main.yml

- name: restart memcached

  service: name=memcached state=restarted

[root@centos7 memcached]#cd /apps/yaml/

[root@centos7 yaml]#ansible-playbook   mem.yml  #执行剧本

 

 

关于更多ansible的介绍和查看ansible官网:http://www.ansible.com.cn