Ansible 自动化部署

本文讲解运维自动化的发展与分类、Ansible 的架构与准备工作、inventory 主机清单、ad-hoc 临时命令、常用模块(command、shell、script、copy、stat、get_url、yum、cron、mount、service、user、file 等)、YAML 与 playbook、变量、template 模板以及 roles 角色等内容。

一、运维自动化概述

运维发展经历了三个阶段:

  1. 靠纯手工、重复地进行软件部署和运维。
  2. 通过编写脚本方便地进行软件部署和运维。
  3. 借助第三方工具高效、方便地进行软件部署和运维。

运维自动化就是把零碎的工作集中化,把复杂的工作简单有序化,把流程规范化,最大化地解放生产力,也就是解放运维人员。自动化针对的范围大致可分为安装自动化、部署自动化、监控自动化等。

常见运维自动化工具:

安装自动化 部署自动化 监控自动化
kickstart ansible Nagios
cobbler ControlTier Cacti
OpenQRM Func Zabbix
Spacewalk Puppet Zenoss Core

注:原文中的 “Catci” 应为 “Cacti”。

二、Ansible 架构与准备工作

架构特点

Ansible 基于 SSH 协议管理被管机器,无需在被管节点安装 Agent,管理端通过 SSH 连接并执行任务。

开始前准备

  1. 关闭防火墙和 SELinux。
  2. 绑定主机名。
  3. 绑定 hosts。

由于 Ansible 使用 SSH 协议,需要先在每台服务器之间设置好 SSH 等效性(密钥对登录)。

配置 SSH 密钥对登录

第一步:在管理机生成密钥对,全部回车即可:

ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
......

第二步:将公钥写入需要管理的服务器:

ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@3.3.3.9

安装 Ansible

yum -y install ansible

安装完成后查看配置目录:

ll /etc/ansible
总用量 24
-rw-r--r-- 1 root root 19179 1月  30 2018 ansible.cfg
-rw-r--r-- 1 root root  1016 1月  30 2018 hosts
drwxr-xr-x 2 root root     6 1月  30 2018 roles
文件/目录 作用
ansible.cfg Ansible 主配置文件
hosts 存放被管理机器列表(inventory)
roles 存放 Ansible 的角色(任务文件)

三、Inventory 主机清单

编辑 /etc/ansible/hosts,指定需要被管理的服务器,并使用组名进行分类:

[client]          # 指定服务器群组,下面的 IP 即为该群组的所有成员
3.3.3.9
3.3.3.10

[webserver]       # 群组可以有多个
3.3.3.11
3.3.3.12

使用 ansible 命令对指定组或所有主机执行 ping 测试:

ansible client -m ping     # client 表示只查看这个群组里的主机,all 表示所有
node2.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
node3.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

四、Ansible 常用模块

查看模块帮助:

ansible-doc -l          # 列出 Ansible 支持的模块
ansible-doc ping        # 查看 ping 模块帮助信息

1. command 模块

command 是 Ansible 的默认模块,支持所有远程权限范围内的命令,不支持管道。

ansible client -m command -a 'free -m'
node3.com | SUCCESS | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            976         613          68           4         294         162
Swap:          1999         225        1774

2. shell 模块

与 command 类似,但支持管道符号。

ansible client -m shell -a 'cat /etc/passwd|head -1'
node2.com | SUCCESS | rc=0 >>
root:x:0:0:root:/root:/bin/bash

3. script 模块

在被管理机器上执行管理机器上的脚本,相当于先 scp 再 sh。

ansible client -m script -a '/root/test.sh'
node3.com | SUCCESS => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to node3.com closed.\r\n",
    "stdout": "test\r\n",
    "stdout_lines": [
        "test"
    ]
}

4. copy 模块

从管理机器拷贝文件到被管理机器,类似 scp。

ansible client -m copy -a 'src=/root/test.sh dest=/root/ owner=root group=root mode=0755'
参数 说明
src 指定管理机器上的文件路径
dest 传过去后存放在被管理机器的目录
owner 传过去后文件所有者
group 传过去后文件所属组
mode 传过去后文件的权限

5. stat 模块

获取被管理机器上文件的状态信息(atime、ctime、mtime、md5、uid、gid 等)。

ansible client -m stat -a 'path=/etc/passwd'
参数 说明
path 指定要查看的文件路径

6. get_url 模块

让被管理机器下载指定 URL 内容到指定文件内。

ansible client -m get_url -a 'url=http://www.baidu.com dest=/index.html mode=0440 force=yes'
参数 说明
url 指定要下载的 URL
dest 指定下载到哪里
mode 指定下载后文件权限
force 是否强制覆盖

原文中对 force 的说明为“是否强行对齐代码”,语义不明,此处按模块通用含义修正为“是否强制覆盖”。

7. yum 模块

管理被管理机器上的 RPM 包。

ansible client -m yum -a 'name=nmap'
参数 说明
name 指定要安装的 RPM 包名称

