自动化运维利器 ansible-入门

2020-12-10 11:20:05 浏览数 (1)

阅读本文大约需要 10 分钟

ansible 简介

ansible 是一款强大的配置管理工具,诣在帮助系统管理员高效率地管理成百上千台主机。设想一个主机是一个士兵,那么有了 ansible ,作为系统管理员的你就是一个将领,你可以通过口头命令,即一次下发一条命令(ansible ad-hoc 模式)方式让一个或一组或全部的士兵按你的指令行事,也可以将多条命令写在纸上(ansible playbook 模式), 需要执行命令时只需要提供这张纸即可。你可以让多个士兵同时做相同或不同的事情,可以方便的让新加入的士兵快速加入已有的兵种队伍,也以快速改变兵种(配置管理),一句话,士兵都严格听你的,你做好命令的设计,ansible 自动帮你发布和执行。

我们只需要在一台机器(类 unix 系统)上安装 ansible,即可在这台机器上管理其他主机,ansible 使用 ssh 协议与被管理的主机通讯,只要能 ssh 连接这些主机,ansible 便可以控制他们。

ansible 安装

ansible 的安装轻而易举,安装方法如下:

1. 使用 pip 安装

pip 是 python 的包管理工具,使用起来非常方便,只要操作系统安装有 pip,直接 pip install 包名即可,安装 ansible 的方法如下:

代码语言:javascript复制
pip install ansible

2. 使用 apt-get 安装

在基于 Debian/Ubuntu Linux 的系统中可使用 apt-get 安装 ansible

代码语言:javascript复制
sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

3. 使用 yum 安装 在基于 RHEL/CentOS Linux 的系统中可使用 yum 安装 ansible

代码语言:javascript复制
sudo yum install ansible

4. 使用源码安装 可以从 github 上安装最新版本

代码语言:javascript复制
cd ~
git clone git://github.com/ansible/ansible.git
cd ./ansible
source ./hacking/env-setup

ansible 配置文件

ansible 的配置文件有多个位置,查找顺序如下:

1. 环境变量 ANSIBLE_CONFIG 所指向的位置

2. 当前目录下的 ansible.cfg

3. HOME 目录下的配置文件 ~/.ansible.cfg

4. /etc/ansible/ansible.cfg

在大多数场景下默认的配置就能满足大多数用户的需求,在一些特殊场景下,用户还是需要自行修改这些配置文件, 如果安装后没有在以上 3 个位置找到配置文件的话,自己在 HOME 目录新建一个 .ansible.cfg 即可。

ansible 常见的配置参数如下所示:

代码语言:javascript复制
inventory = ~/ansible_hosts      #这个参数表示主机清单 inventory 文件的位置
forks = 5        #并发连接数,默认为5
sudo_user = root        #设置默认执行命令的用户
remote_port = 22        #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60          #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log     #指定一个存储ansible日志的文件(默认不记录日志)

更为详细的配置参数详见

ansible 详细配置文件 见 https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg

Inventory 文件

Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为 /etc/ansible/hosts,我们也可以通过 ansible 的配置文件来指定 inventory 文件位置。 除默认文件外,你还可以同时使用多个 inventory 文件,也可以从动态源,或云上拉取 inventory 配置信息。

一个简单的 Inventory 文件示例

代码语言:javascript复制
192.168.0.111

也可以对主机进行分组

代码语言:javascript复制
mail.example.com[webservers]
foo.example.com
bar.example.com[dbservers]
one.example.com
two.example.com
three.example.com

方括号[]中是组名,用于对系统进行分类,便于对不同系统进行个别的管理。一个系统可以属于不同的组,比如一台服务器可以同时属于 webserver 组和 dbserver 组。这时属于两个组的变量都可以为这台主机所用。

主机变量 前面已经提到过,分配变量给主机很容易做到,这些变量定义后可在 playbooks 中使用:

代码语言:javascript复制
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

组的变量 也可以定义属于整个组的变量:

代码语言:javascript复制
[atlanta]
host1
host2[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

把一个组作为另一个组的子成员 可以把一个组作为另一个组的子成员,以及分配变量给整个组使用. 这些变量可以给 /usr/bin/ansible-playbook 使用,但不能给 /usr/bin/ansible 使用:

代码语言:javascript复制
[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2

[usa:children]
southeast
northeast
southwest
northwest

对于每一个 host,你还可以选择连接类型和连接用户名:

代码语言:javascript复制
[targets]localhost              ansible_connection=local
other1.example.com     ansible_connection=ssh        ansible_ssh_user=mpdehaan
other2.example.com     ansible_connection=ssh        ansible_ssh_user=mdehaan

Inventory 参数的说明

如同前面提到的,通过设置下面的参数,可以控制 ansible 与远程主机的交互方式,如下:

代码语言:javascript复制
ansible_ssh_host
      将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.

ansible_ssh_port
      ssh端口号.如果不是默认的端口号,通过此变量设置.

ansible_ssh_user
      默认的 ssh 用户名

ansible_ssh_pass
      ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)

ansible_sudo_pass
      sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)

