mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5
3246 字
9 分钟
ansible学习笔记
2026-07-06

1-关于ansible#

介绍#

ansible是一款开源的it自动化引擎,你可以把它理解成一个统一的指挥棒,用来管理成百上千台服务器。它的核心目标就是简单和易用,旨在消除重复性工作,简化复杂的工作流程

须知#

我会尽可能的记录学习到的功能并添加一些简单案例,不然没有案例我为什么不去看官方文档 骗你的官方文档也有案例

本文所有内容运行在Centos7-2009版本

2-安装部署#

控制节点#

输入以下指令即可安装,这是我在centos的安装,如果涉及其他系统,可以查看官方文档并使用相应的包管理器

sudo yum install epel-release -y
sudo yum install ansible -y

被管理节点#

不需要任何额外软件

配置ssh#

ansible使用ssh连接对应的主机,配置ssh连接免密让我们方便些

ssh-keygen
ssh-copy-id [主机ip]

3-定义主机清单#

增加主机#

Ansible需要知道自己管理的机器有哪些,默认的主机目录文件路径在**/etc/ansible/hosts**,可以直接修改,

例如

127.0.0.1
server.text.com

这就是一个简单的hosts文件案例,里面包含了一个ip地址和一个域名

增加主机组#

可以在使用方括号命名一个主机组并在下面写入主机

[web]
127.0.0.1
server.text.com

这样执行的时候就可以直接使用主机组的名称对多个主机执行指令

ansible会默认为你创建两个父组

all(清单里出现的所有主机、所有分组,在底层都会自动成为 all 组的子成员) ungrouped(清单中没有任何分组的主机)

子父组#

在主机名后写入后缀,即可定义一个父组,支持多层嵌套

[web]
127.0.0.1
server.text.com
[db]
127.0.0.2
server.text2.com
[dev:children]
web
db

需要注意的是,只要定义了,ansible就会默认其中的是子组名称,所以不能往其中写主机地址

参数#

可以在主机清单中添加参数,更多的参数具体可以参考官方文档

例如

127.0.0.1 ansible_ssh_user='root' ansible_ssh_pass='000000' ansible_port="2222"

这条主机定义还定义了几个参数,分别是 ansible_ssh_user(连接到主机时使用的用户名) ansible_ssh_pass(用于对主机进行身份验证的密码) ansible_port(ssh连接的端口号)

变量#

可以在主机清单中定义自定义变量

192.168.1.10 max_connections=100 http_port=80

这样在后续对该主机进行操作时,都可以使用 {{max_connections}} 和 {{http_port}} 来使用其中的数据

继承#

对于父组,可以使用后缀vars来继承变量和参数,并且可以单独对某一个主机定义变量或参数

[web]
127.0.0.1 ansible_port=2222 ansible_ssh_user='deploy' #单独定义
server.text.com
[db]
127.0.0.2
server.text2.com
[dev:children]
web
db
[dev:vars]
ansible_port=22 #组继承参数
ansible_user='root'
ansible_ssh_user='root' #组继承变量
ansible_ssh_pass='666666'

这样做会让所有在dev这个组中的主机继承其中的变量和参数,而我们单独定义的主机 127.0.0.1 则会保持自己单独定义的部分,局部特例永远优先于通用规则

别名#

在主机清单中,可以为主机定义别名

[web]
web1 ansible_host=127.0.0.1
web2 ansible_host=server.text.com
[db]
db-a ansible_host=127.0.0.2
db-b ansible_host=server.text2.com
[dev:children]
web[1:2] #主机范围[1:2]
db[a-b] #主机范围[a-f]

添加别名后,可以直接输入对于的别名进行使用,还可以使用主机范围,如上面的案例所示,web[1-2]等价于web1与web2,db[a-b]等价于db-a与db-f

还支持自定义步长和数字填充,可以在文档中详细参考,这里不再赘述

别名与变量参数等功能一起使用,能极大方便管理,例如我们可以将同一台机器,定义不同的别名、连接端口或是变量

ad hoc命令#

关于该命令#

ad hoc命令一般使用在那些很少重复或是需要快速执行的任务

ansible <主机模式> -i <清单文件> -m <模块名> -a "<模块参数>" [选项]

下面给出一些常用选项,可以在文档中找到更加详细的选项

  • <主机模式>: 在其中输入你想要运行的组或主机
  • -i:指定清单文件(你可以创建一个ini文件来定义主机清单并在此使用,否则ansible会使用/etc/ansible/hosts处的主机清单)
  • -m:指定要使用的模块(默认 command)
  • -a:传递给模块的参数
  • -f: 指定要使用的并行进程数(用于重复执行)

