我正在编写剧本,以获取部署到Mirantis的UCP/MKE集群的服务列表,并检查该集群中的所有Docker工作器,确保每个外部集群服务端口都是开放的。
playbook从localhost调用API,以获取部署到集群的服务的广泛JSON对象,使用jmespath简化为仅包含名称、ID和端口。
作为另一个剧本,我的剧本在集群中的每个worker上运行shell命令以获取开放端口列表。
我想循环遍历每个服务的每个端口,并确认端口是否在每个工作节点上打开。
我的services/ports数据对象可以像这样:
[
{
"ID": "aefgergergergergerg",
"Name": "application1_service",
"Ports": [
[
30950,
"tcp"
],
[
30951,
"tcp"
]
]
},
{
"ID": "sdfthtrhrthrthrthrthtrh",
"Name": "application2_service",
"Ports": [
[
31190,
"tcp"
]
]
},
...
]
(通过API调用获得,可以使用jmespath查询简化:
'[?Endpoint.Ports].{ ID: ID, Name: Spec.Name, Ports: Endpoint.Ports[?contains(@.PublishMode,`ingress`)].[PublishedPort, PublishMode, Protocol] }'
和我的工人的开放端口对象看起来像这样:
ok: [worker1] => {
"msg": [
"tcp:31557",
"tcp:31501",
"tcp:31556",
"tcp:31500",
"tcp:30231",
"tcp:30230",
"tcp:30651",
"tcp:30650"
]
}
ok: [worker2] => {
"msg": [
"tcp:31557",
"tcp:31501",
"tcp:31556",
"tcp:31500",
"tcp:30231",
"tcp:30230",
"tcp:30651",
"tcp:30650"
]
}
ok: [worker3] => {
"msg": [
"tcp:31557",
"tcp:31501",
"tcp:31556",
"tcp:31500",
"tcp:30231",
"tcp:30230",
"tcp:30651",
"tcp:30650"
]
}
获得与
iptables -L DOCKER-INGRESS | awk -F ' {2,}' '($1 == "ACCEPT") && ($6 ~ /dpt/) {print $6}' | sed 's/ dpt//g')
在我的脑海中,我想将with_subelements
循环(每个给定服务的端口)与with_nested
循环(我的子元素作为第一个列表,我的开放端口作为嵌套列表)结合起来,但我确信这是不太可能的。
这是我剧本的相关部分(我已经剪掉了真实逻辑,因为它不相关)
- name: Ensure secrets are in the required collections
hosts: localhost
gather_facts: false
vars_files: vars.yaml
[SNIP]
- name: "Get a list of services from https://{{ endpoint }}/services"
ansible.builtin.uri:
url: "https://{{ endpoint }}/services"
body_format: json
headers:
Authorization: "Bearer {{ auth.json.auth_token }}"
validate_certs: "{{ validate_ssl_certs | default('yes') }}"
register: services
- name: "Create a simplified JSON object of services and ports"
ansible.builtin.set_fact:
services_ports: "{{ services.json | json_query(jmesquery) }}"
vars:
jmesquery: "{{ jmesquery_services }}"
- name: See what ports are open on which workers
hosts: workers
gather_facts: false
become: true
vars_files: vars.yaml
tasks:
- name: Get the list of open ports
shell: iptables -L DOCKER-INGRESS | awk -F ' {2,}' '($1 == "ACCEPT") && ($6 ~ /dpt/) {print $6}' | sed 's/ dpt//g'
register: iptables_rules
- name: debug
debug:
msg: "{{ iptables_rules.stdout_lines }}"
与vars.yaml
相关位:
---
jmesquery_services: '[?Endpoint.Ports].{ ID: ID, Name: Spec.Name, Ports: Endpoint.Ports[?contains(@.PublishMode,`ingress`)].[PublishedPort, PublishMode, Protocol] }'
如何根据每个worker上的每个开放端口检查服务的每个这些端口?
您在subelements
查找插件的正确轨道上,您应该简单地循环服务/端口对并检查iptables_rules.stdout_lines
中是否存在此类端口。
下面是一个关于如何使用虚拟数据的示例剧本:
- hosts: localhost
gather_facts: false
become: false
tasks:
- name: check if all service ports are open
# Loop over service/port pairs
loop: "{{ lookup('subelements', services_ports, 'Ports') }}"
# Set variables for clarity
vars:
service_name: "{{ item[0]['Name'] }}"
iptables_port: "{{ item[1][1] ~ ':' ~ item[1][0] }}"
iptables_port_exists: "{{ iptables_port in iptables_rules.stdout_lines }}"
# Fail the module if port is not found
failed_when: "not iptables_port_exists"
# For demo, print out the service status
debug:
msg: "Service {{ service_name }} is {{ 'up' if iptables_port_exists else 'down' }} on port {{ iptables_port }}"
# Example data
vars:
services_ports:
- ID: aefgergergergergerg
Name: application1_service
Ports:
- ["30950", "tcp"]
- ["30951", "tcp"]
- ID: sdfthtrhrthrthrthrthtrh
Name: application2_service
Ports:
- ["31190", "tcp"]
iptables_rules:
stdout_lines: [
"tcp:30950",
"tcp:31190",
]
输出如下:
TASK [check if all service ports are open] *************************************
ok: [localhost] => (item=[{'ID': 'aefgergergergergerg', 'Name': 'application1_service'}, ['30950', 'tcp']]) => {
"msg": "Service application1_service is up on port tcp:30950"
}
failed: [localhost] (item=[{'ID': 'aefgergergergergerg', 'Name': 'application1_service'}, ['30951', 'tcp']]) => {
"msg": "Service application1_service is down on port tcp:30951"
}
ok: [localhost] => (item=[{'ID': 'sdfthtrhrthrthrthrthtrh', 'Name': 'application2_service'}, ['31190', 'tcp']]) => {
"msg": "Service application2_service is up on port tcp:31190"
}
fatal: [localhost]: FAILED! => {"msg": "One or more items failed"}
PS !我不熟悉jmespath,但是您可能需要在worker上使用hostvars['localhost']['services_ports']
,以便访问在localhost