首页
科技
vivo Pulsar 万亿级消息处理实践(4)-Ansible运维部署

vivo Pulsar 万亿级消息处理实践(4)-Ansible运维部署

热心网友
31
转载
2025-09-05
来源:https://www.51cto.com/article/822927.html

本篇文章主要从Pulsar运维痛点、Ansible简介、Ansible核心模块详解、Ansible自动化部署zk集群、Ansible自动化部署Pulsar集群几个维度向大家介绍vivo Pulsar万亿级消息处理实践之运维部署。

Pulsar作为下一代云原生架构的分布式消息中间件,存算分离的架构设计能有效解决大数据场景下分布式消息中间件老牌一哥“Kafka”存在的诸多问题,2024年vivo 分布式消息中间件团队正式开启对Pulsar的调研,2024年正式引入Pulsar作为大数据场景下的分布式消息中间件,本篇文章主要从Pulsar运维痛点、Ansible简介、Ansible核心模块详解、Ansible自动化部署zk集群、Ansible自动化部署Pulsar集群几个维度向大家介绍vivo Pulsar万亿级消息处理实践之运维部署。

注:本文是《vivo Pulsar万亿级消息处理实践》系列文章第4篇。

01、简介

1.1Pulsar 运维面临的问题

新业务增长快,很多新业务接入需要搭建独立的集群或者资源组。

升级频次高,对于bug修复,配置更改以及依赖组件替换等,都需要对全集群进行升级、配置更改或组件替换。

人力投入大,在集群运维时,需要对公共的执行步骤进行批处理封装,否则会耗费大量人力在集群的部署和升级上。

1.2什么是 Ansible Playbook

Asnible Playbooks是Ansible自动化工具的核心部分。它是基于YAML文件格式,用于在多个主机上执行的任务。通过在Playbook中设置变量、处理器、角色和任务标签等功能,可以大大提高自动化脚本的复用性和可维护性。可以理解为批处理任务。

上图中我们看到Playbook的主要模块如下:

Ansible:Ansible 的核心程序。HostInventory:记录由 Ansible 管理的主机信息,包括端口、密码、ip 等。Playbooks:“剧本” YAML 格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。CoreModules:核心模块,主要操作是通过调用核心模块来完成管理任务。CustomModules:自定义模块,完成核心模块无法完成的功能,支持多种语言。ConnectionPlugins:连接插件,Ansible 和 Host 通信使用。

02、Playbook 语法

2.1书写格式

playbook 常用到的YMAL格式:

文件的第一行应该以 "---" (三个连字符)开始,表明 YMAL 文件的开始。在同一行中,# 之后的内容表示注释,类似于 shell,python 和 ruby。YMAL 中的列表元素以 ”-” 开头然后紧跟着一个空格,后面为元素内容。同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。play 中 hosts,variables,roles,tasks 等对象的表示方法都是键值中间以 ":" 分隔表示,":" 后面还要增加一个空格。

以下是 Playbook 的基本语法书写格式:

- name: playbook的名称 hosts: 目标主机或主机组 # 可以使用普通的 IP 地址或域名,也可以使用主机组名称 remote_user: 远程用户 # 使用 SSH 登录远程主机时使用的用户名 become: yes # 是否使用特权(例如 sudo)运行命令 tasks: # Playbook 中的任务列表 - name: 任务名称 module_name: 参数 # Ansible 模块的名称和参数组成的字典,用于执行操作 tags: # 与该任务相关的标记列表,用于执行特定的任务 - 标签名称 when: 条件 # 指定该任务在满足特定条件下才会被执行 notify: 通知列表 # 指定依赖于该任务的另一个任务列表,当这个任务被执行后会自动触发这些任务

2.2Tasks & Modules

在Ansible Playbook的语法中,

"Tasks"和"Modules"是两个核心概念。

Tasks(任务):Tasks是Playbook中的操作步骤或任务,它们定义了要在目标主机上执行的操作。可以在Playbook中定义一个或多个任务。Tasks按照顺序执行,并且可以有条件地执行或跳过。

Modules(模块):Modules提供了执行特定任务的功能单元。每个模块负责处理不同的操作,如管理文件、安装软件包、查询系统信息等。Ansible提供了许多内置模块,可以满足大多数常见的操作。

通过组合不同的模块和任务,可以构建复杂的Playbooks来执行各种操作和配置任务。

2.3任务之间的依赖关系

在 Ansible 的 playbook 中,任务之间可以有依赖关系,你可以使用 dependencies 或者 notify 语句来定义。