8. cron 模块

修改被管理机的 crontab 任务。

ansible client -m cron -a "name='check dirs' hour='5,2' job='ls -alh > /dev/null'"
参数 说明
name 指定定时任务名称(加备注)
hour 指定定时任务周期
job 指定任务内容(minute、hour、day、month、weekday)

创建后在被管理机上查看:

crontab -l
#Ansible: check dirs
* 5,2 * * * ls -alh > /dev/null

9. mount 模块

实现被管理机的分区挂载(添加至 /etc/fstab 文件)。

ansible client -m mount -a 'name=/yum src=/dev/sdb1 fstype=ext4 opts=ro state=present'
参数 说明
name 指定挂载目录
src 指定挂载源
fstype 指定挂载源的文件系统类型
opts 指定挂载后的权限
state 指定状态,取值见下表

state 取值:

取值 说明
present 只修改 fstab 文件内容,不做挂载操作
absent 取消挂载,并将挂载目录删除,还会删除 fstab 文件中对应内容
unmounted 取消当前挂载的内容,而不修改 fstab 文件内容
mounted 如果指定的挂载点没有挂载,则挂载,且将会写入 fstab 文件

10. service 模块

管理被管理机器上的服务(启动、停止、重启等)。

ansible client -m service -a "name=nginx state=stopped"     # 停止 nginx
ansible client -m service -a "name=nginx state=started"     # 启动 nginx
ansible client -m service -a "name=nginx state=restarted"   # 重启 nginx
ansible client -m service -a "name=nginx state=reloaded"    # 重载 nginx
参数 说明
name 指定服务名
state 指定需要执行的操作

原文将 state=reloaded 注释为“查看 nginx 状态”,实际为重载配置,这里按模块真实含义修正。

11. user 模块

管理被管理机器上的用户。

ansible client -m user -a "name=ninmu shell=/bin/sh home=/home/munin group=8888 uid=8888 comment='user ninmu'"

创建后在 /etc/passwd 中格式如下:

ninmu:x:8888:1000:user ninmu:/home/munin:/bin/sh
参数 说明
name 指定用户名
shell 指定 shell 类型
home 指定用户家目录
group 指定用户所属组(前提是指定的组已经存在)
uid 指定用户 uid
comment 指定用户描述项
remove 删除用户时是否删除家目录(remove=yes)
state 指定状态,absent 表示删除用户

删除用户示例:

ansible client -m user -a 'name=ninmu state=absent remove=yes'

12. file 模块

管理被管理机器上的文件和目录(创建、删除等)。

创建目录:

ansible client -m file -a 'name=/data mode=644 state=directory'

创建普通文件:

ansible client -m file -a 'name=/data/test.txt mode=777 state=touch'

删除文件或目录:

ansible client -m file -a 'name=/data/abc state=absent'

创建软链接:

ansible client -m file -a 'name=/data/test.txt dest=/root/test state=link'
参数 说明
name 指定目录或文件名
mode 指定创建后文件或目录的权限
dest 指定目标路径
owner 指定所属用户
group 指定所属组
state 指定类型:directory、touch、absent、link

state 取值:

取值 说明
directory 如果目录不存在则创建该目录
touch 创建普通文件
absent 删除文件或目录
link 创建软链接

更多模块请查阅官方文档。

五、YAML 语法与 Playbook

YAML 文件是 playbook 使用的配置管理语言。

一定要注意缩进:playbook 中不同级别间要严格缩进,多一个或少一个空格都会导致脚本无法执行;缩进不能使用 Tab 键。

Ansible 基本目录结构

.
├── ansible.cfg        # ansible 主配置文件
├── hosts              # 存放被管理机器列表
└── roles              # 存放 ansible 的角色
    ├── files          # 存放要推送到被管理机器上的文件,调用该目录文件无需加路径
    ├── tasks          # 存放 yml 执行文件
    ├── templates      # 存放可变文件(内部包含变量)
    └── vars           # 存放定义变量的文件

YAML 变量格式

键值对(普通变量):

key: value
name: user1

冒号与 value 之间必须有一个空格。

列表:

name:
  - user1
  - user2
  - user3

- 与每个 value 之间必须有一个空格。

字典:

name: zhangsan
shell: /bin/bash
home: /home/abc

也可以写成一行:

{name: zhangsan, shell: /bin/bash, home: /home/abc}

六、变量的种类与使用

Ansible 的变量分为几种:

  1. 写入 vars 目录的变量(全局变量)。
  2. 使用 vars: 直接写入动作脚本的变量(局部变量)。
  3. 使用 with_items: 直接写入动作脚本的迭代变量。

1. vars 目录中的全局变量

写入 vars 目录内文件中的变量可理解为全局变量,任何动作脚本都可以调用,格式为 key: values:

vim /etc/ansible/vars/test.yml
user: test
ip: 3.3.3.3
dir: /etc/ansible

