暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

vivo互联网技术 2025-08-14
94

作者:Liu Sikang、互联网大数据团队-Luo Mingbo


目录

01.  简介

02.  Playbook 语法

03.  Playbook 组织

04.  服务安装与主机管理

05.  常用模块的 playbook 语法 

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

07.  Playbooks运维Pulsar集群总结

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


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


1分钟看图掌握核心观点👇



01

简  介


1.1

Pulsar 运维面临的问题


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


升级频次高,对于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.2

    Tasks & 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.1

              Inclusions


              在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.2

                  Roles


                  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 update
                              sudo 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/ansible
                                sudo apt update
                                sudo apt-get install -y ansible



                                4.1.3 (可选)安装 git


                                (点击查看👇)

                                  sudo apt update
                                  sudo 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.100
                                      192.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=xxx
                                            ansible_ssh_pass=xxx


                                            [zk]
                                            127.xxx.xxx.1 myid=1
                                            127.xxx.xxx.2 myid=2
                                            127.xxx.xxx.3 myid=3
                                            127.xxx.xxx.4 myid=4
                                            127.xxx.xxx.5 myid=5



                                            6.1.2 定义变量


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


                                            (点击查看👇)

                                              group_vars/
                                              ├── all


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


                                              (点击查看👇)

                                                inst_home: opt/bigdata/inst
                                                app_home: opt/bigdata/app
                                                zk_inst_home: zookeeper-3.6.3
                                                zk_app_home: zookeeper
                                                jdk_inst_home: jdk1.8.0_192
                                                jdk_app_home: jdk
                                                jdk_tgz: jdk1.8.0_192.tar.gz
                                                zk_tgz: zookeeper-3.6.3.tar.gz


                                                cluster_name=clusterName
                                                client_port=2181
                                                server_port1=2881
                                                server_port2=2882
                                                jmx_port=9012
                                                admin_port=18080
                                                dataDir="/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.yml
                                                  main.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=2000
                                                              initLimit=10
                                                              syncLimit=5
                                                              maxClientCnxns=65535
                                                              autopurge.snapRetainCount=30
                                                              autopurge.purgeInterval=48
                                                              clientPort={{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/jdk
                                                                  JRE_HOME=$JAVA_HOME/jre
                                                                  PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
                                                                  CLASSPATH=$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
                                                                      commandmv /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=xxx
                                                                              ansible_ssh_pass=xxx


                                                                              [pulsar]
                                                                              127.xxx.xxx.1
                                                                              127.xxx.xxx.2
                                                                              127.xxx.xxx.3
                                                                              127.xxx.xxx.4
                                                                              127.xxx.xxx.5



                                                                              6.2.2 定义全局变量


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


                                                                              (点击查看👇)

                                                                                group_vars/
                                                                                ├── all

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

                                                                                  bigdata_home: opt/bigdata
                                                                                  inst_home: opt/bigdata/inst
                                                                                  app_home: opt/bigdata/app
                                                                                  pulsar_app_home: pulsar
                                                                                  pulsar_inst_home: apache-pulsar-2.9.2-1.3
                                                                                  pulsar_tgz: apache-pulsar-2.9.2-1.3-bin.tar.gz
                                                                                  pulsar_conf: "{{ app_home }}/pulsar/conf"
                                                                                  secret_key_dir: "{{ app_home }}/pulsar/data"


                                                                                  #bookkeeper.conf
                                                                                  ledgerDirectories: data1/bookkeeper/ledger,/data2/bookkeeper/ledger,/data3/bookkeeper/ledger,/data4/bookkeeper/ledger


                                                                                  #broker.conf or client.conf
                                                                                  zkServers: "127.xxx.xxx.1:2183,127.xxx.xxx.2:2183,127.xxx.xxx.3:2183/clusterName"
                                                                                  clusterName: wenzhu
                                                                                  webServiceUrl: http://clusterNamexxxx:8080
                                                                                  brokerServiceUrl: 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 }}"
                                                                                          statelink




                                                                                      ② 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 -9
                                                                                                          init_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.1

                                                                                                                  Pulsar运维实践总结


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


                                                                                                                  7.2

                                                                                                                  playbooks服务部署步骤


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




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


                                                                                                                  END


                                                                                                                  猜你喜欢


                                                                                                                  文章转载自vivo互联网技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                                                                                  评论