Ansible 入门教程

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible 入门教程相关的知识,希望对你有一定的参考价值。

新手 ansible 入门教程

why ansible?

Ansible作为最受欢迎的自动化配置工具,主要得益于其设计上的优势。

1、无需客户端。与Chef、Puppet以及Saltstack(现在也支持Agentless方式salt-ssh)不同,Ansible是无客户端Agent的,所以无需在客户机上安装或配置任何程序,就可以运行Ansible任务。由于Ansible不会在客户机上安装任何软件或运行监听程序,因此消除了许多管理开销,我们可以在即可上手使用Ansible管理服务器,同时Ansible的更新也不会影响任何客户机。

2、使用SSH进行通讯

默认情况下,Ansible使用SSH协议在管理机和客户机之间进行通信。可以使用SFTP与客户机进行安全的文件传输。

3、并行执行

Ansible与客户机并行通信,可以更快地运行自动化任务。默认情况下,forks值为5,可以按需,在配置文件中增大该值。

安装 ansible

Ansible可以运行在任何机器上,但是对管理机有一定要求。管理机应安装Python 2(2.7)或Python 3(3.5或更高版本),另外,管理机不支持Windows控制节点。我们可以使用Linux发行版包管理器、源码安装或者Python包管理器(PIP)来安装Ansible。

我使用的是 CentOS7。

1、配置EPEL YUM

2、yum install ansible -y #yum安装最新版

3、ansible --version #安装后查看版本以及模块路径等信息

配置证书登录

为了使Ansible与客户端通信,需要使用用户帐户配置管理机和客户机。为了方便快捷安全,一般会配置证书方式连接客户机。

在所有客户机和管理上创建新的ansible用户之后,我们在管理机(ansible用户)生成SSH密钥,然后将SSH公钥复制到所有客户机。

ssh-keygen

三个回车,要是想后面执行一条命令就要输入一次 ssh 密码的话也可以给它个密码。

现在,将SSH公钥复制到所有客户机,这使管理机ansible用户无需输入密码即可登录客户机:

ssh-copy-id -i ~/.ssh/id_rsa.pub 远程主机名@远程主机ip

Ansible 配置文件

1、/etc/ansible/hosts:主机列表清单,也叫Inventory。在大规模的配置管理工作中,特别是云服务提供商或者IDC厂家,需要管理不同业务的不同机器,这些机器的信息都存放在Ansible的inventory组件里面。在我们使用Ansible进行远程主机管理时,必须先将主机信息存放在inventory里面,这样才能使用Ansible对它进行操作。如果不想使用默认清单的话可以用-i选项指定自定义的清单文件,防止多人混合使用一个主机清单。如果没有定义在主机列表文件中,执行命令会提示“No hosts matched”

2、/etc/ansible/ansible.cfg:Ansible服务主配置文件,比如并发数控制等在此文件定义

Inventory 定义方法

方法一:将主机IP、端口、用户名、密码写在配置文件的不同组中,多种写法格式如下

vim /etc/ansible/hosts
[webserver]  #组名为webserver
192.168.1.31 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
192.168.1.32 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
192.168.1.33 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
192.168.1.36 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"

[dbserver]  #组名为dbserver
192.168.1.4[1:3] ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"  #连续IP的简写

[redis]
192.168.1.5[1:3]
[redisserver:vars]  #将信息定义为变量
ansible_ssh_pass="123456"

[nginx] #推荐写法
nginx_1 ansible_ssh_host=192.168.1.61 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
nginx_2 ansible_ssh_host=192.168.1.62 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"

方法二:基于秘钥管理

#管理端创建秘钥并发送到每个被管理端
ssh-keygen
ssh-copy-id -i $被管理端IP

#管理端清单文件
vim /etc/ansible/hosts
[webserver]  #做好秘钥的机器只用写IP即可
192.168.1.31:22
192.168.1.32
192.168.1.33
192.168.1.36

[dbserver]  #也可以通过别名方式进行配置
node1 ansible_ssh_host=192.168.1.31 ansible_ssh_port=22
node2 ansible_ssh_host=192.168.1.32 ansible_ssh_port=22
node3 ansible_ssh_host=192.168.1.33 ansible_ssh_port=22