模块#

ansible命令的关键在于调用对应的模块来干对应的事,对于模块详情可以查询官方文档,记得善用ctrl+f,这里同样只介绍部分简单的模块

shell#

ansible dev -m shell -a 'hostname' -o

上面这条指令用于获取对应主机的主机名,下面来详细解释

  • ansible:这是主命令,告诉系统我要使用即时模式。
  • dev:目标主机/主机组。这里调用的就是之前在 /etc/ansible/hosts 里配置的父分组。Ansible 会自动找到里面的子分组
  • -m shell:-m 代表 module(模块)。这里指定使用 shell 模块。
  • -a ‘hostname’:-a 代表 arguments(参数)。这里输入你想让远程机器执行的真实 Linux 命令。

copy#

ansible webservers -m copy -a "src=/root/project/nginx.conf dest=/etc/nginx/nginx.conf owner=root group=root mode=0644" -o
  • src=/root/project/nginx.conf:Source(源路径)指控制机本地的配置文件路径
  • dest=/etc/nginx/nginx.conf:Destination(目标路径)指远程服务器上文件要保存的绝对路径
  • owner=root 和 group=root:文件传过去之后,自动把远程机上该文件的所有者和所属组修改为 root
  • mode=0644:修改文件权限。0644 代表 root 用户可读写(rw-),其他用户和组只能读取(r—)

yum#

ansible dev -m yum -a "name=httpd state=present" -o

这条指令会在主机上安装apache,name值指定软件名,state值指定要进行什么操作

  • state=present:安装软件。如果机器上没装,就下载安装,如果已经装了,就直接跳过(返回绿色 SUCCESS)
  • state=latest:确保是最新版本。如果没装就安装最新版;如果装了但有新版本,它会默默帮你在远程机上运行 yum update 升级到最新
  • state=absent:批量卸载/删除软件。相当于远程运行 yum remove 如果机器上本来就没装,它也会直接跳过

service#

ansible dev -m service -a "name=httpd state=started enabled=yes" -o

这条指令指定了httpd服务为启动状态并开启了开机自启,service有三个参数

name:对其进行操作的服务名称 state:需要服务改变成什么状态 enabled:是否对服务启动开机自启

playbooks#

这是ansible的核心功能,playbooks相当于一份自定义蓝图,告诉主机该怎么做,编写过程类似与jenkins和github action那样的自动任务

需要注意的是playbooks使用YAML格式编写,并且执行顺序是由上到下

关于YAML#

yaml使用缩进表示层级关系,缩进的空格数不重要,只要相同层级的元素左对齐即可,冒号后面要加空格 在ansible中几乎每个YAML文件都以列表开始,列表中的每个项目都是一组键/值对

这是关于ansible的文章,有关它的详细语法不会赘述

简单使用playbooks#

接下来,我们来尝试编写一个简单的playbooks,我们来新建一个yaml文件

---
- hosts: web #表示执行此脚本的对象为[web]主机组
remote_user: root #表示使用root用户执行此脚本
tasks: #下方定义了要执行的动作
- name: Install httpd #标注执行的操作,注意一个name里只能包含一个模块调用
yum: name=httpd state=latest #调用yum模块下载名称为httpd的包的latest版本

干的事情很简单,就是安装一个Apache,我们来一条条拆解看他都用了哪些东西

  • hosts:用于指定运行此脚本的对象
  • remote_user:用来指定运行此脚本的用户
  • tasks:列表下定义了要执行的任务,可以使用的模块与ad hoc命令一样
  • name:用来给人类看的,标注执行的操作,执行时会输出正在执行的操作name,但要注意一个name里只能包含一个模块调用

所以本质上,playbooks就是这样一个个关键字和模块构筑出一个完整的任务,所有有关的关键词依然可以查阅官方文档,下面来按照不同的区块和功能来简单介绍一些其他功能

变量#

简单变量#

在playbooks中也可以定义变量,相关的文档

可以在playbooks中使用 vars 关键字来定义变量区块,并在其中定义变量

使用变量用两个大括号包起来的变量名即可

---
- hosts: web
vars:
my_name: "shoulong" #在这里定义变量(名字叫 my_name,值叫 shoulong)
tasks:
- name: 把变量写入远程文件
copy:
content: "Hello, my name is {{ my_name }}!" #在这里用{{ }}使用变量
dest: /tmp/name.txt

