目录
一、Ansible工作机制与特点
(一)Ansible工作机制
1. 初始化与配置
2. 编写Playbook
3. 调用模块
4. 加密敏感数据
5. 执行Playbook
6. 收集执行结果
7. 错误处理与回滚
8. 反馈与报告
(二)Ansible 的主要特点包括
(三)安装ansible
二、主机组
(一)定义主机组
(二)组嵌套
(三)组变量
三、Ansiible模块使用
(一)Command 模块
(二)shell模块
(三)Yum模块
(四)Service模块
四、Playbook
(一)Playbook基础
(二)Playbook结构
(三)Playbook示例
(四)定义、引用变量
(五)when条件判断
(六)迭代
五、实战---使用Playbook编译安装nginx
Ansible,作为一款强大的自动化运维工具,以其简洁的语法、零代理架构以及广泛的支持度,在DevOps领域占据了一席之地。它允许系统管理员和开发人员以声明式的方式描述基础设施的配置状态,从而实现跨平台的配置管理、应用部署、任务自动化等
一、Ansible工作机制与特点
(一)Ansible工作机制
1. 初始化与配置
- 安装Ansible:首先确保Ansible已在控制节点(通常是运维人员的电脑或服务器)上安装并配置好。
- 准备Inventory:创建或编辑
/etc/ansible/hosts
文件,定义要管理的目标主机或主机组,包括IP地址、主机名等。
2. 编写Playbook
- Playbook编写:使用YAML格式编写Playbook,这是Ansible的核心配置文件,描述了需要在目标主机上执行的任务序列、角色分配、变量、条件判断等。
3. 调用模块
- 模块选择与定义:在Playbook中,每个任务都会调用一个或多个Ansible模块。Ansible拥有大量内置模块,覆盖了系统管理、网络配置、云服务管理等多个方面。
- 模块参数:为每个模块指定参数,以定制任务的具体行为。
4. 加密敏感数据
- 使用Ansible Vault:对于Playbook中的敏感信息(如密码、密钥),可以使用Ansible Vault进行加密保护。
5. 执行Playbook
- 执行模式选择:可以直接在命令行执行Ansible命令,或通过Ansible Tower等UI界面进行。
- 提供认证信息:如果Playbook中使用到了加密数据,需要提供Ansible Vault的密码。
- 解析Inventory:Ansible根据Inventory文件确定目标主机。
- 连接目标主机:Ansible通过SSH(默认)或其他连接插件与目标主机建立连接。
- 模块执行:Ansible在每个目标主机上顺序执行Playbook中定义的任务,调用相应的模块。
- 幂等性执行:Ansible确保模块操作是幂等的,即重复执行相同任务,系统状态保持不变。
6. 收集执行结果
- 输出与日志:Ansible收集每个任务的执行结果,输出到控制台或日志文件中。如果任务失败,会提供详细的错误信息。
7. 错误处理与回滚
- 错误处理:通过Playbook中的错误处理机制(如
rescue
和always
块)来捕获异常并执行相应的恢复操作。 - 状态跟踪:Ansible可以追踪任务的执行状态,便于后续的审计和故障排查。
8. 反馈与报告
- 生成报告:Ansible执行完成后,可以生成执行报告,便于分析任务的成功率、耗时等指标。
(二)Ansible 的主要特点包括
简单易用:基于 YAML 格式的 playbook 定义任务,直观且易于理解。
无代理架构:通过 SSH 连接直接在远程主机上执行任务,无需在目标机器上安装任何代理软件或守护进程。
模块化设计:提供了大量的内置模块,覆盖了操作系统配置、网络设备管理、云计算服务操作等众多领域。用户也可以自定义模块来满足特定需求。
幂等性:许多 Ansible 模块都具有幂等性,即无论执行多少次,只要系统状态达到预期,都不会再做更改,确保了系统的稳定性。
库存管理(Inventory):Ansible 使用 inventory 文件管理要操作的目标主机列表,可以灵活地根据组(groups)和主机变量进行运维操作。
角色(Roles):为了代码复用和组织结构清晰,Ansible 提供了角色的概念,用于将一组相关的任务、文件和模板打包在一起。
动态_inventory:支持从各种源获取动态主机信息,如 EC2 API、OpenStack 或者 CMDB 系统。
安全传输:通过使用 SSH 密钥对等方式保证数据的安全传输。
扩展性强:除了丰富的官方模块库,Ansible 还有一个活跃的社区,不断开发新的模块和插件以支持更多的功能。
一键回滚:部分高级特性如 ansible-bender 支持容器镜像构建时的一键回滚。
(三)安装ansible
[root@test opt]#yum install epel-release.noarch -y
#安装epel源
[root@test opt]#yum install ansible -y
#安装ansible
二、主机组
Inventory支持对主机进行分组,每个组内可以定义多个主机,每个主机都可以定义在任何一个或多个主机组内
(一)定义主机组
[root@test opt]#vim /etc/ansible/hosts
......
[web]
192.168.83.60
192.168.83.100
#定义一个主机组,组名为web,改组包含的IP地址有192.168.83.60与192.168.83.100
......
使用ssh-keygen对指定主机进行免密登录
[root@test opt]#ssh-keygen -t rsa #生成密钥文件
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:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:zMgIug5GNxry7YClXFETG+Lqh14BAkZEQCAhNkOE3HY root@docker
The key's randomart image is:
+---[RSA 2048]----+
|^&.. =. |
|B.+ooE+ |
|..oo.. |
|..o..o + |
|o+.=. o S |
|=**.o |
|=*oo. |
|= oo |
| o . |
+----[SHA256]-----+
[root@test opt]#sshpass -p '123' ssh-copy-id root@192.168.83.60
-p '123':指定远程主机,root用户的登录密码
[root@test opt]#sshpass -p '123' ssh-copy-id root@192.168.83.100
测试联通性
[root@test opt]#ansible web -m ping
192.168.83.60 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.83.100 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
(二)组嵌套
可以将多个组合并在同一个组内
在/etc/ansible/hosts文件中添加多个主机清单
[root@test opt]#vim /etc/ansible/hosts
......
[web]
192.168.83.60
192.168.83.100
[web1]
192.168.83.[10:15] #表示IP地址为192.168.83.10~192.168.83.15之间的所有主机
[webs:children]
web
web1
#将组名为web与web1中的所有主机,嵌套在同一个组下,取名为webs,childern为固定格式
#webs: 是一个父组,通过:children后缀表明它用来汇总或包含其他组作为其“子组”(children)
......
使用 ansible [组名] --list 列出指定组名包含的所有IP地址
(三)组变量
Inventory变量名 | 作用 |
ansible_host | ansible连接节点时的IP地址 |
ansible_port | 连接对方的端口号,ssh连接时默认为22 |
ansible_user | 连接对方主机时使用的主机名。不指定时,将使用执行ansible或 ansible-playbook命令的用户 |
ansible_password | 连接时的用户的ssh密码,仅在未使用密钥对验证的情况下有效 |
ansible_ssh_private_key_file | 指定密钥认证ssh连接时的私钥文件 |
ansible_ssh_common_args | 提供给ssh、sftp、scp命令的额外参数 |
ansible_become | 允许进行权限提升 |
ansible_become_method | 指定提升权限的方式,例如可使用sudo/su/runas等方式 |
ansible_become_user | 提升为哪个用户的权限,默认提升为root |
ansible_become_password | 提升为指定用户权限时的密码 |
[root@test opt]#vim /etc/ansible/hosts
......
[web]
192.168.83.60
192.168.83.100
192.168.83.30 ansible_password=123 ansible_port=22 ansible_user=root
#指定链接主机IP地址为192.168.83.30
#ansible_password=123:表示使用ssh协议访问该主机的密码为123
#ansible_port=22:指定访问端口为22。默认端口为22
#ansible_user=root:指定访问用户为root用户,可以指定其它普通用户,但是在操作命令时,需要一定权限
......
添加完变量后,就可以不是用ssh-keygen进行免密登录,但是一般不推荐这种方法,因为是明文密码,可能会造成外泄
三、Ansiible模块使用
[root@test opt]#ansible-doc -l |wc -l #统计ansible一共有多少个模块
3387
下面就列举几个常用的模块
(一)Command 模块
功能:在远程主机执行命令,此为默认模块,可忽略 -m 选项
注意:此命令不支持 $VARNAME < > | ; & 等,可以用shell模块实现
注意:此模块不具有幂等性
比如查看定义的host组中的主机/opt目录下的文件
(二)shell模块
功能:和command相似,用shell执行命令,支持各种符号,比如:*,$, >
注意:此模块不具有幂等性
(三)Yum模块
yum和apt模块分别用于管理基于RHEL/CentOS系列(使用Yum或DNF包管理器)以及基于Debian/Ubuntu系列(使用Apt包管理器)的Linux系统的软件包。
常用参数
name 所安装的包的名称
state present--->安装, latest--->安装最新的, absent---> 卸载软件。
update_cache 强制更新yum的缓存
conf_file 指定远程yum安装时所依赖的配置文件(安装本地已有的包)。
disable_pgp_check 是否禁止GPG checking,只用于presentor latest。
disablerepo 临时禁止使用yum库。 只用于安装或更新时。
enablerepo 临时使用的yum库。只用于安装或更新时
使用yum模块,可以在远程主机上同时安装软件
使用shell模块查看安装版本
(四)Service模块
service模块的作用是管理远程主机上的服务
常用参数
name参数 #指定需要操作的服务名称,比如httpd
state参数 #指定服务的状态,可用值有 started(开启)、stopped(关闭)、restarted(重启)、reloaded(重新加载配置文件)。
enabled参数 #指定是否将服务设置为开机启动项, yes表示设置为开机启动,no不设置
ansible的核心模块较多,更多的模块操作,可以访问下列的链接,去查看更多的模块使用
链接地址:Ansible基本介绍与模块使用_ansible script模块-CSDN博客
四、Playbook
(一)Playbook基础
Playbook是Ansible的配置、部署和编排语言。它以YAML格式编写,用来描述一组任务序列,以及这些任务如何在不同主机上执行。Playbook使得复杂的多步骤部署变得简单易管理。
(二)Playbook结构
一个基本的Playbook由以下部分构成:
Hosts指定:定义了执行任务的目标主机或主机组。
Tasks:一系列要执行的任务列表,每个任务调用一个特定的模块。
Handlers:特殊任务,仅在被其它任务通知时执行,常用于服务重启等。
Variables:用于存储配置信息,可以在Playbook中或外部文件定义。
Roles:组织相关任务、文件、变量的集合,促进代码复用和模块化。
(三)Playbook示例
[root@test opt]#cat tree.yaml
---
#这是YAML文档的开始声明,表明一个新的文档或“playbook”即将开始
- name: tree
#Playbook的描述性名称,本例中为"tree",用于说明此Playbook的功能或目的
hosts: host
#指定此Playbook将要执行于host组的所有主机上
gather_facts: false
#设置是否收集目标主机的系统信息,默认为True。设为false可以加快执行速度
remote_user: root
#指定连接目标主机时使用的用户名
tasks:
#Playbook的核心部分,包含了一系列任务(tasks),这些任务将会在上面定义的主机上顺序执行
- name: install tree
#任务的描述性名称,这里是"install tree",说明任务是为了安装tree软件包
yum: name=tree state=latest
#使用Ansible的yum模块来管理软件包,state=latest表示安装最新版本
ignore_errors: True
#该任务的配置选项,当设为True时,即使该任务执行出错,Ansible也会继续执行后续任务,而不是立即停止
[root@test opt]#ansible-playbook tree.yaml #加载执行指定的yaml文件
PLAY [tree] ***************************************************************************************************
TASK [install tree] *******************************************************************************************
changed: [192.168.83.60]
PLAY RECAP ****************************************************************************************************
192.168.83.60 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
yaml文件注意格式,以空格缩进区分层级
验证命令是否安装
(四)定义、引用变量
[root@test opt]#vim vars.yaml
[root@test opt]#cat vars.yaml
---
- name: vars
#Playbook的描述性名称
hosts: host
#指定此Playbook将要执行于host组的所有主机上
gather_facts: false
remote_user: root
vars:
- username: lisi
#在vars下定义了一个变量 username,其值为 "lisi"。这个变量在playbook的后续任务中引用
tasks:
- name: create user
#描述为 "create user",意在创建一个新的系统用户
user: name={{username}} uid=1200
#使用user模块
#name={{username}}:设置用户名称,使用刚才定义的变量 {{username}},创建用户名为lisi的用户
#uid=1200:设置uid为1200
- name: copy file
#描述为 "copy file",目的是将一段内容复制到远程主机上的一个文件中
copy: content="{{ansible_version}}" dest=/opt/kernel.txt
#使用coyp模块
#content: 指定了要写入文件的内容,这里使用了内置的 Ansible 变量 {{ansible_version}},
#即 Ansible 的当前运行版本号,作为文件内容
#dest: 指定目标文件的路径,即/opt/kernel.txt
常用的Ansible内置变量
ansible_version | 表示 Ansible 的版本信息。 |
inventory_hostname | 返回当前正在处理的主机名,即清单文件中定义的主机名。 |
inventory_hostname_short | 返回清单文件中主机名的第一部分,通常是去掉域名后的主机名。 |
hostvars | 一个字典,包含了在同一 playbook 运行中所有主机的变量。 可以通过 hostvars['hostname'] 访问其他主机的变量。 |
group_names | 当前主机所属的所有组名列表。 |
play_hosts | 当前 play 中所有目标主机的列表。 |
ansible_facts | 一个包含收集到的目标系统事实信息的字典, 例如网络接口信息 (ansible_default_ipv4, ansible_all_ipv4_addresses)、 操作系统类型 (ansible_system)、主机架构 (ansible_architecture) 等。 |
ansible_os_family | 表示操作系统家族,如 'RedHat', 'Debian' 等。 |
ansible_distribution | 操作系统的具体发行版名称,如 'Ubuntu', 'CentOS' 等。 |
ansible_hostname | 目标主机的 hostname。 |
ansible_env | 包含目标主机环境变量的字典。 |
ansible_connection | 当前连接到主机所使用的连接插件类型。 |
ansible_python_interpreter | 当前用于执行Python脚本的Python解释器路径。 |
(五)when条件判断
在Ansible中,when条件判断是一种强大的控制结构,允许你根据特定条件来决定是否执行某个任务。这对于实现任务执行的灵活性和针对性非常有用,特别是在管理具有不同配置或需求的多主机环境时
基本语法
when条件可以放在任务定义之下,使用YAML语法编写。其基本形式如下:
- name: 任务描述
action: 任务模块及参数
when: 条件表达式
条件表达式
条件表达式可以是简单的布尔表达式、比较运算符、变量检查、逻辑运算符组合等。一些常见的用法包括:
- 简单条件:直接比较或检查变量,如 when: ansible_os_family == RedHat'',这会检查目标主机的操作系统家族是否为RedHat
- 逻辑运算:支持and、or、not等逻辑运算符,例如 when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'CentOS'。
- 存在性检查:使用when: variable is defined或when: variable | default('') != ''来检查变量是否已定义或非空。
- 数值和字符串比较:比如 when: ansible_memory_mb.real.total > 2048,比较内存大小
首先定义多个主机
在主机名为hy的主机上安装 httpd服务
---
- name: httpd
hosts: web
remote_user: root
tasks:
- name: firewalld
service: name=firewalld state=stopped
#使用service模块,关闭防火墙,也可以使用shell或command模块关闭selinux
- name: install httpd
yum: name=httpd
#使用yum模块安装httpd软件包
when: ansible_hostname == 'hy'
#进行条件判断,仅当主机名为'hy'时执行此任务
#ansible_hostname为内置变量,反回组内的所有主机名
- name: start httpd
service: name=httpd state=started
when: ansible_hostname == 'hy'
注意:
gather_facts 参数的值需要设置为ture(默认),可以不添加参数,因为关闭此参数,ansible获取不到主机信息,后面的内置变量,如ansible_hostname无法识别
[root@test opt]#vim httpd.yaml
[root@test opt]#ansible-playbook httpd.yaml
PLAY [httpd] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************
ok: [192.168.83.60]
ok: [192.168.83.100]
ok: [192.168.83.30]
......
[root@test opt]#ansible web -a 'rpm -q httpd'
192.168.83.30 | FAILED | rc=1 >>
未安装软件包 httpd non-zero return code
192.168.83.60 | FAILED | rc=1 >>
未安装软件包 httpd non-zero return code
192.168.83.100 | CHANGED | rc=0 >>
httpd-2.4.6-99.el7.centos.1.x86_64 #主机名为hy
(六)迭代
Ansible中的迭代允许你对列表或其他可迭代对象中的每一项执行一个任务或一组任务,这是处理重复性工作时非常有用的特性。迭代可以通过几种方式实现,最常用的是使用loop或历史上的with_items
---
- name: Create Directories on Hosts
hosts: host
tasks:
- name: Create Specified Directories
file: #使用file模块
path: "{{item}}"
#指定要操作的文件或目录路径。
#使用{{ item }}表示循环中的当前项目,每次迭代时item的值会依次替换为列表中的每个路径
state: directory
#设定资源的状态,这里是directory,意味着如果指定的路径不存在,则创建目录
with_items:
#Ansible中用来迭代列表的关键词。指定接下来的任务需要对提供的列表中的每一个元素执行一次。
- /data
- /data/test01
- /data/test02
#定义了要创建的目录路径
#整个playbook定义了一个操作,即在名为host的组内所有主机上创建with_items定义的一系列目录
五、实战---使用Playbook编译安装nginx
[root@test opt]#vim /etc/ansible/hosts
......
[nginx]
192.168.83.30
准备nginx安装包与安装脚本文件
[root@test data]#ls
nginx-1.18.0.tar.gz nginx.sh
[root@test data]#chmod +x nginx.sh
#给脚本文件添加执行权限
查看脚本文件
[root@test data]#cat nginx.sh
#/bin/bash
systemctl start nginx >>/dev/null
if [ $? -eq 0 ];then
echo "nginx服务已安装"
else
useradd -M -s /sbin/nologin nginx
cd /opt
wget http://nginx.org/download/nginx-1.18.0.tar.gz >>/dev/null
echo "正在安装,请耐心等待"
tar xf nginx-1.18.0.tar.gz
cd /opt/nginx-1.18.0
yum -y install gcc pcre-devel openssl-devel zlib-devel openssl openssl-devel &>>/dev/null
./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module
make -j `lscpu|sed -n '4p'|awk '{print $2}'`&>>/dev/null
make install &>>/dev/null
ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
cat > /usr/lib/systemd/system/nginx.service <<EOF
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -1 $MAINPID
ExecStop=/bin/kill -3 $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
chown -R nginx.nginx /usr/local/nginx
systemctl daemon-reload &>>/dev/null
systemctl enable --now nginx
echo "nginx服务已开启"
fi
编写playbook副本
[root@test opt]#vim nginx.yaml
[root@test opt]#cat nginx.yaml
---
- name: install nginx #Playbook的描述性名称,这里是安装Nginx
hosts: nginx #定义执行此Playbook的目标主机组,这里指的是名为nginx的主机组
remote_user: root #指定远程执行任务时使用的用户名,这里是root用户
tasks: #开始定义具体任务列表
- name: firewalld stop #任务一:停止firewalld服务
service: name=firewalld state=stopped
- name: package #任务二:复制Nginx安装包到目标主机
copy: src=/data/nginx-1.18.0.tar.gz dest=/opt/ owner=root group=root
- name: Execute script #任务三:执行编译安装nginx脚本文件
script: /data/nginx.sh #使用script模块
执行playbook脚本并进行测试