事实证明这就是段费话,照样要 ssh 的密码。推荐用方法一中的推荐写法。

方法三:自定义Inventory清单文件

#创建清单文件
vim /etc/ansible/dockers
[dockers]
192.168.1.31 ansible_ssh_pass='123456'
192.168.1.32
192.168.1.33
#使用-i指定清单文件
ansible dockers -m ping -i /etc/dockers

Inventory内置参数

参数名参数含义示例
ansible_ssh_host定义host ssh地址ansible_ssh_host=10.132.42.1.117
ansible_ssh_port定义hots ssh端口ansible_ssh_port=3009
ansible_ssh_user定义hosts ssh 认证用户ansible_ssh_user=michael
ansible_ssh_pass定义hosts ssh认证密码ansible_ssh_pass=root123
ansible_sudo定义hosts sudo的用户ansible_sudo=michael
ansible_sudo_pass定义hosts sudo密码ansible_sudo_pass=“12345”
ansible_sudo_exe定义hosts sudo 路径ansible_sudo_exe=/usr/bin/sudo密码
ansible_ssh_private_key_file定义hosts私钥ansible_ssh_private_key_file=/root/key
ansible_shell_type定义hosts shell类型ansible_shell_type=bash
ansible_python_interpreter定义hosts任务执行python的路径ansible_python_interpreter=/usr/bin/python2.7
ansible_interpreter定义hosts其他语言解析器路径ansible_interpreter=/usr/bin/ruby

动态inventory

上面也说到了,对于那些云服务提供商或者IDC厂家会有大量的主机列表;如果手动维护这些列表将是一个非常繁琐的事情。其实Ansible是支持动态的inventory的,动态inventory就是Ansible所有的inventory文件里面的主机列表和变量信息都是从外部拉取的。比如我们可以从CMDB系统和Zabbix监控系统拉取所有的主机信息,然后使用Ansible进行管理。这样一来我们就可以很方便的将Ansible与其它运维系统结合起来。关于引用动态inventory的功能配置起来是非常简单的;我们只需要把ansible.cfg文件中inventory的定义值改成一个执行脚本即可。这个脚本的内容不受任何编程语言限制,但是这个脚本使用参数时有一定的规范并且对脚本执行的结果也有要求。这个脚本需要支持两个参数:

  • --list或者-l:这个参数运行后会显示所有的主机以及主机组的信息(JSON格式);
  • --host或者-H:这个参数后面需要指定一个host,运行结果会返回这台主机的所有信息(包括认证信息、主机变量等),也是JSON格式。

来看一个演示脚本:

#!/usr/bin/env python3

# -- coding:utf-8 --

import argparse
import json

def lists():
    r = 
    h = ['192.168.1.2', '192.168.1.4']
    hosts = 'hosts':h
    r['web'] = hosts
    return json.dumps(r, indent=4)

def hosts(name):
    r = 'ansible_ssh_user':'jelly', 'ansible_ssh_pass':'123456'
    return json.dumps(r)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-l', '--list', help='hosts list', action='store_true')
    parser.add_argument('-H', '--host', help='hosts vars')
    args = vars(parser.parse_args())

if args['list']:
    print(lists())
elif args['host']:
    print(hosts(args['host']))
else:
    parser.print_help()

接下来,我们先不修改ansible.cfg中的inventory配置,直接在命令行指定配置文件进行运行:

ansible -i inventoryDemo.py web -m ping

输出结果如下:

192.168.1.2 | SUCCESS => 
    "changed": false,
    "ping": "pong"

192.168.1.4 | SUCCESS => 
    "changed": false,
    "ping": "pong"

在生产环境,我们需要将ansible.cfg中的inventory配置指定为这个python脚本的路径,后续正常执行各个ansible命令即可,比如这样:

ansible web -m ping

ansible.cfg

