Ansible入门:打造你的首个自动化运维帝国
Ansible 简介
Ansible 是一种开源的 IT 自动化引擎,用于配置管理、应用部署、任务自动化等。它由 Michael DeHaan 于2012年推出,并在2015年被 Red Hat 收购。Ansible 以其简单性、无代理架构和强大的功能而受到广泛欢迎。主要应用场景有配置系统、软件部署、持续发布及不停服平滑滚动更新的高级任务编排。
Ansible 本身非常简单易用,同时注重安全和可靠性,以最小化变动为特色,使用 OpenSSH 实现数据传输 ( 如果有需要的话也可以使用其它传输模式或者 pull 模式 ),其语言设计非常利于人类阅读,即使是针对不刚接触 Ansible 的新手来讲亦是如此。
无论什么范围的环境,简单都是必须的,所以我们的设计尽可能满足各类型的繁忙人群:开发人员、系统管理员、发布工程师、IT 管理员等所有类型的人。同时, Ansible 适用于各种环境,小到几台多到成千上万台的企业实际环境都完全满足。
Ansible 不使用C/S架构管理节点,即没有 Agent 。 这样的架构使得 Ansible 不会存在如何升级远程 Agent 管理进程或者因为没有安装 Agent 而无法管理系统。 因为 OpenSSH 是非常流行的开源组件,安全问题也非常少 。 Ansible 的 去中心化 管理方式深受业内认可, 即它只依赖 OS 的 KEY 认证访问远程主机。 Ansible 可以便捷接入 Kerberos, LDAP 或者其它认证系统。
安装
- 安装 Ansible:可以通过包管理器安装,如在 Ubuntu 上使用 apt,在 CentOS 上使用 yum。也可以通过源代码编译安装或使用 Python 的包管理器 pip 安装。
# CentOS 系统安装命令
yum install ansible -y
# Ubuntu 系统安装命令
sudo apt install ansible
更多安装细节可参考: https://cn-ansibledoc.readthedocs.io/zh-cn/latest/installation_guide/intro_installation.html#ansible-on-rhel-centos-or-fedora
- 配置 SSH:确保你的机器上安装了 SSH 服务,并且配置了无密码登录,这对于 Ansible 来说是必要的。
配置主机清单(Inventory)
- Ansible 使用主机清单文件来定义和管理多台服务器。默认情况下,主机清单文件位于 /etc/ansible/hosts。
# 建立一个分组,名称为 syndic 后面可以通过这个分组来控制多台主机
[syndic]
uid-sync ansible_host=172.16.1.10 # uid-sync 给172.16.1.10 这台主机起一个别名,后面可以用过别名来控制
[minions]
uid-m1 ansible_hosts=172.16.1.12
uid-m2 ansible_hosts=172.16.1.13
学习常用模块
ping 模块
- 用于检查目标主机是否可达,通常用于测试连接
- 示例
ansible all -m ping # inventory 文件中所有的主机来执行ping命令,验证主机的连通性
ansible syndic -m ping # syndic 组中所有的主机来执行ping命令
ansible uid-m1 -m ping # 别名为uid-m1 即172.16.1.12 这台主机来执行ping 命令
command 模块
- 用于在目标主机上执行命令。command 模块不通过 shell 执行命令,因此不会使用 shell 特性(如管道或重定向)。
- 示例
ansible syndic -m command -a "ls /tmp" # 在 syndic 这个组内所有的主机执行命令,其中 -m 表示选择
# 的模块名为 command, -a 表示参数,这里的参数是 " ls /tmp"
# 查看 /tmp 目录下的内容
shell 模块
- 类似于 command 模块,但 shell 模块允许使用 shell 特性,如管道、重定向和变量。
- 示例
# 将'hello' 写入 /tmp/test.txt 文件中
[root@master ~]# ansible all -m shell -u zhany --extra-vars "ansible_ssh_pass=1" -a 'echo 'hello' | tee /tmp/test.txt'
uid-sync | CHANGED | rc=0 >>
hello
# 查看文件内容
[root@master ~]# ansible syndic -m command -a 'cat /tmp/test.txt'
uid-sync | CHANGED | rc=0 >>
hello
copy 模块
- 用于将本地文件复制到远程主机上。
- 示例
# 将本机的家目录下data.zip 文件拷贝到目标名为syndic 组下主机/opt 目录下
[root@master ~]# ansible syndic -m copy -a 'src=~/data.zip dest=/opt/'
uid-sync | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "b3f2e3db1802c5906f1eee024c3d039589aaf386",
"dest": "/opt/data.zip",
"gid": 0,
"group": "root",
"md5sum": "a932ada4ba78b2450a38b3eacf34beb4",
"mode": "0644",
"owner": "root",
"secontext": "system_u:object_r:usr_t:s0",
"size": 61098159,
"src": "/root/.ansible/tmp/ansible-tmp-1734103712.2-68102-155567919271246/source",
"state": "file",
"uid": 0
}
# 查看 目标主机下 /opt 目录下的文件
[root@master ~]# ansible syndic -m command -a 'ls -al /opt/'
uid-sync | CHANGED | rc=0 >>
total 59668
drwxr-xr-x. 3 root root 37 Dec 13 23:25 .
dr-xr-xr-x. 17 root root 224 Dec 12 14:40 ..
-rw-r--r--. 1 root root 61098159 Dec 13 23:25 data.zip
drwxr-xr-x. 2 root root 204 Dec 12 15:50 package
file 模块
- 用于在远程主机上创建、删除、修改和查看文件属性。这个模块提供了多种参数来控制文件操作,包括文件路径、权限、所有者和组等。
- 示例
# 将目标主机上的/tmp/test.txt 文件的用户和组修改为root, 权限修改为644
ansible syndic -m file -a 'path=/tmp/test.txt state=file owner=root group=root mode=0644'
template 模块
# nginx.conf.j2 的 Jinja2 模板文件
server {
listen {{ port }};
server_name {{ server_name }};
location / {
proxy_pass http://{{ backend_server }};
}
}
可以使用以下 Ansible playbook 来渲染并部署这个模板:
---
- name: Deploy Nginx configuration using template
hosts: webservers
vars:
port: 80
server_name: example.com
backend_server: 192.168.1.100
tasks:
- name: Render and copy the Nginx configuration file
template:
src: /path/to/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
yum / apt 模块
- 用于管理包的安装、卸载和更新。yum 用于基于 RedHat 的系统,apt 用于基于 Debian 的系统。
- 示例
# 在 uid-sync 这台机器上安装 htop 工具,对于ubuntu 或 debian 系统只需要将 yum 换成 apt即可
[root@master ~]# ansible uid-sync -m yum -u root --extra-vars "ansible_ssh_pass=1" -a 'name=htop state=present'
uid-sync | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"htop"
]
},
"msg": "warning: /var/cache/yum/x86_64/7/epel/packages/htop-2.2.0-3.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 352G key 0x352C64E5:\n Userid : \"Fedora EPEL (7) <epel@fedoraproject.org>\"\n Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f ae: epel-release-7-11.noarch (@extras)\n From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7\n",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * epel: fedora-a extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package hill be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n======================================================\n Package Arch Version Repository Size\n======================================================\nInstalling:\n htop x86_64 2.2.0-3.el7 epel 103 k\n\nTransaction Summary\=======================================================\nInstall 1 Package\n\nTotal download size: 103 k\nInstalled size: 218 k\nlic key for htop-2.2.0-3.el7.x86_64.rpm is not installed\nRetrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : htop-2.2.0-3.el7.x86_64 fying : htop-2.2.0-3.el7.x86_64 1/1 \n\nInstalled:\n htop.x86_64 0:2.2.0-3.el7 \n\nComplete!\n"
]
}
service 模块
- service 模块用于管理远程主机上的系统服务(如启动、停止、重启等)。它允许你在 Playbook 中控制服务的状态,如启动、停止、重启、重载和启用或禁用服务。service 模块通过调用操作系统本身的服务管理器(如 systemd、init 或 service 命令)来管理服务。
- 基本语法
- name: Manage a service
ansible.builtin.service:
name: <service_name>
state: <state>
enabled: <enabled>
daemon_reload: <daemon_reload>
user: <user>
group: <group>
- 参数详解
name (必需)
定义要管理的服务的名称。例如,httpd、nginx、mysql 等。这个名称通常与服务的配置文件名称或进程名称相对应。
state (必需)
定义服务的目标状态。state 参数控制服务的启动、停止、重启等状态。常见的状态包括:
started:确保服务正在运行。如果服务没有运行,Ansible 会启动它。
stopped:确保服务已经停止。如果服务正在运行,Ansible 会停止它。
restarted:确保服务重新启动,即先停止再启动服务。
reloaded:重新加载服务的配置文件(适用于支持此操作的服务)。
present:通常与 enabled 配合使用,确保服务已启用。
absent:确保服务不存在(适用于一些服务管理工具)
user 模块
- 用于管理远程主机上的系统用户。你可以使用该模块来创建、修改或删除用户,设置用户的密码、权限、组、主目录等。user 模块是 Ansible 中管理用户帐户和权限的核心模块之一,它支持多种操作,如创建用户、设置密码、添加到组等。
- 基本语法
- name: Manage user
ansible.builtin.user:
name: <username> # 用户名,必填
state: <state> # 可取值 present 用于确保用户存在,absent 确保用户不存在
password: <password>
group: <group>
groups: <groups>
append: <append>
shell: <shell>
home: <home_directory>
create_home: <create_home>
update_password: <update_password>
expire: <expire>
uid: <uid>
comment: <comment>
remove: <remove>
- 示例
# 创建一个名为zhany的用户,并设置其密码,主目录
- name: Ensure user johndoe exists
ansible.builtin.user:
name: zhany
state: present
password: "$6$rounds=656000$yRgQYdVwFSJq3Z9X$F1yIhDOpJ6oRzE7jrLZBcsu7tx.jBZn1ZhHGRG7c3WvQhVJ4Pszwn1E2rMm2gUqeLvDMIJ5n0HRR6B/"
shell: /bin/bash
home: /home/zhany
create_home: yes
groups: wheel, developers
append: yes
group 模块
- 管理远程主机上的用户组。你可以使用该模块来创建、删除或修改用户组,设置组的成员或其他相关属性。该模块的功能与用户组的管理紧密相关,是管理员管理系统中用户组的常用工具。
- 基本语法
- name: Manage group
ansible.builtin.group:
name: <group_name> # 管理用户组的名称,必填
state: <state> # 设置目标用户组的状态,present 确保用户组存在,absent 确保用户组不存在
gid: <gid> # 设置用户组GID,可选
system: <system> # 如果为yes, 则该用户组为系统组,系统组通常用于某些系统用户的管理。系统组的 GID 通常小于 1000
members: <members> # 设置要添加到该组的成员。你可以指定一个或多个用户名,多个用户应以逗号分隔。如果该组已经存在,该参数会将指定的用户添加到组中
append: <append> # 如果为 yes,则在将用户添加到组时,不会删除用户已属于的其他组。默认值为 no,即会替换用户的组成员
- 示例
- name: Ensure developers group exists
ansible.builtin.group:
name: developers
state: present
gid: 1001
wait_for 模块
- 模块是一个非常实用的模块,用于等待某个条件满足或者某个状态变为可用。它可以用于等待网络服务可用、端口开放、文件存在、文件内容变化等操作。常用于自动化运维和部署过程中,确保某些资源在执行后续任务之前处于预期状态。
- 示例
# 等待 192.168.1.10 主机上的8080 端口可用
- name: Wait for port to be open
ansible.builtin.wait_for:
host: "192.168.1.10"
port: 8080
stat 模块
- 模块用于获取远程主机上文件或目录的状态信息。它提供有关文件或目录的详细信息,如权限、大小、修改时间、创建时间等。这个模块通常用于检查文件或目录的存在性、权限设置等信息,并根据这些信息采取后续操作。
- 示例
[root@master ~]# ansible syndic -m stat -a 'path=/tmp/data.zip'
uid-sync | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"stat": {
"atime": 1733991168.8676677,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 119336,
"charset": "binary",
"checksum": "b3f2e3db1802c5906f1eee024c3d039589aaf386",
"ctime": 1733991170.2856774,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 34044423,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "application/zip",
"mode": "0644",
"mtime": 1733991170.2856774,
"nlink": 1,
"path": "/tmp/data.zip",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 61098159,
"uid": 0,
"version": "39966759",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
cron 模块
- 用于管理定时任务(Cron Jobs)
- 基本语法
- name: Manage cron job
ansible.builtin.cron:
name: <job_name> # 用于标识 cron 作业的名称。
minute: <minute> # 指定任务执行的分钟。
hour: <hour> # 指定任务执行的小时。
day: <day> # 指定任务执行的日期(1-31)
month: <month> # 指定任务执行的月份(1-12)
weekday: <weekday> # 指定任务执行的星期几(0-6,0 表示星期天)
job: <command> # 你要执行的命令或脚本
state: <state> # 定义任务的状态, present 确保任务存在, absent 确保任务被删除
user: <user> # 指定哪个用户的 cron 表上添加或删除任务
special_time: <special_time> # 用于指定常见的特殊时间字符串
validate: <validate> 指定命令是否需要验证执行的命令
- 示例
# 每小时执行一次备份脚本
- name: Ensure backup cron job is present
ansible.builtin.cron:
name: "Backup cron job"
minute: "0"
hour: "2"
job: "/usr/bin/python3 /home/user/scripts/backup.py"
state: present
user: "root"
set_fact 模块
- set_fact模块是一个非常有用的模块,它允许你在任务中设置自定义的变量。这些变量可以在后续任务中使用,或者根据计算结果动态地生成。set_fact模块可以用来临时存储数据,这些数据在当前playbook中是有效的,直到playbook的执行结束。
- 基本用法
# 设置一个名为my_var的变量,值为"Hello, World!",可以在后续的任务中引用这个变量。
- name: Set a fact
ansible.builtin.set_fact:
my_var: "Hello, World!"
Ansible Playbook
Ansible Playbook 是 Ansible 中的核心组件,用于自动化管理和配置系统。Playbook 是一个由多个 Play 组成的 YAML 格式的文件,每个 Play 负责在一组主机上执行一组任务。Playbook 使得 Ansible 能够处理复杂的任务,并能够组织成清晰、可维护的自动化脚本。
Playbook 结构
一个基本的 Playbook 由以下几个部分组成:
- Play: 一个 Play 定义了一组任务,这些任务将在特定的主机上运行。
- Tasks: 每个 Play 包含多个任务,任务定义了将要执行的具体操作。
- Handlers: 处理程序(Handlers)是响应任务变化的特殊任务,通常用于重启服务等操作。
- Variables: 变量可以在 Playbook 中定义,并在任务中使用,用来提高灵活性和可重用性。
- Conditionals: 条件语句允许在任务执行前判断是否满足条件,来决定是否执行某个任务。
- Loops: 循环语句可以帮助你重复执行相同任务,处理列表或字典等数据结构。
- Includes/Imports: 用于组织和重用 Playbook,避免冗余代码。
1. 基本结构
一个简单的 Playbook 包含以下基本元素:
---
- name: Example playbook
hosts: all # 指定主机
become: true # 使用 sudo 权限执行任务
tasks:
- name: Install a package
ansible.builtin.yum:
name: httpd
state: present
解释:
- name: Playbook 或任务的名称,便于描述和调试。
- hosts: 指定 Playbook 要操作的主机或主机组。
- become: 是否使用 sudo 或其他权限提升方法执行任务,通常用于需要管理员权限的任务。
- tasks: 一个任务列表,每个任务指定了要在主机上执行的操作。
2. Playbook 的高级结构
---
- name: Install and configure Apache
hosts: webservers # 指定目标主机组
become: true
vars: # 定义变量
httpd_package: httpd
httpd_service: httpd
tasks:
- name: Install HTTPD package
ansible.builtin.yum:
name: "{{ httpd_package }}"
state: present
- name: Ensure HTTPD service is running
ansible.builtin.service:
name: "{{ httpd_service }}"
state: started
handlers: # 处理程序
- name: Restart HTTPD
ansible.builtin.service:
name: "{{ httpd_service }}"
state: restarted
解释:
- vars: 用于定义变量,可以在 Playbook 中随处引用。
- handlers: 处理程序是响应任务变化的任务,通常用于在服务配置更改时重启服务等。
- name: 每个任务、处理程序或 play 都有一个名称,用于描述其功能。
3. Playbook 中的常见元素
1.Hosts
hosts 关键字指定 Playbook 要作用的目标主机。可以使用以下几种方式:
- hosts: all: 作用于所有主机。
- hosts: webservers: 作用于 webservers 组中的所有主机(如果在 inventory 中定义了该组)。
- hosts: localhost: 只作用于本地主机。
2.Variables
变量是 Playbook 中灵活性的重要来源,可以通过 vars 部分定义变量,或者在命令行、主机文件、环境变量中传递。
vars:
user_name: "admin"
user_password: "password123"
在任务中引用变量:
- name: Create user
ansible.builtin.user:
name: "{{ user_name }}"
password: "{{ user_password }}"
3.Tasks
任务是 Playbook 中的核心部分。每个任务定义了要执行的操作。任务通常使用模块来执行操作,模块是 Ansible 的基本功能单元。
tasks:
- name: Install package
ansible.builtin.yum:
name: httpd
state: present
任务的结构:
- name: 描述任务的目的。
- 模块名称(如 ansible.builtin.yum): 执行的操作。
- args: 该模块需要的参数(例如 name、state、dest 等)。
4.Conditionals (条件语句)
可以使用 when 语句来决定是否执行任务。
- name: Install HTTPD only if not already installed
ansible.builtin.yum:
name: httpd
state: present
when: ansible_facts.packages['httpd'] is not defined
when 用于指定任务的条件,只有在满足条件时,任务才会被执行。
5.Loops (循环语句)
loop 用于重复执行任务。例如,你可以通过循环来安装多个软件包:
- name: Install multiple packages
ansible.builtin.yum:
name: "{{ item }}"
state: present
loop:
- httpd
- git
- vim
6.Includes / Imports
- include 和 import 用于将其他 Playbook 文件或任务包含到当前 Playbook 中。这可以帮助你组织 Playbook,避免冗余代码。
- name: Include other tasks
include_tasks: install_software.yml
import 用于引入 Playbook 文件,执行时会解析和加载整个文件。
4. Playbook 执行流程
- Playbook 解析: Ansible 会首先解析 Playbook 文件,读取每个 Play 中的主机、任务、变量等。
- 任务执行: Ansible 按照定义的顺序执行任务,任务执行顺序从上到下。任务的执行是逐个主机进行的,确保每个主机都按顺序执行任务。
- 处理程序: 如果某些任务发生了改变(例如安装了新软件包),会触发相应的处理程序(如重启服务)。
- 报告输出: Ansible 会在执行过程中输出详细的日志和执行状态,帮助用户调试和确认操作结果。
5. Playbook 高级功能
1.Error Handling (错误处理)
使用 block、rescue 和 always 可以处理任务失败时的情形:
- name: Ensure service is running
block:
- name: Start service
ansible.builtin.service:
name: nginx
state: started
rescue:
- name: Restart service if failed
ansible.builtin.service:
name: nginx
state: restarted
always:
- name: Log the result
ansible.builtin.debug:
msg: "Service task finished."
2.Tags
通过 tags 关键字,可以为任务添加标签,执行时可以指定要运行的标签,来选择执行某些任务。
- name: Install httpd
ansible.builtin.yum:
name: httpd
state: present
tags:
- install
运行时可以使用 --tags 参数来只执行带有特定标签的任务:
ansible-playbook playbook.yml --tags install
3.Include and Import Playbooks
可以在一个 Playbook 中包含其他 Playbook 文件,便于模块化和复用配置。
- name: Include another playbook
import_playbook: other_playbook.yml
6. Playbook 示例
---
- name: Configure Web Server
hosts: webservers
become: true
vars:
httpd_package: httpd
tasks:
- name: Install HTTPD package
ansible.builtin.yum:
name: "{{ httpd_package }}"
state: present
- name: Ensure HTTPD service is running
ansible.builtin.service:
name: "{{ httpd_package }}"
state: started
handlers:
- name: Restart HTTPD
ansible.builtin.service:
name: "{{ httpd_package }}"
state: restarted
这个 Playbook 会在 webservers 组的主机上安装并启动 HTTPD 服务