2.3.1 使用 dependencies 定义任务依赖关系

如果任务 A 依赖任务 B 完成,可以使用 dependencies 定义任务依赖关系,语法如下:

- hosts: web tasks: - name: Install Nginx yum: name: nginx state: present - name: Start Nginx service: name: nginx state: started become: true dependencies: - Install Nginx

在上面的示例中,Start Nginx 任务在 Install Nginx 任务完成之后才会执行。如果在执行 Start Nginx 任务之前,Install Nginx 任务未完成或者执行失败,则 Start Nginx 任务也会失败。

2.3.2 使用 notify 定义任务依赖关系

如果任务 A 完成后需要通知任务 B 执行,可以使用 notify 定义任务依赖关系,语法如下:

- hosts: web tasks: - name: Install Nginx yum: name: nginx state: present notify: -Start Nginx - name: Start Nginx service: name: nginx state: started become: true listen: Start Nginx

在上面的示例中,Install Nginx 任务完成后会通知 Start Nginx 任务执行。然后 Start Nginx 任务会通过 listen 参数监听,等待通知执行。

总之,Ansible 支持在 playbook 中定义任务之间的依赖关系。你可以使用 dependencies 或 notify 语句来定义任务之间的顺序和依赖关系。

2.4条件判断

在Playbook中,可以使用when关键字来添加条件判断。when关键字后面跟一个条件表达式,如果表达式返回True,则任务会被执行;如果返回False,则任务会被跳过。

条件表达式可以使用Ansible的Jinja2模板来编写,例如:

tasks: - name: Install Apache if not installed package: name: apache2 state: present when: ansible_pkg_mgr == 'apt'

在这个例子中,如果ansible_pkg_mgr变量等于"apt",则安装Apache;否则跳过这个任务。

除了使用任务级别的条件判断,还可以使用Play级别的条件判断来控制整个Playbook的执行。这可以通过在Play的开始处添加when关键字来实现,例如:

- name: Deploy Web App hosts: all vars: deploy_web_app: true tasks: - name: Install Dependencies apt: name: "{{ item }}" state: present with_items: - python3 - python3-pip when: deploy_web_app


在这个例子中,deploy_web_app变量的值为True时,才会执行任务Install Dependencies。如果deploy_web_app变量的值为False,则跳过整个Playbook的执行。

2.5循环

在Playbook中,可以使用循环结构来遍历列表或其他可迭代对象,并对每个迭代项执行相同的任务。这可以使用Ansible的with_*系列模块来实现。

以下是一些常见的循环结构的示例:

2.5.1 使用with_items模块来遍历列表

tasks: - name: Install packages apt: name: "{{ item }}" state: present with_items: - python3 - python3-pip - git

在这个例子中,将依次安装python3、python3-pip和git。

03、Playbook 组织

3.1Inclusions

在Playbook的组织中,include和import两个指令都可以用来将其他的yaml文件(也就是Tasks文件)包含到当前的Playbook中。

它们的区别在于,当主Playbook执行到include指令时,它将处理包含的文件中的所有任务,并且在处理完之后继续主Playbook的执行。而当主Playbook执行到import指令时,它只会处理被导入的文件中的变量定义,而不会处理任务,任务只有在需要的时候才会被引入执行。

下面是一个使用include指令包含其他文件的例子:

- hosts: webservers tasks: - name: Include web tasks include: web-tasks.yml

在这个例子中,主Playbook从web-tasks.yml文件中导入任务,并在执行完后继续执行余下的任务。

下面是一个使用import指令包含其他文件的例子:

- name: Load variables import_vars: vars.yml- name: Deploy web app hosts: webservers tasks: - name: Install dependencies apt: name: "{{ item }}" state: present with_items: - python3 - python3-pip - name: Deploy app include: app-tasks.yml

在这个例子中,在主Playbook中使用import_vars指令来导入变量定义,然后在每个任务中都可以使用这些变量。然后我们使用include指令从app-tasks.yml文件中包含任务,这些任务可以使用在vars.yml文件中定义的变量。这种方式可以在需要时懒加载任务,提高性能。

需要注意的是,在被引入的文件中,不能再次使用- hosts:指令定义新的主机组,因为Ansible只允许在主Playbook中定义主机组。被引入的文件只包含任务,任务必须使用被定义的主机组来指定目标主机。

3.2Roles

