
Apache Pulsar is a distributed messaging and streaming platform that combines high-throughput message delivery with durable storage and built-in serverless computing. It supports multi-tenancy, geo-replication, and tiered storage. Google Pub/Sub is a fully managed messaging service that provides asynchronous messaging between applications with automatic scaling and global availability.
This article explains how to deploy Apache Pulsar as a self-hosted alternative to Google Pub/Sub. It covers Docker-based installation, Pulsar Manager UI setup, multi-tenancy configuration, Pulsar Functions for serverless processing, IO connectors for data integration, authentication and authorization, and migration strategies from Google Pub/Sub.
Google Pub/Sub is a fully managed messaging service tightly integrated with the Google Cloud ecosystem. Apache Pulsar offers comparable functionality with infrastructure independence and advanced features like built-in Functions and tiered storage.
Apache Pulsar maps to Google Pub/Sub concepts while providing additional flexibility through its layered architecture.
The Pulsar architecture consists of:
Before you begin, you need to:
pulsar.example.com).Docker provides the fastest path to a running Pulsar cluster. This setup uses the official Apache Pulsar images in standalone mode, running the broker, BookKeeper, and metadata store in one container. The broker exposes port 6650 for binary connections and port 8080 for the Admin REST API. Traefik handles HTTPS for the Pulsar Manager UI. The broker advertises localhost, so pulsar-admin and pulsar-client commands in this article run via docker exec rather than from outside the container.
Create the project directory with subdirectories for data, configuration, functions, and IO connectors.
Navigate to the project directory.
Create a .env file to store configuration values.
Add the following environment variables. Replace pulsar.example.com with your domain, admin@example.com with your email address, and PULSAR_MANAGER_PASSWORD with a strong password (minimum 6 characters) for the Pulsar Manager admin account.
Save and close the file.
Set permissions on the data directory so the container can write to it.
Create the admin initialization script. This script runs once on startup to create the Pulsar Manager admin account using the credentials from your .env file.
Add the following content.
Save and close the file.
Make the script executable.
Add your user to the docker group to run Docker commands without sudo.
Apply the group membership to the current session.
Create the Docker Compose configuration file.
Add the following configuration:
Save and close the file.
Start the stack.
Verify that the traefik, pulsar, and pulsar-manager containers show a running status.
The output shows all three containers with a status of Up.
Check the Pulsar startup logs for any errors.
The output shows the broker and BookKeeper starting. Wait until the broker is fully ready before proceeding.
Verify that the admin user was created by the init service.
The output shows {"message":"Add super user success, please login"}. The pulsar-manager-init container exits after this one-time setup and does not restart.
Pulsar Manager provides a web-based interface for managing clusters, tenants, namespaces, topics, subscriptions, and monitoring broker metrics. Pulsar creates two default tenants on startup: public, used for the default namespace, and pulsar, used for internal system topics.
Open a web browser and navigate to https://pulsar.example.com, replacing pulsar.example.com with your configured domain.
Log in with the administrator credentials created during setup and click Log in.
Click New Environment to register your Pulsar cluster.
Fill in the dialog fields:
local).http://pulsar:8080 in the Service URL field.http://pulsar:6650 in the Bookie URL field.
Click the environment name in the list to navigate to the management interface. Verify that the left sidebar shows Tenants, Namespaces, Topics, and Tokens under the Management section.
Pulsar's multi-tenancy model provides logical isolation between different teams, applications, or customers. Each tenant can have multiple namespaces, and each namespace can contain multiple topics with independent policies.
Create a new tenant using the Pulsar admin CLI.
Create a namespace within the tenant.
Configure retention policies for the namespace. This example retains messages for 7 days or up to 10 GB.
Configure message Time-to-Live (TTL) to automatically expire unacknowledged messages after 1 hour.
Create a topic within the namespace.
Verify that the topic was created.
The output displays the full topic name in the format persistent://my-tenant/production/orders.
Open the NAMESPACES tab for the my-tenant tenant in Pulsar Manager to view its namespaces.
Pulsar Functions provide lightweight serverless computing for stream processing directly within the Pulsar cluster. Functions can transform, filter, route, or aggregate messages without external systems like Apache Flink or Spark.
Create a sample Python function that converts messages to uppercase in the functions directory you created earlier.
Add the following code:
Save and close the file.
Deploy the function to process messages from an input topic and publish results to an output topic.
Verify that the function is running.
The output shows the function instances and their running status.
Test the function by producing a message to the input topic.
The Pulsar client prints several INFO log lines during startup. That is expected. The command is successful when it ends with 1 messages successfully produced.
Consume messages from the output topic.
The output displays content:HELLO WORLD, confirming the function processed the message.
Pulsar IO provides a framework for moving data between Pulsar and external systems. Source connectors ingest data from external systems into Pulsar topics, while sink connectors export data from Pulsar topics to external databases, storage systems, or services.
The standard Pulsar Docker image does not include built-in connector NAR files. Download the connector you need before deploying it. This section demonstrates the file source connector, which reads files from a local directory and publishes their content as messages to a Pulsar topic.
Download the file source connector NAR file into the connectors directory you created earlier.
Restart the Pulsar container to load the connector. Running admin commands before the broker is fully ready can return transient BookKeeper availability errors.
Wait for the broker to be fully ready before proceeding. Run the following command repeatedly until it returns ["standalone"].
List available source connectors to verify the file connector loaded.
The output shows file with its description.
Create the directory that the connector will monitor for new files.
Grant the Pulsar container write access to the input directory. The container runs as a non-root user, so open permissions are required for it to read files placed here.
Create the file source connector configuration file.
Add the following configuration:
Save and close the file.
Copy the configuration into the container.
Deploy the file source connector to publish file contents to a topic.
Verify the source connector is running.
The output shows "running": true when the connector is active.
Create a file in the input directory with two lines.
Consume the messages ingested by the connector.
The output displays two messages. Each message contains one line from the file in the content field and includes file.name, file.path, and file.modified.time in the properties field. The messages may arrive in any order. The final line confirms success. If you repeat this step, use a different value for --subscription-name each time, as an existing subscription resumes from where it last stopped and will not replay already-consumed messages.
Pulsar supports multiple authentication mechanisms including Transport Layer Security (TLS) certificates, JSON Web Tokens (JWT), and OAuth 2.0. This section configures JWT-based authentication for client connections.
Generate a secret key for signing JWT tokens.
Generate an admin token using the secret key and save it to a file.
Generate a client token for application access and save it to a file.
Stop the Pulsar container to apply configuration changes.
Export the default Pulsar configuration as a starting point.
Open the configuration file to append the authentication settings.
Scroll to the end of the file and append the following authentication settings.
The brokerClientAuthenticationPlugin and brokerClientAuthenticationParameters entries allow internal broker components such as the Functions worker to authenticate against the broker when JWT is enabled. Save and close the file.
Open the Docker Compose configuration file.
Add the following line to the volumes block under the pulsar service.
Save and close the file.
Start the Pulsar container with the new configuration. Wait for the broker to be fully ready before running authenticated commands.
Grant permissions to the client role on a namespace.
Test authenticated access using the client token saved earlier.
Pulsar Manager makes its own admin API calls to the broker, so it also needs a token now that authentication is enabled. Without this, the UI returns 401 Unauthorized on every tenant and topic request.
Export the default Pulsar Manager configuration as a starting point. This reads the file from the image directly rather than the running container, so it stays safe to rerun even after the file is bind-mounted in a later step.
Open the file to set the broker JWT properties.
Locate the following properties and set their values:
Replace YOUR_ADMIN_TOKEN with the contents of ~/pulsar/data/admin-token.txt. Save and close the file.
Open the Docker Compose configuration file.
Add a volumes block under the pulsar-manager service with the following lines.
A bind mount keeps this configuration in place if the container is ever recreated. A plain docker cp into the container only lasts until that happens. The dbdata mount covers Pulsar Manager's own database, which stores the admin login and any registered environments. Without it, both are lost on every recreation. Save and close the file.
Copy Pulsar Manager's existing database into the new mount point so the current admin login and environment carry over, then recreate the container to apply the configuration.
Each of the following checks covers an independent failure domain. These steps assume you completed Configure Authentication and Authorization earlier. All pulsar-admin and pulsar-client invocations require --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationToken and --auth-params "token:$(cat ~/pulsar/data/admin-token.txt)". Omitting them causes HTTP 401 Unauthorized.
Navigate to https://pulsar.example.com, log in with your configured credentials, and verify that the cluster dashboard loads correctly.
Test that the Pulsar binary protocol port accepts TCP connections. Replace SERVER-IP with your server's IP address. This confirms the port is open. Use docker exec for pulsar-admin and pulsar-client operations, since the broker advertises localhost for lookups.
Verify that the Admin REST API responds correctly using the admin token saved earlier.
The output displays ["standalone"] for a single-node deployment.
Create the verification topic if it does not already exist.
Verify that the topic appears in the topic list. JWT tokens generated with bin/pulsar tokens create are valid for broker authentication but do not appear in Pulsar Manager's Tokens page.
Produce a test message to the verification topic.
Consume the test message with a new subscription name. If you repeat this check, use a different subscription name such as verify-sub-2. --subscription-position Earliest only applies when a subscription is first created.
Check the status of the uppercase function.
A healthy function shows "running" : true.
Migrating from Google Pub/Sub to Pulsar involves mapping Google concepts to Pulsar equivalents, updating client configurations, and transferring message schemas and data. The examples below assume you completed Configure Authentication and Authorization earlier in this article.
Google Pub/Sub topics map directly to Pulsar persistent topics, and subscriptions map to Pulsar subscriptions with different types.
persistent://tenant/namespace/topic-name.Replace the Google Cloud Pub/Sub client library with the Pulsar client library for your language. Pulsar provides official clients for Java, Python, Go, Node.js, C++, and C#.
Google Pub/Sub supports Avro and Protocol Buffer schemas per topic. Pulsar includes a built-in schema registry. Refer to the Pulsar schema documentation for the schema format Pulsar expects and how to register schemas using pulsar-admin.
Google Pub/Sub push subscriptions deliver messages to HTTP endpoints. Replace these with Pulsar Functions that forward messages to external services. Refer to the Pulsar Functions documentation for implementation details.
Google Pub/Sub routes failed messages to a dead-letter topic after the maximum delivery attempts are exceeded. Pulsar supports equivalent behavior through dead-letter policies configured on subscriptions. Refer to the Pulsar dead-letter topic documentation for configuration details.
For topics with existing messages that need to be preserved:
http://localhost:8080/metrics/.You have deployed Apache Pulsar as a self-hosted alternative to Google Pub/Sub using Docker, configured multi-tenancy with namespaces and retention policies, deployed Pulsar Functions for serverless stream processing, set up IO connectors for data integration, enabled JWT-based authentication and authorization, and applied migration strategies for topics, schemas, and dead-letter queues. For more information, refer to the official Apache Pulsar documentation.
0 Comments
Be the first to comment and share your perspective with the community.