在Ansible中,它的配置文件是一个名为ansible.cfg的配置文件,ansible.cfg配置文件是以ini格式存储配置数据的。但是ansible.cfg配置文件可以存放在不同的目录,但只有一个可用,在运行Ansible命令时,Ansible将会按照预先设定的顺序查找配置文件,检查到哪个就用哪个。Ansible预先设定的优先级顺序如下:

  • ANSIBLE_CFG:首先,Ansible命令会先检查环境变量,及这个环境变量将指向的配置文件;
  • ./ansible.cfg:其次,将会检查当前目录下的ansible.cfg配置文件;
  • ~/.ansible.cfg:再次,将会检查当前用户home目录下的.ansible.cfg配置文件;
  • /etc/ansible/ansible.cfg:最后,将会检查在安装Ansible时自动生产的配置文件。

几乎所有的配置项都可以通过 Ansible 的 playbook 或环境变量来重新赋值,所以当你怎么都不知道这个变量在哪里定义的时候,不妨去看看环境变量里看看。建议使用~/.ansible.cfg作为配置文件使用,这样就可以实现每个用户都有自己独自的配置文件,不污染其它用户正常使用Ansible,同时也方便进行选项配置。

由于Ansible本身没有服务的概念,所以只要配置修改后配置将马上生效。

常用的配置选项

  • defaults配置

    配置项说明默认值
    inventoryansible inventory文件路径/etc/ansible/hosts
    libraryansible模块文件路径/usr/share/my_modules/
    remote_tmpansible远程主机脚本临时存放目录~/.ansible/tmp
    local_tmpansible管理节点脚本临时存放目录~/.ansible/tmp
    forksansible执行并发数5
    poll_intervalansible异步任务查询间隔15
    sudo_useransible sudo用户root
    ask_sudo_pass运行ansible是否提示输入sudo密码True
    ask_pass运行ansible是否提示输入密码True
    transportansible远程传输模式smart
    remote_port远程主机SSH端口22
    module_langansible模块运行默认语言环境C
    gatheringfacts信息收集开关定义smart
    roles_pathansible role存放路径/etc/ansible/roles
    timeoutansible SSH连接超时时间10
    remote_useransible远程认证用户root
    log_pathansible日志记录文件/var/log/ansible.log
    module_nameansible默认执行模块command
    executableansible命令执行shell/bin/sh
    hash_behaviouransible主机变量重复处理方式replace
    private_role_vars默认情况下,角色中的变量将在全局变量范围中可见。 为了防止这种情况,可以启用以下选项,只有tasks的任务和handlers得任务可以看到角色变量yes
    vault_password_file指定vault密码文件路径
    ansible_managed定义的一个Jinja2变量,可以插入到Ansible配置模版系统生成的文件中Ansible managed
    display_skipped_hosts开启显示跳过的主机True
    error_on_undefined_vars开启错误,或者没有定义的变量False
    action_pluginsansible action插件路径
    cache_pluginsansible cache插件路径
    callback_pluginsansible callback插件路径
    connection_pluginsansible connection插件路径
    lookup_pluginsansible lookup插件路径
    inventory_pluginsansible inventory插件路径
    vars_pluginsansible vars插件路径
    filter_pluginsansible filter插件路径
    terminal_pluginsansible terminal插件路径
    strategy_pluginsansible strategy插件路径
    fact_caching定义ansible facts缓存方式memory
    fact_caching_connection定义ansible facts缓存路径
  • privilege_escalation配置

    配置项说明默认值
    become是否开启become模式True
    become_method定义become方式sudo
    become_user定义become方式root
    become_ask_pass是否定义become提示密码False

Andible 常用模块基本操作

这些常用的模块,就好比基本功,基本招式一样,我们需要掌握这些基本功,掌握这些基本招式。

ping 模块

ping是测试远程节点的SSH连接是否就绪的常用模块,但是它并不像Linux命令那样简单地ping一下远程节点,而是先检查能否通过SSH登陆远程节点,再检查其Python版本能否满足要求,如果都满足则会返回pong,表示成功。使用方式如下:

ansible web -m ping

ping无须任何参数。上述命令输出结果如下所示:

192.168.1.2 | SUCCESS => 
    "changed": false,
    "ping": "pong"

192.168.1.4 | SUCCESS => 
    "changed": false,
    "ping": "pong"

debug模块

打印输出信息,类似Linux上的echo命令。在后续的学习过程中,我们会经常用这个命令来调试我们写的playbook。