Ansible的Roles是一种组织Playbook的方式,它将Playbook和相关的变量、模板和其他资源打包在一起,并且可以轻松地在Playbook中重用和分享。一个Role通常适用于一种操作或功能,比如安装和配置一个应用程序、部署Web服务、安装软件包等等。

一个Role目录通常包含以下文件和目录:

my-role/├── README.md├── defaults/│ └── main.yml├── files/├── handlers/│ └── main.yml├── meta/│ └── main.yml├── tasks/│ └── main.yml├── templates/├── tests/│ ├── inventory│ └── test.yml└── vars/ └── main.yml


README.md:Role的说明文档。defaults/main.yml:默认变量定义文件。files:包含角色使用的文件。handlers/main.yml:Role的处理程序。meta/main.yml:Role的元数据,例如角色名称、作者、依赖等。tasks/main.yml:包含Role组成部分的主要任务。templates:包含角色使用的Jinja2模板。tests:Role的测试脚本。vars/main.yml:包含Role的变量。

要使用Role,需要在Playbook中定义roles扩展,例如:

- hosts: webservers roles: - my-role

这将运行my-role目录中包含的所有任务。

通过使用Role,可以更好地组织和重复使用代码,并提高代码的可读性和可维护性。它还可以帮助您在Ansible社区中分享自己的工作,或从其他用户那里获得高质量的Roles。

3.3引用/定义变量

在Playbook中,可以使用vars关键字来定义变量。例如:

vars: my_var: "Hello World"

这将定义一个名为my_var的变量,其值为字符串"Hello World"。

要在Playbook中访问这个变量,可以使用{{ my_var }}语法。例如:

tasks: - name: Print Message debug: msg: "{{ my_var }}"

除了在vars中定义变量,还可以通过set_fact模块来动态设置变量。例如:

tasks: - name: SetDynamic Variable set_fact: my_var: "{{ inventory_hostname }} is awesome"

3.4使用插件和模板

Ansible提供了插件和模板的功能,使得在Playbook中使用动态内容变得更加简单和方便。

插件是一种可以扩展和定制Ansible功能的机制,可以在Playbook中调用和使用。常见的插件包括Action、Lookup、Filter、Callback等。使用插件和模板可以使Playbook更加具有可读性和可维护性,使得动态内容的生成更加灵活和方便。

04、服务安装与主机管理

4.1安装服务器依赖

Playbook是Ansible的核心组件之一,用于定义和执行一系列任务。在使用Playbook之前,需要确保服务器上已经安装了Ansible和相关的依赖项。以下是安装服务器依赖的步骤:

4.1.1 安装Python3及其相关依赖项

sudo apt updatesudo apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev

4.1.2 安装Ansible

sudo apt-add-repository ppa:ansible/ansiblesudo apt updatesudo apt-get install -y ansible

4.1.3 (可选)安装 git

sudo apt updatesudo apt-get install -y git

4.1.4 检查Ansible是否安装

ansible --version

这样,您的服务器就已经安装了所需的依赖项以及Ansible。如果您计划在多台服务器上使用Ansible,则需要在每台服务器上重复这些步骤。

4.2配置远程服务器

在使用Playbook配置远程服务器之前,需要确保Ansible已经正确安装在本地机器上。然后,您需要做以下几个步骤:

4.2.1 创建inventory文件

创建新的inventory文件,用于定义您要配置的远程服务器的IP地址或域名。例如,您可以创建一个名为inventory的文件,并包含以下内容:

[webservers]192.168.1.100192.168.1.101[dbservers]192.168.1.102

在此示例中,我们定义了两个组,webservers和dbservers,并列出了它们中每个服务器的IP地址。

4.2.2 编写Playbook

编写一个Playbook,用于在远程服务器上执行特定的任务。例如,您可以创建一个名为web.yml的Playbook,并包含以下内容:

- name: Install andstart Nginx hosts: webservers become: true tasks: - name: Install Nginx apt: name: nginx update_cache: yes state: latest - name: Start Nginx service: name: nginx state: started enabled: true

在这个Playbook示例中,我们定义了一个名为Install and start Nginx的任务,它会在webservers组中的服务器上启动Nginx服务器。

4.2.3 运行Playbook

运行Playbook,在远程服务器上执行配置任务。例如,要在远程服务器上运行示例中的web.yml Playbook,可以使用以下命令:

ansible-playbook -i inventory web.yml

在执行此命令后,Ansible将使用inventory文件中定义的远程服务器的IP地址,并执行web.yml Playbook中定义的任务。

这是一个基本的Playbook配置远程服务器的示例。需要根据具体的场景和任务需求来进行个性化配置和修改。