需要注意的是,变量名只能包含字母数字和下划线,且不能使用py与playbooks的关键词

列表变量#

还可以使用yaml列表定义有多个值的变量

var:
user_list:
- user1
- user2
- user3

使用确定元素即可,例如{{user_list[0]}}的值为”user1”

字典变量#

还可以定义具有键值的变量

var:
user_list:
- user1: tom
- user2: jreey
- user3: leo

user_list{{user1}}的值为”tom”

循环#

简单循环#

playbooks中可以使用循环,可以避免很多重复的任务

---
- name: 批量创建业务目录
file:
path: "{{ item }}" #以此将下方的loop中的内容送入其中
state: directory
loop: #开始排队
- /data/app
- /data/logs
- /data/configs

实际运行中,ansible会自动把loop列表中的内容与{{item}}相匹配,大大方方写

字典列表循环#

循环自然也有稍微复杂的用法

---
- name: 批量创建不同权限的用户
ansible.builtin.user:
name: "{{ item.uname }}"
group: "{{ item.ugroup }}"
state: present
loop:
- { uname: 'tom', ugroup: 'developer' }
- { uname: 'jerry', ugroup: 'tester' }
- { uname: 'shoulong', ugroup: 'admin' }

运行时,loop会找到相应的键值一一对应填入其中

条件#

可以在playbooks中使用when来进行条件判断,更好的控制任务的运行

- name: 仅在centos系统上安装apache
yum:
name: httpd
state: present
when: ansible_distribution == "CentOS" #如果远程机系统确实是CentOS才执行这个任务

when语句会在执行时对设置的语句进行判断,若条件通过则执行对应任务;when语句本质上就是py代码,所以你能想到的逻辑运算符、in关键字等都能使用

触发器#

在playbooks中使用handlers以使用触发器,触发器的工作旨在指定的任务执行状态为 changed 时,执行计划好的代码,这在一些修改配置重启服务的场景很好用

---
- hosts: webservers
become: yes
tasks:
- name: 步骤 1:修改测试文件的内容
copy:
content: "配置文件内容已被修改"
dest: /tmp/test_config.txt #文件内容发生变化
notify: click_me_to_run
handlers:
- name: click_me_to_run #名字必须和notify完全一致
debug:
msg: "检测到文件被改动了Handler执行"

触发器在这里的工作是,当name:click_me_to_run对应的notify的任务状态为change时,输出信息 “检测到文件被改动了Handler执行”

运行#

运行playbooks很简单

ansible-playbook <你的playbook文件.yml>

role#

role就像是把playbooks中的一个个任务打包成一个”积木包”,编写好后可以随时拿出来在其他地方复用,还可以针对不同的任务创建不同的变量以适应需求

文件结构#

下面列出一个role的文件结构

roles/
└── httpd/ # Role 的名字叫 httpd
├── defaults/ # 其中定义了默认变量 —— 优先级最低,最容易被覆盖
├── vars/ # 其中定义了强变量 —— 优先级高,不容易被覆盖
├── tasks/ # 核心:要做的每一步动作
├── handlers/ # 触发器
├── templates/ # 模板文件:里面有 {{变量}},会动态生成真实文件
├── files/ # 普通文件:直接拷贝,不做变量替换
└── meta/ # 元信息:作者、依赖关系等(可选)

简单示例#

下面拿出上篇文章中安装http服务的案例,用role实现,结合之前的知识很容易看懂

defaults/main.yml

httpd_port: 8080
student_name: "张三"
student_id: "20240001"

tasks/main.yml

- name: 安装 httpd 软件包
yum: name=httpd state=present
- name: 复制配置文件模板
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: 复制首页模板
template: src=index.html.j2 dest=/var/www/html/index.html
- name: 启动并开机自启
service: name=httpd state=started enabled=yes

handlers/main.yml

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

templates/httpd.conf.j2 默认配置,无需理解

# 全局环境
ServerRoot "/etc/httpd"
Listen {{ httpd_port }}
User apache
Group apache
ServerAdmin root@localhost
ServerName localhost:{{ httpd_port }}
# 加载 MPM 模块(通过主配置文件加载,不依赖 conf.modules.d)
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
# 加载其他必需模块
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule dir_module modules/mod_dir.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule unixd_module modules/mod_unixd.so
# 文档根目录
DocumentRoot "/var/www/html"
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# 默认首页
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
# 日志配置
ErrorLog "logs/error_log"
CustomLog "logs/access_log" combined
# MPM 配置(prefork 默认值)
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 256
MaxConnectionsPerChild 3000
</IfModule>

