IT 自动化工具 Ansible 入门指南

Ansible 是一个非常简单的 IT 自动化引擎,可以完成诸如云端资源调配、配置管理、应用部署、服务协调等众多 IT 自动化任务。它不需要在受控端安装配置额外的 agent 软件,因此部署流程非常简单。
Ansible 的运行机制也并不复杂,它通过 SSH 协议向远程节点推送特定的“小程序”(Ansible modules)并运行,一旦运行完成则将其移除。
同时 Ansible 提供了一种非常简单易懂的语言(YAML)用于编写自动化代码。

一、简介

Ansible 通常会被描述为一个配置管理工具,类似于 ChefPuppetSalt 等。
通过配置管理工具,我们可以确保服务器主机处于某种期望的状态,比如指定的软件包已安装,配置文件中包含正确的值,运行着特定的服务等。
与其他配置管理工具一样,Ansible 也加入了自己的 DSL(领域专用语言)用来描述服务器的状态,即后面会介绍到的用于编写 Playbook 的 YAML 语言。

Ansible 也可以用于部署任务,比如通过源代码生成可执行程序或静态资源并发布到服务器,然后开启远程主机上的对应服务。类似的开源部署工具如 Fabric 等。

还有一种需求叫做流程编排,通常会涉及到多个远程服务器,用于确保各类型的任务以特定顺序执行。比如在开启 Web 服务器之前确保数据库服务处于已经运行的状态。
Ansible 从设计之初即关注多个服务器状态下任务的执行,它有一个非常简单的模块用于控制动作的顺序。

此外,Ansible 还提供众多的模块用来与常见的云服务进行交互,包括 Amazon EC2、Azure、Digital Ocean、Linode 以及任何支持 OpenStack API 的云端服务。

一个简单的 Ansible 运行实例如下图:


在三个服务器上运行 Playbook

二、Ansible 安装

绝大部分 Linux 发行版的软件镜像中都默认包含了 Ansible 的安装包, 可以直接通过对应的包管理器进行安装。如 Ubuntu 系统:
$ sudo apt-get install ansible

Ansible 是基于 Python 语言开发的,因此也可以通过 Python 的包管理器进行安装,命令如下:
$ pip install ansible

我用 VirtualBox 软件搭建了两台 Ubuntu 19.04 虚拟机,配置了内部网络(Internal)的联网方式。
server1 IP 地址为 192.168.1.101,用于安装 Ansible 环境。
server2 IP 地址为 192.168.1.102,作为远程主机进行测试。两者可以相互 ping 通。

SSH 的密钥认证

为了使得每次运行 Ansible 任务时,不需要重复输入远程主机的认证信息,这里先配置好 SSH 连接的无密码认证(即 RSA 密钥认证)。命令如下:

$ # 生成 SSH 密钥文件
$ ssh-keygen
$ # 复制公钥文件到远程主机(需要输入密码)
$ ssh-copy-id remoteuser@remoteserver

运行成功后,使用 $ ssh remoteuser@remoteserver 命令进行测试,如可以自动登录,则配置完成。

PS:被控制的远程主机不需要安装任何客户端软件,但是必须确保已安装 Python 且 sshd 服务处于运行状态。如两者未正确安装,可运行以下命令:

$ sudo apt-get install python
$ sudo apt-get install openssh-server
主机清单(Inventory)

Ansible 通过一个主机清单文件(hosts)存放被管理的服务器的列表。
创建 playbooks 目录作为存放 ansible 脚本和配置文件的项目文件夹,进入该目录并编辑如下 hosts 文件:

server2 ansible_ssh_host=192.168.1.102 ansible_ssh_user=skitar ansible_ssh_private_key_file=~/.ssh/id_rsa

通过 hosts 中定义的服务器别名和连接信息访问远程主机并执行 ping 模块:
$ ansible server2 -i hosts -m ping

输出内容如下:

server2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

如看到类似上面的输出则 Ansible 环境配置完成。

PS:Ansible 主机清单的配置文件默认为 /etc/ansible/hosts。如需使用其他位置的主机清单文件,可以通过 -i 选项手动指定,或者修改 ansible.cfg 配置文件的 inventory 项。

ansible.cfg

ansible.cfg 文件中包含了 Ansible 工具的一些默认配置,该文件通常位于以下位置:

  • 当前目录(./ansible.cfg)
  • Home 目录(~/.ansible.cfg)
  • /etc/ansible/ansible.cfg

