ansible 是一个开源的自动化运维工具,主要用于系统配置管理、应用部署、任务编排等场景。它使用 YAML 语法编写配置文件,语法简单易懂,学习曲线平缓。ansible 的任务是幂等的,意味着多次执行结果是一致的,不会产生意外结果,非常适合于持续部署和集成。
ansible 支持众多常见操作系统和中间件,具有良好的扩展性。同时它还支持自定义模块,可以满足各种复杂的自动化需求。另一个特点是 ansible 不需要在远程主机上安装任何代理,只需要有 SSH 访问权限即可,并且不需要中央控制节点,使用 SSH 协议直接连接远程主机,部署和维护相对简单。ansible 使用 SSH 进行远程连接和命令执行,保证了数据传输的安全性。
ansible由python开发,集合了众多自动化运维工具的优点,实现了批量系统部署、批量程序部署,批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力,真正具有批量部署能力的是ansible运行的模块,ansible只是提供一个框架。
ansible:ansible核心程序。 HostInventory:记录由ansible管理的主机信息,包括端口、密码、ip等。 Playbooks:“剧本”YAML格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。 CoreModules:核心模块,主要操作是通过调用核心模块来完成管理任务。 CustomModules:自定义模块,完成核心模块无法完成的功能,支持多种语言。 ConnectionPlugins:连接插件,ansible和Host通信使用
1[root@localhost ~]# yum install -y epel-release
2[root@localhost ~]# yum install -y ansible
说明:ansible只是一个工具,不需要启动,安装好以后,直接使用即可。并且只有服务端需要安装,客户端不需要安装....
xxxxxxxxxx
221`Inventory 文件参数:
2-i 或 --inventory: 指定 Inventory 文件的路径
3-l 或 --limit: 限制操作的主机范围
4-g 或 --groups: 指定要操作的主机组
5`剧本(Playbook)参数:
6-p 或 --playbook-dir: 指定 Playbook 所在目录
7-e 或 --extra-vars: 传递额外的变量
8`任务(Task)参数:
9-m 或 --module-name: 指定要使用的模块名称
10-a 或 --args: 传递模块的参数
11`连接参数:
12-c 或 --connection: 指定连接类型,如 ssh、local 等
13-u 或 --user: 指定远程连接的用户
14`输出参数:
15-v 或 --verbose: 增加输出信息的详细程度
16--check: 进行一次"试运行",不会实际改变任何状态
17--diff: 显示配置文件的改动情况
18`其他参数:
19-f 或 --forks: 指定并行执行的进程数
20-t 或 --tags: 只执行带有指定 tag 的任务
21--list-hosts: 列出受管主机
22--list-tasks: 列出所有任务
实验环境:四台Linux虚拟机,HOSTNAME分别为:ansible、server1、server2、server3
其中,ansible做为服务端,其他server均作为客户端
x1# 在ansible上修改hosts文件,方便使用主机名管理主机
2[root@ansible ~]# vim /etc/hosts
3.......
4192.168.88.10 server1
5192.168.88.20 server2
6192.168.88.30 server3
7
8# 生成密钥对
9[root@ansible ~]# ssh-keygen -P "" -t rsa
10.....
11# 将公钥发送给需要被管理端,以实现免密登录
12
13[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server1
14[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server2
15[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server3
编辑/etc/ansible/hosts
文件,再最后面添加上被管理端
xxxxxxxxxx
291[root@ansible ~]# vim /etc/ansible/hosts
2......
3......
4......
5## [dbservers]
6##
7## db01.intranet.mydomain.net
8## db02.intranet.mydomain.net
9## 10.25.1.56
10## 10.25.1.57
11
12# Here's another example of host ranges, this time there are no
13# leading 0s:
14
15## db-[99:101]-node.example.com
16# 定义自己的主机组
17[all_servers]
18server1
19server2
20server3
21
22[node1]
23server1
24
25[node2]
26server2
27
28[node3]
29server3
ansible.cfg
,默认可以不用改xxxxxxxxxx
201[root@localhost ~]# vim /etc/ansible/ansible.cfg
2[defaults]
3
4# some basic default values...
5
6#inventory = /etc/ansible/hosts # 定义主机清单文件
7#library = /usr/share/my_modules/ # 库文件的存放位置
8#module_utils = /usr/share/my_module_utils/
9#remote_tmp = ~/.ansible/tmp # 生成的临时py文件在远程主机的目录
10#local_tmp = ~/.ansible/tmp # 生成的临时py文件在本地主机的目录
11#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
12#forks = 5 # 默认的并发数
13#poll_interval = 15 # 默认的线程池
14#sudo_user = root # 默认的sudo用户
15#ask_sudo_pass = True
16#ask_pass = True
17#transport = smart
18#remote_port = 22
19#module_lang = C
20#module_set_locale = False
xxxxxxxxxx
91transport = smart
2在ansible配置中,transport = smart 是指定 ansible 用于远程连接的传输机制。smart 是 ansible 的默认传输选项,它会尝试根据环境自动选择最佳的传输机制。
3
4当 smart 被设置时,ansible 会按照以下顺序尝试不同的传输机制:
5
6如果已经建立了 SSH 连接(例如,通过 SSH Agent 或者在 ansible.cfg 中配置了 SSH 连接参数),则使用 SSH 传输。
7如果未建立 SSH 连接,并且目标主机是本地主机,则使用本地传输(即直接在本地执行命令)。
8如果未建立 SSH 连接,并且目标主机是远程主机,则使用 Paramiko 传输(基于 Python 的 SSH2 实现)。
9通过使用 smart 选项,ansible 可以自动选择合适的传输机制,以确保在不同的环境中都能正常工作。如果您希望显式地指定传输机制,可以将 transport 设置为 ssh、local 或 paramiko,以强制使用相应的传输方式。
ansible的执行状态
测试与主机的连通性
示例:
xxxxxxxxxx
291[root@ansible ~]# ansible -m ping all_servers
2server1 | SUCCESS => {
3 "ansible_facts": {
4 "discovered_interpreter_python": "/usr/bin/python"
5 },
6 "changed": false,
7 "ping": "pong"
8}
9server3 | SUCCESS => {
10 "ansible_facts": {
11 "discovered_interpreter_python": "/usr/bin/python"
12 },
13 "changed": false,
14 "ping": "pong"
15}
16server2 | SUCCESS => {
17 "ansible_facts": {
18 "discovered_interpreter_python": "/usr/bin/python"
19 },
20 "changed": false,
21 "ping": "pong"
22}
23
24# 返回说明:
25"SUCCESS" 表示 ansible 成功执行了任务,没有遇到错误。
26"ansible_facts" 是一个包含 ansible 任务执行期间收集到的事实(facts)的字典。
27"discovered_interpreter_python" 是一个收集到的事实,它指示目标主机上的 Python 解释器的路径为 /usr/bin/python。这对于后续的 ansible 任务可能需要使用 Python 的情况很有用。
28"changed" 表示 ansible 是否对目标主机进行了更改。在这种情况下,值为 false 表示没有进行任何更改。
29"ping" 是一个简单的回应,用于测试与目标主机的连通性。如果值为 "pong",表示与目标主机的连接正常。
用户创建和修改用户组
示例:对node1主机组的成员创建一个IT组,组ID为111
xxxxxxxxxx
181[root@ansible ~]# ansible-doc -s group
2action: group
3gid # 设置组的GID号
4name= # 管理组的名称
5state # 指定组状态,默认为创建,设置值为absent为删除
6system # 设置值为yes,表示为创建系统组
7
8[root@ansible ~]# ansible -m group -a "name=IT gid=111 system=yes" node1
9server1 | CHANGED => {
10 "ansible_facts": {
11 "discovered_interpreter_python": "/usr/bin/python"
12 },
13 "changed": true,
14 "gid": 111,
15 "name": "IT",
16 "state": "present",
17 "system": true
18}
用于对用户的创建,修改和删除等操作
xxxxxxxxxx
201# 查看某个模块的具体用法
2[root@ansible ~]# ansible-doc -l|wc -l
33387 #共有3387个模块
4[root@ansible ~]# ansible‐doc ‐s user
5 comment # 用户的描述信息
6 createhom # 是否创建家目录
7 force # 在使用`state=absent'是, 行为与`userdel ‐‐force'一致.
8 group # 指定基本组
9 groups # 指定附加组,如果指定为('groups=')表示删除所有组
10 home # 指定用户家目录
11 name # 指定用户名
12 password # 指定用户密码
13 remove # 在使用 `state=absent'时, 行为是与 `userdel ‐‐remove'一致.
14 shell # 指定默认shell
15 state #设置帐号状态,不指定为创建,指定值为absent表示删除
16 system # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
17 uid #指定用户的uid
18 update_password # 更新用户密码
19 expires #指明密码的过期时间
20 ......
示例:在主机组node1上创建一个系统用户张三,家目录为/home/zhangsan,uid为111,附加组为IT,以及给一个注释
xxxxxxxxxx
251[root@ansible ~]# ansible -m user -a "system=yes name=zhangsan home=/home/zhangsan uid=111 groups=IT comment='hello zhangsan'" node1
2server1 | CHANGED => {
3 "ansible_facts": {
4 "discovered_interpreter_python": "/usr/bin/python"
5 },
6 "changed": true,
7 "comment": "hello zhangsan",
8 "create_home": true,
9 "group": 995,
10 "groups": "IT",
11 "home": "/home/zhangsan",
12 "name": "zhangsan",
13 "shell": "/bin/bash",
14 "state": "present",
15 "system": true,
16 "uid": 111
17}
18
19
20
21# 删除用户及家目录
22[root@ansible ~]# ansible -m user -a "name=zhangsan state=absent remove=yes" node1
23
24# 添加系统用户,指定uid、家目录、主组及注释、密码
25[root@ansible ~]# ansible -m user -a "system=yes name=zhangsan home=/home/zhangsan uid=111 group=root comment='hello zhangsan' password='123456' shell=/bin/cbash " node1
command模块是ansible默认使用的模块。不支持管道,变量及重定向等
示例:
xxxxxxxxxx
221[root@ansible ~]# ansible-doc ‐s command
2......
3......
4[root@ansible ~]# ansible -a "touch /root/ansible.txt" all_servers
5[WARNING]: Consider using the file module with state=touch rather than running
6'touch'. If you need to use command because file is insufficient you can add
7'warn: false' to this command task or set 'command_warnings=False' in
8ansible.cfg to get rid of this message.
9server2 | CHANGED | rc=0 >>
10
11server1 | CHANGED | rc=0 >>
12
13server3 | CHANGED | rc=0 >>
14
15
16[root@ansible ~]# ansible -a "find / -name ifcfg-ens33" all_servers
17server1 | CHANGED | rc=0 >>
18/etc/sysconfig/network-scripts/ifcfg-ens33
19server2 | CHANGED | rc=0 >>
20/etc/sysconfig/network-scripts/ifcfg-ens33
21server3 | CHANGED | rc=0 >>
22/etc/sysconfig/network-scripts/ifcfg-ens33
在远程主机上执行bash命令
相对于command而言,支持性更好一点,但是对于某些复杂的命令,也可能会执行失败
解决方法:可以把命令卸载脚本中,使用script模块执行脚本到远程主机
xxxxxxxxxx
71[root@ansible ~]# ansible -m shell -a "hostname" all_servers
2server1 | CHANGED | rc=0 >>
3server1
4server2 | CHANGED | rc=0 >>
5server2
6server3 | CHANGED | rc=0 >>
7server3
可以发送shell脚本到远程主机上并执行
示例:
xxxxxxxxxx
291[root@ansible ~]# vim test.sh
2
3for i in `seq 5`
4do
5 touch /root/test_${i}.txt
6done
7
8# script模块
9[root@ansible ~]# ansible -m script -a "/root/test.sh" node2
10server2 | CHANGED => {
11 "changed": true,
12 "rc": 0,
13 "stderr": "Shared connection to server2 closed.\r\n",
14 "stderr_lines": [
15 "Shared connection to server2 closed."
16 ],
17 "stdout": "",
18 "stdout_lines": []
19}
20
21# server2验证
22[root@server2 ~]# ls
23anaconda-ks.cfg test_1.txt test_3.txt test_5.txt
24ansible.txt test_2.txt test_4.txt
25
26# 参数说明
27chdir参数: 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到 chdir 参数指定的目录中。
28creates参数: 使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本
29removes参数: 使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本
用于向复制文件到主机组中
参数解释:
xxxxxxxxxx
101[root@ansible ~]# ansible-doc -s copy
2backup:在覆盖之前,将源文件备份,备份文件包含时间信息。
3content:用于替代“src”,可以直接设定指定文件的值
4dest:必选项。要将源文件复制到的远程主机的绝对路径
5directory_mode:递归设定目录的权限,默认为系统默认权限
6force:强制覆盖目的文件内容,默认为yes
7others:所有的file模块里的选项都可以在这里使用
8src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制
9
10ansible -m copy -a "src=/本地文件 dest=/远程文件" nodes
示例:
xxxxxxxxxx
11[root@ansible ~]# ansible -m copy -a "src=/root/test.sh dest=/root/test1 owner=zhangsan group=ansibles" node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m copy -a "src=/root/test.sh dest=/root/test2 backup=yes mode=777" node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m copy -a "content='hello ansibles\n' dest=/root/test3" node1
用于对文件进行相关操作
参数解释:
xxxxxxxxxx
171[root@ansible ~]# ansible‐doc ‐s file
2‐ name: Sets attributes of files
3 force:需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
4 group:定义文件/目录的属组
5 mode:定义文件/目录的权限
6 owner:定义文件/目录的属主
7 path:必选项,定义文件/目录的路径
8 recurse:递归设置文件的属性,只对目录有效
9 src:被链接的源文件路径,只应用于state=link的情况
10 dest:被链接到的路径,只应用于state=link的情况
11 state:
12 absent: 删除文件
13 directory:如果目录不存在,就创建目录
14 file:验证文件是否存在,即使文件不存在,也不会被创建
15 link:创建软链接
16 hard:创建硬链接
17 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其后修改时间
示例:
xxxxxxxxxx
11[root@ansible ~]# ansible -m file -a "name=test1 owner=root group=root mode=644 state=directory " node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m file -a "path=/root/test2 owner=root group=root mode=644 state=touch" node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m file -a "path=/root/test2 state=absent" node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m file -a "src=/root/test1 dest=/root/test2 state=link" node1
xxxxxxxxxx
11[root@ansible ~]# ansible -m file -a "src=/root/test.txt dest=/root/test2 state=hard" node2
用于远程操作主机下载软件包
参数说明:
xxxxxxxxxx
81[root@ansible ~]# ansible‐doc ‐s yum
2 conf_file #设定远程yum安装时所依赖的配置文件。如配置文件没有在默认的位置。
3 disable_gpg_check #是否禁止GPG checking,只用于`present' or `latest'。
4 disablerepo #临时禁止使用yum库。 只用于安装或更新时。
5 enablerepo #临时使用的yum库。只用于安装或更新时。
6 name= #所安装的包的名称
7 state #present安装, latest安装最新的, absent 卸载软件。
8 update_cache #强制更新yum的缓存
示例:
xxxxxxxxxx
141[root@ansible ~]# ansible -m yum -a "name=httpd state=latest" node3
2server3 | CHANGED => {
3 "ansible_facts": {
4 "discovered_interpreter_python": "/usr/bin/python"
5 },
6 "changed": true,
7 "changes": {
8 "installed": [
9 "httpd"
10 ],
11 "updated": []
12 },
13 "msg": "",
14 "rc": 0,
用于远程管理主机上的service服务类
参数说明:
xxxxxxxxxx
131[root@ansible ~]# ansible-doc -s service
2> SERVICE (/usr/lib/python2.7/site‐packages/ansible/modules/system/service.py)
3 Controls services on remote hosts. Supported init systems include BSD init, OpenRC, SysV, Solaris
4 SMF, systemd, upstart. For Windows targets, use the [win_service] module instead.
5 * note: This module has a corresponding action plugin.
6 ......
7 ......
8 arguments #命令行提供额外的参数
9 enabled #设置开机启动,可以设置为yes或者no。
10 name= #服务名称
11 runlevel #开机启动的级别,一般不用指定。
12 sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。
13 state #started启动服务, stopped停止服务, restarted重启服务, reloaded重载配置
示例:
xxxxxxxxxx
101[root@ansible ~]# ansible -m service -a "name=httpd state=started" node3
2server3 | CHANGED => {
3 "ansible_facts": {
4 "discovered_interpreter_python": "/usr/bin/python"
5 },
6 "changed": true,
7 "name": "httpd",
8 "state": "started"
9 .....
10 .....
用于管理远程主机的selinux设置
参考说明:
xxxxxxxxxx
161[root@node1 ~]# ansible-doc -s selinux
2# selinux模块针对selinux的修改操作是针对配置文件进行修改的
3‐ name: Change policy and state of SELinux
4configfile:
5描述: SELinux 配置文件的路径,如果不是标准路径。
6参数类型: 字符串
7policy:
8描述: 要使用的 SELinux 策略的名称。
9参数类型: 字符串
10state:
11描述: (必需) SELinux 的模式。
12参数类型: 字符串
13可选值:
14enforcing: 强制 SELinux 策略生效。
15permissive: 以警告模式运行 SELinux,不会阻止任何操作。
16disabled: 完全禁用 SELinux。
示例:
xxxxxxxxxx
131[root@ansible ~]# ansible -m selinux -a "state=enforcing policy=targeted" node1
2[WARNING]: Reboot is required to set SELinux state to 'enforcing'
3server1 | CHANGED => {
4 "ansible_facts": {
5 "discovered_interpreter_python": "/usr/bin/python"
6 },
7 "changed": true,
8 "configfile": "/etc/selinux/config",
9 "msg": "Config SELinux state changed from 'disabled' to 'enforcing'",
10 "policy": "targeted",
11 "reboot_required": true,
12 "state": "enforcing"
13}
Ansible playbook是一种可执行的YAML文件,用于描述如何部署和配置一个系统或应用程序。一个playbook由一个或多个play组成,每个play都针对特定的主机或主机组执行一系列任务。
一个playbook的基本结构如下:
xxxxxxxxxx
201- hosts: all
2 vars:
3 package_name: nginx
4 config_file: /etc/nginx/nginx.conf
5 tasks:
6 - name: Install Nginx
7 yum:
8 name: "{{ package_name }}"
9 state: present
10 - name: Copy Nginx configuration
11 copy:
12 src: nginx.conf
13 dest: "{{ config_file }}"
14 notify:
15 - restart nginx
16 handlers:
17 - name: restart nginx
18 service:
19 name: nginx
20 state: restarted
在上面的例子中,我们定义了以下几个主要字段:
hosts
: 指定要运行任务的主机或主机组。vars
: 定义要在playbook中使用的变量。tasks
: 定义要执行的任务列表。每个任务都有一个名称和一个模块。handlers
: 定义当某些任务触发时需要执行的处理程序,比如重启服务。执行playbook剧本:
ansible-playbook xxxxx.yaml
即可
安装nginx并且修改配置文件
xxxxxxxxxx
121[root@ansible ~]# mkdir -p playbook/conf
2[root@ansible ~]# cd playbook/conf
3[root@ansible conf]# cat site.conf
4server {
5 listen 666;
6 server_name localhost;
7
8 location / {
9 root /data;
10 index index.html
11 }
12}
xxxxxxxxxx
331 root@ansible playbook # vim nginx.yaml
2name install nginx web server
3 hosts node1
4 remote_user root
5
6 tasks
7name Install epel-release
8 yum
9 name epel-release
10 state latest
11
12name Install Nginx
13 yum
14 name nginx
15 state latest
16
17name Copy conf to nginx.conf.d
18 copy
19 src /root/playbook/conf/site.conf
20 dest /etc/nginx/conf.d/site.conf
21
22name Create "data" directory
23 file
24 name /data
25 state directory
26
27name Start Nginx service
28 service
29 name nginx
30 state started
31
32name create web index file
33 shell echo "Install Nginx use Ansible...." > /data/index.html
Ansible 内置了大量的事实(fact)变量,可以在 Playbook 中使用。这些事实变量可以帮助我们更好地了解目标主机的环境和配置信息,从而编写更加智能和动态的自动化脚本。
常用的内置事实变量包括:
操作系统信息:
ansible_distribution
: 操作系统发行版名称,如 "CentOS"、"Ubuntu"ansible_distribution_version
: 操作系统版本号ansible_os_family
: 操作系统家族,如 "RedHat"、"Debian"ansible_kernel
: 内核版本硬件信息:
ansible_processor
: CPU 型号ansible_processor_vcpus
: 虚拟 CPU 核数ansible_memtotal_mb
: 内存总量(MB)ansible_architecture
: CPU 架构,如 "x86_64"网络信息:
ansible_default_ipv4
: 默认 IPv4 地址和网关ansible_all_ipv4_addresses
: 所有 IPv4 地址ansible_interfaces
: 所有网络接口名称ansible_hostname
: 主机名其他信息:
ansible_user_id
: 当前执行 Ansible 的用户 IDansible_date_time
: 主机当前日期和时间ansible_env
: 主机环境变量ansible_play_hosts
: 当前 play 中涉及的所有主机这些事实变量可以帮助我们编写出更加智能和定制化的 Playbook。比如,我们可以根据操作系统的不同,执行不同的软件包安装任务;根据 CPU 架构,选择合适的软件包版本;根据内存大小,调整应用程序的配置等。
在playbook中,可以使用循环进行数据的迭代。这样一个模块就可以执行多次任务,因为往往我们部署一个服务的时候,都需要安装多个软件包的。
示例:使用yum循环安装软件包
xxxxxxxxxx
81- name: Install packages
2 yum:
3 name: "{{ item }}"
4 state: present
5 loop:
6 - nginx
7 - mysql
8 - php
或者:
xxxxxxxxxx
81- name: Install packages
2 yum:
3 name: "{{ item }}"
4 state: present
5 with_items:
6 - httpd
7 - mysql
8 - php
这样就可以实现一个yum安装多个软件包了,避免了playbook过于臃肿。
创建一个名为 /home/student/ansible/packages.yml的 playbook:
xxxxxxxxxx
281[root@ansible ~]# vim playbook/packages.yml
2- name: install pkgs
3 hosts: dev,test,prod
4 tasks:
5 - name: install mariadb php
6 yum:
7 name: "{{ item }}"
8 state: present
9 loop:
10 - php
11 - mariadb
12
13- name: install group pkgs
14 hosts: dev
15 tasks:
16 - name: install Development Tools
17 yum:
18 name: "@Development Tools"
19 state: present
20
21- name: update pkgs
22 hosts: dev
23 tasks:
24 - name: update pkgs
25 yum:
26 name: "*"
27 state: latest
28
循环创建用户,用户信息如下 名称、组、家目录、shell、描述信息 zhangsan xsb /home/xsb/zhangsan /bin/bash 销售 lisi xsb /home/xsb/lisi /bin/bash 销售 wangwu jsb /home/jsb/wangwu /bin/sh java工程师 maliu jsb /home/jsb/maliu /bin/sh linux工程师 zhaoqi cwb /home/cwb/zhaoqi /bin/sh 会计
循环创建出以上用户并指定用户信息:
xxxxxxxxxx
271[root@ansible ~]# vim playbook/user.yml
2- name: Manage user
3 hosts: node1
4 remote_user: root
5 tasks:
6 - name: Ensure groups xsb, jsb, cwb exist
7 group:
8 name: "{{ item.group }}"
9 with_items:
10 - { group: xsb }
11 - { group: jsb }
12 - { group: cwb }
13
14 - name: Create users zhangsan, lisi, wangwu, maliu, zhaoqi
15 user:
16 name: "{{ item.name }}"
17 group: "{{ item.group }}"
18 shell: "{{ item.shell }}"
19 comment: "{{ item.comment }}"
20 home: "{{ item.home }}"
21 with_items:
22 - { name: 'zhangsan', group: 'xsb', home: '/home/xsb/zhangsan', shell: '/bin/bash', comment: '销售' }
23 - { name: 'lisi', group: 'xsb', home: '/home/xsb/lisi', shell: '/bin/bash', comment: '销售' }
24 - { name: 'wangwu', group: 'jsb', home: '/home/jsb/wangwu', shell: '/bin/sh', comment: 'java工程师' }
25 - { name: 'maliu', group: 'jsb', home: '/home/jsb/maliu', shell: '/bin/sh', comment: 'linux工程师' }
26 - { name: 'zhaoqi', group: 'cwb', home: '/home/cwb/zhaoqi', shell: '/bin/sh', comment: '会计' }
27
在 Ansible Playbook 中,我们可以使用条件判断语句来根据不同的条件执行不同的任务。
when 语句:
when
语句是最常用的条件判断语句。它可以根据变量的值、事实(facts)或者 Jinja2 表达式来决定是否执行某个任务。
xxxxxxxxxx
151name Install packages on CentOS 7
2 yum
3 name
4 httpd
5 mariadb-server
6 state present
7 when ansible_distribution == 'CentOS' and ansible_distribution_major_version|int == 7
8
9name Install packages on CentOS 8
10 yum
11 name
12 nginx
13 mysql-server
14 state present
15 when ansible_distribution == 'CentOS' and ansible_distribution_major_version|int == 8
在这个例子中:
when
语句确保了只有在 ansible_distribution
等于 'CentOS' 且 ansible_distribution_major_version
等于 7 时,这个任务才会执行。when
语句确保了只有在 ansible_distribution
等于 'CentOS' 且 ansible_distribution_major_version
等于 8 时,这个任务才会执行。考试原题(第八题):
创建一个名为/home/student/ansible/parted.yml 的playbook,它将在dev主机组上运行下列任务
简化题目:在所有机器上创建sdb1分区,大小为1Gib,前提是sdb存在,如果不存在,请提示.......
xxxxxxxxxx
381[root@ansible playbook]# vim disk.yaml
2- name: Create sdb1 partition
3 hosts: all_servers
4 tasks:
5 - name: Check if sdb block device exists
6 stat:
7 path: /dev/sdb
8 register: sdb_stat
9
10 - name: Create 1GB partition on sdb
11 parted:
12 device: /dev/sdb
13 number: 1
14 state: present
15 part_end: 1GB
16 when: sdb_stat.stat.exists
17
18 - name: sdb block device not exists
19 debug:
20 msg: "sdb block device does not exist, cannot create partition."
21 when: not sdb_stat.stat.exists
22
23
24
25# Output:
26TASK [Create 1GB partition on sdb] ************************************ *********
27skipping: [server1]
28skipping: [server3]
29changed: [server2]
30
31TASK [sdb block device not exists] ************************************ *********
32ok: [server1] => {
33 "msg": "sdb block device does not exist, cannot create partition."
34}
35skipping: [server2]
36ok: [server3] => {
37 "msg": "sdb block device does not exist, cannot create partition."
38}
验证:
xxxxxxxxxx
101[root@server2 ~]# lsblk
2NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
3sda 8:0 0 20G 0 disk
4├─sda1 8:1 0 1G 0 part /boot
5└─sda2 8:2 0 19G 0 part
6 ├─centos-root 253:0 0 17G 0 lvm /
7 └─centos-swap 253:1 0 2G 0 lvm [SWAP]
8sdb 8:16 0 2G 0 disk
9└─sdb1 8:17 0 953M 0 part
10sr0 11:0 1 918M 0 rom
Jinja2是一个功能强大的Python模板引擎,它被广泛应用于Ansible的playbook中。Jinja2模板语法提供了丰富的功能,使得在playbook中插入动态内容变得更加容易和灵活。
简单来讲,就是将原本静态的playbook转变为动态的。
原题(第九题):生成主机文件
题目变更如下:
我们使用jinjia2和ansible内置变量动态的生成hosts文件,并且发送给远程主机
xxxxxxxxxx
71[root@ansible playbook]# vim hosts.j2
2127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
3::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
4
5{% for host in groups.all_servers %}
6{{hostvars[host].ansible_ens33.ipv4.address}} {{hostvars[host].ansible_hostname}}
7{% endfor %}
xxxxxxxxxx
131[root@ansible playbook]# vim hosts.yaml
2- name: Config hosts file
3 hosts: all_servers
4 remote_user: root
5
6 tasks:
7 - name: copy hosts.j2 to group servers
8 template:
9 src: hosts.j2
10 dest: /etc/hosts
11
12# 执行该playbook
13[root@ansible playbook]# ansible-playbook hosts.yaml
xxxxxxxxxx
71[root@server1 ~]# cat /etc/hosts
2127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
3::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
4
5192.168.88.10 server1
6192.168.88.20 server2
7192.168.88.30 server3
我们可以在playbook中自定义变量,然后更具自定义的变量使用jinjia2模板渲染nginx的配置文件
xxxxxxxxxx
281[root@ansible ~]# mkdir ansible
2[root@ansible ~]# cd ansible
3[root@ansible ansible]# vim nginx.yaml
4- name: nginx conf
5 hosts: node1
6 remote_user: root
7 vars:
8 nginx_vhosts:
9 - web1:
10 listen: 8080
11 root: "/var/www/nginx/web1/"
12 - web2:
13 listen: 8080
14 server_name: "web2.baidu.com"
15 root: "/var/www/nginx/web2/"
16 - web3:
17 listen: 8080
18 server_name: "web3.baidu.com"
19 root: "/var/www/nginx/web3/"
20 tasks:
21 - name: mkdir /data
22 file:
23 name: /data
24 state: directory
25 - name: template config
26 template:
27 src: /root/ansible/site.conf.j2
28 dest: /data/nginx.conf
xxxxxxxxxx
101[root@ansible ansible]# vim site.conf.j2
2{% for vhost in nginx_vhosts %}
3server {
4 listen {{ vhost.listen }}
5 {% if vhost.server_name is defined %}
6server_name {{ vhost.server_name }}
7 {% endif %}
8root {{ vhost.root }}
9}
10{% endfor %}
xxxxxxxxxx
151[root@server1 ~]# cat /data/nginx.conf
2server {
3 listen 8080
4 root /var/www/nginx/web1/
5}
6server {
7 listen 8080
8 server_name web2.baidu.com
9 root /var/www/nginx/web2/
10}
11server {
12 listen 8080
13 server_name web3.baidu.com
14 root /var/www/nginx/web3/
15}
Ansible 中的 Role 是一种组织和重用代码的强大方式。角色可以帮助你将相关的任务、变量、文件等集中管理,使得代码更加模块化和可重用。
如果将所有的play都写在一个playbook中,很容易导致这个playbook文件变得臃肿庞大,且不易读。因此,可以将多个不同任务分别写在不同的playbook中,然后使用include将其包含进去即可。而role则是整合playbook的方式。无论是include还是role,其目的都是分割大playbook以及复用某些细化的play甚至是task。
在角色中,将task,templates,handlers,files等内容都分开存放,然后再playbook中直接调用角色即可.....
xxxxxxxxxx
181[root@ansible roles]# tree apache/
2apache/
3├── defaults
4│ └── main.yml
5├── files
6├── handlers
7│ └── main.yml
8├── meta
9│ └── main.yml
10├── README.md
11├── tasks
12│ └── main.yml
13├── templates
14├── tests
15│ ├── inventory
16│ └── test.yml
17└── vars
18 └── main.yml
defaults/main.yml
: 定义角色的默认变量handlers/main.yml
: 定义角色的处理程序meta/main.yml
: 定义角色的元数据,如依赖关系、作者信息等tasks/main.yml
: 定义角色的主要任务templates/
: 存放角色使用的模板文件tests/
: 存放角色的测试相关文件vars/main.yml
: 定义角色的变量可以使用ansible-galaxy工具通过init选项初始化一个角色
xxxxxxxxxx
41[root@ansible roles]# ansible-galaxy init apache
2- Role apache was created successfully
3[root@ansible role]# ls apache/
4defaults files handlers meta README.md tasks templates tests vars
xxxxxxxxxx
221[root@ansible roles]# ansible-galaxy init httpd
2- Role httpd was created successfully
3[root@ansible role]# tree httpd/
4httpd/
5├── defaults
6│ └── main.yml
7├── files
8├── handlers
9│ └── main.yml
10├── meta
11│ └── main.yml
12├── README.md
13├── tasks
14│ └── main.yml
15├── templates
16├── tests
17│ ├── inventory
18│ └── test.yml
19└── vars
20 └── main.yml
21
228 directories, 8 files
xxxxxxxxxx
271[root@ansible httpd]# vim tasks/main.yml
2# tasks file for httpd
3- name: Install httpd
4 yum:
5 name: httpd
6 state: present
7- name: copy site2.conf to apache web server
8 copy:
9 src: site.conf
10 dest: /etc/httpd/conf.d/site2.conf
11
12- name: create directory1 for apache web server
13 file:
14 name: /data/site1/
15 state: directory
16
17- name: create directory2 for apache web server
18 file:
19 name: /data/site2/
20 state: directory
21
22- name: Start httpd
23 service:
24 name: httpd
25 state: started
26- name: Write index file
27 shell: echo "site1" > /data/site1/index.html && echo "site2" > /data/site2/index.html
xxxxxxxxxx
151[root@ansible httpd]# vim files/site.conf
2Listen 8080
3Listen 9090
4
5<Directory "/data/">
6Require all granted
7</Directory>
8
9<VirtualHost *:8080>
10DocumentRoot "/data/site1/"
11</VirtualHost>
12
13<VirtualHost *:9090>
14DocumentRoot "/data/site2/"
15</VirtualHost>
xxxxxxxxxx
51[root@ansible roles]# vim httpd.yaml
2- name: Install httpd web server
3 hosts: node1
4 roles:
5 - httpd
xxxxxxxxxx
91[root@server1 ~]# ss -nlt
2State Recv-Q Send-Q Local Address:Port Peer Address:Port
3LISTEN 0 128 *:22 *:*
4LISTEN 0 100 127.0.0.1:25 *:*
5LISTEN 0 128 :::8080 :::*
6LISTEN 0 128 :::80 :::*
7LISTEN 0 128 :::22 :::*
8LISTEN 0 100 ::1:25 :::*
9LISTEN 0 128 :::9090 :::*
题目(第六题):
根据下列要求,在 /home/student/ansible/roles中创建名为 apache 的角色:
xxxxxxxxxx
451[student@workstation ansible# cd roles/
2[student@workstation roles]# ansible-galaxy init apache
3[student@workstation roles]# vim apache/tasks/main.yml
4---
5# tasks file for apache
6- name: install http
7 yum:
8 name: httpd
9 state: present
10- name: config system service
11 service:
12 name: "{{ item }}"
13 state: started
14 enabled: yes
15 loop:
16 - httpd
17 - firewalld
18- name: firewalld service
19 firewalld:
20 zone: public
21 service: http
22 permanent: yes
23 immediate: yes
24 state: enabled
25- name: user templates
26 template:
27 src: index.html.j2
28 dest: /var/www/html/index.html
29[student@workstation roles]# vim apache/templates/index.html.j2
30Welcome to {{ ansible_fqdn }} on {{ ansible_default_ipv4.address }}
31
32[student@workstation roles]# cd ..
33[student@workstation ansible]# vim newrole.yml
34- name: use apache role
35 hosts: webservers
36 roles:
37 - apache
38
39# 运行脚本
40[student@workstation ansible]# ansible-playbook newrole.yml
41# 访问测试
42[student@workstation ansible]# curl serverc
43Welcome to serverc.lab.example.com on 172.25.250.12
44[student@workstation ansible]# curl serverd
45Welcome to serverd.lab.example.com on 172.25.250.13
#