ansible_sudo_exe (new in version 1.8)
      sudo 命令路径(适用于1.8及以上版本)

ansible_connection
      与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.

ansible_ssh_private_key_file
      ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.

ansible_shell_type
      目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.

ansible_python_interpreter
      目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如  *BSD, 或者 /usr/bin/python
      不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).

      与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

一个主机文件的例子

代码语言:javascript复制
some_host         ansible_ssh_port=2222     ansible_ssh_user=manager
aws_host          ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host      ansible_python_interpreter=/usr/local/bin/python
ruby_module_host  ansible_ruby_interpreter=/usr/bin/ruby.1.9.3

执行 ansible 命令(ad-hoc 命令)

接下来我们展示如何 ansible 命令,配置文件如下所示:

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ cat ~/.ansible.cfg 
[defaults]
inventory = ~/ansible_hosts

inventory 文件如下所示:

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ cat ~/ansible_hosts 
[master]
localhost ansible_connection=local ansible_ssh_user=aaron
192.168.0.111 ansible_ssh_user=aaron
[slave]
192.168.0.112 ansible_ssh_user=aaron

可能每台机器登陆的用户名都不一样,这里我指明了每台机器连接的 ssh 登陆用户名,在执行 ansible 命令时就不需要再指定用户名,如果不指定用户名,andible 则尝试使用本机已登陆的用户去登陆远程主机。

使用 ansible 命令的帮助

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible -help
Usage: ansible <host-pattern> [options]

Define and run a single task 'playbook' against a set of hosts

Options:
  -a MODULE_ARGS, --args=MODULE_ARGS
                        module arguments
  --ask-vault-pass      ask for vault password
  -B SECONDS, --background=SECONDS
                        run asynchronously, failing after X seconds
                        (default=N/A)
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
                        set additional variables as key=value or YAML/JSON, if
                        filename prepend with @
  -f FORKS, --forks=FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path or comma separated host
                        list. --inventory-file is deprecated
  -l SUBSET, --limit=SUBSET
                        further limit selected hosts to an additional pattern
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  ......

所有的命令参数都可以从 ansible -h 找到,接下接让我们列出主机列表

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all --list-host
  hosts (3):
    192.168.0.112
    localhost
    192.168.0.111
(py37env) aaron@ubuntu:~$ ansible master --list-host
  hosts (2):
    localhost
    192.168.0.111

执行第一条 ansible 命令

可以看出 ansible 命令后跟的是主机的组的名称,all 代表所有的主机。 接下来让我们执行第一条 ansible 命令.

ping 所有主机

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m ping 
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.0.112 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).rn",
    "unreachable": true
}
192.168.0.111 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).rn",
    "unreachable": true
}

可以看出 ansible 返回的类型是一个键值对的 json 格式的数据,其中 localhost 成功,其他两个主机均失败了,原因是 ssh 是一个安全的协议,如果不提供用户名密码就可以随便连接,会出大问题的。

我们使用密码来执行 ansible 的 ping 命令:

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m ping --ask-pass
SSH password: 
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.0.111 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.0.112 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

输入密码后(如果每台机器密码相同,则只需要执行一次命令,输入一次密码,若不同,需要多次执行命令,每次输入不同的密码),命令被成功执行,在一些机器上你会需要安装 sshpass 或者指定 -c paramiko。 从运行结果可以看出,都是 ping 通的,返回结果为 “pong”, changed 是 false 表示未改变远程主机任何文件。 这样一指令就分别发送到 3 台主机进行执行,是不是很高效?短时间内无需再重复输入密码。 那么问题来了,每次都输入密码太烦了,有没有不输入密码的方法呢?当然有了,ansible 使用 ssh 协议登陆远程主机,接下来我们使用 ansible 将 localhost 的公钥复制到远程主机的 authorized_keys

首先检查本机是否已生成公钥,如果没有则在 shell 中执行 ssh-keygen 命令后一直回车即可。

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ls -ltr ~/.ssh
total 12
-rw-r--r-- 1 aaron aaron  394 Aug  2 21:39 id_rsa.pub
-rw------- 1 aaron aaron 1679 Aug  2 21:39 id_rsa
-rw-r--r-- 1 aaron aaron  666 Aug  4 09:11 known_hosts

