偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

vivo Pulsar 萬億級消息處理實(shí)踐(4)-Ansible運(yùn)維部署

運(yùn)維
本篇文章主要從Pulsar運(yùn)維痛點(diǎn)、Ansible簡介、Ansible核心模塊詳解、Ansible自動(dòng)化部署zk集群、Ansible自動(dòng)化部署Pulsar集群幾個(gè)維度向大家介紹vivo Pulsar萬億級消息處理實(shí)踐之運(yùn)維部署。

Pulsar作為下一代云原生架構(gòu)的分布式消息中間件,存算分離的架構(gòu)設(shè)計(jì)能有效解決大數(shù)據(jù)場景下分布式消息中間件老牌一哥“Kafka”存在的諸多問題,2021年vivo 分布式消息中間件團(tuán)隊(duì)正式開啟對Pulsar的調(diào)研,2022年正式引入Pulsar作為大數(shù)據(jù)場景下的分布式消息中間件,本篇文章主要從Pulsar運(yùn)維痛點(diǎn)、Ansible簡介、Ansible核心模塊詳解、Ansible自動(dòng)化部署zk集群、Ansible自動(dòng)化部署Pulsar集群幾個(gè)維度向大家介紹vivo Pulsar萬億級消息處理實(shí)踐之運(yùn)維部署。

注:本文是《vivo Pulsar萬億級消息處理實(shí)踐》系列文章第4篇。

01、簡介

1.1Pulsar 運(yùn)維面臨的問題

新業(yè)務(wù)增長快,很多新業(yè)務(wù)接入需要搭建獨(dú)立的集群或者資源組。

升級頻次高,對于bug修復(fù),配置更改以及依賴組件替換等,都需要對全集群進(jìn)行升級、配置更改或組件替換。

人力投入大,在集群運(yùn)維時(shí),需要對公共的執(zhí)行步驟進(jìn)行批處理封裝,否則會(huì)耗費(fèi)大量人力在集群的部署和升級上。

1.2什么是 Ansible Playbook

Asnible Playbooks是Ansible自動(dòng)化工具的核心部分。它是基于YAML文件格式,用于在多個(gè)主機(jī)上執(zhí)行的任務(wù)。通過在Playbook中設(shè)置變量、處理器、角色和任務(wù)標(biāo)簽等功能,可以大大提高自動(dòng)化腳本的復(fù)用性和可維護(hù)性。可以理解為批處理任務(wù)。

上圖中我們看到Playbook的主要模塊如下:

  • Ansible:Ansible 的核心程序。
  • HostInventory:記錄由 Ansible 管理的主機(jī)信息,包括端口、密碼、ip 等。
  • Playbooks:“劇本” YAML 格式文件,多個(gè)任務(wù)定義在一個(gè)文件中,定義主機(jī)需要調(diào)用哪些模塊來完成的功能。
  • CoreModules:核心模塊,主要操作是通過調(diào)用核心模塊來完成管理任務(wù)。
  • CustomModules:自定義模塊,完成核心模塊無法完成的功能,支持多種語言。
  • ConnectionPlugins:連接插件,Ansible 和 Host 通信使用。

02、Playbook 語法

2.1書寫格式

playbook 常用到的YMAL格式:

  • 文件的第一行應(yīng)該以 "---" (三個(gè)連字符)開始,表明 YMAL 文件的開始。
  • 在同一行中,# 之后的內(nèi)容表示注釋,類似于 shell,python 和 ruby。
  • YMAL 中的列表元素以 ”-” 開頭然后緊跟著一個(gè)空格,后面為元素內(nèi)容。
  • 同一個(gè)列表中的元素應(yīng)該保持相同的縮進(jìn)。否則會(huì)被當(dāng)做錯(cuò)誤處理。
  • play 中 hosts,variables,roles,tasks 等對象的表示方法都是鍵值中間以 ":" 分隔表示,":" 后面還要增加一個(gè)空格。

以下是 Playbook 的基本語法書寫格式:

