自动化运维工具之ansible的简单应用

ansible:     

        ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,例如shell,copy,ping等,ansible只是提供一种框架。ansible的主要特性:      

     模块化:调用特定的模块,完成特定任务

         基于Python语言实现,由Paramiko,PyYAML和jinja2三个关键模块

         部署简单:agentless,无需在管控主机安装任何客户端

         支持自定义模块;

         支持playbook(剧本);

运维工具的工作模式:

  1、agent :需要在管控主机上安装客户端,和客户端通信,比如:zabbix,puppt

  2、agentless:无需安装客户端,基于SSH协议通信,比如:ansible


     ansible是工作在agentless模式下具有幂等性,意思就是无论任务执行一遍或者多遍,对结果都不会产生影响。ansible在控制端只需要告诉监控端的期望状态就可以实现批量部署,只需告诉管控主机需要干什么就行。


ansible的架构图:

     

   ansible通过连接插件Connaction Plugins来负责基于SSH和管控主机进行通信,Host Inventoy则记录了需操作主机的信息。ansible除了直接使用命令行控制外,还可以基于PlayBooks(剧本)来实现管理主机,通过各种模块和自定义模块来操作主机,并借助插件来记录日志和邮件等。



一、ansible的安装    

]# yum -y install ansible
]# ls /etc/ansible/
ansible.cfg                    //配置文件 
hosts                         //主机清单
roles/                       //定义角色

 1、定义hosts:

]# vim /etc/ansible/hosts 

[webserver]     //定义主机组

172.18.250.77  ansible_ssh_user=root ansible_ssh_pass=123456  //连接主机的账号密码

172.18.250.78  ansible_ssh_user=root ansible_ssh_pass=123456

 

 2、直接给出主机的账号密码不太安全,这时可以基于密钥方式认证:

]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P''
]# ansible webserver -m copy -a "src=/root/.ssh/id_rsa.pub dest=/root/"
]# ansible webserver -m shell -a "cat /root/id_rsa.pub >>/root/.ssh/authorized_keys"

 3、可以把账号密码去掉,试试能不能执行

]# vim /etc/ansible/hosts 
[webserver]    
172.18.250.77 
172.18.250.78 
]# ansible webserver -m ping 
172.18.250.78 | success >> {
    "changed": false, 
    "ping": "pong"
}

172.18.250.77 | success >> {
    "changed": false, 
    "ping": "pong"
}

 4、ansible的简单语法格式:

          ansible HOST-PATTERN [-f forks] [-m MODULE_name] [-a args]

                  HOST-PATTERN:主机清单,可以是单个主机,也可以是主机组 

                  -m module:       指明模块,默认为command   

                   -f forks:           指明一次发送几个连接请求

                   -a args:              在远程主机上执行的参数   

      查看ansible的常用模块命令: ansible-doc -l


 5、常用模块

       command模块:在远程主机上执行命令,不支持管道

]# ansible webserver -m command -a "cat /etc/issue"
172.18.250.77 | success | rc=0 >>
\S
Kernel \r on an \m

172.18.250.78 | success | rc=0 >>
\S
Kernel \r on an \m

   shell模块:在远程主机shell上执行命令,支持管道

]# ansible webserver -m shell -a "ss -tan |grep :8080"
172.18.250.78 | success | rc=0 >>
LISTEN     0      128                      :::8080                    :::*     

172.18.250.77 | success | rc=0 >>
LISTEN     0      128                      :::8080                    :::*

     copy模块:复制本地文件到远程主机,或者直接在远程主机上写内容

            1、src=/path/to/somefile        dest=/path/to/somefile

            2、content=someting              dest=/path/to/somefile

]# ansible webserver -m copy -a "src=/etc/issue dest=/tmp"
172.18.250.78 | success >> {
    "changed": true, 
    "checksum": "5f63a8ace67bf6a8b62aa7da2cf5eccc05a89308", 

172.18.250.77 | success >> {
    "changed": true, 
    "checksum": "5f63a8ace67bf6a8b62aa7da2cf5eccc05a89308", 

]# ls /tmp/
issue

   cron模块:管理定时计划任务

]# ansible webserver -m cron -a "minute=*/5 state=present job='ntpdate 172.18.0.1 >/dev/null' name=Rsynctime"
172.18.250.78 | success >> {
    "changed": true, 
    "jobs": [
        "Rsynctime"
    ]
}

172.18.250.77 | success >> {
    "changed": true, 
    "jobs": [
        "Rsynctime"
    ]
}
]# crontab -l
#Ansible: Rsynctime
*/5 * * * * ntpdate 172.18.0.1 >/dev/null

mintue=    //分钟
hour=      //小时  
day=       //哪天 
weekday=   //星期几
month=     //哪月
job=       //内容
name=      //名称
state=     //对内容做什么操作,present:创建  absent:删除

    ping模块,对远程主机实行ping操作

]# ansible webserver -m ping 
172.18.250.78 | success >> {
    "changed": false, 
    "ping": "pong"
}