在当前目录下创建 ansible.cfg 文件并输入以下内容:

[defaults]
inventory = hosts
remote_user = skitar
private_key_file = ~/.ssh/id_rsa
host_key_checking = False

由于部分默认选项已配置,此时的 hosts 文件则可以省略用户名和密钥文件等信息,简化为如下形式:

server2 ansible_ssh_host=192.168.1.102

使用 ansible 命令时也无需再通过 -i hosts 选项手动指定主机清单文件。即之前的 ping 模块可以这样调用:
$ ansible server2 -m ping

Ad-Hoc 命令

即通过命令行的形式直接调用 Ansible 模块。
Ansible 有着功能丰富的内置模块,可以通过 ansible-doc -l 命令显示所有的内置模块,通过 ansible-doc <module> 命令查看指定模块的介绍以及使用案例。

Ansible 内置的 command 模块可以用来在远程主机上执行 Linux 命令。如执行 uptime 命令:

$ ansible server2 -m command -a uptime
server2 | CHANGED | rc=0 >>
 17:45:12 up  5:13,  1 user,  load average: 0.12, 0.08, 0.02

其中 -m 用于指定调用的模块,-a 用于指定传递给该模块的选项,此处即某个具体的命令。
由于 command 模块很常用,它其实是不指定任何模块情况下的默认模块。所以上面的命令也可以使用如下形式:
$ ansible server2 -a uptime

当远程主机上执行的命令中包含空格时,需要用引号括起来,示例如下:

$ ansible server2 -a "tail /var/log/syslog"
server2 | CHANGED | rc=0 >>
Jul  8 18:18:18 server2 systemd[6250]: Reached target Paths.
Jul  8 18:18:18 server2 systemd[6250]: Listening on GnuPG cryptographic agent and passphrase cache (access for web browsers).
Jul  8 18:18:18 server2 systemd[6250]: Listening on D-Bus User Message Bus Socket.
Jul  8 18:18:18 server2 systemd[6250]: Reached target Sockets.
Jul  8 18:18:18 server2 systemd[6250]: Reached target Basic System.
Jul  8 18:18:18 server2 systemd[1]: Started User Manager for UID 1000.
Jul  8 18:18:18 server2 systemd[1]: Started Session 47 of user skitar.
Jul  8 18:18:18 server2 systemd[6250]: Reached target Default.
Jul  8 18:18:18 server2 systemd[6250]: Startup finished in 75ms.
Jul  8 18:18:19 server2 python3[6304]: ansible-command Invoked with _raw_params=tail /var/log/syslog warn=True _uses_shell=False stdin_add_newline=True strip_empty_ends=True argv=None chdir=None executable=None creates=None removes=None stdin=None

对于某些需要 root 权限才能执行的操作,则需要加上 --become --ask-become-pass 或者 -b -K 选项通过 sudo 执行。如使用 service 模块重启远程主机上的 nginx 服务:

$ ansible server2 -b -K -m service -a "name=nginx state=restarted"
BECOME password:
server2 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "name": "nginx",
    "state": "started",
    "status": {
        "ActiveEnterTimestamp": "Mon 2019-07-08 18:16:58 CST",
        "ActiveEnterTimestampMonotonic": "20685653757",
        "ActiveExitTimestamp": "Mon 2019-07-08 18:16:57 CST",
        "ActiveExitTimestampMonotonic": "20685035019",
        "ActiveState": "active",
...

其他常用的内置模块还有 apt、copy、user 等。

如通过 apt 模块管理远程主机上的软件包:

$ ansible server2 --b -K -m apt -a "name=nginx state=latest"
BECOME password:
 [WARNING]: Could not find aptitude. Using apt-get instead

server2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "cache_update_time": 1562598780,
    "cache_updated": false,
    "changed": false
}

通过 copy 模块复制本地文件到远程主机:

$ ansible server2 -m copy -a "src=ansible.cfg dest=/home/skitar/ansible.cfg owner=skitar mode=644"
server2 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "checksum": "2f4f9975ef1875adcc2a299d3962f70630f49965",
    "dest": "/home/skitar/ansible.cfg",
    "gid": 1001,
    "group": "skitar",
    "mode": "0644",
    "owner": "skitar",
    "path": "/home/skitar/ansible.cfg",
    "size": 109,
    "state": "file",
    "uid": 1000
}