- name: playbook的名稱
  hosts: 目標(biāo)主機(jī)或主機(jī)組     # 可以使用普通的 IP 地址或域名,也可以使用主機(jī)組名稱
  remote_user: 遠(yuǎn)程用戶        # 使用 SSH 登錄遠(yuǎn)程主機(jī)時(shí)使用的用戶名
  become: yes                # 是否使用特權(quán)(例如 sudo)運(yùn)行命令
  tasks:                     # Playbook 中的任務(wù)列表
     - name: 任務(wù)名稱
       module_name: 參數(shù)       # Ansible 模塊的名稱和參數(shù)組成的字典,用于執(zhí)行操作
       tags:                    # 與該任務(wù)相關(guān)的標(biāo)記列表,用于執(zhí)行特定的任務(wù)
         - 標(biāo)簽名稱
       when: 條件             # 指定該任務(wù)在滿足特定條件下才會(huì)被執(zhí)行
       notify: 通知列表       # 指定依賴于該任務(wù)的另一個(gè)任務(wù)列表,當(dāng)這個(gè)任務(wù)被執(zhí)行后會(huì)自動(dòng)觸發(fā)這些任務(wù)

2.2Tasks & Modules

在Ansible Playbook的語法中,

"Tasks"和"Modules"是兩個(gè)核心概念。

Tasks(任務(wù)):Tasks是Playbook中的操作步驟或任務(wù),它們定義了要在目標(biāo)主機(jī)上執(zhí)行的操作??梢栽赑laybook中定義一個(gè)或多個(gè)任務(wù)。Tasks按照順序執(zhí)行,并且可以有條件地執(zhí)行或跳過。

Modules(模塊):Modules提供了執(zhí)行特定任務(wù)的功能單元。每個(gè)模塊負(fù)責(zé)處理不同的操作,如管理文件、安裝軟件包、查詢系統(tǒng)信息等。Ansible提供了許多內(nèi)置模塊,可以滿足大多數(shù)常見的操作。

通過組合不同的模塊和任務(wù),可以構(gòu)建復(fù)雜的Playbooks來執(zhí)行各種操作和配置任務(wù)。

2.3任務(wù)之間的依賴關(guān)系

在 Ansible 的 playbook 中,任務(wù)之間可以有依賴關(guān)系,你可以使用 dependencies 或者 notify 語句來定義。

2.3.1 使用 dependencies 定義任務(wù)依賴關(guān)系

如果任務(wù) A 依賴任務(wù) B 完成,可以使用 dependencies 定義任務(wù)依賴關(guān)系,語法如下:

- 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 任務(wù)在 Install Nginx 任務(wù)完成之后才會(huì)執(zhí)行。如果在執(zhí)行 Start Nginx 任務(wù)之前,Install Nginx 任務(wù)未完成或者執(zhí)行失敗,則 Start Nginx 任務(wù)也會(huì)失敗。

2.3.2 使用 notify 定義任務(wù)依賴關(guān)系

如果任務(wù) A 完成后需要通知任務(wù) B 執(zhí)行,可以使用 notify 定義任務(wù)依賴關(guān)系,語法如下:

- 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 任務(wù)完成后會(huì)通知 Start Nginx 任務(wù)執(zhí)行。然后 Start Nginx 任務(wù)會(huì)通過 listen 參數(shù)監(jiān)聽,等待通知執(zhí)行。

總之,Ansible 支持在 playbook 中定義任務(wù)之間的依賴關(guān)系。你可以使用 dependencies 或 notify 語句來定義任務(wù)之間的順序和依賴關(guān)系。

2.4條件判斷

在Playbook中,可以使用when關(guān)鍵字來添加條件判斷。when關(guān)鍵字后面跟一個(gè)條件表達(dá)式,如果表達(dá)式返回True,則任務(wù)會(huì)被執(zhí)行;如果返回False,則任務(wù)會(huì)被跳過。

條件表達(dá)式可以使用Ansible的Jinja2模板來編寫,例如:

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

在這個(gè)例子中,如果ansible_pkg_mgr變量等于"apt",則安裝Apache;否則跳過這個(gè)任務(wù)。

