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-release2[root@localhost ~]# yum install -y ansible说明:ansible只是一个工具,不需要启动,安装好以后,直接使用即可。并且只有服务端需要安装,客户端不需要安装....
xxxxxxxxxx221`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/hosts3.......4192.168.88.10 server15192.168.88.20 server26192.168.88.30 server37
8# 生成密钥对9[root@ansible ~]# ssh-keygen -P "" -t rsa10.....11# 将公钥发送给需要被管理端,以实现免密登录12
13[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server114[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server215[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@server3编辑/etc/ansible/hosts文件,再最后面添加上被管理端
xxxxxxxxxx291[root@ansible ~]# vim /etc/ansible/hosts2......3......4......5## [dbservers]6##7## db01.intranet.mydomain.net8## db02.intranet.mydomain.net9## 10.25.1.5610## 10.25.1.5711
12# Here's another example of host ranges, this time there are no13# leading 0s:14
15## db-[99:101]-node.example.com16# 定义自己的主机组17[all_servers]18server119server220server321
22[node1]23server124
25[node2]26server227
28[node3]29server3ansible.cfg,默认可以不用改xxxxxxxxxx201[root@localhost ~]# vim /etc/ansible/ansible.cfg2[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.yml12#forks = 5 # 默认的并发数13#poll_interval = 15 # 默认的线程池14#sudo_user = root # 默认的sudo用户15#ask_sudo_pass = True 16#ask_pass = True17#transport = smart18#remote_port = 2219#module_lang = C20#module_set_locale = Falsexxxxxxxxxx91transport = smart2在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的执行状态
测试与主机的连通性
示例:
xxxxxxxxxx291[root@ansible ~]# ansible -m ping all_servers2server1 | 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
xxxxxxxxxx181[root@ansible ~]# ansible-doc -s group2action: group 3gid # 设置组的GID号 4name= # 管理组的名称 5state # 指定组状态,默认为创建,设置值为absent为删除 6system # 设置值为yes,表示为创建系统组7
8[root@ansible ~]# ansible -m group -a "name=IT gid=111 system=yes" node19server1 | 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": true18}用于对用户的创建,修改和删除等操作
xxxxxxxxxx201# 查看某个模块的具体用法2[root@ansible ~]# ansible-doc -l|wc -l33387 #共有3387个模块4[root@ansible ~]# ansible‐doc ‐s user5 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,以及给一个注释
xxxxxxxxxx251[root@ansible ~]# ansible -m user -a "system=yes name=zhangsan home=/home/zhangsan uid=111 groups=IT comment='hello zhangsan'" node12server1 | 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": 11117}18
19
20
21# 删除用户及家目录22[root@ansible ~]# ansible -m user -a "name=zhangsan state=absent remove=yes" node123
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 " node1command模块是ansible默认使用的模块。不支持管道,变量及重定向等
示例:
xxxxxxxxxx221[root@ansible ~]# ansible-doc ‐s command2......3......4[root@ansible ~]# ansible -a "touch /root/ansible.txt" all_servers5[WARNING]: Consider using the file module with state=touch rather than running6'touch'. If you need to use command because file is insufficient you can add7'warn: false' to this command task or set 'command_warnings=False' in8ansible.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_servers17server1 | CHANGED | rc=0 >>18/etc/sysconfig/network-scripts/ifcfg-ens3319server2 | CHANGED | rc=0 >>20/etc/sysconfig/network-scripts/ifcfg-ens3321server3 | CHANGED | rc=0 >>22/etc/sysconfig/network-scripts/ifcfg-ens33在远程主机上执行bash命令
相对于command而言,支持性更好一点,但是对于某些复杂的命令,也可能会执行失败
解决方法:可以把命令卸载脚本中,使用script模块执行脚本到远程主机
xxxxxxxxxx71[root@ansible ~]# ansible -m shell -a "hostname" all_servers2server1 | CHANGED | rc=0 >>3server14server2 | CHANGED | rc=0 >>5server26server3 | CHANGED | rc=0 >>7server3可以发送shell脚本到远程主机上并执行
示例:
xxxxxxxxxx291[root@ansible ~]# vim test.sh23for i in `seq 5`4do5 touch /root/test_${i}.txt6done7
8# script模块9[root@ansible ~]# ansible -m script -a "/root/test.sh" node210server2 | 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 ~]# ls23anaconda-ks.cfg test_1.txt test_3.txt test_5.txt24ansible.txt test_2.txt test_4.txt25
26# 参数说明27chdir参数: 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到 chdir 参数指定的目录中。28creates参数: 使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本29removes参数: 使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本用于向复制文件到主机组中
参数解释:
xxxxxxxxxx101[root@ansible ~]# ansible-doc -s copy2backup:在覆盖之前,将源文件备份,备份文件包含时间信息。 3content:用于替代“src”,可以直接设定指定文件的值 4dest:必选项。要将源文件复制到的远程主机的绝对路径 5directory_mode:递归设定目录的权限,默认为系统默认权限 6force:强制覆盖目的文件内容,默认为yes 7others:所有的file模块里的选项都可以在这里使用 8src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制9
10ansible -m copy -a "src=/本地文件 dest=/远程文件" nodes示例:
xxxxxxxxxx11[root@ansible ~]# ansible -m copy -a "src=/root/test.sh dest=/root/test1 owner=zhangsan group=ansibles" node1xxxxxxxxxx11[root@ansible ~]# ansible -m copy -a "src=/root/test.sh dest=/root/test2 backup=yes mode=777" node1xxxxxxxxxx11[root@ansible ~]# ansible -m copy -a "content='hello ansibles\n' dest=/root/test3" node1用于对文件进行相关操作
参数解释:
xxxxxxxxxx171[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:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其后修改时间示例:
xxxxxxxxxx11[root@ansible ~]# ansible -m file -a "name=test1 owner=root group=root mode=644 state=directory " node1xxxxxxxxxx11[root@ansible ~]# ansible -m file -a "path=/root/test2 owner=root group=root mode=644 state=touch" node1xxxxxxxxxx11[root@ansible ~]# ansible -m file -a "path=/root/test2 state=absent" node1xxxxxxxxxx11[root@ansible ~]# ansible -m file -a "src=/root/test1 dest=/root/test2 state=link" node1xxxxxxxxxx11[root@ansible ~]# ansible -m file -a "src=/root/test.txt dest=/root/test2 state=hard" node2用于远程操作主机下载软件包
参数说明:
xxxxxxxxxx81[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的缓存示例:
xxxxxxxxxx141[root@ansible ~]# ansible -m yum -a "name=httpd state=latest" node32server3 | 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服务类
参数说明:
xxxxxxxxxx131[root@ansible ~]# ansible-doc -s service2> 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重载配置示例:
xxxxxxxxxx101[root@ansible ~]# ansible -m service -a "name=httpd state=started" node32server3 | CHANGED => {3 "ansible_facts": {4 "discovered_interpreter_python": "/usr/bin/python"5 },6 "changed": true,7 "name": "httpd",8 "state": "started"9 .....10 .....用于管理远程主机的selinux设置
参考说明:
xxxxxxxxxx161[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。示例:
xxxxxxxxxx131[root@ansible ~]# ansible -m selinux -a "state=enforcing policy=targeted" node12[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的基本结构如下:
xxxxxxxxxx201- hosts: all2 vars:3 package_name: nginx4 config_file: /etc/nginx/nginx.conf5 tasks:6 - name: Install Nginx7 yum:8 name: "{{ package_name }}"9 state: present10 - name: Copy Nginx configuration11 copy:12 src: nginx.conf13 dest: "{{ config_file }}"14 notify:15 - restart nginx16 handlers:17 - name: restart nginx18 service:19 name: nginx20 state: restarted在上面的例子中,我们定义了以下几个主要字段:
hosts: 指定要运行任务的主机或主机组。vars: 定义要在playbook中使用的变量。tasks: 定义要执行的任务列表。每个任务都有一个名称和一个模块。handlers: 定义当某些任务触发时需要执行的处理程序,比如重启服务。执行playbook剧本:
ansible-playbook xxxxx.yaml即可
安装nginx并且修改配置文件
xxxxxxxxxx121[root@ansible ~]# mkdir -p playbook/conf2[root@ansible ~]# cd playbook/conf3[root@ansible conf]# cat site.conf4server {5 listen 666;6 server_name localhost;7
8 location / {9 root /data;10 index index.html11 }12}xxxxxxxxxx331root@ansible playbook# vim nginx.yaml2nameinstall nginx web server3 hostsnode14 remote_userroot5
6 tasks7nameInstall epel-release8 yum9 nameepel-release10 statelatest11
12nameInstall Nginx13 yum14 namenginx15 statelatest16
17nameCopy conf to nginx.conf.d18 copy19 src/root/playbook/conf/site.conf20 dest/etc/nginx/conf.d/site.conf21
22nameCreate "data" directory23 file24 name/data25 statedirectory26
27nameStart Nginx service28 service29 namenginx30 statestarted31
32namecreate web index file33 shellecho "Install Nginx use Ansible...." > /data/index.htmlAnsible 内置了大量的事实(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循环安装软件包
xxxxxxxxxx81- name: Install packages2 yum:3 name: "{{ item }}"4 state: present5 loop:6 - nginx7 - mysql8 - php或者:
xxxxxxxxxx81- name: Install packages2 yum:3 name: "{{ item }}"4 state: present5 with_items:6 - httpd7 - mysql8 - php这样就可以实现一个yum安装多个软件包了,避免了playbook过于臃肿。
创建一个名为 /home/student/ansible/packages.yml的 playbook:
xxxxxxxxxx281[root@ansible ~]# vim playbook/packages.yml2- name: install pkgs3 hosts: dev,test,prod4 tasks:5 - name: install mariadb php6 yum:7 name: "{{ item }}"8 state: present9 loop:10 - php11 - mariadb12
13- name: install group pkgs14 hosts: dev15 tasks:16 - name: install Development Tools17 yum:18 name: "@Development Tools"19 state: present20
21- name: update pkgs22 hosts: dev23 tasks:24 - name: update pkgs25 yum:26 name: "*"27 state: latest28
循环创建用户,用户信息如下 名称、组、家目录、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 会计
循环创建出以上用户并指定用户信息:
xxxxxxxxxx271[root@ansible ~]# vim playbook/user.yml2- name: Manage user3 hosts: node14 remote_user: root5 tasks:6 - name: Ensure groups xsb, jsb, cwb exist7 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, zhaoqi15 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 表达式来决定是否执行某个任务。
xxxxxxxxxx151nameInstall packages on CentOS 72 yum3 name4httpd5mariadb-server6 statepresent7 whenansible_distribution == 'CentOS' and ansible_distribution_major_version|int == 78
9nameInstall packages on CentOS 810 yum11 name12nginx13mysql-server14 statepresent15 whenansible_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存在,如果不存在,请提示.......
xxxxxxxxxx381[root@ansible playbook]# vim disk.yaml2- name: Create sdb1 partition3 hosts: all_servers4 tasks:5 - name: Check if sdb block device exists6 stat:7 path: /dev/sdb8 register: sdb_stat9
10 - name: Create 1GB partition on sdb11 parted:12 device: /dev/sdb13 number: 114 state: present15 part_end: 1GB16 when: sdb_stat.stat.exists17
18 - name: sdb block device not exists19 debug:20 msg: "sdb block device does not exist, cannot create partition."21 when: not sdb_stat.stat.exists22 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}验证:
xxxxxxxxxx101[root@server2 ~]# lsblk2NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT3sda 8:0 0 20G 0 disk4├─sda1 8:1 0 1G 0 part /boot5└─sda2 8:2 0 19G 0 part6 ├─centos-root 253:0 0 17G 0 lvm /7 └─centos-swap 253:1 0 2G 0 lvm [SWAP]8sdb 8:16 0 2G 0 disk9└─sdb1 8:17 0 953M 0 part10sr0 11:0 1 918M 0 romJinja2是一个功能强大的Python模板引擎,它被广泛应用于Ansible的playbook中。Jinja2模板语法提供了丰富的功能,使得在playbook中插入动态内容变得更加容易和灵活。
简单来讲,就是将原本静态的playbook转变为动态的。
原题(第九题):生成主机文件
题目变更如下:
我们使用jinjia2和ansible内置变量动态的生成hosts文件,并且发送给远程主机
xxxxxxxxxx71[root@ansible playbook]# vim hosts.j22127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain43::1 localhost localhost.localdomain localhost6 localhost6.localdomain64
5{% for host in groups.all_servers %}6{{hostvars[host].ansible_ens33.ipv4.address}} {{hostvars[host].ansible_hostname}}7{% endfor %}xxxxxxxxxx131[root@ansible playbook]# vim hosts.yaml2- name: Config hosts file3 hosts: all_servers4 remote_user: root5
6 tasks:7 - name: copy hosts.j2 to group servers8 template:9 src: hosts.j210 dest: /etc/hosts11 12# 执行该playbook13[root@ansible playbook]# ansible-playbook hosts.yamlxxxxxxxxxx71[root@server1 ~]# cat /etc/hosts2127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain43::1 localhost localhost.localdomain localhost6 localhost6.localdomain64
5192.168.88.10 server16192.168.88.20 server27192.168.88.30 server3我们可以在playbook中自定义变量,然后更具自定义的变量使用jinjia2模板渲染nginx的配置文件
xxxxxxxxxx281[root@ansible ~]# mkdir ansible2[root@ansible ~]# cd ansible3[root@ansible ansible]# vim nginx.yaml4- name: nginx conf5 hosts: node16 remote_user: root7 vars:8 nginx_vhosts:9 - web1:10 listen: 808011 root: "/var/www/nginx/web1/"12 - web2:13 listen: 808014 server_name: "web2.baidu.com"15 root: "/var/www/nginx/web2/"16 - web3:17 listen: 808018 server_name: "web3.baidu.com"19 root: "/var/www/nginx/web3/"20 tasks:21 - name: mkdir /data22 file:23 name: /data24 state: directory25 - name: template config26 template:27 src: /root/ansible/site.conf.j228 dest: /data/nginx.confxxxxxxxxxx101[root@ansible ansible]# vim site.conf.j22{% 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 %}xxxxxxxxxx151[root@server1 ~]# cat /data/nginx.conf2server {3 listen 80804 root /var/www/nginx/web1/5}6server {7 listen 80808 server_name web2.baidu.com9 root /var/www/nginx/web2/10}11server {12 listen 808013 server_name web3.baidu.com14 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中直接调用角色即可.....
xxxxxxxxxx181[root@ansible roles]# tree apache/2apache/3├── defaults4│ └── main.yml5├── files6├── handlers7│ └── main.yml8├── meta9│ └── main.yml10├── README.md11├── tasks12│ └── main.yml13├── templates14├── tests15│ ├── inventory16│ └── test.yml17└── vars18 └── main.ymldefaults/main.yml: 定义角色的默认变量handlers/main.yml: 定义角色的处理程序meta/main.yml: 定义角色的元数据,如依赖关系、作者信息等tasks/main.yml: 定义角色的主要任务templates/: 存放角色使用的模板文件tests/: 存放角色的测试相关文件vars/main.yml: 定义角色的变量可以使用ansible-galaxy工具通过init选项初始化一个角色
xxxxxxxxxx41[root@ansible roles]# ansible-galaxy init apache2- Role apache was created successfully3[root@ansible role]# ls apache/4defaults files handlers meta README.md tasks templates tests varsxxxxxxxxxx221[root@ansible roles]# ansible-galaxy init httpd2- Role httpd was created successfully3[root@ansible role]# tree httpd/4httpd/5├── defaults6│ └── main.yml7├── files8├── handlers9│ └── main.yml10├── meta11│ └── main.yml12├── README.md13├── tasks14│ └── main.yml15├── templates16├── tests17│ ├── inventory18│ └── test.yml19└── vars20 └── main.yml21
228 directories, 8 filesxxxxxxxxxx271[root@ansible httpd]# vim tasks/main.yml2# tasks file for httpd3- name: Install httpd4 yum:5 name: httpd6 state: present7- name: copy site2.conf to apache web server8 copy:9 src: site.conf10 dest: /etc/httpd/conf.d/site2.conf11
12- name: create directory1 for apache web server13 file:14 name: /data/site1/15 state: directory16
17- name: create directory2 for apache web server18 file:19 name: /data/site2/20 state: directory21
22- name: Start httpd23 service:24 name: httpd25 state: started26- name: Write index file27 shell: echo "site1" > /data/site1/index.html && echo "site2" > /data/site2/index.htmlxxxxxxxxxx151[root@ansible httpd]# vim files/site.conf2Listen 80803Listen 90904
5<Directory "/data/">6Require all granted7</Directory>8
9<VirtualHost *:8080>10DocumentRoot "/data/site1/"11</VirtualHost>12
13<VirtualHost *:9090>14DocumentRoot "/data/site2/"15</VirtualHost>xxxxxxxxxx51[root@ansible roles]# vim httpd.yaml2- name: Install httpd web server3 hosts: node14 roles:5 - httpdxxxxxxxxxx91[root@server1 ~]# ss -nlt2State Recv-Q Send-Q Local Address:Port Peer Address:Port3LISTEN 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 的角色:
xxxxxxxxxx451[student@workstation ansible# cd roles/2[student@workstation roles]# ansible-galaxy init apache3[student@workstation roles]# vim apache/tasks/main.yml4---5# tasks file for apache6- name: install http7 yum:8 name: httpd9 state: present10- name: config system service11 service:12 name: "{{ item }}"13 state: started14 enabled: yes15 loop:16 - httpd17 - firewalld18- name: firewalld service19 firewalld:20 zone: public21 service: http22 permanent: yes23 immediate: yes24 state: enabled25- name: user templates26 template:27 src: index.html.j228 dest: /var/www/html/index.html29[student@workstation roles]# vim apache/templates/index.html.j230Welcome to {{ ansible_fqdn }} on {{ ansible_default_ipv4.address }}31
32[student@workstation roles]# cd ..33[student@workstation ansible]# vim newrole.yml34- name: use apache role35 hosts: webservers36 roles:37 - apache38
39# 运行脚本40[student@workstation ansible]# ansible-playbook newrole.yml41# 访问测试42[student@workstation ansible]# curl serverc43Welcome to serverc.lab.example.com on 172.25.250.1244[student@workstation ansible]# curl serverd45Welcome to serverd.lab.example.com on 172.25.250.13#