通过 user 模块管理远程主机上的用户(需要先通过 openssl 命令生成密码,因为 user 模块的 password 参数只接受加密后的值):

$ echo ansible | openssl passwd -1 -stdin
$1$ZyNqkbXH$i.4R0EDQZV.zu8akyJAu10
$ ansible server2 -b -K -m user -a 'name=starky password="$1$ZyNqkbXH$i.4R0EDQZV.zu8akyJAu10" shell=/bin/bash'
BECOME password:
server2 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "append": false,
    "changed": true,
    "comment": "",
    "group": 1002,
    "home": "/home/starky",
    "move_home": false,
    "name": "starky",
    "password": "NOT_LOGGING_PASSWORD",
    "shell": "/bin/bash",
    "state": "present",
    "uid": 1001
}

三、Playbooks

Playbooks 即 Ansible 用于执行自动化配置的脚本文件。它使用非常简单的 YAML 语言描述期望达到的状态,YAML 之于 JSON 类似于 Markdown 之于 HTML 。

一个简单的用于配置 nginx 站点的 playbook 示例(web-notls.yml)如下:

- name: Configure webserver with nginx
  hosts: webservers
  become: True
  tasks:
    - name: install nginx
      apt: name=nginx update_cache=yes

    - name: copy nginx config file
      copy: src=files/nginx.conf dest=/etc/nginx/sites-available/default

    - name: enable configuration
      file: >
        dest=/etc/nginx/sites-enabled/default
        src=/etc/nginx/sites-available/default
        state=link

    - name: copy index.html
      template: src=templates/index.html.j2 dest=/var/www/html/index.html mode=0644

    - name: restart nginx
      service: name=nginx state=restarted

编辑 nginx 配置文件,即 playbook 中 copy 模块的 src 选项指定的文件(files/nginx.conf),内容如下:

server {
        listen 80 default_server;

        root /var/www/html;
        index index.html;

        server_name 192.168.1.102;

        location / {
                try_files $uri $uri/ =404;
        }
}

编辑 nginx 站点的主页文件,即 playbook 中 template 模块的src 选项指定的文件(templates/index.html.j2),内容如下:

<html>
  <head>
    <title>Welcome to ansible</title>
  </head>
  <body>
  <h1>nginx, configured by Ansible</h1>
  <p>If you see this, Ansible successfuly installed nginx.</p>
  <p>Current time is {{ now() }}</p>
  </body>
</html>

此处使用了 Jinjia2 模板引擎,所以可以通过 {{ now() }} 获取当前系统时间并替换到 HTML 文档中。

编辑 Inventory (主机清单)即hosts 文件,创建 webservers 主机组

[webservers]
server2 ansible_ssh_host=192.168.1.102

主机组中可以包含一个或多个远程主机,便于同时管理多个远程节点。

上述配置完成后,通过 ansible-playbook web-nolts.yml -K 命令运行 playbook,输出如下:

$ ansible-playbook web-notls.yml -K
BECOME password:

PLAY [Configure webserver with nginx] **********************************************************

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

TASK [install nginx] ***************************************************************************
 [WARNING]: Could not find aptitude. Using apt-get instead

ok: [server2]

TASK [copy nginx config file] ******************************************************************
changed: [server2]

TASK [enable configuration] ********************************************************************
ok: [server2]

TASK [copy index.html] *************************************************************************
changed: [server2]

TASK [restart nginx] ***************************************************************************
changed: [server2]

PLAY RECAP *************************************************************************************
server2                    : ok=6    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

注意 ansibe-playbook 命令的 -K 选项(即 --ask-become-pass),由于 playbook 中的部分任务需要 root 权限执行,加上 -K 选项后,执行 playbook 时会出现 BECOME password: 提示用于输入 sudo 密码。否则会报错。

playbook 执行成功后,使用 curl 192.168.1.102 命令访问 server2 上刚刚配置的 nginx 站点,输出如下:

$ curl 192.168.1.102
<html>
  <head>
    <title>Welcome to ansible</title>
  </head>
  <body>
  <h1>nginx, configured by Ansible</h1>
  <p>If you see this, Ansible successfuly installed nginx.</p>
  <p>Current time is 2019-07-09 00:28:46.484053</p>
  </body>
</html>

参考资料

Ansible: Up and Running, 2nd Edition

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容