除了使用任務(wù)級別的條件判斷,還可以使用Play級別的條件判斷來控制整個(gè)Playbook的執(zhí)行。這可以通過在Play的開始處添加when關(guān)鍵字來實(shí)現(xiàn),例如:

- 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


在這個(gè)例子中,deploy_web_app變量的值為True時(shí),才會(huì)執(zhí)行任務(wù)Install Dependencies。如果deploy_web_app變量的值為False,則跳過整個(gè)Playbook的執(zhí)行。

2.5循環(huán)

在Playbook中,可以使用循環(huán)結(jié)構(gòu)來遍歷列表或其他可迭代對象,并對每個(gè)迭代項(xiàng)執(zhí)行相同的任務(wù)。這可以使用Ansible的with_*系列模塊來實(shí)現(xiàn)。

以下是一些常見的循環(huán)結(jié)構(gòu)的示例:

2.5.1 使用with_items模塊來遍歷列表

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

在這個(gè)例子中,將依次安裝python3、python3-pip和git。

03、Playbook 組織

3.1Inclusions

在Playbook的組織中,include和import兩個(gè)指令都可以用來將其他的yaml文件(也就是Tasks文件)包含到當(dāng)前的Playbook中。

它們的區(qū)別在于,當(dāng)主Playbook執(zhí)行到include指令時(shí),它將處理包含的文件中的所有任務(wù),并且在處理完之后繼續(xù)主Playbook的執(zhí)行。而當(dāng)主Playbook執(zhí)行到import指令時(shí),它只會(huì)處理被導(dǎo)入的文件中的變量定義,而不會(huì)處理任務(wù),任務(wù)只有在需要的時(shí)候才會(huì)被引入執(zhí)行。

下面是一個(gè)使用include指令包含其他文件的例子:

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

在這個(gè)例子中,主Playbook從web-tasks.yml文件中導(dǎo)入任務(wù),并在執(zhí)行完后繼續(xù)執(zhí)行余下的任務(wù)。

下面是一個(gè)使用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

在這個(gè)例子中,在主Playbook中使用import_vars指令來導(dǎo)入變量定義,然后在每個(gè)任務(wù)中都可以使用這些變量。然后我們使用include指令從app-tasks.yml文件中包含任務(wù),這些任務(wù)可以使用在vars.yml文件中定義的變量。這種方式可以在需要時(shí)懶加載任務(wù),提高性能。

需要注意的是,在被引入的文件中,不能再次使用- hosts:指令定義新的主機(jī)組,因?yàn)锳nsible只允許在主Playbook中定義主機(jī)組。被引入的文件只包含任務(wù),任務(wù)必須使用被定義的主機(jī)組來指定目標(biāo)主機(jī)。

3.2Roles

Ansible的Roles是一種組織Playbook的方式,它將Playbook和相關(guān)的變量、模板和其他資源打包在一起,并且可以輕松地在Playbook中重用和分享。一個(gè)Role通常適用于一種操作或功能,比如安裝和配置一個(gè)應(yīng)用程序、部署Web服務(wù)、安裝軟件包等等。

一個(gè)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:默認(rèn)變量定義文件。
  • files:包含角色使用的文件。
  • handlers/main.yml:Role的處理程序。
  • meta/main.yml:Role的元數(shù)據(jù),例如角色名稱、作者、依賴等。
  • tasks/main.yml:包含Role組成部分的主要任務(wù)。
  • templates:包含角色使用的Jinja2模板。
  • tests:Role的測試腳本。
  • vars/main.yml:包含Role的變量。

要使用Role,需要在Playbook中定義roles擴(kuò)展,例如:

- hosts: webservers
  roles:
    - my-role

這將運(yùn)行my-role目錄中包含的所有任務(wù)。

通過使用Role,可以更好地組織和重復(fù)使用代碼,并提高代碼的可讀性和可維護(hù)性。它還可以幫助您在Ansible社區(qū)中分享自己的工作,或從其他用戶那里獲得高質(zhì)量的Roles。

3.3引用/定義變量

在Playbook中,可以使用vars關(guān)鍵字來定義變量。例如:

vars:
  my_var: "Hello World"

這將定義一個(gè)名為my_var的變量,其值為字符串"Hello World"。

要在Playbook中訪問這個(gè)變量,可以使用{{ my_var }}語法。例如:

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

除了在vars中定義變量,還可以通過set_fact模塊來動(dòng)態(tài)設(shè)置變量。例如:

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

3.4使用插件和模板

Ansible提供了插件和模板的功能,使得在Playbook中使用動(dòng)態(tài)內(nèi)容變得更加簡單和方便。

插件是一種可以擴(kuò)展和定制Ansible功能的機(jī)制,可以在Playbook中調(diào)用和使用。常見的插件包括Action、Lookup、Filter、Callback等。使用插件和模板可以使Playbook更加具有可讀性和可維護(hù)性,使得動(dòng)態(tài)內(nèi)容的生成更加靈活和方便。

04、服務(wù)安裝與主機(jī)管理

4.1安裝服務(wù)器依賴

Playbook是Ansible的核心組件之一,用于定義和執(zhí)行一系列任務(wù)。在使用Playbook之前,需要確保服務(wù)器上已經(jīng)安裝了Ansible和相關(guān)的依賴項(xiàng)。以下是安裝服務(wù)器依賴的步驟:

4.1.1 安裝Python3及其相關(guān)依賴項(xiàng)

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

這樣,您的服務(wù)器就已經(jīng)安裝了所需的依賴項(xiàng)以及Ansible。如果您計(jì)劃在多臺服務(wù)器上使用Ansible,則需要在每臺服務(wù)器上重復(fù)這些步驟。

4.2配置遠(yuǎn)程服務(wù)器

在使用Playbook配置遠(yuǎn)程服務(wù)器之前,需要確保Ansible已經(jīng)正確安裝在本地機(jī)器上。然后,您需要做以下幾個(gè)步驟:

4.2.1 創(chuàng)建inventory文件

創(chuàng)建新的inventory文件,用于定義您要配置的遠(yuǎn)程服務(wù)器的IP地址或域名。例如,您可以創(chuàng)建一個(gè)名為inventory的文件,并包含以下內(nèi)容:

[webservers]
192.168.1.100
192.168.1.101


[dbservers]
192.168.1.102

在此示例中,我們定義了兩個(gè)組,webservers和dbservers,并列出了它們中每個(gè)服務(wù)器的IP地址。

4.2.2 編寫Playbook

編寫一個(gè)Playbook,用于在遠(yuǎn)程服務(wù)器上執(zhí)行特定的任務(wù)。例如,您可以創(chuàng)建一個(gè)名為web.yml的Playbook,并包含以下內(nèi)容:

- 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

在這個(gè)Playbook示例中,我們定義了一個(gè)名為Install and start Nginx的任務(wù),它會(huì)在webservers組中的服務(wù)器上啟動(dòng)Nginx服務(wù)器。

4.2.3 運(yùn)行Playbook

運(yùn)行Playbook,在遠(yuǎn)程服務(wù)器上執(zhí)行配置任務(wù)。例如,要在遠(yuǎn)程服務(wù)器上運(yùn)行示例中的web.yml Playbook,可以使用以下命令:

ansible-playbook -i inventory web.yml

在執(zhí)行此命令后,Ansible將使用inventory文件中定義的遠(yuǎn)程服務(wù)器的IP地址,并執(zhí)行web.yml Playbook中定義的任務(wù)。

這是一個(gè)基本的Playbook配置遠(yuǎn)程服務(wù)器的示例。需要根據(jù)具體的場景和任務(wù)需求來進(jìn)行個(gè)性化配置和修改。

4.3部署應(yīng)用程序

Playbook部署應(yīng)用程序一般步驟:

1、準(zhǔn)備應(yīng)用程序的部署包。這通常是一個(gè).tar.gz或.zip文件,包含應(yīng)用程序代碼、依賴項(xiàng)和其他必要文件。
2、在目標(biāo)主機(jī)上安裝所需的依賴項(xiàng)和軟件包。例如,在部署Python應(yīng)用程序時(shí),需要安裝Python解釋器、pip和其他依賴項(xiàng)。
3、創(chuàng)建一個(gè)目錄用于應(yīng)用程序的部署。這通常是在目標(biāo)主機(jī)上的一個(gè)新目錄,例如/home/user/myapp。
4、上傳應(yīng)用程序部署包到目標(biāo)主機(jī)并解壓縮。您可以使用copy模塊將部署包部署到目標(biāo)主機(jī)上。
5、配置應(yīng)用程序的運(yùn)行環(huán)境。例如,在部署Flask應(yīng)用程序時(shí),需要設(shè)置環(huán)境變量、安裝必要的Python包等。
6、配置Web服務(wù)器以偵聽?wèi)?yīng)用程序的請求。例如,您可以使用Nginx或Apache等Web服務(wù)器來代理應(yīng)用程序請求。

05、常用模塊的 playbook 語法

  • file模塊:可以管理文件系統(tǒng)中的文件和目錄。下面是該模塊的常用參數(shù):
  • copy模塊:可以將本地文件復(fù)制到遠(yuǎn)程服務(wù)器上。
  • unarchive模塊:Ansible 中用于將壓縮文件解壓縮的模塊。
  • apt模塊:可以在Ubuntu或Debian系統(tǒng)上安裝、升級、刪除軟件包。
  • service模塊:可以在系統(tǒng)上管理服務(wù)。
  • user模塊:可以管理系統(tǒng)用戶。
  • shell模塊:可以在遠(yuǎn)程服務(wù)器上運(yùn)行基于命令行的任務(wù)。該模塊只能運(yùn)行命令,不能使用管道、重定向和通配符。
  • script模塊:可以將本地腳本或可執(zhí)行文件上傳到遠(yuǎn)程服務(wù)器并在遠(yuǎn)程服務(wù)器上運(yùn)行。該模塊適用于運(yùn)行復(fù)雜的命令和復(fù)雜的腳本。
  • template模塊:可以將在Ansible中定義的Jinja2模板應(yīng)用于遠(yuǎn)程服務(wù)器上的文件。在應(yīng)用模板時(shí),您可以使用變量來一次生成多個(gè)文件的不同版本。
  • lineinfile模塊:可以從文件中添加、修改或刪除單行文本。該模塊可用于修改文件中的配置文件或語言文件,或添加新行。
  • blockinfile模塊:可以在遠(yuǎn)程服務(wù)器文件中添加、修改或刪除代碼塊。該模塊可以替代lineinfile模塊,以單個(gè)塊更新文件。
  • debug模塊:可以輸出調(diào)試信息。該模塊在編寫Playbooks時(shí)非常有用,因?yàn)榭梢詸z查任務(wù)的變量和結(jié)果。

06、Ansible部署Pulsar集群運(yùn)維實(shí)戰(zhàn)

6.1部署zookeeper集群

6.1.1 定義host文件

host 文件指定了要在哪些主機(jī)上執(zhí)行任務(wù)。在 playbook 中,可以將 hosts 指定為一個(gè)變量,也可以通過 -i 參數(shù)指定一個(gè)主機(jī)清單文件,該文件包含要操作的主機(jī)列表。