对于debug模块有两种用法。下面就对这两种用法都进行详细的总结。

  • 通过参数msg定义打印的字符串
    msg中可以嵌入变量,比如我先定义了以下的一个playbook。

    ---
    
    - hosts: web
      vars:
        name: jellythink
      tasks:
        - name: display
          debug: msg="I am name"
    
  • 通过参数var定义需要打印的变量
    变量可以是系统变量,也可以是动态的执行结果,通过关键字register注入变量中。对于变量,我们可以这样玩:

---

- hosts: web
  vars:
    name: jellythink
  tasks:
    - name: display
      debug:
        var: name

对于注入变量,可以这样玩:

---

- hosts: web
  tasks:
    - name: register var
      shell: hostname
      register: result
    - name: display
      debug:
        var: result

copy模块

从当前的机器上复制静态文件到远程节点上,并且设置合理的文件权限。copy模块在复制文件的时候,会先比较一下文件的 checksum,如果相同则不会复制,返回状态为 OK;如果不同才会复制,返回状态为 changed。

一般情况的使用,就是这样的:

---

- hosts: server1
  tasks:
    - name: copyDemo
      copy:
        src: /home/jelly/nameList.txt 
        dest: /home/test1/nameList.txt

在实际的工作中,一般会在进行文件分发时,需要备份原文件,这个时候就需要我们加上backup选项:

---

- hosts: server1
  tasks:
    - name: copyDemo
      copy:
        src: /home/jelly/nameList.txt 
        dest: /home/test1/nameList.txt
        backup: yes

加上backup: yes后,在目标主机上,就会对原来的文件进行备份,比如这样子的备份文件:

nameList.txt.8648.2019-09-28@06:27:18~

template模块

如果只是复制静态文件,使用copy模块就可以了;但是如果在复制的同时需要根据实际情况修改部分内容,那么就需要用到template模块了。

比如我们在分发配置文件时,每个配置文件需要根据远程主机的一些属性不同而配置不同的值,对于需要替换的部分,我们就可以使用template模块来进行替换。template模块使用的是Python中的Jinja2模板引擎,这里我们不需要过多的去关注这个模板引擎,只需要知道变量的表示法是就可以了。比如这里就有一个http.conf.j2的模板文件,文件内容如下:

Listen ansible_default_ipv4.address
Port http_port

其中ansible_default_ipv4.address就是需要根据不同的主机,动态变化的。接下来,我们就可以这样使用template模块来完成变量的替换。

---

- hosts: server1
  vars:
    http_port: 8080

  tasks:
  - name: Write Config File
    template:
      src: http.conf.j2
      dest: /home/test1/http.conf

在目的主机上,文件内容如下:

Listen 192.168.1.3
Port 8080

copy模块一样,template模块也可以进行权限设置和文件备份等功能。

file模块

file模块可以用来设置远程主机上的文件、软链接和文件夹的权限,也可以用来创建和删除它们。

我们可以使用mode参数进行权限修改,可以直接赋值数字权限(必须以0开头)。

---

- hosts: server1
  tasks:
  - name: Modify Mode
    file:
      path: /home/test1/http.conf
      mode: 0777

我们还可以根据state参数的不同,实现不同的行为,比如创建软链接:

---

- hosts: server1
  tasks:
    - name: Create Soft Link
      file:
        src: /home/test1/http.conf
        dest: /home/test1/conf
        state: link

也可以设置state: touch创建一个新文件,比如这样:

---

- hosts: server1
  tasks:
    - name: Create a new file
      file:
        path: /home/test1/touchfile
        state: touch 
        mode: 0700

还可以设置state: directory新建一个文件夹,比如这样:

---

- hosts: server1
  tasks:
    - name: Create directory
      file: 
        path: /home/test1/testDir
        state: directory
        mode: 0755

user模块

user模块可以对用户进行管理,实现增、删、改Linux远程节点的用户账户。比如增加用户:

---

- hosts: server1
  tasks:
    - name: Add user
      user:
        name: test3

删除用户:

---

- hosts: server1
  tasks:
    - name: Add user
      user:
        name: test3
        state: absent
        remove: yes

但是在使用这个user模块时,需要注意权限问题。

shell模块