4.3部署应用程序

Playbook部署应用程序一般步骤:

1、准备应用程序的部署包。这通常是一个.tar.gz或.zip文件,包含应用程序代码、依赖项和其他必要文件。2、在目标主机上安装所需的依赖项和软件包。例如,在部署Python应用程序时,需要安装Python解释器、pip和其他依赖项。3、创建一个目录用于应用程序的部署。这通常是在目标主机上的一个新目录,例如/home/user/myapp。4、上传应用程序部署包到目标主机并解压缩。您可以使用copy模块将部署包部署到目标主机上。5、配置应用程序的运行环境。例如,在部署Flask应用程序时,需要设置环境变量、安装必要的Python包等。6、配置Web服务器以侦听应用程序的请求。例如,您可以使用Nginx或Apache等Web服务器来代理应用程序请求。

05、常用模块的 playbook 语法

file模块:可以管理文件系统中的文件和目录。下面是该模块的常用参数:copy模块:可以将本地文件复制到远程服务器上。unarchive模块:Ansible 中用于将压缩文件解压缩的模块。apt模块:可以在Ubuntu或Debian系统上安装、升级、删除软件包。service模块:可以在系统上管理服务。user模块:可以管理系统用户。shell模块:可以在远程服务器上运行基于命令行的任务。该模块只能运行命令,不能使用管道、重定向和通配符。script模块:可以将本地脚本或可执行文件上传到远程服务器并在远程服务器上运行。该模块适用于运行复杂的命令和复杂的脚本。template模块:可以将在Ansible中定义的Jinja2模板应用于远程服务器上的文件。在应用模板时,您可以使用变量来一次生成多个文件的不同版本。lineinfile模块:可以从文件中添加、修改或删除单行文本。该模块可用于修改文件中的配置文件或语言文件,或添加新行。blockinfile模块:可以在远程服务器文件中添加、修改或删除代码块。该模块可以替代lineinfile模块,以单个块更新文件。debug模块:可以输出调试信息。该模块在编写Playbooks时非常有用,因为可以检查任务的变量和结果。

06、Ansible部署Pulsar集群运维实战

6.1部署zookeeper集群

6.1.1 定义host文件

host 文件指定了要在哪些主机上执行任务。在 playbook 中,可以将 hosts 指定为一个变量,也可以通过 -i 参数指定一个主机清单文件,该文件包含要操作的主机列表。

[all:vars]ansible_ssh_user=xxxansible_ssh_pass=xxx[zk]127.xxx.xxx.1 myid=1127.xxx.xxx.2 myid=2127.xxx.xxx.3 myid=3127.xxx.xxx.4 myid=4127.xxx.xxx.5 myid=5

6.1.2 定义变量

group_vars 目录用于存放针对不同主机组的变量文件,其中 all 文件是一种特殊的变量文件,它包含了全局的变量定义,将适用于所有主机组。路径结构如下:

group_vars/├── all

在all文件中,我们可以定义安装路径、JDK版本为、zookeeper版本以及zookeeper相关的配置信息。比如:

inst_home: /opt/bigdata/instapp_home: /opt/bigdata/appzk_inst_home: zookeeper-3.6.3zk_app_home: zookeeperjdk_inst_home: jdk1.8.0_192jdk_app_home: jdkjdk_tgz: jdk1.8.0_192.tar.gzzk_tgz: zookeeper-3.6.3.tar.gzcluster_name=clusterNameclient_port=2181server_port1=2881server_port2=2882jmx_port=9012admin_port=18080dataDir="/data/bigdata/zookeeper_{{cluster_name}}/zkDataDir"dataLogDir="/data/bigdata/zookeeper_{{cluster_name}}/zkDataLogDir"zoo_log_dir="/opt/bigdata/inst/zookeeper-3.6.3-{{cluster_name}}/logs/"

6.1.3 编辑roles模块

① check_port:检查端口

判断配置的端口是否被占用,如果被占用,则不能执行后续的步骤。

目录结构如下:

check_port/├── tasks/│ └── main.ymlmain.yml

#循环检查端口是否是停用状态

- name: Check port wait_for: host: "{{ inventory_hostname }}" port: "{{ item }}" delay: 2 timeout: 3 state: stopped register: result with_items: - "{{ client_port }}" - "{{ server_port1 }}" - "{{ server_port2 }}" - "{{ jmx_port }}" - "{{ admin_port }}"- name: print result debug: msg: "Port {{ item.item }} is {{ item.state }}" with_items: "{{ result.results }}"