172.18.250.77 | success >> {
    "changed": false, 
    "ping": "pong"
}

   yum模块,程序包管理

]# ansible webserver -m yum -a "name=httpd state=present"
172.18.250.78 | success >> {
    "changed": false, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "httpd-2.4.6-31.el7.centos.x86_64 providing httpd is already installed"
    ]
}

172.18.250.77 | success >> {
    "changed": false, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "httpd-2.4.6-40.el7.centos.x86_64 providing httpd is already installed"
    ]
}

   service模块,管理远程主机上的服务

]# ansible webserver -m service -a "name=httpd state=started enabled=1"
172.18.250.78 | success >> {
    "changed": true, 
    "enabled": true, 
    "name": "httpd", 
    "state": "started"
}

172.18.250.77 | success >> {
    "changed": true, 
    "enabled": true, 
    "name": "httpd", 
    "state": "started"
}
name=         //程序名称
state=        //执行的操作,started、stoped、restarted、reloaded
enabled=      //是否开机自启 
runlevel=     //运行的级别

  script模块,在远程主机上执行本地脚本,无需传递脚本过去

]# ansible webserver -m script -a "/tmp/mkdir.sh"(本地路径)
172.18.250.78 | success >> {
    "changed": true, 
172.18.250.77 | success >> {
    "changed": true, 
 
默认是运行在用户的家目录下

   user模块和group模块,在远程主机上创建用户和组

]# ansible webserver -m group -a "name=testgroup system=no gid=2000 state=present"
]# ansible webserver -m user -a "name=usertest system=no uid=2000 group=testgroup state=present"


二、playbooks的应用      

    运行playbook的方式:

             1、只检测可能会发生的改变,但不真正执行操作

                   ansible-playbook --check file.yaml  

             2、运行

                   ansible-playbook file.yaml 

      先要了解YAML的语法,YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔。

           YAML文件扩展名通常为.yaml,如example.yaml。

列表(list)的所有元素均使用“-”打头,例如:
# A list of tasty fruits
- Apple
- Orange

字典(dictionary)通过key与value进行标识,例如:
---
# An employee record
name: Example Developer
job: Developer
skill: Elite

也可以将key:value放置于{}中进行表示,例如:
---
# An employee record
{name: Example Developer, job: Developer, skill: Elite}

     playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏。    

   playbook的核心元素:

         Tasks: 任务

         Variables: 变量

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

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

         Roles: 角色

         Hosts:  主机


1、hosts主机和用户

     playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户。      

  - hosts: webserver
    remote_user: root
    tasks:
    - name: ping
      ping:
      remote_user: usertest 
      sudo: yes
 
    remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。

2、tasks任务和action

     play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自下而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。  

    task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。

     每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。

tasks:
    - name: yum install httpd packages
      yum:  name=httpd state=present
    - name: start httpd
      service: name=httpd state=started

3、   Variables: 变量

       3.1、由ansible自己提供的变量:facts,可以直接调用

]# ansible webserver -m setup
172.18.250.78 | success >> {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.18.250.78"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:fefa:c47b"
        ], 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "07/31/2013", 
        "ansible_bios_version": "6.00",

   3.2、ansible-playbook命令的命令行中的自定义变量

]# vim /tmp/test.yaml
- hosts: webserver
  remote_user: root
  tasks:
  - name: useradd
    user: name={{ pkiname }} state=present
]# ansible-playbook  -e pkiname=user111 --check test.yaml

   3.3 向不同的主机中传递变量,在服务的配置文件中直接调用就行

]# vim /etc/ansible/hosts
[webserver]
172.18.250.77  http_port=80
172.18.250.78  http_port=8080

  3.4、向组中的主机传递相同的变量,以便在playbook中使用

]# vim /etc/ansible/hosts
[webserver]
172.18.250.77 
172.18.250.78  
[webserver:vars]
httpd_port=8080

4、 Templates:  包含了模板语法的文本文件,嵌套有脚本(使用模板编程语言编写)

     有时候需要根据服务器的配置来修改服务配置文件,这时可以根据模板来解决

]# vim /tmp/nginx.conf.j2
user nginx;
worker_processes {{ ansible_processor_vcpus-1 }};    //根据服务器cpu核数减1
]# vim /tmp/test.yaml
 - hosts: webserver
   remote_user: root
   tasks:
   - name: nginx conf
     template: src=/tmp/template/nginx.conf.j2 dest=/etc/nginx/nginx.conf
   - name: restart
     service: name=nginx state=restarted

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

    “notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。

]# vim /tmp/test.yaml
- hosts: webserver
  remote_user: root
  tasks:
  - name: install nginx
    yum: name=nginx state=present
  - name: nginx conf
    template: src=/tmp/template/nginx.conf.j2 dest=/etc/nginx/nginx.conf
    notify: restart            //只有当配置文件发生改变时才会触发notify
  - name: start nginx
    service: name=nginx state=started
  handlers:
    - name: restart           //触发notify时就执行重启操作
      service: name=nginx state=restarted