[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 目錄用于存放針對不同主機(jī)組的變量文件,其中 all 文件是一種特殊的變量文件,它包含了全局的變量定義,將適用于所有主機(jī)組。路徑結(jié)構(gòu)如下:

group_vars/
├── all

在all文件中,我們可以定義安裝路徑、JDK版本為、zookeeper版本以及zookeeper相關(guān)的配置信息。比如:

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:檢查端口

判斷配置的端口是否被占用,如果被占用,則不能執(zhí)行后續(xù)的步驟。

目錄結(jié)構(gòu)如下:

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

#循環(huán)檢查端口是否是停用狀態(tài)

- 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:分發(fā)安裝包

目錄結(jié)構(gòu)如下:

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

files:放zookeeper安裝包文件。

main.yml

#分發(fā)zk安裝包并解壓到/tmp路徑下
- name: dispatch_zk
  unarchive:
    src: "{{zk_tgz}}"
    dest: "/tmp"
    mode: 755
    owner: root
    group: root

③ config_zk:配置zookeeper

目錄結(jié)構(gòu)如下:

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

main.yml

#zoo.cfg模板文件應(yīng)用到指定的路徑下
- name: zoo.cfg
  template:
    src: zoo.cfg
    dest: "{{ app_home }}/zk-{{ cluster_name }}/conf"
#創(chuàng)建zoo_log_dir目錄
- name: mkdir forlog
  shell: mkdir -p "{{zoo_log_dir}}"


#創(chuàng)建zk數(shù)據(jù)目錄
- name: mkdir for dataDir
  shell: mkdir -p "{{dataDir}}"


#創(chuàng)建zk日志目錄
- name: mkdir for dataLogDir
  shell: mkdir -p "{{dataLogDir}}"


#myid文件中輸入每臺主機(jī)的編號
- 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服務(wù)

目錄結(jié)構(gòu)如下:

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

env.sh:jdk環(huán)境變量配置

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

#創(chuàng)建/opt/bigdata/inst目錄
- name: mkdir for inst_home
  shell: mkdir -p {{ inst_home }}


#創(chuàng)建/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


#當(dāng)zk_dir存在時(shí),將/tmp路徑安裝包移到指定目錄并重命名
- name: rename zookeeper dir
  command: mv /tmp/{{zk_inst_home}} {{ inst_home }}/{{zk_inst_home}}-{{cluster_name}}
  when: zk_dir.stat.exists == False


#創(chuàng)建zk集群軟連接
- name: soft link
  file:
    path: "{{ app_home }}/zk-{{ cluster_name }}"
    src: "{{ inst_home }}/{{ zk_inst_home }}-{{ cluster_name }}"
    state: link


#分發(fā)并解壓jdk安裝包
- name: deploy jdk
  unarchive:
    src: "{{ jdk_tgz }}"
    dest: "{{ inst_home }}"


#創(chuàng)建jdk軟連接
- name: create soft link for jdk
  file:
    path: "{{ app_home }}/{{ jdk_app_home }}"
    src: "{{ inst_home }}/{{ jdk_inst_home }}"
    state: link


#運(yùn)行jdk環(huán)境變量,使其生效
- name: env
  script: env.sh

⑤ start_zk:啟動(dòng)zookeeper服務(wù)

目錄結(jié)構(gòu)如下:

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

main.yml

#啟動(dòng)zk服務(wù)

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

6.1.4 編輯任務(wù)執(zhí)行和啟動(dòng)腳本

zookeeper.yml:任務(wù)執(zhí)行腳本

---
- 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 部署并啟動(dòng)zookeeper服務(wù)

# 部署并啟動(dòng)zookeeper服務(wù)
ansible-playbook -i hosts-clusterName zookeeper.yml


#只檢查端口和分發(fā)安裝包
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 目錄用于存放針對不同主機(jī)組的變量文件,其中 all 文件是一種特殊的變量文件,它包含了全局的變量定義,將適用于所有主機(jī)組。路徑結(jié)構(gòu)如下:

group_vars/
├── all

all文件內(nèi)容中定義變量信息,如下:

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:分發(fā)安裝包

目錄結(jié)構(gòu)如下:

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

main.yml

#創(chuàng)建inst_home定義的目錄
- name: mkdir_inst_home
  file:
    path: "{{ inst_home }}"
    state: directory


#創(chuàng)建app_home定義的目錄
- name: mkdir_app_home
  file:
    path: "{{ app_home }}"
    state: directory


#分發(fā)并解壓pulsar安裝包到指定目錄
- name: dispatch_packages
  unarchive:
    src: "{{ pulsar_tgz }}"
    dest: "{{ inst_home }}"


#創(chuàng)建pulsar軟連接
- name: soft_link
  file:
    path: "{{ app_home }}/pulsar"
    src: "{{ inst_home }}/{{ pulsar_inst_home }}"
    state: link

② check_nar:校驗(yàn)分層存儲(chǔ)和kop擴(kuò)展的依賴包

目錄結(jié)構(gòu)如下:

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"


#設(shè)置文件匹配的結(jié)果(大于0表示文件存在)
- name: set nar_files_exist variable
  set_fact:
    nar_files_exist_{{item.item}}: "{{ item.matched > 0 }}"
  with_items: "{{ result.results }}"


#如果文件不存在,進(jìn)行提示
- 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

目錄結(jié)構(gòu)如下:

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

main.yml

#匹配broker.conf中的advertisedAddress值并設(shè)置為遠(yuǎn)程主機(jī)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值,設(shè)置為主機(jī)ip地址
- name: config_bk_advertisedAddress
  lineinfile:
    path: "{{ pulsar_conf }}/bookkeeper.conf"
    regexp: "^advertisedAddress="
    line: "advertisedAddress={{ inventory_hostname }}"


#將模板文件bkenv.sh應(yīng)用到pulsar的配置文件中
- name: config_bkenv.sh
  template:
    src: bkenv.sh
    dest: "{{ pulsar_conf }}"


#將模板文件pulsar_env.sh應(yīng)用到pulsar的配置文件中
- name: config_pulsar_env.sh
  template:
    src: pulsar_env.sh
    dest: "{{ pulsar_conf }}"

④ create_data_dir:創(chuàng)建存儲(chǔ)數(shù)據(jù)的目錄

目錄結(jié)構(gòu)如下:

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

main.yml

#循環(huán)創(chuàng)建with_items中的數(shù)據(jù)目錄

- 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:配置安全秘鑰

目錄結(jié)構(gòu)如下:

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

main.yml

#創(chuàng)建存放安全秘鑰的目錄
- name: create_secret_key_dir
  file:
    path: "{{ secret_key_dir }}"
    owner: root
    group: root
    state: directory


#將安裝秘鑰文件分發(fā)到指定的路徑下
- name: dispatch_secret.key
  copy:
    src: admin-secret.key
    dest: "{{ secret_key_dir }}"

⑥ init_meta:初始化集群元數(shù)據(jù)

目錄結(jié)構(gòu)如下:

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

main.yml

#應(yīng)用init_meta.sh腳本到遠(yuǎn)程主機(jī)
- name: scp init_meta.sh
  template:
    src: init_meta.sh
    dest: "{{ app_home }}/pulsar"


#執(zhí)行初始化腳本文件
- name: init_meta
  shell: nohup sh {{ app_home }}/pulsar/init_meta.sh > {{ app_home }}/pulsar/init.log2>&1 &


#等待20s查詢初始化日志中是否出現(xiàn)初始化成功的日志
- name: wait20s
  wait_for:
    path: "{{ app_home }}/pulsar/init.log"
    search_regex: "Cluster metadata for '{{ clusterName }}' setup correctly"
    delay: 20


#殺掉集群元數(shù)據(jù)初始化進(jìn)程
- name: kill metadata
  shell: ps -efww|grep PulsarClusterMetadataSetup|grep -v grep|cut -c 9-15|xargs kill -9
init_meta.sh:初始化集群元數(shù)據(jù)腳本


{{ 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:啟動(dòng)broker和bookkeeper服務(wù)

目錄結(jié)構(gòu)如下:

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

main.yml

#啟動(dòng)遠(yuǎn)程主機(jī)bookkeeper服務(wù)
- name: start bookie
  shell: sh {{ app_home }}/pulsar/bin/pulsar-daemon start bookie


#啟動(dòng)遠(yuǎn)程主機(jī)broker服務(wù)
- name: start broker
  shell: sh {{ app_home }}/pulsar/bin/pulsar-daemon start broker

6.2.4 編輯任務(wù)執(zhí)行腳本

pulsar.yml:任務(wù)執(zhí)行腳本

---
#分發(fā)pulsar安裝包
- name: dispatch_pulsar
  hosts: pulsar
  remote_user: root
  become: yes
  become_flags: '-i'
  roles:
    - dispatch_pulsar
  tags: dispatch_pulsar


#檢查安裝包中kop和分層存儲(chǔ)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
   
  #創(chuàng)建磁盤數(shù)據(jù)目錄
- 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
   
#啟動(dòng)broker和bookkeeper服務(wù)
- name: start_service
  hosts: pulsar
  remote_user: root
  become: yes
  become_flags: '-i'
  roles:
    - start_service
  tags: start_service

6.2.5 執(zhí)行playbook任務(wù)

#執(zhí)行所有pulsar.yml中的任務(wù)
ansible-playbook -i hosts pulsar.yml


#只執(zhí)行pulsar.yml中標(biāo)簽為dispatch_pulsar,check_nar的任務(wù)
ansible-playbook -i hosts pulsar.yml --tags "dispatch_pulsar,check_nar"

07、Playbooks運(yùn)維Pulsar集群總結(jié)

7.1Pulsar運(yùn)維實(shí)踐總結(jié)

Pulsar作為新一代云原生架構(gòu)的分布式消息中間件,目前再超大流量規(guī)模、海量分區(qū)、超高QPS等場景下缺乏長時(shí)間的穩(wěn)定性驗(yàn)證,在極端場景下還存在較多穩(wěn)定性風(fēng)險(xiǎn),當(dāng)前社區(qū)版本迭代活躍;Pulsar集群在vivo內(nèi)部日均處理消息達(dá)萬億+,需要不斷的合并社區(qū)issue及灰度升級高版本。運(yùn)維事項(xiàng)較多、投入的運(yùn)維人力較大。vivo分布式消息中間件團(tuán)隊(duì)通過借助Ansible的模塊化、任務(wù)依賴、配置check、批量腳本執(zhí)行等能力實(shí)現(xiàn)Pulsar集群從zk集群搭建、Pulsar安裝包編譯、自動(dòng)化配置填充、批量分發(fā)部署、服務(wù)啟動(dòng)的一鍵運(yùn)維部署能力。大大縮減了Pulsar集群的運(yùn)維人力投入,Pulsar組件存算分離的架構(gòu)設(shè)計(jì)優(yōu)秀,但部署配置項(xiàng)非常繁雜,通過自動(dòng)化配置填充可有效規(guī)避配置信息不一致、版本不一致等高頻錯(cuò)誤。

7.2playbooks服務(wù)部署步驟

根據(jù)以上實(shí)戰(zhàn)經(jīng)驗(yàn),我們可以總結(jié)出部署某個(gè)服務(wù)時(shí)編寫playbooks腳本的一般步驟如下:

Ansible更多運(yùn)維實(shí)踐可參考:https://github.com/ansible/ansible-examples

責(zé)任編輯:龐桂玉 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2025-07-17 07:40:17

2025-06-12 02:00:00

2025-06-05 09:06:08

2022-09-14 23:14:10

vivoPulsar大數(shù)據(jù)

2025-03-06 10:33:04

2015-10-08 10:55:23

云服務(wù)自動(dòng)化運(yùn)維 ANSIBLE

2022-06-09 13:45:18

vivoK8S集群Kubernetes

2015-06-24 10:42:19

云計(jì)算運(yùn)維自動(dòng)化運(yùn)維ANSIBLE

2015-08-29 13:03:24

運(yùn)維技術(shù)沙龍MDSA

2015-11-03 16:03:09

AppDeploy運(yùn)維工具

2019-09-27 08:44:46

Ansible運(yùn)維DevOps

2016-06-17 15:21:43

小米運(yùn)維

2023-12-06 21:44:28

RocksDBvivo

2022-05-19 09:31:50

Kafka 集群數(shù)據(jù)存儲(chǔ)服務(wù)端

2020-08-06 14:36:24

Elasticsear集群運(yùn)維

2015-03-02 09:21:03

運(yùn)維監(jiān)控系統(tǒng)小米

2025-04-30 05:00:00

批量運(yùn)維系統(tǒng)

2013-06-09 10:38:54

IT運(yùn)維管理運(yùn)維管理ITIL管理

2014-09-22 11:24:18

運(yùn)維

2015-02-04 11:45:52

高效運(yùn)維
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號