当前位置: 首页 > news >正文

Ansible文件部署与大项目多主机管理

Ansible 部署文件到受管主机

实验环境

[wsh@controller ansible ✔]$ pwd
/home/wsh/ansible
[wsh@controller ansible ✔]$ ls
ansible.cfg  inventory
[wsh@controller ansible ✔]$ cat ansible.cfg inventory 
[defaults]
inventory = ./inventory
remote_user = wsh[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[controllers]
controller[nodes]
node[1:4]

修改文件并将其复制到主机

红帽Ansible引擎本身内置附带了大型模块集合(模块库),为了便于整理、记录和管理这些模块,已根据文档中的功能以及在系统上安装的时间将它们分成多个组。

Files 模块库包含的模块允许您完成与Linux文件管理相关的大多数任务,如创建、复制、编辑和修改文件的权限和其他属性,下表列出了常用的Files模块库中使用的模块。

  • file:设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬链接和目录的时间戳等属性。此模块还可以创建或删除常规文件、符号链接、硬链接和目录。
  • sefcontext,设置持久selinux上下文。
  • lineinfile:确保特定行位于某个文件中,或使用反向引用正则表达式来替换现有行。
  • replace:查找文件中行,一次性替换成对应内容。
  • blockinfile:插入、更新或删除多行文本块。
  • stat:检索文件的状态信息,类似于Linux stat命令。
  • copy:将文件从本地或远程计算机复制到受管节点上的某个位置。
  • synchronize:围绕rsync命令的一个程序,可加快和简化常见任务。
  • fetch:用于从远程计算机获取文件到控制节点。

file 模块

**示例1:**创建文件或修改文件属性

---
- hosts: node1gather_facts: notasks:- name: Touch a file and set permissionsfile:path: /tmp/testfileowner: laomagroup: wheelmode: 0640state: touch

mode选项: 必须使用前导0 (‘0644’ or ‘01777’) 或者引起来 (‘‘644’’ or ‘‘1777’’) 。如果直接写640,则会640当做10进制,并转换成二进制1 010 000 000,最终文件权限是-w- — --T。

**示例2:**创建目录

---
- hosts: node1gather_facts: notasks:- name: create directoryfile:path: /webdevowner: apachegroup: apachemode: 0755state: directory                 

**示例3:**删除文件

---
- hosts: node1gather_facts: notasks:- name: delete file file:path: /tmp/testfilestate: absent

sefcontext 模块

selinux库中添加默认规则。

示例:

---
- hosts: node1gather_facts: notasks:- sefcontext:target: '/samba(/.*)?'setype: samba_share_tstate: present

注意:

  • sefcontext模块是修改selinux 库规则,并不会立刻应用于文件,relabel时候才会生效。
  • file模块会立刻应用于文件。

lineinfile 模块

示例1:确保文件中存在特定行

---
- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /tmp/testfileline: 'Add this line to file'state: present

还可以在特定位置插入:

  • insertbefore,最后一个匹配到前插入

    ---
    - hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /etc/httpd/conf/httpd.confline: 'Listen 82'insertbefore: 'Listen 80'state: present
    
  • insertafter,最后一个匹配到后插入

    ---
    - hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /etc/httpd/conf/httpd.confline: 'Listen 82'insertafter: 'Listen 80'state: present
    

示例2:替换文本行

匹配regexp中的内容将整行替换为line中的内容

---
- hosts: node1gather_facts: notasks:- name: replace linelineinfile:path: /tmp/testfileregexp: 'Add'line: 'replace'state: present
---
- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /etc/httpd/conf/httpd.confline: '#Listen 80'regexp: '^Listen 80'state: present

示例3:替换成多行文本

匹配regexp中的内容将整行替换为line中的多行文本

---
- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /tmp/testfileline: |line 1line 2regexp: 'replace'state: present 

replace 模块

该模块使用正则表达式匹配内容,将匹配的内容替换成指定的内容。匹配的多个地方都会被替换掉。

示例:

---
- hosts: node1gather_facts: notasks:- name: replace multi linereplace:path: /tmp/testfileregexp: '^Hello World.*'replace: 'Hello Laoma'

blockinfile 模块

示例:将文本块添加到现有文件

---
- hosts: node1gather_facts: notasks:- name: add block lines to fileblockinfile:path: /tmp/testfileblock: |line 1 in fileline 2 in fileaaline 3 in file sssstate:  present

添加的内容如下,会在第一行和最后一行额外添加注释。

# BEGIN ANSIBLE MANAGED BLOCK
line 1 in file
line 2 in fileaa
line 3 in file sss
# END ANSIBLE MANAGED BLOCK

stat 模块

**stat 模块检索文件的信息,类似于Linux stat命令。**参数提供检索文件属性、确定文件校验和等功能。

stat 模块返回一个包含文件状态数据的值的散列字典,允许您使用单独的变量引用各条信息。

示例:

---
- hosts: node1gather_facts: notasks:- stat:path: /tmp/testfilechecksum_algorithm: md5register: result- debug:msg: "/tmp/testfile md5 is {{ result.stat.checksum }}"- debug:var: result

copy 模块

示例1:将控制节点上文件拷贝到受管理节点,类似于Linux中scp命令。

---
- hosts: node1gather_facts: notasks:- name: copy /tmp/testfile to remote nodecopy:src: /tmp/testfiledest: /tmp

说明:此模块假定设置了force: yes,强制覆盖远程文件,类似scp命令。如果设置force: no, 则不会出现覆盖。

示例2:写入字符串到文件

---
- hosts: node1gather_facts: notasks:- name: write string into /tmp/testfilecopy:content: "hello world\n"dest: /tmp/testfile

synchronize 模块

synchronize 模块是一个围绕 rsync 工具的打包程序,它简化了playbook中的常见文件管理任务。

rsync工具必须同时安装在本地和远程主机上。默认情况下,在使用synchronize模块时, “本地主机”是同步任务的源主机, 而 “目标主机”是synchronize连接到的主机。

示例1:同步文件

---
- hosts: node1gather_facts: notasks:- name: synchronize filesynchronize:src: /tmp/testfiledest: /tmp/

示例2:同步目录

---
- hosts: node1gather_facts: noremote_user: roottasks:- name: synchronize directorysynchronize:src: /etc/sysconfigdest: /tmp/

fetch 模块

从受管节点检索文件,例如将被管理节点文件先取到控制节点,然后用于分发到其他节点。诸如SSH公钥之类的文件。

示例:

---
- hosts: node1gather_facts: notasks:- name: fetch file from remote nodefetch:src: /tmp/testfiledest: /tmp

文件保存在:/tmp/node1/tmp/testfile。

[wsh@controller ansible ✔]$ tree /tmp/node1
/tmp/node1
└── tmp└── testfile1 directory, 1 file

使用JINJA2模板部署文件

JINJA2 模板介绍

Jinja2 模板是功能强大的工具,可用于自定义要在受管节点上部署的配置文件。 创建Jinja2 模板后,可以通过template模块部署到受管节点上, 该模块支持将控制节点中的本地文件转移到受管节点。

示例1:部署web服务器,主页内容显示为Welcome to HOSTNAME。HOSTNAME为受管主机完全主机名。

playbook内容如下:

---
- name: Enable intranet serviceshosts: node1tasks:- name: ensure latest version of httpd yum:name: httpdstate: latest- name: test html page is installed# template模块: 复制文件到受管主机时,根据jinja2语法替换template:# 指定 Jinja2 模板来源src: index.html.j2# 指定要在目标主机上创建的文件dest: /var/www/html/index.html- name: httpd enabled and runningservice:name: httpdenabled: truestate: restarted
...

index.html.j2 内容如下:

Welcome to {{ ansible_fqdn }}

剧本执行完成后,index.html内容如下:

Welcome to node1.laoma.cloud

template模块,与copy模块类似,允许指定已部署文件的所有者(拥有该文件的用户) 、组、权限和 SELinux上下文 。

示例2:推送 ssh 服务配置文件。 sshd_config.j2内容如下:

# {{ ansible_managed }}
# DO NOT MAKE LOCAL MODIFICATIONS TO THIS FILE AS THEY WILL BE LOST
Port {{ ssh_port }}
ListenAddress {{ ansible_facts['default_ipv4']['address'] }}HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
PermitRootLogin  {{ root_allowed }}
AllowGroups {{ groups_allowed }}AuthorizedKeysFile      /etc/.rht_authorized_keys .ssh/authorized_keys
PasswordAuthentication {{ passwords_allowed }}

playbook 参考

---
- name: config sshd servicehosts: node1vars:ssh_port: 1022root_allowed: "yes"groups_allowed: wheelpasswords_allowed: "yes"ansible_managed: "Ansible managed"tasks:- name: config sshd servicetemplate:src: sshd_config.j2dest: /root/sshd_config

Jinja2 模板语法

Jinja2 模板由多个元素组成:数据、变量和表达式。在呈现Jinja2模板时, 这些变量和表达式被替换为对应的值。模板中使用的变量可以在playbook的vars部分中指定,也可以使用受管主机FACTS。

变量和逻辑表达式置于分隔符之间:

  • {{ EXPR }},用于装载表达式,比如变量,运算表达式,比较表达式。
  • {% EXPR %},用于装载控制语句,比如iffor等。
  • {# #},用于装载注释,模板文件中的注释不会包含在最终生成文件中。
for 语句

Jinja2使用for语句来提供循环功能。

示例1:

---
- name: test templatehosts: node1vars:users:- tom- jack- Snoopy- lucytasks:- name: test templatetemplate:src: testfile.j2dest: /tmp/testfile
...

testfile.j2内容如下:

{% for user in users %}
{{ user }}
{% endfor %}

for用于声明循环,{% endfor %} 表示结束。user变量会遍历users变量中所有值。

生成的/tmp/testfile内容如下:

tom
jack
Snoopy
lucy

**示例2:**testfile.j2内容如下

{# for statement #}
{% for user in users %}
{{ loop.index }} - {{ user }}
{% endfor %} 

loop.index代表当前循环的索引号,从1开始到最后循环体的数量。例如循环体有12个,那么loop.index代表1,2,3,…,12。

生成的/tmp/testfile内容如下:

1 - tom
2 - jack
3 - Snoopy
4 - lucy

**示例3:**部署myhosts

创建 playbook:

  • 使用模板文件hosts.j2在dev主机组中的主机上生成文件/etc/myhosts。

  • hosts.j2内容如下:

    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
    
  • 针对每个受管节点包含一行内容:

    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain610.1.8.10 controller.laoma.cloud controller
    10.1.8.11 node1.laoma.cloud node1 
    10.1.8.12 node2.laoma.cloud node2 
    10.1.8.13 node3.laoma.cloud node3 
    10.1.8.14 node4.laoma.cloud node4
    

    注:清单主机名称的显示顺序不重要。

inventory 内容如下:

[controllers]
controller[dev]
node1[test]
node2[prod]
node3
node4

答案如下:

---
- name: /etc/myhosts is up to datehosts: alltasks:- name: Deploy /etc/myhoststemplate:src: hosts.j2dest: /etc/myhostswhen: inventory_hostname in groups.dev

hosts.j2内容如下:

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6{% for server in groups.all %}
{{ hostvars[server].ansible_default_ipv4.address }} {{ hostvars[server].ansible_fqdn }} {{ hostvars[server].ansible_hostname }}
{% endfor %}

说明:

  • hostvars是magic 变量,通过该变量引用其他受管主机facts。
  • [server]不能使用单引号,因为server作为变量处理,替换为all中主机。
  • play 必须针对所有主机执行,收集所有主机facts,因为模版需要引用所有主机的facts。
  • 只部署到dev主机组,使用when语句。groups.dev是magic变量,该变量获取dev主机组中主机清单。

**示例4: **num 变量引用方括号中列表

{% for num in [3,1,7,8,2] %}
{{ num }}
{% endfor %}

生成的文件内容如下:

3
1
7
8
2

示例5: range(3)代表 0 1 2,循环三次。

{% for num in range(3) %}
{{ num }}
{% endfor %}

生成的文件内容如下:

0
1
2

**示例6:**range(1,4,2),从1开始,到4结束,步长2。

{% for num in range(1,4,2) %}
{{ num }}
{% endfor %}

生成的文件内容如下:

1
3
if 语句

Jinja2使用if语句来提供条件控制。如果满足某些条件, 则在部署文件中放置一行。if语句判断条件同ansible中when语句。

示例1: 只要变量finished不是假值,那么输出finished变量值。

{% if finished %}
{{ finished }}
{% endif %}

示例2: 如果PORT定义了端口,那么使用该值,否则使用默认3306。

{% if PORT is defined %}
bind-address=0.0.0.0:{{ PORT }}
{% else %}
bind-address=0.0.0.0:3306
{% endif %}

示例3:

{% if 条件1 %}
...
{% elif 条件2 %}
...
{% elif 条件n %}
...
{% else %}
...
{% endif %}

{% elif 条件N %}可以多次使用。

示例4: for和if配合使用

{% for num in [7,1,5,3,9] if num>3 %}
{{ num }}
{% endfor %}

等同于:

{% for num in [7,1,5,3,9] %}
{% if num>3 %}
{{ num }}
{% endif %}
{% endfor %}

生成的文件内容如下:

7
5
9
表达式

示例1:

{{ 1 == 1 }}
{{ 2 != 2 }}
{{ 2 > 1 }}
{{ 2 >= 1 }}
{{ 2 < 1 }}
{{ 2 <= 1 }}

生成的文件内容如下:

True
False
True
True
False
False

**示例2: **

jinja2 test
{{ (2 > 1) or (1 > 2) }}
{{ (2 > 1) and (1 > 2) }}
{{ not true }}
{{ not True }}
{{ not false }}
{{ not False }}

生成的文件内容如下:

jinja2 test
True
False
False
False
True
True

**示例3: **

{{ 3 + 2 }}
{{ 3 - 4 }}
{{ 3 * 5 }}
{{ 2 ** 3 }}
{{ 7 / 5 }}
{{ 7 // 5 }}
{{ 17 % 5 }}

生成的文件内容如下:

5
-1
15
8
1.4
1
2

**示例4: **

jinja2 test
{{ 1 in [1,2,3,4] }}
{{ 1 not in [1,2,3,4] }}

生成的文件内容如下:

jinja2 test
True
False
模版注释

{# #},用于装载注释,模板文件中的注释不会包含在最终生成文件中。

示例:

{# 此处是注释 #}
{% for num in [7,1,5,3,9] %}
{% if num>3 %}
{{ num }}
{% endif %}
{% endfor %}

生成的文件内容如下:

7
5
9

ansible_managed 变量

为避免系统管理员修改Ansible部署的文件,最好在模板顶部包含注释,指示不应手动编辑该文件。

在/etc/ansible/ansible.cfg配置文件[defaults]块中有如下默认配置:

[defaults]
ansible_managed = Ansible managed

可使用ansible_managed变量来引用“Ansible managed” 字符串。

要想在jinja2 模板内,使用ansible_managed变量代表的字符串,使用下列语法:

{{ ansible_managed }}

filter 过滤器

Jinja2还提供filter,对输出的结果进行格式化输出。

  • “{{ output | to_json }}”,使用JSON格式输出。
  • “{{ output | to_yaml }}”,使用YAML格式输出。
  • “{{ output | to_nice_json }}”,使用人们更加可读的JSON格式输出。
  • “{{ output | to_nice_yaml }}”,使用人们更加可读的YAML格式输出。
  • “{{ output | from_json }}”,把output当做JSON格式解析。
  • “{{ output | from_yaml }}”,把output当做YAML格式解析。

字符串处理过滤器:

  • “{{ testvar | upper }}” ,将字符串转换成纯大写。
  • “{{ testvar | lower }}” ,将字符串转换成纯小写。
  • “{{ testvar | capitalize }}”,将字符串变成首字母大写,之后所有字母纯小写。
  • “{{ testvar | reverse }}”,将字符串反转。
  • “{{ testvar | first }}”,返回字符串的第一个字符。
  • “{{ testvar | last }}”,返回字符串的最后一个字符。
  • “{{ testvar | trim }}”,将字符串开头和结尾的空格去除。
  • “{{ testvar | center(width=30) }}”,将字符串放在中间,并且设置字符串的长度为30,字符串两边用空格补齐30位长。
  • “{{ testvar | length }}”,返回字符串长度,length与count等效,可以写为count。
  • “{{ testvar | list }}”,将字符串转换成列表,每个字符作为一个元素。

列表处理过滤器:

  • “{{ testvar | first }}”,返回列表中的第一个值。
  • “{{ testvar | last }}”,返回列表中的最后一个值。
  • “{{ testvar | min }}”,返回列表中最小的值。
  • “{{ testvar | max }}”,返回列表中最大的值。
  • “{{ testvar | sort }}”,将列表升序排序输出。
  • “{{ testvar | sort(reverse=true) }}”,将列表降序排序输出。
  • “{{ testvar | sum }}”,返回纯数字非嵌套列表中所有数字的和。
  • “{{ testvar | join }}”,将列表中的元素合并成一个字符串。
  • “{{ testvar | join(’ , ') }}”,将列表中的元素使用指定分隔符合并成一个字符串。
  • “{{ testvar | random }}”,从列表中随机返回一个元素。
  • “{{ testvar | unique }}”,去掉列表中重复的元素,重复的元素只留下一个。

数字处理过滤器

  • {{ ‘a’ | int }}",将对应的值转换成int类型,如果无法转换,默认返回0。使用int(default=6)或者int(6)时,如果无法转换则返回指定值6。
  • “{{ ‘a’ | float }}”,将对应的值转换成浮点型,如果无法转换,默认返回’0.0’。使用float(default=8.88)或者float(8.88)时,如果无法转换则返回默认值’8.88’。
  • “{{ testvar4 | abs }}”,获取对应数值的绝对值。
  • “{{ 12.5 | round }}”,四舍五入。
  • “{{ 3.1415926 | round(5) }}”,取小数点后五位。
  • “{{ 100 | random }}”,从0到100中随机返回一个随机数。
  • “{{ 10 | random(start=5) }}”,从5到10中随机返回一个随机数。
  • “{{ 15 | random(step=5) }}”,从0到15中随机返回一个随机数,这个随机数是5的倍数。
  • “{{ 15 | random(start=5,step=3) }}”,从5到15中随机返回一个随机数,步长为3。

Ansible管理大项目

实验环境

[wsh@controller ansible ✔]$ pwd
/home/wsh/ansible
[wsh@controller ansible ✔]$ ls
ansible.cfg  inventory
[wsh@controller ansible ✔]$ cat ansible.cfg inventory 
[defaults]
inventory = ./inventory
remote_user = wsh[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[controllers]
controller[nodes]
node[1:4]

利用主机模式选择主机

ansible 命令语法:

ansible host-pattern -m module [-a 'module arguments'] [-i inventory]
  • host-pattern 用于指定ad-hoc命令的目标主机。

  • host-pattern 也适用于playbook中hosts声明的主机对象。

host-pattern是inventory中定义的主机或主机组,可以为ip、hostname、inventory中的group组名、具有“,”或“*”或“:”等特殊字符的匹配型字符串,host-pattern是必须项,不可忽略。

优先使用主机模式匹配主机,而不是在play的任务中设置复杂的when语句。

本小节使用的 inventory 如下:

localhost
server[lab]
node1
node2[test]
node3
node4[datacenter1]
node1
node3[datacenter2]
node2
node4[datacenter:children]
datacenter1
datacenter2[new]
10.1.8.10
10.1.8.11
单个主机匹配
[wsh@controller ansible ✔]$ ansible --list-hosts node1hosts (1):node1[wsh@controller ansible ✔]$ ansible --list-hosts 10.1.8.10hosts (1):10.1.8.10
单个主机组匹配
[wsh@controller ansible ✔]$ ansible --list-hosts labhosts (2):node1node2
[wsh@controller ansible ✔]$ ansible --list-hosts datacenterhosts (4):node1node3node2node4
[wsh@controller ansible ✔]$ ansible --list-hosts ungroupedhosts (2):localhostserver
[wsh@controller ansible ✔]$ ansible --list-hosts allhosts (8):localhostservernode1node2node3node410.1.8.1010.1.8.11
模糊匹配

*****通配符在Ansible表示0个或多个任意字符,主要应用于一些模糊规则匹配。

# 匹配所有主机,all或*号功能相同。
[wsh@controller ansible ✔]$ ansible --list-hosts '*'hosts (8):node1node3node2node4localhostserver10.1.8.1010.1.8.11
[wsh@controller ansible ✔]$ ansible --list-hosts '10.*'hosts (2):10.1.8.1010.1.8.11
[wsh@controller ansible ✔]$ ansible --list-hosts 'ser*r'hosts (1):server
逻辑或匹配

如我们希望同时对多个主机或多个主机组同时执行,相互之间用“:”(冒号)或者“,”(逗号)分隔即可,类似于取两个集合的并集。

[wsh@controller ansible ✔]$ ansible --list-hosts 'node1,10.1.8.11'hosts (2):node110.1.8.11
[wsh@controller ansible ✔]$ ansible --list-hosts 'lab,datacenter1' hosts (3):node1node2node3
[wsh@controller ansible ✔]$ ansible --list-hosts 'lab,data*,10.1.8.11'hosts (5):node1node2node3node410.1.8.11
逻辑与匹配

逻辑与用(,&)或者(:&)表示,匹配两个集合的交集。

[wsh@controller ansible ✔]$ ansible --list-hosts 'lab,&datacenter1'hosts (1):node1
逻辑非匹配

逻辑非用(,!)表示,用于排除特定主机或主机组。

[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter,!node1'hosts (3):node3node2node4
多条件匹配

Ansible也支持多条件的复杂组合。

[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter,new,!node1'hosts (5):node3node2node410.1.8.1010.1.8.11
域切割匹配

Ansible底层基于Python,Python字符串域切割的示例如下:

str = ‘12345678’

通过[0]即可获取数值1。

该功能在Ansible中也支持:

[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter'hosts (4):node1node3node2node4# 获取第1个元素
[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter[0]'hosts (1):node1# 获取第1-2个元素
[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter[0:1]'hosts (2):node1node3# 获取最后1个元素  
[wsh@controller ansible ✔]$ ansible --list-hosts 'datacenter[-1]'hosts (1):node4

配置并行

playbook 执行顺序

当Ansible处理playbook时:

  • 按playbook中定义顺序运行。
  • 每个play中所有主机分批次执行第一个任务,直到所有批次主机执行完该任务。
  • 然后play中所有主机分批次再执行下一个任务,直到所有批次主机执行完所有任务。
  • 以此类推,直到所有主机执行完所有任务,ansible才会释放shell。

理论上, Ansible可以同时连接到 play 中的所有主机以执行每项任务,适用于小型主机列表。但如果该play以数百台主机为目标, 则控制主机负载比较大。

配置 forks

Ansible 所进行的最大同时连接数由Ansible配置文件中的forks参数控制。

默认值为 5。

[wsh@controller ansible ✔]$ ansible-config dump|grep FORKS
DEFAULT_FORKS(default) = 5[wsh@controller ansible ✔]$ grep forks /etc/ansible/ansible.cfg 
# forks          = 5

示例:

  • 清单内容如下:

    controller[webs]
    node1
    node3[dbs]
    node2
    node4
    
  • 剧本内容如下:

    ---
    - name: connectionhosts: alltasks:- name: conneciton 1shell: sleep 5- name: conneciton 2debug: msg: connection 2
    

验证:每一批2个主机执行同一个任务。

[wsh@controller ansible ✔]$ ansible-playbook playbook.yaml -f 2

结果:

  • 第一个任务 controller、node1同时完成,然后node3、node2同时完成,最后node4完成。
  • 第二个任务 似乎 5台主机同时完成。

解释:第一个任务执行需要5秒,所以看起来比较明显。第二个任务执行速度非常块,所以感知不到先后顺序。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

forks 的默认值设置得非常保守:

  • 如果受管主机是Linux主机,则大多数任务将在受管主机上运行,并且控制主机的负载较少。在这种情況下,您通常可以将forks的值设置得更高,可能接近100 ,然后性能就会提高。
  • 如果控制主机管理网络设备,路由器和交换机,则大多数模块在控制主机上运行而不在网络设备上运行,这会增加控制主机上的负载,因此其支持forks数量增加的能力将显著低于仅管理Linux主机的控制主机。

配置 serial

Ansible运行play时,所有受管主机按顺序执行完所有任务,然后运行通知的处理程序。

在所有主机上运行所有任务可能会导致意外行为。例如,更新负载平衡Web服务器集群,则可能需要在进行更新时让每个Web服务器停止服务。如果所有服务器都在同一个play中更新,则它们可能全部同时停止服务;如果某个任务失败,这将导致整个playbook运行失败。

避免此问题的一种方法是使用serial关键字,先让一批主机执行完play中所有任务,再让下一批主机执行完play中所有任务。以此类推,直到所有主机分批次执行play完成。

示例剧本内容如下:

---        
- name: connection     hosts: allserial: 2tasks:   - name: conneciton 1shell: sleep 5   - name: conneciton 2debug:           msg: connection 2

在这里插入图片描述

serial关键字也可以指定为百分比。此百分比应用于play中的主机总数,以确定滚动更新批处理大小。主机数不能小于1。

配置 async

ansible 默认行为:必须等当前任务执行完成,才能执行下一个任务。

有些操作需要很长时间才能完成,例如下载一个大文件,重启服务器等。使用异步并行模式,ansible可以很快在受管主机上这些执行命令,但是需要等待命令执行完成才能将主机置于相应状态。

Ansible使用async触发异步并行运作任务:

  • async:async的值是ansible等待运行这个任务的最大超时值(如果执行超时任务会强制中断导致失败)。
  • poll:ansible检查这个任务是否完成的时间间隔。ansible poll_interval 默认值是 15。

示例1: 任务执行失败,在规定时间内容任务没有执行完成。

---
- name: connectionhosts: node1tasks:- name: conneciton shell: sleep 10async: 5poll: 2

示例2: 放入后台下载,立刻执行下一个任务。

---
- name: connectionhosts: node1tasks:- name: downloadget_url: url: http://192.168.48.100/ISOS/openEuler-24.03-LTS-x86_64-dvd.isodest: /home/laomaasync: 100poll: 0

示例3: ansible 默认行为,等该任务执行完,再执行下一个任务。

---
- name: connectionhosts: node1tasks:- name: conneciton shell: sleep 10async: 0poll: 2

wait_for 模块

使用 wait_for 模块检查之前的任务是否达到预期状态。

示例1: 测试文件是否存在

---
- name: test wait forhosts: node1tasks:- shell: sleep 10 && touch /tmp/hello# async时间要大于sleep的时间async: 20poll: 0register: out- name: wait for create /tmp/hellowait_for:path: /tmp/hellostate: presentdelay: 5timeout: 30sleep: 2

选项说明:

  • delay,设置检测前延迟时间。
  • timeout,设置检测超时时间。
  • sleep,设置检测时间间隔。

示例2: 测试主机端口是否打开

---
- name: test wait_forhosts: node1,node2tasks:- name: reboot node1shell: shutdown -r now "Ansible updates triggered"async: 1poll: 0when: inventory_hostname == "node1"- name: wait for node1 come backwait_for:host: node1port: 22state: starteddelay: 10sleep: 2timeout: 300when: inventory_hostname == "node2"

async_status 模块

使用 async_status 模块检查之前的任务是否运行完成。

示例:

---
- name: test async_statushosts: node1tasks:- shell: sleep 10 async: 20poll: 0register: out- name: wait forasync_status:# 通过任务的 ansible_job_id 属性跟踪任务jid: "{{ out.ansible_job_id }}"register: job_result# 根据当前任务执行结果的finished值,判断跟踪任务是否执行完成until: job_result.finishedretries: 30delay: 2

选项说明:

  • retries,设置重试次数,默认值为3。
  • delay,设置检测时间间隔,默认5秒检测一次。

Including 和 importing 文件

如果playbook很长或很复杂,可以将其分成较小的文件以便于管理。

采用模块化方式将多个playbook组合为一个main playbook或者将文件中的任务列表插入play。这样可以更轻松地在不同项目中重用play或任务。

ansible重用内容主要有两种方式:

  • 使用任何 include 关键字任务(include_tasks、include_role 等),它将是动态的。
  • 使用任何 import 关键字任务(import_playbook、import_tasks、import_role等),它将是静态的。
  • 只使用include的任务(用于 task 级别和 Playbook 级别)仍然可用,此功能将在 2.12 版中删除。
[wsh@controller ansible ✔]$ ansible-doc -l|grep -e ^import -e ^include
import_playbook                                Import a playbook      
import_role                                    Import a role into a pl...
import_tasks                                   Import a task list     
include                                        Include a play or task ...
include_role                                   Load and execute a role
include_tasks                                  Dynamically include a t...
include_vars                                   Load variables from fil...

playbook 级别

import_playbook 支持导入外部playbooks。

  • 导入的内容是完整的playbook,只能在play级别使用。
  • 导入的多个playbooks,则按导入顺序执行。

示例:

  • 主剧本内容如下

    - name: prepare the web serverimport_playbook: pre_web.yml- name: prepare the vsftpd serverimport_playbook: pre_vsftpd.yml- name: prepare the databse serverimport_playbook: pre_db.yml
    
  • pre_web.yml 内容如下:

    cat > pre_web.yml << EOF
    - name: Play webhosts: node1tasks:- name: install httpdyum:name: httpdstate: present
    EOF
    
  • pre_vsftpd.yml 内容如下:

    cat > pre_vsftpd.yml << EOF
    - name: Play vsftpdhosts: node1tasks:- name: install vsftpdyum:name: vsftpdstate: present
    EOF
    
  • pre_db.yml 内容如下:

    cat > pre_db.yml << EOF
    - name: Play dbhosts: node1tasks:- name: install mariadb-serveryum:name: mariadb-serverstate: present
    EOF
    

task 级别

示例:

  • 主剧本内容如下:

    ---
    - name: Install web serverhosts: node1tasks:- name: import a task fileimport_tasks: tasks.yaml#include: tasks.yaml#include_tasks: tasks.yaml
    
  • tasks.yaml 内容如下:

    - name: Install the httpdyum:name: httpdstate: present- name: Starts httpdservice:name: httpdstate: started
    
任务文件用例

在这些情景中将任务组作为与playbook独立的外部文件来管理或许有所帮助:

  1. 如果新服务器需要全面配置,则管理员可以创建不同的任务集合,分别用于创建用户、安装软件包、配置服务、配置特权、设置对共享文件系统的访问权限、强化服务器、安装安全更新,以及安装监控代理等。如果一组服务器需要运行某一项/组任务,则它们可以仅在属于特定主机组的服务器上运行。
  2. 如果服务器由不同部门管理,例如开发人员、系统管理员和数据库管理员,则每个部门可以编写自己的任务文件,再由系统经理进行审核和集成。
  3. 如果服务器要求特定的配置,它可以整合为按照某一条件来执行的一组任务。换句话说,仅在满足特定标准时才包含任务。

我们可以创建专用目录存储任务文件, playbook 就可以从该目录包含任务文件。这便能够构建复杂的 playbook,同时简化其结构和组件的管理。

include_vars 模块

导入外部yaml格式的变量文件。

示例:

  • 主剧本内容如下:

    ---
    - name: Install web application packageshosts: node1tasks:- name: Includes variables.yml include_vars: variables.yml- name: Debugs the variables includeddebug:msg: >"{{ packages['web_package'] }} and {{ packages.db_package }} have been included"
    
  • variables.yml 内容如下:

    ---
    packages:web_package: httpddb_package: mariadb-server
    
http://www.lryc.cn/news/624498.html

相关文章:

  • 大数据开发面试题:美团秋招一面
  • 数据赋能(401)——大数据——持续学习与优化原则
  • 自建K8s集群无缝集成阿里云RAM完整指南
  • The Open Group 休斯敦峰会:进步之路——以开放标准定义未来
  • [openvela] Hello World :从零开始的完整实践与问题复盘
  • PDF转图片需要用到什么技术?苹果手机怎样将PDF转为jpg?
  • 在Excel启动时直接打开多个Excel文件
  • 2025上半年AI核心成果与趋势报告深度解析:技术突破、应用落地与未来展望
  • SQLsever基本操作
  • 网络间的通用语言TCP/IP-网络中的通用规则1
  • H264: SPS和PPS概念
  • thinkphp8:一、环境准备
  • Java-101 深入浅出 MySQL InnoDB 锁机制全景图:行锁原理、Next-Key Lock、Gap Lock 详解
  • 机器学习——XGBoost算法
  • python-----机器学习中常用的数据预处理
  • 机器学习之数据预处理(一)
  • 英特尔公司Darren Pulsipher 博士:以架构之力推动政府数字化转型
  • STM32使用WS2812灯环
  • 吴恩达 Machine Learning(Class 2)
  • Windows桌面自动化的革命性突破:深度解析Windows-MCP.Net Desktop模块的技术奥秘
  • 从零到一构建企业级GraphRAG系统:GraphRag.Net深度技术解析
  • OpenCV---特征检测算法(ORB,Oriented FAST and Rotated BRIEF)
  • SkyWalking + Elasticsearch8 容器化部署指南:国内镜像加速与生产级调优
  • 深度解析阿里巴巴国际站商品详情 API:从接口调用到数据结构化处理
  • Vision Master的C#脚本与opencv联合编程
  • 【GM3568JHF】FPGA+ARM异构开发板烧录指南
  • [系统架构设计师]软件可靠性基础知识(九)
  • 蔬菜批发小程序:生产商的数字化转型利器——仙盟创梦IDE
  • 【Linux系统】进程间通信:System V IPC——消息队列和信号量
  • VLN视觉与语言导航(1)——数学与人工智能基础理论