6、playbook还支持条件测试和循环:

条件测试:
when语句:在task中使用,jinja2语法格式
      tasks:
      - name: install conf file to centos7
        template:src=files/nginx.conf.c7.j2
        when: ansible_distribution_major_version == "7"
      - name:  install conf file to centos7            
        template:src=files/nginx.conf.c6.j2
        when: ansible_distribution_major_version == "6"
        
循环语句:对迭代项的引用,固定变量名为"item",而后,要在task中使用with_items给定要迭代的元素列表;
   with_items两个方法表示:
      列表方法:字符串、字典

   1、字符串表示
       - hosts: all
         remote_user: root
	 tasks:
	 - name: install some package
           yum: name={{ item }} state=present
	   with_items:
	   - nginx
	   - httpd 
   2、字典表示:
      - hosts: all
	remote_user: root
        tasks:
        - name: add group
	  group: name={{ item }} state=present
	  with_items:
          - group11
	  - group22
          - group33
        - name: add user
	  user: name={{ item.name }} group={{ item.group }} state=present
	  with_items:
	  - { name: 'user11',group: 'group11' }
          - { name: 'user22',group: 'group22' }
	  - { name: 'user33',group: 'group33' }	

 7、tags:标签

       tags用于让用户选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断。

]# vim /tmp/test.yaml
- hosts: webserver
  remote_user: root
  tasks:
  - name: install nginx
    yum: name=nginx state=present
  - name: nginx conf
    template: src=/tmp/template/nginx.conf.j2 dest=/etc/nginx/nginx.conf
    notify: restart  
    tags: res                //在配置文件修改这打标签,执行时不会测试instll和start两部分   - name: start nginx          代码  
    service: name=nginx state=started
  handlers:
    - name: restart         
      service: name=nginx state=restarted
]# ansible-playbook  --tags=res --check test.yaml


三、roles

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

创建role的步骤

(1) 创建以roles命名的目录;

(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等;

(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建;

(4) 在playbook文件中,调用各角色;

       

role内各目录中可用的文件

tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;此文件可以使用include包含其它的位于此目录中的task文件;

files目录:存放由copy或script等模块调用的文件;

templates目录:template模块会自动在此目录中寻找Jinja2模板文件;

handlers目录:此目录中应当包含一个main.yml文件,用于定义此角色用到的各handler;在handler中使用include包含的其它的handler文件也应该位于此目录中;

       vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量;

       meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible 1.3及其以后的版本才支持;

       default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件;


示例:创建个nginx角色,实现nginx的安装

]# mkdir /etc/ansible/roles/nginx
]# cd /etc/ansible/roles/nginx/
]# mkdir tasks files templates handlers vars meta default
]# cd tasks/       
]# vim main.yml              //编辑task
- name: install nginx
  yum: name=nginx state=present
- name: nginx conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  notify: restart nginx
  tags: res
- name:  start nginx
  service: name=nginx state=started  

]# cd handlers/ 
]# vim main.yml             //编辑handlers
- name: restart nginx
  service: name=nginx state=restarted

]# cd templates/
]# cp /tmp/nginx.conf.j2 ./    //准备模板
]# vim /etc/ansible/roles/nginx/templates/nginx.conf.j2
user {{ username }};

]# cd vars/
]# vim main.yml            //定义变量
username: deamon          //变量定义时较特殊,不要加“-”,定义运行nginx的用户

]# vim /tmp/nginx.yml
- hosts:websrvs
  remote_user:root
  roles:
  - nginx                 //直接调用nginx
# 调用变量:
 - host:
   remote_user:
   roles:
   - { role: nginx,username: nginx }  
# 还可以基于条件测试实现角色调用;
 - host:
   remote_user:
   roles:
   - { role: nginx,when: ansible_distribution_majro_version == ’7‘ }     

]# ansible-playbook --check /tmp/nginx.yml   

PLAY [webserver] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [172.18.250.78]
ok: [172.18.250.77]

TASK: [nginx | install nginx] ************************************************* 
changed: [172.18.250.78]
changed: [172.18.250.77]

TASK: [nginx | nginx conf] **************************************************** 
changed: [172.18.250.78]
changed: [172.18.250.77]

TASK: [nginx | start nginx] *************************************************** 
changed: [172.18.250.78]
changed: [172.18.250.77]

NOTIFIED: [nginx | restart nginx] ********************************************* 
changed: [172.18.250.78]
changed: [172.18.250.77]

PLAY RECAP ******************************************************************** 
172.18.250.77              : ok=5    changed=4    unreachable=0    failed=0   
172.18.250.78              : ok=5    changed=4    unreachable=0    failed=0

你可能感兴趣的:(运维,自动化,ansible)