一、ansible介绍
1.ansible概述:
Ansible是一个基于Python开发的配置管理和应用部署工具,现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点,Pubbet和Saltstack能实现的功能,Ansible基本上都可以实现。
Ansible能批量配置、部署、管理上千台主机。比如以前需要切换到每个主机上执行的一或多个操作,使用Ansible只需在固定的一台Ansible控制节点上去完成所有主机的操作。
Ansible是基于模块工作的,它只是提供了一种运行框架,它本身没有完成任务的能力,真正执行操作的是Ansible的模块, 比如copy模块用于拷贝文件到远程主机上,service模块用于管理服务的启动、停止、重启等。
2.Ansible的四个组件
Inventory 主机清单(主机组):
-
Inventory 文件是 Ansible 用来描述服务器信息的配置文件,其中定义了要管理的主机及其分组。它可以是 INI 或 YAML 格式的静态文件,也可以是动态生成的。在 Inventory 文件中,主机可以被划分为不同的组,这样可以更容易地管理和引用相关联的服务器集合。例如,你可以有 'web' 组包含所有的 web 服务器,'db' 组包含所有数据库服务器等等。组内的每个主机可以使用主机名、别名或 IP 地址来标识,还可以针对每个主机设置特定的变量。
Modules 模块:
-
Modules 是 Ansible 的核心功能,它们是一些专门的插件,可以执行特定任务。例如
copy
模块用于复制文件到远程主机,file
模块用于文件管理,在远程主机上创建或删除文件,yum
和apt
用于在基于 RedHat 或 Debian 的系统上管理包,等等。当你在 playbooks 或是 ad-hoc 命令中调用模块时,Ansible 会在目标主机上推送模块代码并执行。
Plugins 插件:
-
Plugins 是用来扩展 Ansible 的功能的特殊脚本。它们分为很多种类型,如 Inventory Plugins、Callback Plugins、Action Plugins 等等。Inventory Plugins 可以用来创建动态的 Inventory 清单,Callback Plugins 可以用来自定义 Ansible 输出日志的格式,Action Plugins 来扩展或修改模块的行为。Plugins 非常强大,因为它们让 Ansible 的行为可以根据需要进行定制。
Playbooks 剧本(相当于脚本):
-
Playbooks 是定义在 Ansible 中自动化操作的配置文件,使用 YAML 格式编写。Playbook 可以理解为一个脚本集合,它不仅描述了要在哪些主机上执行什么操作,还说明了这些操作应该如何执行,包括任务顺序、所需参数、相关变量等。一个 playbook 可以包含多个 play,每个 play 可以针对不同的主机组执行一系列任务。Playbooks 是 Ansible 自动化的核心,可用于配置管理、应用部署、任务编排和连续的服务部署等。
总的来说,Inventory 是 Ansible 知晓要管理那些主机的地方,Modules 是实现各种管理任务的工具,Plugins 提供了扩展 Ansible 功能的能力,而 Playbooks 则是把这一切组织起来,为你的基础架构和应用按需自动化的场本。
3.Ansible的特性
特性一:
-
Ansible其中一个比较鲜明的特性Agentless,即无Agent的存在(无代理端,即无客户端),它就像普通命令一样, 并非c/s软件,也只需在某个作为控制节点的主机上安装一次Ansible即可,通常它基于ssh连接来控制远程主机,远程主机上不需要安装Ansible或其它额外的服务。
-
使用者在使用时,在服务器终端输入命令或者playbooks,会通过预定好的规则将playbook拆解为play(一个play就是一个Linux操作),再组织成ansible可以识别的任务,调用模块和插件,根据主机清单通过SSH将临时文件发给远程的客户端执行并返回结果,执行结束后自动删除。
特性二:
-
Ansible的另一个比较鲜明的特性是它的绝大多数模块都具备幂等性(idempotence)。所谓幂等性,指的是多次操作或多次执行对系统资源的影响是一致的。
-
比如执行
systemctl stop xxx
命令来停止服务,当发现要停止的目标服务已经处于停止状态,它什么也不会做,所以多次停止的结果仍然是停止,不会改变结果,它是幂等的,而systemctl restart xxx是非幂等的。
Ansible的很多模块在执行时都会先判断目标节点是否要执行任务,所以,可以放心大胆地让Ansible去执行任务,重复执行某个任务绝大多数时候不会产生任何副作用。
二、ansible 环境安装部署
-
管理端ansible:192.168.160.6
-
被管理端:192.168.160.3 192.168.160.4 192.168.160.5
管理端安装ansible:
1.yum安装epel-release和ansible
yum install -y epel-release //先安装 epel 源,在线源安装 yum install -y ansible
2.查看ansible目录结构:
[root@michaelxct ~]# tree /etc/ansible/ /etc/ansible/ ├── ansible.cfg ├── hosts └── roles 1 directory, 2 files
3.配置主机清单:
第一种方法(需要免密登录):
[root@michaelxct ~] vim /etc/ansible/hosts #可以包含多台被管理的主机名或者IP地址,主机名需要先修改/etc/hosts文件 [webservers] 192.168.160.3 192.168.160.4 192.168.160.5 ## [dbservers] ## ## db01.intranet.mydomain.net ## db02.intranet.mydomain.net ## 10.25.1.56 ## 10.25.1.57
在 Ansible 中,主机清单(inventory)是定义你管理和自动化的所有服务器的地方。webservers
和dbservers
是两个常见的主机组名称,它们在Ansible主机清单中代表了不同的服务器角色或组。
webservers:
-
这个组通常包括运行Web服务器软件(如Apache, Nginx等)的主机。
-
这些主机负责处理用户的HTTP请求并提供网页内容。
dbservers:
-
这个组通常指的是运行数据库服务(如MySQL, PostgreSQL等)的主机。
-
这些主机主要用于数据存储和查询功能。
第二种方法(不需要免密登录):
。
[root@private-172-xx-xx-xx ~]# cat test.hosts [all] 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 192.168.160.1 [all:vars] ansible_ssh_user=root ansible_ssh_port=xxxx ansible_ssh_pass='xxxxxxxx='
在Ansible中配置主机清单时,可以将主机分类到不同的组中,以便能更方便地对特定类型的服务器执行特定的自动化任务。例如,你可能想要仅针对Web服务器群组webservers
执行更新Web服务器配置文件的任务,而对数据库服务器群组dbservers
执行备份数据库的任务。
4.设置免密登录:
ssh-keygen -t rsa:生成密钥文件,一路Enter即可:
[root@michaelxct ansible] 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:MUBTHGuMpKq38Rlo/X61eP0es5n7q8mNnXg4mSY1K9E root@michaelxct The key's randomart image is: +---[RSA 2048]----+ | .=oo. | | o =.. | | . . * | | . . o | | . S . | | . o .. E | |. = o o oo O | | o + + o oooB*B.| | . o.o. . +O@Bo| +----[SHA256]-----+
查看目录可以看到生成两个,id_rsa为私钥,id_rsa.pub为公钥:
[root@michaelxct ansible] cd /root/.ssh/ [root@michaelxct .ssh] ls id_rsa id_rsa.pub
修改/etc/ssh/ssh_config,开启免密交互
[root@michaelxct ~] vim /etc/ssh/ssh_config # Host * # ForwardAgent no # ForwardX11 no # RhostsRSAAuthentication no # RSAAuthentication yes # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # GSSAPIKeyExchange no # GSSAPITrustDNS no # BatchMode no # CheckHostIP yes # AddressFamily any # ConnectTimeout 0 StrictHostKeyChecking no # IdentityFile ~/.ssh/identity # IdentityFile ~/.ssh/id_rsa # IdentityFile ~/.ssh/id_dsa # IdentityFile ~/.ssh/id_ecdsa # IdentityFile ~/.ssh/id_ed25519 # Port 22 # Protocol 2 # Cipher 3des # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc # MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 # EscapeChar ~ # Tunnel no # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h
修改完后重启sshd
[root@michaelxct .ssh] systemctl restart sshd
把密钥推送给其它的主机:
[root@michaelxct .ssh] ssh-copy-id root@192.168.160.3 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.160.3's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@192.168.160.3'" and check to make sure that only the key(s) you wanted were added. [root@michaelxct .ssh] ssh-copy-id root@192.168.160.4 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.160.4's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@192.168.160.4'" and check to make sure that only the key(s) you wanted were added. [root@michaelxct .ssh] ssh-copy-id root@192.168.160.5 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.160.5's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@192.168.160.5'" and check to make sure that only the key(s) you wanted were added.
5.使用sshpass
如果有成百上千台主机,不可能一次一次输入密码,因此就需要sshpass。sshpass这个工具可以实现ssh的免交互。
安装sshpass
yum install sshpass -y
使用sshpass
在sshpass
选项之后指定要运行的命令。通常,该命令ssh
带有参数,但也可以是任何其他命令。不过,目前SSH密码提示已硬编码为sshpass
。
sshpass [-f filename | -d num | -p password | -e] [options]
-p 密码 密码在命令行中给出。 -f 文件名 密码是文件名的第一行。 -d number number是sshpass从运行程序继承的文件描述符。从打开的文件描述符中读取密码。 -e 密码来自环境变量"SSHPASS"。
三、ansible的使用方式:
1.Ad-hoc Commands(临时命令):
这种方式是指在命令行直接使用 ansible
命令执行单个任务。它适合于需要快速执行操作的场景,例如迅速检查一组服务器的状态或者在多台服务器上执行单一命令。Ad-hoc命令的格式通常是这样的:
ansible [pattern] -m [module] -a [arguments]
ansible <组名> -m <模块> -a <参数列表>
:
-
-m
参数后面跟着的是要执行的模块名称。 -
-a
参数后面是传递给模块的参数列表,具体取决于使用的模块。
以下是一些常用的模块:
-
command:在远程服务器上执行命令,但不支持管道符和重定向等操作。
-
shell:与
command
功能类似,但支持更复杂的shell命令,包括管道、重定向等。 -
copy:用于将本地文件复制到远程主机上。
-
file:用来设置文件属性,例如权限、所有权,也可以用来创建和删除文件或目录。
-
git:用于管理git仓库,可以克隆、更新、检出特定的分支或标签。
-
user:用于管理用户账户。
-
group:用于管理用户组。
-
apt 和 yum:分别用于基于Debian和基于RedHat的系统,管理软件包的安装、卸载、更新。
-
service:用于控制服务(服务的启动、停止、重启等)。
-
stat:获取远程主机上文件的状态信息。
-
ping:不是传统的 ICMP ping,而是用来检查远程主机是否能够被 Ansible 成功访问。
-
setup:收集远程主机的详细信息,这在动态使用变量时很有帮助。
示例:
ansible webservers -m ping -a ''
这个例子将会向“webservers”这个组里面的所有主机发送 ping
请求,仅仅检查它们是否能够被 Ansible 访问到。
ansible <主机IP> -m <模块> -a <参数列表>
: 与上一命令类似,但是这个命令是针对单个主机IP地址执行模块。它会在指定的 IP 地址的主机上执行模块。
示例:
ansible 192.168.1.50 -m shell -a 'echo hello world'
这个例子会在 IP 地址为 192.168.1.50 的主机上执行 echo hello world
命令。
ansible <主机名> -a <参数列表>
: 这个命令格式没有指定 -m
参数,默认使用的模块是 command
,所以它将在指定的主机名上执行提供的命令。
示例:
ansible server1 -a 'uptime'
这个例子会在主机名为 “server1” 的服务器上执行 uptime
命令,并显示系统的运行时长。
其中,[pattern]
表示目标主机,可以是组名、IP地址、主机名或者是清单文件中定义的一个模式。-m [module]
指定使用的模块,-a [arguments]
是传递给模块的参数。
2.Playbooks:
playbooks是 一个不同于使用Ansible命令行执行方式的模式,其功能更强大灵活。简单来说,playbook是一个非常简单的配置管理和多主机部署系统,不同于任何已经存在的模式,可作为一个适合部署复杂应用程序的基础。Playbook可以定制配置,可以按照指定的操作步骤有序执行,支持同步和异步方式。值得注意的是playbook是通过YAML格式来进行描述定义的。
2.1 playbook格式
playbook由YAML语言编写。YAML语言参考了其他多种语言,包括:XML、C语言、Python、Perl等。MAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。以下为playbook常用到的YAML格式。
--- - name: Playbook名称 hosts: 目标主机或主机组 become: yes become_user: root vars: var_name: var_value tasks: - name: 任务1标题 模块名: 参数1: 值1 参数2: 值2 - name: 任务2标题 模块名: 参数1: 值1 参数2: 值2
每个部分的含义:
-
---
:YAML 文档开始的标记,用于表示接下来的内容是一个 YAML 文档。 -
- name: Playbook名称
:定义了 playbook 的名称。 -
hosts: 目标主机或主机组
:指定了这个 playbook 将要操作的目标主机或主机组。 -
become: yes
和become_user: root
:这两个选项用于指定在执行任务时要以特权用户(例如 root)身份运行。 -
vars:
:定义了 playbook 中可用的变量,可以在任务中使用这些变量。 -
tasks:
:定义了一系列任务,每个任务都是一个列表项,包含了任务的具体定义。-
- name: 任务1标题
:定义了第一个任务的标题。 -
模块名:
:指定了要使用的模块(例如copy
、file
、command
等),用于执行任务操作。 -
参数1: 值1
、参数2: 值2
:指定了模块执行任务时的参数和对应的值。
-
每个任务都由一个 -
开头,后面跟着任务的具体定义,包括任务名称、模块名、模块参数等。Playbook 中可以包含多个任务,每个任务的执行顺序按照它们在文件中的顺序来执行。
2.2 playbook组成部分
-
Tasks:任务,即通过task调用ansible的模板将多个操作组织在一个playbook中运行
-
Variables:变量
-
Templates:模板
-
Handlers:处理器,当changed状态条件满足时,(notify)触发执行的操作
-
Roles:角色
常见的 Ansible 模块:
-
apt
模块:-
功能:用于管理基于 Debian 或 Ubuntu 的系统上的软件包。
-
参数:
-
name
:要安装、卸载或检查状态的软件包名称。 -
state
:软件包的状态,可以是present
(安装)、absent
(卸载)或latest
(确保是最新版本)等。 -
其他参数如
update_cache
(是否更新软件包列表)、cache_valid_time
(软件包列表缓存的有效时间)等。
-
-
-
yum
模块:-
功能:用于管理基于 Red Hat、CentOS 或 Fedora 的系统上的软件包。
-
参数:
-
name
:要安装、卸载或检查状态的软件包名称。 -
state
:软件包的状态,可以是present
(安装)、absent
(卸载)或latest
(确保是最新版本)等。 -
其他参数如
disablerepo
(禁用指定的软件源)、enablerepo
(启用指定的软件源)等。
-
-
-
copy
模块:-
功能:复制文件或目录到目标主机。
-
参数:
-
src
:源文件或目录的路径。 -
dest
:目标路径,可以是文件或目录。 -
其他参数如
mode
(权限)、owner
(所有者)、group
(所属组)等。
-
-
-
template
模块:-
功能:根据模板文件生成配置文件。
-
参数:
-
src
:模板文件的路径。 -
dest
:生成的目标文件路径。 -
其他参数如
mode
(权限)、owner
(所有者)、group
(所属组)、backup
(备份旧文件)等。
-
-
-
file
模块:-
功能:管理文件系统上的文件或目录。
-
参数:
-
path
:文件或目录的路径。 -
state
:文件或目录的状态,可以是directory
(目录)、file
(文件)、absent
(不存在)等。 -
其他参数如
mode
(权限)、owner
(所有者)、group
(所属组)、recurse
(递归操作)等。
-
-
-
lineinfile
模块:-
功能:在文件中查找并修改特定行。
-
参数:
-
path
:文件的路径。 -
line
:要添加、修改或删除的行内容。 -
state
:行的状态,可以是present
(存在)、absent
(不存在)、before
(插入到指定行之前)等。 -
其他参数如
insertafter
(在指定行之后插入)、regexp
(使用正则表达式匹配行)等。
-
-
-
command
模块:-
功能:执行 shell 命令。
-
参数:
-
cmd
:要执行的命令。 -
其他参数如
chdir
(命令执行的工作目录)、creates
(如果文件存在则不执行命令)等。
-
-
-
debug
模块:-
功能:打印调试信息。
-
参数:
-
msg
:要打印的消息内容。 -
其他参数如
var
(打印变量的值)、verbosity
(调试级别)等。
-
-
2.3 示例
安装git
--- - name: first play # 定义一个 Play 的名称为 first play gather_facts: false # 不进行事实信息收集,加快执行速度 hosts: all # 在所有主机组中执行任务 remote_user: root # 使用 root 用户执行任务 tasks: # 定义任务列表 - name: test connection # 任务名称为 test connection ping: # 使用 ping 模块测试连接 - name: Install Git # 任务名称为 Install Git yum: # 使用 yum 模块管理软件包 name: git # 要安装的软件包为 git state: present # 确保软件包存在 - name: print message # 任务名称为 print message debug: # 使用 debug 模块打印消息 msg: "安装git成功" # 要打印的消息内容为 "安装git成功" - name: get version # 任务名称为 get version command: # 使用 command 模块执行命令 cmd: git --version # 执行命令为 git --version register: get_version # 将命令执行结果存储到变量 get_version 中 - name: # 任务名称为空,表示这个任务不会执行任何操作 debug: # 使用 debug 模块打印消息 msg: "git的版本为:{{get_version.stdout }}" # 打印 get_version.stdout 变量的值
运行playbook
//运行playbook ansible-playbook test.yaml //补充参数: -k(–ask-pass):用来交互输入ssh密码 -K(-ask-become-pass):用来交互输入sudo密码 -u:指定用户 ansible-playbook test1.yaml --syntax-check #检查yaml文件的语法是否正确 ansible-playbook test1.yaml --list-task #检查tasks任务 ansible-playbook test1.yaml --list-hosts #检查生效的主机 ansible-playbook test1.yaml --start-at-task='Install Git' #指定从某个task开始运行
卸载git
--- - name: second play # Playbook 名称为 second play gather_facts: false # 不收集主机的事实信息 hosts: all # 在所有主机上执行任务 remote_user: root # 远程用户为 root tasks: - name: test connection # 任务名称为 test connection ping: # 使用 ping 模块测试主机连接 - name: remove git # 任务名称为 remove git yum: # 使用 yum 模块管理软件包 name: git # 要卸载的软件包名称为 git state: absent # 将软件包状态设置为 absent,表示卸载 - name: print message # 任务名称为 print message debug: # 使用 debug 模块打印消息 msg: "卸载成功" # 要打印的消息内容为 "卸载成功"
定义、引用变量
--- - name: second play # Playbook 名称为 second play hosts: all # 在所有主机上执行任务 remote_user: root # 远程用户为 root vars: # 定义变量 - groupname: mysql # 定义 groupname 变量,值为 mysql - username: nginx # 定义 username 变量,值为 nginx tasks: - name: create group # 任务名称为 create group group: # 使用 group 模块创建用户组 name: "{{groupname}}" # 使用变量 groupname 的值作为用户组名称 system: yes # 创建系统用户组 gid: 306 # 指定用户组的 GID - name: create user # 任务名称为 create user user: # 使用 user 模块创建用户 name: "{{username}}" # 使用变量 username 的值作为用户名 uid: 306 # 指定用户的 UID group: "{{groupname}}" # 指定用户所属的用户组 - name: copy file # 任务名称为 copy file copy: # 使用 copy 模块复制文件 content: "{{ansible_default_ipv4}}" # 使用 ansible_default_ipv4 变量的值作为文件内容 dest: /opt/vars.txt # 复制文件到目标路径 /opt/vars.txt ansible-playbook test2.yaml -e "username=nginx" #在命令行里定义变量
指定远程主机sudo切换用户
--- - hosts: dbservers # 应用于名为 dbservers 的主机组 remote_user: zhangsan # 使用 zhangsan 用户进行远程连接 become: yes # 启用特权升级(become),在 2.6 版本之前是 sudo 模块,意味着切换 用户运行 become_user: root # 切换到 root 用户进行任务执行 tasks: - name: Task Name # 任务名称 module_name: # 模块名称 parameter1: value1 # 模块参数1 parameter2: value2 # 模块参数2 ... 执行playbook时:ansible-playbook test3.yml -k -K
when条件判断:
在Ansible中,提供的唯一一个通用的条件判断是when指令,当when指令的值为true时,则该任务执行,否则不执行该任务。
--- - hosts: all # 在所有主机上执行任务 remote_user: root # 远程用户为 root tasks: - name: shutdown host # 任务名称为 shutdown host command: /sbin/shutdown -r now # 执行重启命令 when: ansible_default_ipv4.address == "192.168.160.3" # 当 Ansible 默认的 IPv4 地址为 "192.168.160.3" 时才执行该任务 # ansible_default_ipv4 是一个事先定义好的变量,用于获取主机的默认 IPv4 地址 # 或者可以根据主机名来执行任务 # - name: shutdown host # command: /sbin/shutdown -r now # when: inventory_hostname == "<主机名>" # # 当当前主机的名称为指定的主机名时才执行该任务
迭代
--- - name: play1 # Playbook 名称为 play1 hosts: all # 在所有主机上执行任务 gather_facts: false # 不收集主机的事实信息 tasks: - name: create file # 任务名称为 create file file: # 使用 file 模块创建文件 path: "{{item}}" # 文件路径使用循环变量 item state: touch # 创建一个空文件 with_items: # 对列表中的每个元素执行任务 - /opt/a # 创建 /opt/a 文件 - /opt/b # 创建 /opt/b 文件 - /opt/c # 创建 /opt/c 文件 - /opt/d # 创建 /opt/d 文件 - name: play2 # Playbook 名称为 play2 hosts: all # 在所有主机上执行任务 gather_facts: false # 不收集主机的事实信息 vars: # 定义变量 test: # 变量名为 test - /tmp/test1 # 包含多个路径 - /tmp/test2 - /tmp/test3 - /tmp/test4 tasks: - name: create directories # 任务名称为 create directories file: # 使用 file 模块创建目录 path: "{{item}}" # 目录路径使用循环变量 item state: directory # 创建目录 with_items: "{{test}}" # 对变量 test 中的每个元素执行任务 - name: play3 # Playbook 名称为 play3 hosts: all # 在所有主机上执行任务 gather_facts: false # 不收集主机的事实信息 tasks: - name: add users # 任务名称为 add users user: # 使用 user 模块添加用户 name: "{{item.name}}" # 用户名使用循环变量 item 的 name 字段 state: present # 确保用户存在 groups: "{{item.groups}}" # 用户所属组使用循环变量 item 的 groups 字段 with_items: # 对列表中的每个元素执行任务 - name: test1 # 用户名为 test1,所属组为 wheel groups: wheel - name: test2 # 用户名为 test2,所属组为 root groups: root
2.4 Templates模块
Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件,可以看作是一个编译过的模板文件,用来产生目标文本,传递Python的变量给模板去替换模板中的标记。
-
先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量
# 这是一个简单的 Nginx 配置文件模板示例 # 定义一个 HTTP 服务器 server { # 监听端口 listen 80; # 定义服务器名 server_name {{ server_name }}; # 定义网站根目录 root /var/www/html; # 定义访问日志和错误日志路径 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # 匹配 / 请求路径 location / { # 将请求转发到后端服务器 proxy_pass http://backend_server; } }
--- - hosts: all # 应用于所有主机 remote_user: root # 使用 root 用户进行远程连接 vars: # 定义变量 - package: nginx # 定义要安装的软件包名称为 nginx - service: nginx # 定义要管理的服务名称为 nginx - server_name: example.com # 定义服务器名为 example.com - backend_server: 127.0.0.1:8080 # 定义后端服务器地址和端口 tasks: # 定义任务列表 - name: install nginx package # 安装 nginx 软件包 yum: # 使用 yum 模块管理软件包 name: "{{package}}" # 安装的软件包名称为变量 package 的值 state: latest # 确保安装最新版本的软件包 - name: install configure file # 安装配置文件 template: # 使用 template 模块生成配置文件 src: nginx.conf.j2 # Nginx 配置文件的模板路径 dest: /etc/nginx/nginx.conf # Nginx 配置文件的目标路径 notify: # 在任务执行后发送通知 - restart nginx # 通知名为 restart nginx - name: create web root dir # 创建网站根目录 file: # 使用 file 模块管理文件系统 path: /var/www/html # 网站根目录路径 state: directory # 确保是一个目录 - name: start nginx server # 启动 Nginx 服务 service: # 使用 service 模块管理系统服务 name: "{{service}}" # 服务名称为变量 service 的值 enabled: true # 设置服务为开机自启动 state: started # 启动服务 handlers: # 定义处理程序列表 - name: restart nginx # 重新启动 Nginx 服务的处理程序 service: # 使用 service 模块管理系统服务 name: "{{service}}" # 服务名称为变量 service 的值 state: restarted # 重新启动服务
2.5 tags模块
-
playbook
标记:-
作用:为整个 Playbook 添加标记,用于控制整个 Playbook 的执行。
-
示例用法:
tags: - playbook
,在运行 Playbook 时使用--tags="playbook"
参数来运行整个 Playbook。
-
-
only
标记:-
作用:表示这个任务只有在使用了
--tags="only"
参数时才会执行。 -
示例用法:
tags: - only
,用于标记只在特定条件下执行的任务。
-
-
自定义标记:
-
作用:根据具体需求自定义的标记,用于区分和控制不同类型的任务。
-
示例用法:
tags: - tag_name
,例如将相关的安装任务标记为install
,配置任务标记为config
等。
-
-
排除标记:
-
作用:用于排除特定的标记,表示只执行没有被排除标记的任务。
-
示例用法:
tags: - tag_name:!skip
,表示只执行没有被排除标记skip
的任务。
-
-
交集标记:
-
作用:表示同时满足两个标记的任务才会执行,即取两个标记的交集。
-
示例用法:
tags: - tag_name:&install
,表示同时满足tag_name
和install
标记的任务才会执行。
-
-
并集标记:
-
作用:表示满足任意一个标记的任务都会执行,即取两个标记的并集。
-
示例用法:
tags: - tag_name:|config
,表示满足tag_name
或者config
标记的任务都会执行。
-
--- - hosts: all remote_user: root tasks: - name: Task 1 command: echo "This is Task 1" - name: Task 2 command: echo "This is Task 2" tags: - playbook ansible-playbook your_playbook.yaml --tags task1,task2
2.6 Roles模块
在 Ansible 中,Roles 是一种组织和重用任务、变量和文件结构的方法。Roles 模块使得管理复杂的 Playbooks 变得更加容易和模块化,有助于将任务组织成逻辑单元,并且可以在多个 Playbooks 中重复使用。
一个典型的 Ansible Roles 目录结构如下:
pythonCopy code roles/ ├── myrole/ │ ├── defaults/ # 默认变量 │ │ └── main.yml │ ├── files/ # 需要拷贝到目标主机的文件 │ ├── handlers/ # 处理程序(handlers) │ │ └── main.yml │ ├── meta/ # 元数据信息 │ │ └── main.yml │ ├── tasks/ # 任务 │ │ └── main.yml │ ├── templates/ # 模板文件 │ ├── tests/ # 测试相关文件 │ ├── vars/ # 变量文件 │ │ └── main.yml │ └── README.md # 角色说明文档
在这个目录结构中,各个目录的作用如下:
-
defaults/
:存放默认变量。 -
files/
:存放需要拷贝到目标主机的文件。 -
handlers/
:存放处理程序(handlers)。 -
meta/
:存放角色的元数据信息,如依赖关系。 -
tasks/
:存放任务。 -
templates/
:存放模板文件。 -
tests/
:存放测试相关文件。 -
vars/
:存放变量文件。
-
使用 Roles: 要在 Playbooks 中使用 Roles,可以通过
roles
关键字引入角色,例如:yamlCopy code --- - name: Playbook using roles hosts: all roles: - myrole # 引入名为 myrole 的角色
-
角色的主要文件:
-
defaults/main.yml
:定义默认变量。 -
handlers/main.yml
:定义处理程序(handlers)。 -
meta/main.yml
:定义角色的元数据信息,如依赖关系。 -
tasks/main.yml
:定义任务。 -
templates/
:存放模板文件。 -
vars/main.yml
:定义变量文件。
-
-
角色的元数据信息: 在
meta/main.yml
中可以定义角色的元数据信息,如依赖关系和角色的作者信息等。示例:yamlCopy code --- dependencies: - { role: common } author: John Doe
-
调用角色的变量和任务: 在 Playbooks 或者其他角色中可以调用角色的变量和任务,例如:
yamlCopy code - name: Include role variables include_vars: path/to/myrole/defaults/main.yml - name: Run role tasks include_tasks: path/to/myrole/tasks/main.yml
5.示例:nginx
首先,创建一个名为 webserver
的角色目录结构,并添加相应的文件:
roles/ └── webserver/ ├── defaults/ │ └── main.yml # 默认变量文件 ├── tasks/ │ └── main.yml # 任务文件 ├── templates/ │ └── nginx.conf.j2 # Nginx 配置文件模板 └── meta/ └── main.yml # 元数据信息
接下来,分别编辑这些文件:
-
roles/webserver/defaults/main.yml
:定义默认变量,例如 Nginx 的安装路径等。yamlCopy code --- nginx_install_path: /etc/nginx nginx_config_path: /etc/nginx/nginx.conf
-
roles/webserver/tasks/main.yml
:定义角色的任务。yamlCopy code --- - name: Install Nginx package: name: nginx state: present - name: Copy Nginx configuration file template: src: nginx.conf.j2 dest: "{{ nginx_config_path }}" notify: - restart nginx
-
roles/webserver/templates/nginx.conf.j2
:Nginx 配置文件模板。nginxCopy code # Nginx 配置文件模板示例 # 定义一个 HTTP 服务器 server { # 监听端口 listen 80; # 定义服务器名 server_name {{ server_name }}; # 定义网站根目录 root {{ nginx_install_path }}/html; # 定义访问日志和错误日志路径 access_log {{ nginx_install_path }}/logs/access.log; error_log {{ nginx_install_path }}/logs/error.log; # 匹配 / 请求路径 location / { # 将请求转发到后端服务器 proxy_pass http://backend_server; } }
-
roles/webserver/meta/main.yml
:定义角色的元数据信息。yamlCopy code --- dependencies: [] # 角色依赖关系,如果有其他角色依赖需要在这里添加
5.playbook
--- - name: Deploy Nginx web server hosts: webservers # 在哪些主机上执行角色 become: yes # 使用 sudo 运行任务 roles: - webserver # 引入 webserver 角色