在远程节点上通过/bin/sh执行命令。如果一个命令可以通过模块yumcopy模块实现时,那么建议不要使用shell或者command这样通用的命令模块。因为通用的命令模块不会根据具体操作的特点进行状态判断,所以当没有必要再重新执行的时候,它还是会重新执行一遍。

  • 支持<>|;&

    --- 
    - hosts: server1
      tasks:
        - name: Test shell
          shell: echo "test1" > ~/testDir/test1 && echo "test2" > ~/testDir/test2
    
  • 调用脚本

    ---
    
    - hosts: server1
      tasks:
        - shell: ~/test.sh >> somelog.txt
    

    在执行命令之前,我们可以改变工作目录,并且仅在文件somelog.txt不存在时执行命令,除此之外,还可以指定用bash运行命令:

    ---
    
    - hosts: server1
      tasks:
        - shell: ~/test.sh >> somelog.txt
          args:
            chdir: ~/testDir
            creates: somelog.txt
            executable: /bin/bash
    

command模块

在远程节点上执行命令。和shell模块类似,但不支持<>|;&等操作,其它的大抵都是相似的。

service/systemd

管理服务。

- name: 服务管理
  service:
    name: etcd
    state: started
    #state: stopped
    #state: restarted
    #state: reloaded
- name: 设置开机启动
  service:
    name: httpd
    enabled: yes
- name: 服务管理  
  systemd: 
	name=etcd 
	state=restarted 
	enabled=yes 
	daemon_reload=yes

unarchive

- name: 解压
  unarchive: 
    src=test.tar.gz 
    dest=/tmp

Ansible Ad-Hoc命令

虽然Ad-Hoc命令的功能没有playbook剧本那样强大,但是也足以满足我们工作中的很多场景。在Ansible中命令都是并发执行的,我们可以针对目标主机执行任何命令。默认的并发数目由ansible.cfg中的forks值来控制。当然了,我们也可以在运行Ansible命令的时候通过-f指定并发数。通过ansible -h命令就可以列出所有的命令参数,下面列举了常用的一些参数。

  • -v--verbose:输出详细执行信息,-vvv可以得到执行过程中的所有信息;
  • -i INVENTORY--inventory=INVENTORY--inventory-file=INVENTORY:指定inventory文件,默认使用/etc/ansible/hosts
  • -f FORKS--forks=FORKS:执行时并发的线程个数,默认为5;
  • -m MODULE_NAME:指定module,默认为command模块;
  • -a MODULE_ARGS:指定module的参数;
  • -o:精简输出内容;
  • --list-hosts:列出主机列表,并不会执行其他操作。

ansible命令行语法格式:

ansible <host-pattern> [-f forks] [-m module_name] [-a args]

知道了这些选项,接下来我们就通过一些实际的命令操作来熟悉和理解Ansible Ad-Hoc。

ping模块

ping模块是我们经常使用的一个模块,我们经常会这样使用:

ansible server1 -m ping -o

输出内容如下:

192.168.1.3 | SUCCESS => "changed": false,"ping": "pong"

copy模块

前面是通过playbook的方式来学习copy模块的,这里通过Ansible Ad-Hoc再来熟悉一下。

ansible server1 -m copy -a 'src=/home/jelly/nameList.txt dest=/home/test1/nameList.txt backup=yes' -o

输出如下:

192.168.1.3 | CHANGED => "changed": true,"checksum": "2cb17bce3b65b4168ec1472690e6c49028b5b73b","dest": "/home/test1/nameList.txt","gid": 1001,"group": "test1","md5sum": "39e0c6634669ec88003d6d92f50e879e","mode": "0664","owner": "test1","size": 7,"src": "/home/test1/.ansible/tmp/ansible-tmp-1569858467.3466117-143590544702277/source","state": "file","uid": 1001

command模块

默认模块。让远端主机执行指定的命令,但不支持管道或者重定向。

ansible 192.168.44.130 -a 'date'

shell模块

shell模块是我们使用的最多的模块了。如果学会了Ansible,我想这个命令可能是你今后运维中会经常使用的命令了。为什么这么说呢?就是因为好用!!!

比如:

ansible server1 -m shell -a 'uname -ra' -o

输出如下:

192.168.1.3 | CHANGED | rc=0 | (stdout) Linux localhost.localdomain 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