2. playbook 内 vars 定义的局部变量

直接定义在动作脚本内的变量为局部变量,仅在当前文件内有效。

vim test.yml
---
- hosts: client
  remote_user: root
  vars:                 # 定义变量
    user1: test1
    user2: test2
  tasks:
  - name: add user1
    user: name={{ user1 }}     # 调用变量 user1
  - name: add user2
    user: name={{ user2 }}     # 调用变量 user2

3. vars 目录全局变量实战

创建测试工作路径:

mkdir roles/test/{vars,templates,files,tasks}
cd roles/

创建变量文件,将所有需要的变量写入:

vim test/vars/main.yml
name: testuser
sh: /bin/sh
home: /home/abc
uid: 8888

创建动作文件(名称若不是 main.yml,执行时需要手动指定):

vim test/tasks/main.yml
- name: add server user
  user:
    name: "{{ name }}"     # 直接调用 vars 目录 main.yml 中的变量
    shell: "{{ sh }}"
    home: "{{ home }}"
    uid: "{{ uid }}"

在工作目录创建入口 playbook:

vim adduser.yml
---
- hosts: client
  remote_user: root
  roles:
  - test

执行 playbook:

ansible-playbook adduser.yml

完成后到被管理机检查:

cat /etc/passwd|tail -1
testuser:x:8888:8888::/home/abc:/bin/sh

目录结构关系:

.
├── adduser.yml
└── test
    ├── files
    ├── tasks
    │   └── main.yml
    ├── templates
    └── vars
        └── main.yml

4. with_items 迭代变量

with_items 定义的可迭代变量,调用时会自动从上至下依次使用所有值。

例 1:迭代简单列表

vim /etc/ansible/useradd.yml
---
- hosts: client
  remote_user: root
  tasks:
  - name: add several users
    user: name={{ item }} state=present groups=wheel
    with_items:
      - testuser1
      - testuser2

原文示例中 tasks: 关键字缺失,已按 playbook 规范补全。

例 2:with_items 中的元素还可以是 hash(字典):

vim useradd.yml
---
- hosts: client
  remote_user: root
  tasks:
  - name: add users
    user: name={{ item.name }} shell={{ item.sh }}
    with_items:
      - { name: 'test5', sh: '/bin/sh' }
      - { name: 'test6', sh: '/bin/nologin' }

简单实战练习

  1. 在被管理机器上批量添加用户。
  2. 在被管理机器上批量删除用户。
  3. 在被管理机器上批量安装 httpd 服务并启动。

对应脚本文件名参考:

cat add_user.yml
cat del_user.yml

YAML 语法可通过在线工具校验:http://www.yamllint.com/。

七、template 模板模块

template 模块类似于 copy 模块,但会自动判断文件是否存在:如果目标文件存在且内容一致则不拷贝;同时可以在拷贝过程中使用 vars 中设置的变量。

目录结构:

.
├── test
│   ├── files
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   │   └── test.j2
│   └── vars
│       └── main.yml
└── test.yml

定义变量文件 roles/test/vars/main.yml:

user: zhangsan
pass: 123

可变模板文件 roles/test/templates/test.j2(文件名随意,扩展名通常为 .j2,其中引用了两个变量):

username={{ user }}
password={{ pass }}

入口 playbook work_dir/test.yml:

- hosts: client
  remote_user: root
  roles:
    - test

动作文件 roles/test/tasks/main.yml:

- name: copy configfile to nodes
  template:
    src: test.j2            # 源文件
    dest: /tmp/test.conf    # 目标地址及目标文件名称

执行 playbook:

ansible-playbook work_dir/test.yml

查看结果:

ansible client -m shell -a 'cat /tmp/test.conf'
3.3.3.5 | SUCCESS | rc=0 >>
username=zhangsan
password=123

3.3.3.4 | SUCCESS | rc=0 >>
username=zhangsan
password=123

八、roles 角色实战练习

练习 1:使用 Ansible 批量安装 MariaDB

要求:

  1. 将数据目录指定为 /data/mysql。
  2. 将默认监听端口修改为 3307。
  3. 修改完成后启动 MariaDB。

参考目录结构:

.
├── ansible.cfg
├── hosts
├── roles
│   ├── del_mariadb
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   └── install_mariadb
│       ├── files
│       ├── install_mariadb.yml
│       ├── tasks
│       │   └── main.yml
│       ├── templates
│       │   └── my.cnf
│       └── vars
│           └── main.yml
└── work_dir
    ├── del_mariadb.yml
    └── install_mariadb.yml

配套素材:in_mariadb.tar.gz。

练习 2:批量部署二进制版本 MySQL

要求:先使用 MariaDB 角色批量卸载被管理机器上的 MariaDB,然后批量部署二进制版本的 MySQL,版本不限。

配套素材:in_mysql.tar.gz。

最后修改:2026 年 09 月 20 日
如果觉得我的文章对你有用,请随意赞赏