② dispatch_zk:分发安装包

目录结构如下:

dispatch_zk/├── files/│ └── zookeeper-3.6.3.tar.gz├── tasks/│ └── main.yml

files:放zookeeper安装包文件。

main.yml

#分发zk安装包并解压到/tmp路径下- name: dispatch_zk unarchive: src: "{{zk_tgz}}" dest: "/tmp" mode: 755 owner: root group: root

③ config_zk:配置zookeeper

目录结构如下:

config_zk/├── tasks/│ └── main.yml├── templates/│ └── zoo.cfg

main.yml

#zoo.cfg模板文件应用到指定的路径下- name: zoo.cfg template: src: zoo.cfg dest: "{{ app_home }}/zk-{{ cluster_name }}/conf"#创建zoo_log_dir目录- name: mkdir forlog shell: mkdir -p "{{zoo_log_dir}}"#创建zk数据目录- name: mkdir for dataDir shell: mkdir -p "{{dataDir}}"#创建zk日志目录- name: mkdir for dataLogDir shell: mkdir -p "{{dataLogDir}}"#myid文件中输入每台主机的编号- name: myid file shell: echo "{{myid}}" > {{dataDir}}/myid

zoo.cfg:zookeeper配置文件模板。

tickTime=2000initLimit=10syncLimit=5maxClientCnxns=65535autopurge.snapRetainCount=30autopurge.purgeInterval=48clientPort={{client_port}}admin.serverPort={{admin_port}}dataDir={{dataDir}}dataLogDir={{dataLogDir}}{% for host in groups.zk%}server.{{ hostvars[host]['myid'] }}={{host}}:{{server_port1}}:{{server_port2}}{% endfor %}

deploy_zk:部署zookeeper服务

目录结构如下:

deploy_zk/├── files/│ └── env.sh│ └── jdk1.8.0_192.tar.gz├── tasks/│ └── main.yml

env.sh:jdk环境变量配置

JAVA_HOME=/opt/bigdata/app/jdkJRE_HOME=$JAVA_HOME/jrePATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATHCLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/rt.jar:$CLASSPATH

main.yml

#创建/opt/bigdata/inst目录- name: mkdir for inst_home shell: mkdir -p {{ inst_home }}#创建/opt/bigdata/app目录- name: mkdir for app_home shell: mkdir -p {{ app_home }}#注册zk_dir变量- name: stat_dir stat: path={{ inst_home }}/{{zk_inst_home}}-{{cluster_name}} register: zk_dir#当zk_dir存在时,将/tmp路径安装包移到指定目录并重命名- name: rename zookeeper dir command: mv /tmp/{{zk_inst_home}} {{ inst_home }}/{{zk_inst_home}}-{{cluster_name}} when: zk_dir.stat.exists == False#创建zk集群软连接- name: soft link file: path: "{{ app_home }}/zk-{{ cluster_name }}" src: "{{ inst_home }}/{{ zk_inst_home }}-{{ cluster_name }}" state: link#分发并解压jdk安装包- name: deploy jdk unarchive: src: "{{ jdk_tgz }}" dest: "{{ inst_home }}"#创建jdk软连接- name: create soft link for jdk file: path: "{{ app_home }}/{{ jdk_app_home }}" src: "{{ inst_home }}/{{ jdk_inst_home }}" state: link#运行jdk环境变量,使其生效- name: env script: env.sh

⑤ start_zk:启动zookeeper服务

目录结构如下:

start_zk/├── tasks/│ └── main.yml

main.yml

#启动zk服务

- name: start zookeeper shell: cd {{ app_home }}/zk-{{cluster_name}}; sh bin/zkServer.sh start

6.1.4 编辑任务执行和启动脚本

zookeeper.yml:任务执行脚本

---- name: check_port hosts: zk remote_user: root roles: - check_port tags: check_port- name: dispatch_zk hosts: zk remote_user: root roles: - dispatch_zk tags: dispatch_zk- name: deploy_zk hosts: zk remote_user: root roles: - deploy_zk tags: deploy_zk- name: config_zk hosts: zk remote_user: root roles: - config_zk tags: config_zk - name: start_zk hosts: zk remote_user: root roles: - start_zk tags: start_zk

6.1.5 部署并启动zookeeper服务

# 部署并启动zookeeper服务ansible-playbook -i hosts-clusterName zookeeper.yml#只检查端口和分发安装包ansible-playbook -i hosts-clusterName zookeeper.yml --tags "check_port,dispatch_packages"