总而言之,言而总之,当你想在多台机器上执行某个命令时,不妨试一试这里说的这个方法哦!

cron模块

设置定时任务,其中有个state选项包含present、absent两个参数,分别代表增加和移除

ansible webserver -m cron -a 'minute="*/10" job="/bin/echo test" name="test cron job" '
ansible webserver -m cron -a 'hour="*/1" job="/usr/sbin/ntpdate 10.254.1.10" name="crontab from ansible" state=present'

user模块

管理用户,还有一个group模块用于管理组

ansible webserver -m user -a "name=mysql system=yes"

yum模块

安装程序包,远端主机需要先配置好正确的yum源

ansible -m yum -a 'name=httpd state=present' 

name:指明要安装的程序包,可以带版本号,否则默认最新版本,多个安装包用逗号分隔
state:present代表安装,也是默认操作;absent是卸载;latest最新版本安装

copy模块

实现文件复制

ansible all -m copy -a 'src=/etc/fstab dest=/etc/fstab owner=root mode=640' 
ansible all -m copy -a 'content="hello world" dest=/etc/fstab owner=root mode=640 backup=yes'   

src=:定义本地源文件的路径
dset=:定义目标文件路径
content=:用该选项直接生成内容,替代src
backup=:如果目标路径存在同名文件,将自动备份该文件

这些模块在 ansible 中是通用的,所以有些在上一 part 写了这一 part 不一定写,不代表没有。

查看 ansible 模块帮助信息

1、通过ansible-doc -l命令可以显示当前版本所支持的模块信息

2、通过ansible-doc -s modulename显示指定模块的详细用法

ansible-doc -s yum

Ansible playbook

如果基于AD-Hoc去执行多任务(如安装Nginx、修改配置文件、启动服务),需要先使用yum或command模块安装程序,再使用copy模块复制配置文件,最后使用service模块启动服务。为了解决这种多任务繁琐的情况,可以使用Ansible的playbook(剧本)功能。

playbook 的构成

Inventory:主机列表,表示剧本中的任务要应用在哪些主机上

Tasks:具体任务,即调用哪些模块完成操作,可以配置多个任务

Variables:变量,包含内置变量和自定义变量

Templates:模板,即使用模板语法来灵活变更的配置文件

Handlers与notify:触发器,由某事件触发执行的操作,比如修改配置文件后自动重启服务

playbook本质是包含了一个或多个play的YAML配置文件,通常以.yaml或者.yml结尾。在单一的一个playbook文件中,使用连续的三个中横线(—)作为每个play的区分。

执行playbook命令

我们都是按照yaml语法规则来编写playbook。

Ansible提供了一个单独的命令:ansible-playbook命令,我们可以通过这个命令来执行yaml脚本。常见的ansible-playbook的使用方法如下:

最简单的使用方法:

ansible-playbook copyDemo.yaml

我们还可以使用以下命令查看输出的细节:

ansible-playbook copyDemo.yaml --verbose

我们也可以使用以下命令查看该yaml脚本将影响的主机列表:

ansible-playbook copyDemo.yaml --list-hosts

还可以使用以下命令检查yaml脚本语法是否正确:

ansible-playbook copyDemo.yaml --syntax-check

上面的几种使用方法基本就涵盖了我们日常工作中80%的场景了,剩余的20%场景,比如并行、异步等,很少用到,等真正用到的时候再去查阅相关资料也来的及。而工作中,更多的时候,我们不是在编写playbook,就是在编写playbook的路上。所以,接下来我重点说说如何写这个playbook,也就是playbook的基本语法。

任务控制

如果你有一个大的剧本,那么能够在不运行整个剧本的情况下运行特定部分可能会很有用。

  tasks:
  - name: 安装nginx最新版
    yum: pkg=nginx state=latest
    tags: install
  - name: 写入nginx配置文件
    template: src=/srv/httpd.j2 dest=/etc/nginx/nginx.conf
    tags: config

使用:

ansible-playbook example.yml --tags "install"
ansible-playbook example.yml --tags "install,config"
ansible-playbook example.yml --skip-tags "install"

playbook基本语法

最基本的playbook脚本分为三个部分:

  1. 在哪些机器上以什么身份执行
  2. 执行的任务有哪些
  3. 善后任务有哪些

