Operations 29 min read

Mastering Ansible Playbooks for Automated Pulsar Cluster Deployment

This guide walks through Pulsar's operational challenges and demonstrates how to use Ansible Playbooks—including syntax, modules, roles, variables, and task dependencies—to fully automate the deployment of Zookeeper and Pulsar clusters, dramatically reducing manual effort and configuration errors.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Mastering Ansible Playbooks for Automated Pulsar Cluster Deployment

Introduction

Pulsar, as a next‑generation cloud‑native distributed messaging middleware, solves many limitations of traditional systems like Kafka. In 2021 the vivo distributed messaging team began evaluating Pulsar, and in 2022 officially adopted it for big‑data scenarios. This article presents the operational pain points of Pulsar and shows how Ansible can automate its deployment.

Pulsar Operational Challenges

Rapid growth of new services requires independent clusters or resource groups.

Frequent upgrades demand coordinated configuration changes across the entire cluster.

High manual effort is needed to batch common deployment steps.

What Is an Ansible Playbook?

An Ansible Playbook is the core component of the automation tool, written in YAML. It defines variables, handlers, roles, and task tags to improve script reuse and maintainability.

Pulsar architecture overview
Pulsar architecture overview

The main modules shown in the diagram are:

Ansible : core program.

HostInventory : records managed host information.

Playbooks : YAML files containing multiple tasks.

CoreModules : built‑in modules for management tasks.

CustomModules : user‑defined modules supporting multiple languages.

ConnectionPlugins : handle communication between Ansible and hosts.

Playbook Syntax

A Playbook file starts with ---. Comments begin with #. Lists use - followed by a space. Key‑value pairs are separated by : with a trailing space.

- name: Playbook name
  hosts: target_hosts  # IP, domain, or group name
  remote_user: user
  become: yes
  tasks:
    - name: Task name
      module_name:
        param1: value1
      tags:
        - tag_name
      when: condition
      notify: handler_name

Tasks & Modules

Tasks are ordered steps executed on target hosts. Modules are the functional units that perform specific actions such as file management, package installation, or system queries.

Task Dependencies

Dependencies can be expressed with dependencies or notify statements.

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

Playbook Organization

Use include or import to bring other YAML files into a Playbook. include processes tasks immediately, while import only loads variables until needed.

- hosts: webservers
  tasks:
    - name: Include web tasks
      include: web-tasks.yml
- 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
      when: deploy_web_app

Roles

Roles package Playbooks, variables, templates, and other resources for reuse.

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

Use a role in a Playbook with the roles keyword:

- hosts: webservers
  roles:
    - my-role

Variables

vars:
  my_var: "Hello World"
- name: Print Message
  debug:
    msg: "{{ my_var }}"
- name: Set Dynamic Variable
  set_fact:
    my_var: "{{ inventory_hostname }} is awesome"

Plugins and Templates

Ansible provides plugins (action, lookup, filter, callback) and Jinja2 templates to generate dynamic content.

Service Installation & Host Management

Before using Playbooks, ensure Ansible and its dependencies are installed on the control node.

sudo apt update
sudo apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev
sudo apt-add-repository ppa:ansible/ansible
sudo apt update
sudo apt-get install -y ansible
ansible --version

Configure Remote Servers

Create an inventory file defining host groups:

[webservers]
192.168.1.100
192.168.1.101

[dbservers]
192.168.1.102

Write a Playbook to install and start Nginx:

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

Deploy Zookeeper Cluster (Ansible)

Define host inventory, global variables, and role tasks such as check_port, dispatch_zk, config_zk, and deploy_zk. Example of checking ports:

- 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 }}"

Distribute Zookeeper package:

- name: dispatch_zk
  unarchive:
    src: "{{ zk_tgz }}"
    dest: "/tmp"
    mode: 755
    owner: root
    group: root

Configure Zookeeper using a template zoo.cfg and create necessary directories.

Deploy Pulsar Cluster (Ansible)

Define hosts and global variables for Pulsar, then create roles such as dispatch_pulsar, check_nar, config_pulsar, create_data_dir, config_secret_key, init_meta, and start_service. Example of dispatching the Pulsar package:

- name: mkdir_inst_home
  file:
    path: "{{ inst_home }}"
    state: directory

- name: mkdir_app_home
  file:
    path: "{{ app_home }}"
    state: directory

- name: dispatch_packages
  unarchive:
    src: "{{ pulsar_tgz }}"
    dest: "{{ inst_home }}"

- name: soft_link
  file:
    path: "{{ app_home }}/pulsar"
    src: "{{ inst_home }}/{{ pulsar_inst_home }}"
    state: link

Check for required .nar files:

- name: check nar
  find:
    paths: "{{ app_home }}/pulsar/{{ item }}/"
    patterns: "*.nar"
  register: result
  with_items:
    - "offloaders"
    - "protocols"

- 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 }}"

Configure Pulsar settings via lineinfile and templates:

- name: config_advertisedAddress
  lineinfile:
    path: "{{ pulsar_conf }}/broker.conf"
    regexp: "^advertisedAddress="
    line: "advertisedAddress={{ inventory_hostname }}"

- name: config_zookeeperServers
  lineinfile:
    path: "{{ pulsar_conf }}/broker.conf"
    regexp: "^zookeeperServers="
    line: "zookeeperServers={{ zkServers }}"

- name: config_clusterName
  lineinfile:
    path: "{{ pulsar_conf }}/broker.conf"
    regexp: "^clusterName="
    line: "clusterName={{ clusterName }}"

- name: config_kafkaAdvertisedListeners
  lineinfile:
    path: "{{ pulsar_conf }}/broker.conf"
    regexp: "^kafkaAdvertisedListeners="
    line: "kafkaAdvertisedListeners=PLAINTEXT://{{ inventory_hostname }}:9093"

- name: config_bkenv.sh
  template:
    src: bkenv.sh
    dest: "{{ pulsar_conf }}/bkenv.sh"

- name: config_pulsar_env.sh
  template:
    src: pulsar_env.sh
    dest: "{{ pulsar_conf }}/pulsar_env.sh"

Create data directories, deploy secret keys, initialize cluster metadata, and start services using the respective roles.

Playbooks for Pulsar Deployment Summary

The Pulsar deployment practice shows that, despite Pulsar’s excellent compute‑storage separation architecture, its configuration complexity can lead to frequent errors. By leveraging Ansible’s modular tasks, role‑based organization, and automated checks, the entire deployment—from Zookeeper setup to Pulsar service start‑up—can be performed with a single command, dramatically reducing operational effort and minimizing configuration drift.

For further Ansible examples, see https://github.com/ansible/ansible-examples .

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AutomationdevopsZooKeeperPulsarAnsibleplaybook
vivo Internet Technology
Written by

vivo Internet Technology

Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.