6.2部署Pulsar集群

6.2.1 定义hosts文件

[all:vars]ansible_ssh_user=xxxansible_ssh_pass=xxx[pulsar]127.xxx.xxx.1127.xxx.xxx.2127.xxx.xxx.3127.xxx.xxx.4127.xxx.xxx.5

6.2.2 定义全局变量

group_vars 目录用于存放针对不同主机组的变量文件,其中 all 文件是一种特殊的变量文件,它包含了全局的变量定义,将适用于所有主机组。路径结构如下:

group_vars/├── all

all文件内容中定义变量信息,如下:

bigdata_home: /opt/bigdatainst_home: /opt/bigdata/instapp_home: /opt/bigdata/apppulsar_app_home: pulsarpulsar_inst_home: apache-pulsar-2.9.2-1.3pulsar_tgz: apache-pulsar-2.9.2-1.3-bin.tar.gzpulsar_conf: "{{ app_home }}/pulsar/conf"secret_key_dir: "{{ app_home }}/pulsar/data"#bookkeeper.confledgerDirectories: /data1/bookkeeper/ledger,/data2/bookkeeper/ledger,/data3/bookkeeper/ledger,/data4/bookkeeper/ledger#broker.conf or client.confzkServers: "127.xxx.xxx.1:2183,127.xxx.xxx.2:2183,127.xxx.xxx.3:2183/clusterName"clusterName: wenzhuwebServiceUrl: http://clusterNamexxxx:8080brokerServiceUrl: pulsar://clusterNamexxxx:6650

6.2.3 编辑roles模块

① dispatch_pulsar:分发安装包

目录结构如下:

dispatch_pulsar/├── files/│ └── apache-pulsar-2.9.2-1.3-bin.tar.gz├── tasks/│ └── main.yml

main.yml

#创建inst_home定义的目录- name: mkdir_inst_home file: path: "{{ inst_home }}" state: directory#创建app_home定义的目录- name: mkdir_app_home file: path: "{{ app_home }}" state: directory#分发并解压pulsar安装包到指定目录- name: dispatch_packages unarchive: src: "{{ pulsar_tgz }}" dest: "{{ inst_home }}"#创建pulsar软连接- name: soft_link file: path: "{{ app_home }}/pulsar" src: "{{ inst_home }}/{{ pulsar_inst_home }}" state: link

② check_nar:校验分层存储和kop扩展的依赖包

目录结构如下:

check_nar/├── tasks/│ └── main.yml

main.yml

#匹配指定路径protocols和offloaders下是否有nar后缀的文件- name: check nar find: paths: "{{ app_home }}/pulsar/{{ item }}/" patterns: "*.nar" register: result with_items: - "offloaders" - "protocols"#设置文件匹配的结果(大于0表示文件存在)- name: set nar_files_exist variable set_fact: nar_files_exist_{{item.item}}: "{{ item.matched > 0 }}" with_items: "{{ result.results }}"#如果文件不存在,进行提示- name: nar files not exist fail: msg: "{{ item.item }} nar files not found" when: nar_files_exist_{{ item.item }} == false ignore_errors: true with_items: "{{ result.results }}"#如果文件存在,列出存在的文件名- name: print nar files list debug: msg: "{{ item.files | map(attribute='path') | list }}" when: nar_files_exist_{{item.item}} with_items: "{{ result.results }}"

③ config_pulsar:配置pulsar

目录结构如下:

config_pulsar/├── tasks/│ └── main.yml├── templates/│ └── bkenv.sh│ └── pulsar_env.sh

main.yml

#匹配broker.conf中的advertisedAddress值并设置为远程主机ip地址- name: config_advertisedAddress lineinfile: path: "{{ pulsar_conf }}/broker.conf" regexp: "^advertisedAddress=" line: "advertisedAddress={{ inventory_hostname }}"#配置broker.conf中的zookeeperServers值- name: config_zookeeperServers lineinfile: path: "{{ pulsar_conf }}/broker.conf" regexp: "^zookeeperServers=" line: "zookeeperServers={{ zkServers }}"#配置broker.conf中的clusterName值- name: config_clusterName lineinfile: path: "{{ pulsar_conf }}/broker.conf" regexp: "^clusterName=" line: "clusterName={{ clusterName }}" #配置broker.conf中的kafkaAdvertisedListeners值- name: config_kafkaAdvertisedListeners lineinfile: path: "{{ pulsar_conf }}/broker.conf" regexp: "^kafkaAdvertisedListeners=" line: "kafkaAdvertisedListeners=PLAINTEXT://{{ inventory_hostname }}:9093"#配置bookkeeper.conf中的advertisedAddress值,设置为主机ip地址- name: config_bk_advertisedAddress lineinfile: path: "{{ pulsar_conf }}/bookkeeper.conf" regexp: "^advertisedAddress=" line: "advertisedAddress={{ inventory_hostname }}"#将模板文件bkenv.sh应用到pulsar的配置文件中- name: config_bkenv.sh template: src: bkenv.sh dest: "{{ pulsar_conf }}"#将模板文件pulsar_env.sh应用到pulsar的配置文件中- name: config_pulsar_env.sh template: src: pulsar_env.sh dest: "{{ pulsar_conf }}"