templates/index.html.j2

<h1>Welcome</h1>
<p>Name: {{ student_name }}</p>
<p>ID: {{ student_id }}</p>

添加完以上文件后,这个role的文件结构应该是这样

roles/
└── httpd/
├── defaults/
│ └── main.yml
├── vars/
│ └── main.yml
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ ├── httpd.conf.j2
│ └── index.html.j2
└── meta/

如果调用这个role? 新疆一个playbook文件 text.yml

---
- name: 用role装httpd
hosts: webservers #对其进行操作的组
become: yes
roles:
- httpd #这里就是调用 roles/httpd

运行指令

ansible-playbook text.yml

这样就完成了role的编写与使用

一些需要注意的事#

可以看到,通过roles,playbooks中的调用变得及其简单,需要注意的是,ansible一般会优先在playbooks文件的同级目录中寻找role文件夹,如果你看懂了他的文件结构,就会发现他其实本质就是把一个playbooks的不同区块拆成了不同的文件分开编写,

关于变量优先级#

在ansible中,有很多地方都可以定义变量,为防止冲突,内部指定了很严格的变量优先级,这点在role文件结构中的 defaults 和 vars 中也能看出来

优先级变量定义位置核心角色
1(最低)roles/x/defaults/main.yml默认炮灰。专门用来给 Role 兜底的默认值,极易被外界覆盖。
2Playbook 中的 vars: 区块普通全局。你在主剧本最上面写死的变量。
3roles/x/vars/main.yml角色内定。Role 内部雷打不动的私有变量,一般不希望外界修改
4Playbook 调用 Role 时传参精准打击。在主剧本召唤角色时,当场传进去的临时变量
5命令行 -e 参数能强行覆盖以上所有人

举个例子,在nginx的roles内部,有两个地方能写变量

roles/nginx/defaults/main.yml nginx_port: 80

roles/nginx/vars/main.yml nginx_port: 8080

如果直接运行这个 Role,最终生效的是 8080

那如果我们创建一个playbooks调用它并定义变量呢

---
- hosts: web
vars:
nginx_port: 9000 #在Playbook里定义了9000
roles:
- nginx

它干不过role的 vars/main.yml 最终依然是 8080 生效

如果针对rolea传参呢

- hosts: web
roles:
- { role: nginx, nginx_port: 9999 }

自然是9999赢了

关于Jinja2#

在role中,可以注意到有个文件夹 templates ,里面存储了模板文件,ansibla所使用的引擎就是Jinja2,所以它的后缀是.j2

它十分强大,可以拼接、获取变量或是进行计算和if判断

具体相关知识你可以查阅有关文档

如果只是简单使用,你只需要知道你可以在其中使用{{变量名}}即可

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

ansible学习笔记
https://www.yisibuwang.top/posts/note-ansible/
作者
buwang
发布于
2026-07-06
许可协议
CC BY 4.0

部分信息可能已经过时

相关文章 智能推荐
1
Ansible学习笔记(2)
学习 关于Role,用我的理解来说,你写了一个安装和配置 httpd 的 Playbook,里面有一堆任务、变量和模板,Role 就是把这些东西打包成一个“积木包”。以后想装 httpd,直接拿来用就行,还可以灵活向里面修改添加变量以适应需求
2
Ansible学习笔记(1)
学习 Ansible是一款通过ssh来实现批量自动化的工具,理论上,只要能使用ssh完成的操作,Ansible都能做到,支持多类型主机且部署方便这里记录下自己学习此软件的笔记,会随学习进度更新
3
在windows上安装并简单配置wsl
学习 记得挺久之前微软在宣布更新windows11的时候,就说过wsa和wsl,分别是全程分别是 适用于android的windows子系统 和 适用于liunx的windows子系统,当时我也是因为wsa升级的win11,而wsl听说很垃圾就没有接触过,这几天在群里水群的时候看到有人在用这个,发现这个依旧更新到了2.0版本,据说是好用了很多,便试了试并记录
4
解决虚拟机无法共享宿主机Clash代理问题
踩坑记录 最近我想要在我的虚拟机上运行docker,但运行时却出现镜像容器pull不下来的问题,明明宿主机上的Clash开启了局域网连接,虚拟机内的系统也正确的配置了地址,但就是无法连接
5
博客已升级并对所有文章链接进行的更改
博客更改记录 博客已升级到mizuki V9.0,并进行了多项改动