如果有 id_rsa.pub 则说明已经生成了公钥

接下来我们使用 ansible 将公钥文件的内容复制到远程主机的 authorized_keys 里去。

ansible 批量执行 ssh 授信

代码语言:javascript复制
(py37env) aaron@ubuntu:~/.ssh$ ansible all -m authorized_key -a "user=aaron key='{{ lookup('file', '/home/aaron/.ssh/id_rsa.pub') }}' path=/home/aaron/.ssh/authorized_keys manage_dir=yes" --ask-pass
SSH password: 
localhost | SUCCESS => {
    "changed": true,
    "comment": null,
    "exclusive": false,
    "gid": 1001,
    "group": "aaron",
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
    "key_options": null,
    "keyfile": "/home/aaron/.ssh/authorized_keys",
    "manage_dir": true,
    "mode": "0600",
    "owner": "aaron",
    "path": "/home/aaron/.ssh/authorized_keys",
    "size": 394,
    "state": "file",
    "uid": 1001,
    "unique": false,
    "user": "aaron",
    "validate_certs": true
}
192.168.0.111 | SUCCESS => {
    "changed": true,
    "comment": null,
    "exclusive": false,
    "gid": 1000,
    "group": "aaron",
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
    "key_options": null,
    "keyfile": "/home/aaron/.ssh/authorized_keys",
    "manage_dir": true,
    "mode": "0600",
    "owner": "aaron",
    "path": "/home/aaron/.ssh/authorized_keys",
    "size": 394,
    "state": "file",
    "uid": 1000,
    "unique": false,
    "user": "aaron",
    "validate_certs": true
}
192.168.0.112 | SUCCESS => {
    "changed": true,
    "comment": null,
    "exclusive": false,
    "gid": 1000,
    "group": "aaron",
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
    "key_options": null,
    "keyfile": "/home/aaron/.ssh/authorized_keys",
    "manage_dir": true,
    "mode": "0600",
    "owner": "aaron",
    "path": "/home/aaron/.ssh/authorized_keys",
    "size": 394,
    "state": "file",
    "uid": 1000,
    "unique": false,
    "user": "aaron",
    "validate_certs": true
}

我们利用 ansible 有一个更加方便的内置 SSH 密钥管理支持来执行我们的任务,输入密码后,得到以上运行结果说明成功执行。如果两台 远程主机的密码不相同,执行两次命令,分别输入不同的密码即可。

注意 ssh 对 authorized_keys 的权限要求比较严格,仅所属用户才有读写权限(600)时才生效

到目前为止 ssh 授信成功了,后续可以免密码执行命令了,下面验证下。

获取被管理机器的当前时间

代码语言:javascript复制
(py37env) aaron@ubuntu:~/.ssh$ ansible all -a "date  '%Y-%m-%d %T'"
localhost | SUCCESS | rc=0 >>
2018-08-04 15:04:55

192.168.0.111 | SUCCESS | rc=0 >>
2018-08-04 00:04:57

192.168.0.112 | SUCCESS | rc=0 >>
2018-08-04 00:04:57

现在,不需要输入密码,即可同时获取三台主机的时间,主机的时钟可能不一致,这是正常现象。

使用 ansible 批量传文件。

将一个文本文件上传至远程主机的用户 home 目录中。