④ create_data_dir:创建存储数据的目录

目录结构如下:

create_data_dir/├── tasks/│ └── main.yml

main.yml

#循环创建with_items中的数据目录

- name: mkdir_data_dir file: path: "{{ item }}" state: directory with_items: - /data1/bookkeeper/ledger - /data2/bookkeeper/ledger - /data3/bookkeeper/ledger - /data4/bookkeeper/ledger

⑤ config_secret_key:配置安全秘钥

目录结构如下:

config_secret_key/├── files/│ └── admin-secret.key├── tasks/│ └── main.yml

main.yml

#创建存放安全秘钥的目录- name: create_secret_key_dir file: path: "{{ secret_key_dir }}" owner: root group: root state: directory#将安装秘钥文件分发到指定的路径下- name: dispatch_secret.key copy: src: admin-secret.key dest: "{{ secret_key_dir }}"

⑥ init_meta:初始化集群元数据

目录结构如下:

init_meta/├── tasks/│ └── main.yml├── templates/│ └── init_meta.sh

main.yml

#应用init_meta.sh脚本到远程主机- name: scp init_meta.sh template: src: init_meta.sh dest: "{{ app_home }}/pulsar"#执行初始化脚本文件- name: init_meta shell: nohup sh {{ app_home }}/pulsar/init_meta.sh > {{ app_home }}/pulsar/init.log2>&1 &#等待20s查询初始化日志中是否出现初始化成功的日志- name: wait20s wait_for: path: "{{ app_home }}/pulsar/init.log" search_regex: "Cluster metadata for '{{ clusterName }}' setup correctly" delay: 20#杀掉集群元数据初始化进程- name: kill metadata shell: ps -efww|grep PulsarClusterMetadataSetup|grep -v grep|cut -c 9-15|xargs kill -9init_meta.sh:初始化集群元数据脚本{{ app_home }}/pulsar/bin/pulsar initialize-cluster-metadata \--cluster {{ clusterName }} \--zookeeper {{ zkServers }} \--configuration-store {{ zkServers }} \--web-service-url {{ webServiceUrl }} \--broker-service-url {{ brokerServiceUrl }}

⑦ start_service:启动broker和bookkeeper服务

目录结构如下:

start_service/├── tasks/│ └── main.yml

main.yml

#启动远程主机bookkeeper服务- name: start bookie shell: sh {{ app_home }}/pulsar/bin/pulsar-daemon start bookie#启动远程主机broker服务- name: start broker shell: sh {{ app_home }}/pulsar/bin/pulsar-daemon start broker

6.2.4 编辑任务执行脚本

pulsar.yml:任务执行脚本

---#分发pulsar安装包- name: dispatch_pulsar hosts: pulsar remote_user: root become: yes become_flags: '-i' roles: - dispatch_pulsar tags: dispatch_pulsar#检查安装包中kop和分层存储nar包是否存在- name: check_nar hosts: pulsar remote_user: root roles: - check_nar tags: check_nar#修改pulsar配置- name: config_pulsar hosts: pulsar remote_user: root become: yes become_flags: '-i' roles: - config_pulsar tags: config_pulsar #创建磁盘数据目录- name: create_data_dir hosts: pulsar remote_user: root become: yes become_flags: '-i' roles: - create_data_dir tags: create_data_dir#配置证书文件- name: config_secret_key hosts: pulsar remote_user: root become: yes become_flags: '-i' roles: - config_secret_key tags: config_secret_key#初始化meta信息- name: init_meta hosts: pulsar[0] remote_user: root become: yes become_flags: '-i' roles: - init_meta tags: init_meta #启动broker和bookkeeper服务- name: start_service hosts: pulsar remote_user: root become: yes become_flags: '-i' roles: - start_service tags: start_service