我们在编写playbook脚本的时候,总是离不开上面的三个部分的。下面先来一个稍微有点复杂的playbook脚本,让大家先有一个整体的认识。

---
- hosts: server1
  user: root
  vars:
    http_port: 80
    max_clients: 200

  tasks:
    - name: Write apache config file
      template: src=/home/test1/httpd.j2 dest=/home/test2/httpd.conf
      notify:
        - restart apache
    - name: Ensure apache is running
      service: name=httpd state=started

  handlers:
    - name: restart apache
      service: name=httpd state=restarted

现在就对上述三部分稍作详细总结。

主机和用户

上面的yaml脚本,我们一开始就会看到hostsuservars,其中vars在后面的文章进行专门总结。而这里的hostsuser就是表示我们这个yaml将要在哪些主机上用哪个用户身份去操作。而这里的深一层次的关系如下表所示:

key含义
hosts为主机的IP,或者主机组名,或者关键字all
user在远程以哪个身份执行
become切换成其他用户身份执行,值为yes或者no
become_method与become一起使用,值可以为sudo/su
become_user与become一起使用,可以是root或者其它用户名

在实际工作中,如果我们不指定user时,则默认使用连接远程主机的用户进行操作,如果指定了执行用户而与ansible_ssh_user指定用户不一致时,则需要开启become操作,这里的become配置与ansible.cfg中配置将相互配合完成工作,yaml中的become优先级高于ansible.cfg中配置中的优先级。

任务列表

任务列表是整个playbook的核心,对于任务列表,我们首先需要知道以下三点内容:

  • 任务是从上到下顺序执行的,如果中间发生错误,那么整个playbook会中止;
  • 每一个任务都是对模块的一次调用,只是使用不同的参数和变量而已;
  • 每一个任务最好有一个name属性,这样在执行yaml脚本时,可以看到执行进度信息。

对于任务的参数有两种不同的写法,我们在编写yaml脚本时,可以按照自己的喜好进行选择。

写法一:

- name: Write apache config file
  template: src=/home/test1/httpd.j2 dest=/home/test2/httpd.conf

写法二:

- name: Write apache config file
  template: 
    src: /home/test1/httpd.j2
    dest: /home/test2/httpd.conf

这两种写法都是OK的,我一般喜欢第二种写法。

最后,对于任务我们还需要特别一个点,那就是任务的执行状态。我们在执行Ansible Ad-Hoc或者ansible-playbook的时候,在输出中都会有一个changed字段,比如:

192.168.1.3                : ok=2    changed=0    unreachable=0    failed=0  

或者

192.168.1.3                : ok=2    changed=1    unreachable=0    failed=0

这里的这个changed就是任务的执行状态,但是它为什么一会是0,一会有是1呢?这就要说到Ansible中一个叫做“幂等性”的概念。

幂等性

幂等性是数学和计算机科学上一个常见的概念,多次执行产生的结果不会发生改变,这样的特性就被成为幂等性。

大多数的Ansible模块在设计时保证了幂等性,幂等性保证了Ansible脚本多次执行情况下的相同结果,尽可能的避免使用那些不能满足幂等性的模块。比如我们经常使用的shell模块就是非幂等性的。

我们要明白Ansible是以“结果为导向的”,我们指定了一个“目标状态”,Ansible会自动判断“当前状态”是否与“目标状态”一致,如果一致,则不进行任何操作;如果不一致,那么就将“当前状态”变成“目标状态”,这就是“幂等性”,“幂等性”可以保证我们重复的执行同一项操作时,得到的结果是一样的。

那这个幂等性与上面的changed又有什么关系呢?且听我下面慢慢道来!

  • changed为false或者0时,表示Ansible没有进行任何操作,没有“改变什么”;
  • changed为true或者大于0时,表示Ansible执行了操作,“当前状态”已经被Ansible改变成了“目标状态”。

copy这个模块来举例子

以上是关于Ansible 入门教程的主要内容,如果未能解决你的问题,请参考以下文章

YAML语法入门

YAML语法入门

Perl教程 - 标量

ansible 的Playbook

ansible-playbook使用详解

原创ansible-playbook 详解