先查看远程主机上用户 home 目录上的文件

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls ~/*.*"
localhost | SUCCESS | rc=0 >>
/home/aaron/030303.mp4
/home/aaron/aaa.py
/home/aaron/dfasdfasdfad.py
/home/aaron/examples.desktop
/home/aaron/hello.py
/home/aaron/new.py
/home/aaron/playbook.retry
/home/aaron/playbook.yaml
/home/aaron/setting.py
/home/aaron/test.py
/home/aaron/vimrc.bak_20180719
/home/aaron/你好.txt

192.168.0.111 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop

192.168.0.112 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop

将 “你好.txt” 上传至另外两台服务器

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m copy -a "src=/home/aaron/你好.txt dest=/home/aaron"
localhost | SUCCESS => {
    "changed": false,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/home/aaron/你好.txt",
    "gid": 1001,
    "group": "aaron",
    "mode": "0664",
    "owner": "aaron",
    "path": "/home/aaron/你好.txt",
    "size": 0,
    "state": "file",
    "uid": 1001
}
192.168.0.112 | SUCCESS => {
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/home/aaron/你好.txt",
    "gid": 1000,
    "group": "aaron",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0664",
    "owner": "aaron",
    "size": 0,
    "src": "/home/aaron/.ansible/tmp/ansible-tmp-1533367280.2415307-170986393705436/source",
    "state": "file",
    "uid": 1000
}
192.168.0.111 | SUCCESS => {
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/home/aaron/你好.txt",
    "gid": 1000,
    "group": "aaron",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0664",
    "owner": "aaron",
    "size": 0,
    "src": "/home/aaron/.ansible/tmp/ansible-tmp-1533367280.2476053-270780127291475/source",
    "state": "file",
    "uid": 1000
}

可以看出,localhost 本就有 “你好.txt” 默认不会被覆盖。重新执行第一条命令验证。

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls ~/*.*"
localhost | SUCCESS | rc=0 >>
/home/aaron/030303.mp4
/home/aaron/aaa.py
/home/aaron/dfasdfasdfad.py
/home/aaron/examples.desktop
/home/aaron/hello.py
/home/aaron/new.py
/home/aaron/playbook.retry
/home/aaron/playbook.yaml
/home/aaron/setting.py
/home/aaron/test.py
/home/aaron/vimrc.bak_20180719
/home/aaron/你好.txt

192.168.0.112 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
/home/aaron/你好.txt

192.168.0.111 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
/home/aaron/你好.txt

可以看出文件已经上传成功了。

使用 ansible 的模块帮助文档 ansible-doc

一个优秀的工具一定有着便捷的帮助文档,ansible 也不例外,前述操作,使用了 ansible 的模块有 ping,authorized_key,copy,shell等模块。 如果想知道这些模块的详细说明,只需要执行 ansible-doc 模块名即可。

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible-doc copy
> COPY    (/home/aaron/py37env/lib/python3.7/site-packages/ansible/modules/files/copy.py)

        The `copy' module copies a file from the local or remote machine to a
        location on the remote machine. Use the [fetch] module to copy files
        from remote locations to the local box. If you need variable
        interpolation in copied files, use the [template] module. For Windows
        targets, use the [win_copy] module instead.

  * note: This module has a corresponding action plugin.

OPTIONS (= is mandatory):

- attributes
        Attributes the file or directory should have. To get supported flags
        look at the man page for `chattr' on the target system. This string
        should contain the attributes in the same order as the one displayed by
        `lsattr'.
        (Aliases: attr)[Default: (null)]
        version_added: 2.3

- backup
        Create a backup file including the timestamp information so you can get
        the original file back if you somehow clobbered it incorrectly.
        [Default: no]
        type: bool
        version_added: 0.7

- checksum
        SHA1 checksum of the file being transferred. Used to validate that the
        copy of the file was successful.
        If this is not provided, ansible will use the local calculated checksum
        of the src file.
......

ansible 常用的模块及介绍如下:

.

1. ping: 主机连通性测试。

2. command: 在远程主机上执行命令,并将结果返回。

3. shell: 在远程主机上调用 shell 解释器运行命令,支持 shell 的各种功能。

4. copy: 将文件复制到远程主机,同时支持给定内容生成文件和修改权限等.

5. file: 设置文件的属性,比如创建文件、创建链接文件、删除文件等。

6. fetch: 从远程主机获取文件到本地。

7. cron: 管理远程主机的 crontab 计划任务。

8. yum: 用于软件的安装。

9. service: 用于服务程序的管理。

10. user: 用来管理远程主机的用户账号。

11. group: 用于在添加或删除组。

12. script: 用于将本机的脚本在被管理端的机器上运行.

13. setup: 主要用于收集信息,是通过调用facts组件来实现的.

Playbooks

前述操作对远程执行的命令都是相同的,那么可以同时对不同的主机执行不同的指令吗,当让可以,这就是 Plakbooks。

借用官方的描述,Playbooks 是 Ansible的配置,部署,编排的语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.

首先查看 ansible-playbook 的帮助命令

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible-playbook -h
Usage: ansible-playbook [options] playbook.yml [playbook2 ...]Runs Ansible playbooks, executing the defined tasks on the targeted hosts.Options:
 --ask-vault-pass      ask for vault password个
 -C, --check           don't make any changes; instead, try to predict some
                       of the changes that may occur
 -D, --diff            when changing (small) files and templates, show the
                       differences in those files; works great with --check
 -e EXTRA_VARS, --extra-vars=EXTRA_VARS
                       set additional variables as key=value or YAML/JSON, if
                       filename prepend with @
 --flush-cache         clear the fact cache for every host in inventory
 --force-handlers      run handlers even if a task fails
 -f FORKS, --forks=FORKS
                       specify number of parallel processes to use
                       (default=5)
 -h, --help            show this help message and exit
 -i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
......

发现,ansible-playbook 需要一个 plauybook.yml 的文件。

什么是 yml 文件

yml 文件是 yaml语法格式的文件,我们使用 YAML 是因为它像 XML 或 JSON 是一种利于人们读写的数据格式。此外在大多数变成语言中有使用 YAML 的库。 对于 Ansible, 每一个 YAML 文件都是从一个列表开始。 列表中的每一项都是一个键值对, 通常它们被称为一个 “哈希” 或 “字典”。 所以, 我们需要知道如何在 YAML 中编写列表和字典。 YAML 还有一个小的怪癖。 所有的 YAML 文件(无论和 Ansible 有没有关系)开始行都应该是 —-。 这是 YAML 格式的一部分, 表明一个文件的开始。 列表中的所有成员都开始于相同的缩进级别, 并且使用一个 “- “ 作为开头(一个横杠和一个空格):

代码语言:javascript复制
---
#一个美味水果的列表
 - Apple
 - Orange
 - Strawberry
 - Mango

一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格):

代码语言:javascript复制
---
# 一位职工的记录
name: Example Developer
job: Developer
skill: Elite

字典也可以使用缩进形式来表示, 如果你喜欢这样的话:

代码语言:javascript复制
---
# 一位职工的记录
{name: Example Developer, job: Developer, skill: Elite}

Ansible并不是太多的使用这种格式, 但是你可以通过以下格式来指定一个布尔值(true/fase):

代码语言:javascript复制
---
create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false

让我们把目前所学到的 YAML 例子组合在一起。 这些在 Ansible 中什么也干不了, 但这些格式将会给你感觉:

代码语言:javascript复制
---
# 一位职工记录
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
    - Apple
    - Orange
    - Strawberry
    - Mango
languages:
    ruby: Elite
    python: Elite
    dotnet: Lame

这就是你开始编写 Ansible playbooks 所需要知道的所有 YAML 语法。

现在 让我们写一个简单的 playbook

文件名 myplaybook.yml

代码语言:javascript复制
---
- hosts: master
  remote_user: aaron
  tasks:
      - name: read sys time
        shell: echo "`date  '%Y-%m-%d %T'`">time.txt
- hosts: slave 
  remote_user: aaron
  tasks:
      - name: list file
        shell: ls -ltr>list.txt

上述 yaml 文件分别定义了对两组主机执行不同的 task ,注意缩进格式。

执行 ansible-playbook myplaybook.yml 结果如下:

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible-playbook myplaybook.yml 

PLAY [master] **************************************************************************************

TASK [Gathering Facts] *****************************************************************************
ok: [localhost]
ok: [192.168.0.111]

TASK [read sys time] *******************************************************************************
changed: [localhost]
changed: [192.168.0.111]

PLAY [slave] ***************************************************************************************

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

TASK [list file] ***********************************************************************************
changed: [192.168.0.112]

PLAY RECAP *****************************************************************************************
192.168.0.111              : ok=2    changed=1    unreachable=0    failed=0   
192.168.0.112              : ok=2    changed=1    unreachable=0    failed=0   
localhost                  : ok=2    changed=1    unreachable=0    failed=0

说明3台主机上的任务已成功执行。

验证

代码语言:javascript复制
(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls -ltr *.txt"
localhost | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron  0 Jun 14 06:57 你好.txt
-rw-rw-r-- 1 aaron aaron 20 Aug  4 21:54 time.txt

192.168.0.111 | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron  0 Aug  4 00:21 你好.txt
-rw-rw-r-- 1 aaron aaron 20 Aug  4 06:54 time.txt

192.168.0.112 | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron   0 Aug  4 00:21 你好.txt
-rw-rw-r-- 1 aaron aaron 637 Aug  4 06:54 list.txt

当有许多主机许多任务要执行时,可以指定并发进程数

代码语言:javascript复制
ansible-playbook myplaybook.yml -f 10  # 表示由 10 个并发的进程来执行任务

上述仅为 ansible-playbook 的冰山一角,ansible-playbook 还可以实现 Handlers,当在发生改变时执行的相应的操作,最佳的应用场景是用来重启服务,或者触发系统重启操作。 配置的 yaml 文件支持 Ansible-Pull 进行拉取配置等。 详见 官方文档 http://www.ansible.com.cn/docs/playbooks_intro.html

END

0 人点赞