6.2.5 执行playbook任务

#执行所有pulsar.yml中的任务ansible-playbook -i hosts pulsar.yml#只执行pulsar.yml中标签为dispatch_pulsar,check_nar的任务ansible-playbook -i hosts pulsar.yml --tags "dispatch_pulsar,check_nar"

07、Playbooks运维Pulsar集群总结

7.1Pulsar运维实践总结

Pulsar作为新一代云原生架构的分布式消息中间件,目前再超大流量规模、海量分区、超高QPS等场景下缺乏长时间的稳定性验证,在极端场景下还存在较多稳定性风险,当前社区版本迭代活跃;Pulsar集群在vivo内部日均处理消息达万亿+,需要不断的合并社区issue及灰度升级高版本。运维事项较多、投入的运维人力较大。vivo分布式消息中间件团队通过借助Ansible的模块化、任务依赖、配置check、批量脚本执行等能力实现Pulsar集群从zk集群搭建、Pulsar安装包编译、自动化配置填充、批量分发部署、服务启动的一键运维部署能力。大大缩减了Pulsar集群的运维人力投入,Pulsar组件存算分离的架构设计优秀,但部署配置项非常繁杂,通过自动化配置填充可有效规避配置信息不一致、版本不一致等高频错误。

7.2playbooks服务部署步骤

根据以上实战经验,我们可以总结出部署某个服务时编写playbooks脚本的一般步骤如下:

Ansible更多运维实践可参考:https://github.com/ansible/ansible-examples

免责声明

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

最新文章

1399元起 vivo Y500开售:8200mAh电池 史上最强续航

9月5日消息,今日,vivo Y500正式开售,售价1399元起,国补到手价1189元起。vivo Y500号称“续航耐用双灭霸”,内置8200mAh超薄蓝海电池,成为vivo史上最强续航手机。电池

2025-09-06.
6577

明年10月16上映!《街头霸王》电影真人版官宣:主演公布 春丽扮演者如何

9月5日消息,经历4年准备后,现在《街头霸王》真人电影最新宣布,影片会在2026年10月16日上映。根据最新发布的消息,演员名单中包括“海王”杰森莫玛(Jason Momoa)、说唱歌手50 Cen

2025-09-06.
1992

厉害了!中文有望成俄罗斯学校必学课

9月5日消息,据俄媒报道称,中文接下来可能成为俄罗斯学校的必学课。俄罗斯国家杜马议员阿纳托利·瓦谢尔曼称,由于俄罗斯与中国经济联系加强,中文在俄受欢迎程度不断提高。中文很可能成为俄罗斯学校的必修课。

2025-09-06.
4982

美国又出狠招 提出“GAIN AI”法案:拟全面限制高端AI芯片出口

当地时间9月2日,美国参议院公布了年度国防政策方案的初步版本,其中包括要求美国人工智能(AI)芯片厂商在向海外买家供应高性能AI芯片之前优先考虑国内订单,并明确呼吁拒绝出口最高端的AI GPU。美国

2025-09-06.
3490

时隔4年 麒麟回归!华为公布麒麟9020:专家称可确认全国产 美国制裁失效

9月5日消息,在昨天的发布会上,余承东一句话让现场沸腾。发布会现场,华为公布了麒麟9020处理器了,这一刻也引起了现场的沸腾,因为上一次这么直接公布处理器型号还是在4年前。据了解,麒麟芯片上一次出现

2025-09-06.
7875

热门教程

更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程

最新下载

更多
画境长恨歌手游
画境长恨歌手游 动作冒险 2025-09-05更新
查看
全战天下游戏
全战天下游戏 棋牌策略 2025-09-05更新
查看
Roblox国际服正
Roblox国际服正 休闲益智 2025-09-06更新
查看
罗布乐思地铁跑酷
罗布乐思地铁跑酷 休闲益智 2025-09-06更新
查看
医院逃生者
医院逃生者 休闲益智 2025-09-05更新
查看
战国手游
战国手游 棋牌策略 2025-09-06更新
查看
我的收纳摊
我的收纳摊 休闲益智 2025-09-05更新
查看
星球大爆炸手游
星球大爆炸手游 休闲益智 2025-09-05更新
查看
铠甲勇士英雄归来
铠甲勇士英雄归来 角色扮演 2025-09-06更新
查看
姜饼人王国国际服正
姜饼人王国国际服正 角色扮演 2025-09-06更新
查看