Giter VIP home page Giter VIP logo

pulsar-helm-chart's Introduction

GitHub CircleCI LICENSE

Helm Chart for an Apache Pulsar Cluster

This Helm chart configures an Apache Pulsar cluster. It is designed for production use, but can also be used in local development environments with the proper settings.

It includes support for:

Helm must be installed and initialized to use the chart. Only Helm 3 is supported. Please refer to Helm's documentation to get started.

Upgrade considerations

Minikube quick start

Make sure you have minikube installed and running (e.g., minikube start --cpus 6 --memory 16G.)

Install the Helm chart:

helm repo add datastax-pulsar https://datastax.github.io/pulsar-helm-chart
helm repo update
curl -LOs https://datastax.github.io/pulsar-helm-chart/examples/dev-values.yaml
helm install pulsar -f dev-values.yaml --wait datastax-pulsar/pulsar

The Helm command waits until all pods are up, which takes about 5 minutes.

In another terminal, start the minikube tunnel:

minikube tunnel

Open your browser to http://localhost to view the Admin Console:

Admin Console

You can view the embedded Grafana charts using the Cluster/Monitoring menu in the Admin Console:

Grafana in Admin Console

Grafana is password protected. The username is admin. You can get the password with this command:

kubectl get secret pulsar-grafana -o=jsonpath="{.data.admin-password}" | base64 --decode

Quick start

With Helm installed to your local machine and with access to a Kubernetes cluster (e.g. minikube):

helm repo add datastax-pulsar https://datastax.github.io/pulsar-helm-chart
helm repo update
curl -LOs https://datastax.github.io/pulsar-helm-chart/examples/dev-values.yaml
helm install pulsar -f dev-values.yaml datastax-pulsar/pulsar 

Once all the pods are running (takes 5 to 10 minutes), you can access the admin console by forwarding to localhost:

kubectl port-forward $(kubectl get pods -l component=adminconsole -o jsonpath='{.items[0].metadata.name}') 8888:80

Then open a browser to http://localhost:8888. In the admin console, you can test your Pulsar setup using the built-in clients (Test Clients in the left-hand menu).

If you also forward the Grafana port, like this:

kubectl port-forward $(kubectl get pods -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000

You can view metrics for the Pulsar cluster via the Cluster, Monitoring menu item. You will have to log into Grafana. The username is admin and the password is in the downloaded file dev-values.yaml under the adminPassword setting.

To use the Pulsar admin and client tools (ex pulsar-admin, pulsar-client, pulsar-perf), log into the bastion pod:

kubectl exec $(kubectl get pods -l component=bastion -o jsonpath="{.items[*].metadata.name}") -it -- /bin/bash

You will find the tools in the /pulsar/bin directory.

Note: if you are using Cert-Manager to manage TLS certificates, see Enabling TLS using Cert-Manager for additional configuration information.

Add to local Helm repository

To add this chart to your local Helm repository:

helm repo add datastax-pulsar https://datastax.github.io/pulsar-helm-chart

To update to the latest chart:

helm repo update

Note: This command updates all your Helm charts.

To list the version of the chart in the local Helm repository:

helm search repo datastax-pulsar

Installing Pulsar in a Cloud Provider

Before you can install the chart, you need to configure the storage class settings for your cloud provider. The handling of storage varies from cloud provider to cloud provider.

Create a new file called storage_values.yaml for the storage class settings. To use an existing storage class (including the default one) set this value:

default_storage:
  existingStorageClassName: default or <name of storage class>

For each volume of each component (Zookeeper, Bookkeeper), you can override the default_storage setting by specifying a different existingStorageClassName. This allows you to match the optimum storage type to the volume.

If you have specific storage class requirement, for example fixed IOPS disks in AWS, you can have the chart configure the storage classes for you. Here are examples from the cloud providers:

# For AWS
# default_storage:
#  provisioner: kubernetes.io/aws-ebs
#  type: gp2
#  fsType: ext4
#  extraParams:
#     iopsPerGB: "10"


# For GCP
# default_storage:
#   provisioner: kubernetes.io/gce-pd
#   type: pd-ssd
#   fsType: ext4
#   extraParams:
#      replication-type: none

# For Azure
# default_storage:
#   provisioner: kubernetes.io/azure-disk
#   fsType: ext4
#   type: managed-premium
#   extraParams:
#     storageaccounttype: Premium_LRS
#     kind: Managed
#     cachingmode: ReadOnly

See the values file for more details on these settings.

Once you have your storage settings in the values file, install the chart like this :

helm install pulsar datastax-pulsar/pulsar --namespace pulsar --values storage_values.yaml --create-namespace

Using namespace scoped or cluster level RBAC resources

Up to Helm chart version 2.0.3, the Helm deployment uses ClusterRole and ClusterRoleBinding resources for defining access for service accounts by default. These resources get created outside the namespace defined for deployment. Since version 2.0.4, namespace scoped Role and RoleBinding resources are used by default.

It is possible to revert to use the legacy behavior by setting rbac.clusterRoles to true.

Installing Pulsar for development

This chart is designed for production use, but it can be used in development environments. To use this chart in a development environment (ex minikube), you need to:

  • Disable anti-affinity rules that ensure components run on different nodes
  • Reduce resource requirements
  • Disable persistence (configuration and messages are not stored so are lost on restart). If you want persistence, you will have to configure storage settings that are compatible with your development environment as described above.

For an example set of values, download this values file. Use that values file or one like it to start the cluster:

helm install pulsar -f dev-values.yaml datastax-pulsar/pulsar

Accessing the Pulsar cluster in cloud

The default values will create a ClusterIP for all components. ClusterIPs are only accessible within the Kubernetes cluster. The easiest way to work with Pulsar is to log into the bastion host:

kubectl exec $(kubectl get pods -l component=bastion -o jsonpath="{.items[*].metadata.name}") -it -- /bin/bash

Once you are logged into the bastion, you can run Pulsar admin commands:

bin/pulsar-admin tenants list

For external access, you can use a load balancer. Here is an example set of values to use for load balancer on the proxy:

proxy:
 service:
    type: LoadBalancer

If you are using a load balancer on the proxy, you can find the IP address using:

kubectl get service

Accessing the Pulsar cluster on localhost

To port forward the proxy admin and Pulsar ports to your local machine:

kubectl port-forward -n pulsar $(kubectl get pods -l component=proxy -o jsonpath='{.items[0].metadata.name}') 8080:8080

kubectl port-forward -n pulsar $(kubectl get pods -l component=proxy -o jsonpath='{.items[0].metadata.name}') 6650:6650

Or if you would rather go directly to the broker:

kubectl port-forward -n pulsar $(kubectl get pods -l component=broker -o jsonpath='{.items[0].metadata.name}') 8080:8080

kubectl port-forward -n pulsar $(kubectl get pods -l component=broker -o jsonpath='{.items[0].metadata.name}') 6650:6650

Managing Pulsar using Admin Console

You can install the Pulsar admin console in your cluster by enabling with this values setting:

component:
  pulsarAdminConsole: true

It will be automatically configured to connect to the Pulsar cluster.

By default, the admin console has authentication disabled. You can enable authentication with these settings:

pulsarAdminConsole:
    authMode: k8s

When k8s authentication mode is enabled, the admin console gets the users from Kubernetes secrets that start with dashboard-user- in the same namespace where it is deployed. The text that follows the prefix is the username. For example, for a user admin you need to have a secret dashboard-user-admin. The secret data must have a key named password with the base-64 encoded password. The following command will create a secret for a user admin with a password of password:

kubectl create secret generic dashboard-user-admin --from-literal=password=password

You can create multiple users for the admin console by creating multiple secrets. To change the password for a user, delete the secret then recreate it with a new password:

kubectl delete secret dashboard-user-admin
kubectl create secret generic dashboard-user-admin --from-literal=password=newpassword

For convenience, the Helm chart is able to create an initial user for the admin console with the following settings:

pulsarAdminConsole:
    createUserSecret:
      enabled: true
      user: 'admin'
      password: 'password'

Accessing Admin Console on your local machine

To access the Pulsar admin console on your local machine, forward port 80:

kubectl port-forward -n pulsar $(kubectl get pods -n pulsar -l component=adminconsole -o jsonpath='{.items[0].metadata.name}') 8888:80

Accessing Admin Console from cloud provider

To access Pulsar admin console from a cloud provider, the chart supports Kubernetes Ingress. Your Kubernetes cluster must have a running Ingress controller (ex Nginx, Traefik, etc.).

Set these values to configure the Ingress for the admin console:

pulsarAdminConsole:
  ingress:
    enabled: true
    host: pulsar-ui.example.com

Enabling TLS using Cert-Manager

When using Cert-Manager to create your TLS certificates, you must first install the Cert-Manager CRDs. These are installed using the following command:

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml

NOTE: if you're deploying a version of the chart before 3.0.0, you'll need to use version v1.5.5 of the CRDs.

If you don't, you will get error messages like this:

Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: [resource mapping not found for name: "pulsar-ca-certificate" namespace: "pulsar" from "": no matches for kind "Certificate" in version "cert-manager.io/v1"

Prometheus stack

Enabling the Prometheus stack

You can enable a full Prometheus stack (Prometheus, Alertmanager, Grafana) from kube-prometheus. This includes default Prometheus rules and Grafana dashboards for Kubernetes.

In an addition, this chart can deploy Grafana dashboards for Pulsar as well as Pulsar-specific rules for Prometheus.

To deploy the Prometheus stack, use the following setting in your values file:

kube-prometheus-stack:
  enabled: true

To enable the Kubernetes default rules, use the following setting:

kube-prometheus-stack:
  defaultRules:
    create: true

Deploying and Discovering a PodMonitor

In order to simplify metrics gathering, the helm chart has support for deploying a PodMonitor. This single monitor configures scraping all the available metrics endpoints for a given Pulsar Cluster deployed by the helm chart. This PodMonitor can be deployed by setting the following in your values file:

enablePulsarPodMonitor: true

Note that this will deploy a PodMonitor in the release's namespace. If you are running a Prometheus Operator in another Kubernetes namespace, you may need to modify the configuration to make sure that the operator can discover PodMonitors in the release's namespace.

Disabling the Prometheus stack

As some kube-prometheus-stack components need CRDs to be installed and kube-prometheus-stack.enabled: false does not alone prevent components' CRDs installation, the kube-prometheus-stack components should be disabled one by one, if the service account used to deploy the cluster does not have enough permissions to install CRDs.

In order to prevent all kube-prometheus-stack CRDs from being installed, the following should be added to values.yaml:

kube-prometheus-stack:
  enabled: false
  prometheusOperator:
    enabled: false
  grafana:
    enabled: false
  alertmanager:
    enabled: false
  prometheus:
    enabled: false

Grafana Dashboards

DataStax has several custom dashboards to help interpret Pulsar metrics. These custom dashboards are installed when the following is set in the values file:

grafanaDashboards:
  enabled: true

Starting in Pulsar 2.8.0, the bundled Zookeeper process exports its own metrics instead of using the Pulsar metrics implementation. This results in new metrics names. As a result, we install two Grafana dashboards for Zookeeper. The first is a custom DataStax dashboard that works for versions before 2.8.0. The second is the official Zookeeper community Grafana dashboard: https://grafana.com/grafana/dashboards/10465.

Example configurations

There are several example configurations in the examples directory:

  • dev-values.yaml. A configuration for setting up a development environment to run in a local Kubernetes environment (ex minikube, kind). Message/state persistence, redundancy, authentication, and TLS are disabled.

Note: With message/state persistence disabled, the cluster will not survive a restart of the ZooKeeper or BookKeeper.

  • dev-values-persistence. Same as above, but persistence is enabled. This will allow for the cluster to survive the restarts of the pods, but requires persistent volume claims (PVC) to be supported by the Kubernetes environment.
  • dev-values-auth.yaml. A development environment with authentication enabled. New keys and tokens from those keys are automatically generated and stored in Kubernetes secrets. You can retrieve the superuser token from the admin console (Credentials menu) or from the secret token-superuser.
  • dev-values-keycloak-auth.yaml. A deployment environment with authentication enabled along with a running keycloak server that can create additional tokens. Like the dev-values-auth.yaml, it will create a superuser token for use by pulsar components.

helm install pulsar -f dev-values-auth.yaml datastax-pulsar/pulsar

  • dev-values-tls.yaml. Development environment with self-signed certificate created by cert-manager. You need to install the cert-manager CRDs before installing the Helm chart. The chart will install the cert-manager application.
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml
helm install pulsar -f dev-values-tls.yaml datastax-pulsar/pulsar

NOTE: if you're deploying a version of the chart before 3.0.0, you'll need to use version v1.5.5 of the CRDs.

Tiered Storage

Tiered storage (offload to blob storage) can be configured in the storageOffload section of the values.yaml file. Instructions for AWS S3, Google Cloud Storage and Azure are provided in the file.

In addition, you can configure any S3 compatible storage. There is explicit support for Tardigrade, which is a provider of secure, decentralized storage. You can enable the Tardigrade S3 gateway in the extra configuration. The instructions for configuring the gateway are provided in the tardigrade section of the values.yaml file.

Pulsar SQL

If you enable Pulsar SQL, the cluster provides Presto access to the data stored in BookKeeper (and tiered storage, if enabled). Presto is exposed on the service named <release>-sql.

The easiest way to access the Presto command line is to log into the bastion host and then connect to the Presto service port, like this:

bin/pulsar sql --server pulsar-sql:8090

Where the value for the server option should be the service name plus port. Once you are connected, you can enter Presto commands:

presto> SELECT * FROM system.runtime.nodes;
               node_id                |         http_uri         | node_version | coordinator | state  
--------------------------------------+--------------------------+--------------+-------------+--------
 64b7c5a1-9a72-4598-b494-b140169abc55 | http://10.244.5.164:8080 | 0.206        | true        | active 
 0a92962e-8b44-4bd2-8988-81cbde6bab5b | http://10.244.5.196:8080 | 0.206        | false       | active 
(2 rows)

Query 20200608_155725_00000_gpdae, FINISHED, 2 nodes
Splits: 17 total, 17 done (100.00%)
0:04 [2 rows, 144B] [0 rows/s, 37B/s]

To access Pulsar SQL from outside the cluster, you can enable the ingress option which will expose the Presto port on hostname. We have tested with the Traefik ingress, but any Kubernetes ingress should work. You can then run SQL queries using the Presto CLI and monitoring Presto using the built-in UI (point browser to the ingress hostname). Authentication is not enabled on the UI, so you can log in with any username.

It is recommended that you match the Presto CLI version to the version running as part of Pulsar SQL.

The Presto CLI supports basic authentication, so if you enabled that on the ingress (using annotations), you can have secure Presto access.

presto --server https://presto.example.com --user admin --password
Password: 
presto> show catalogs;
 Catalog 
---------
 pulsar  
 system  
(2 rows)

Query 20200610_131641_00027_tzc7t, FINISHED, 1 node
Splits: 19 total, 19 done (100.00%)
0:01 [0 rows, 0B] [0 rows/s, 0B/s]

Dependencies

The Helm chart has the following optional dependencies:

Authentication

The chart can enable two forms of token-based authentication for a Pulsar cluster. See below for information on each:

The chart includes tooling to automatically create the necessary secrets, or you can do this manually.

OpenID Connect Authentication

DataStax created the OpenID Connect Authentication Plugin to provide a more dynamic authentication option for Pulsar. This plugin integrates with your OIDC compliant Identity Provider or the chart can deploy a Keycloak instance in the kubernetes cluster. This plugin integrates with an Identity Provider to dynamically retrieve Public Keys from the Identity Provider for token validation. This dynamic public key retrieval enables support for key rotation and multiple authentication/identity providers by configuring multiple allowed token issuers. It also means that token secret keys will not be stored in Kubernetes secrets.

In order to simplify deployment for Pulsar cluster components, the plugin provides the option to use OIDC in conjunction with Pulsar's basic token based authentication. See the plugin project for information about configuration.

Bring Your Own Identity Provider

To enable OpenID Connect with your already running Identity Provider, configure the openid section in the values and the authenticationProviders in the broker, proxy, and function worker.

Here is an example of the values using Okta:

openid:
  enabled: true
  # Comma delimited list of issuers to trust
  allowedIssuerUrls: "https://dev-1111111.okta.com/oauth2/abcd878787"
  allowedAudience: api://pulsarClient

broker:
  authenticationProviders: "com.datastax.oss.pulsar.auth.AuthenticationProviderOpenID"
proxy:
  authenticationProviders: "com.datastax.oss.pulsar.auth.AuthenticationProviderOpenID"
function:
  authenticationProviders: "com.datastax.oss.pulsar.auth.AuthenticationProviderOpenID"

The AuthenticationProviderOpenID class is included with all Luna Streaming Docker images.

Using Keycloak Deployed by Chart

Here is an example helm values file for deploying a working cluster that integrates with keycloak. By default, the helm chart creates a pulsar realm within keycloak and sets up the client used by the Pulsar Admin Console as well as a sample client and some sample groups. The configuration for the broker side auth plugin should be placed in the .Values.<component>.configData maps.

Configuring Keycloak for Token Generation

First deploy the cluster:

$ helm install test --values ../../examples/dev-values-keycloak-auth.yaml .

The name of the deployment is very important for a working cluster. The values file assumes that the cluster's name is test, as shown above. Once the cluster is operational, you can start configuring keycloak. Port forward to keycloak:

$ kubectl port-forward test-keycloak-0 8080:8080

Then, using a browser, navigate to localhost:8080. At this point, you will need to retrieve the configured username and password for the admin user in keycloak. The values file configures them here:

keycloak:
  auth:
    adminUser: "admin"
    adminPassword: "F3LVqnxqMmkCQkvyPdJiwXodqQncK@"

Once in to the keycloak UI, you can view the pulsar realm. Note that the realm name must match the configured realm name (.Values.keycloak.realm) for the OpenID Connect plugin to work properly.

The OpenID Connect plugin uses the sub (subject) claim from the JWT as the role used for authorization within Pulsar. In order to get Keycloak to generate the JWT for a client with the right sub, you can create a special "mapper" that is a "Hardcoded claim" mapping claim name sub to a claim value that is the disired role, like superuser. The default config installed by this helm chart provides examples of how to add custom mapper protocols to clients.

Retrieving and Using a token from Keycloak with Pulsar Admin CLI

After creating your realm and client, you can retrieve a token. In order to generate a token that will have an allowed issuer, you should exec into a pod in the k8s cluster. Exec'ing into a bastion host will give you immediate access to a pulsar-admin cli tool that you can use to verify that you have access. The following is run from a bastion pod.

pulsar@pulsar-bastion-85c9b777f6-gt9ct:/pulsar$ curl -d "client_id=test-client" \
       -d "client_secret=19d9f4a2-65fb-4695-873c-d0c1d6bdadad" \
       -d "grant_type=client_credentials" \
       "http://test-keycloak/realms/pulsar/protocol/openid-connect/token"
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJDY3c3ZXcwQ0hKMThfbWpCQzYxb2xOSU1wT0d3TkEyd1ZFbHBZLUdzb2tvIn0.eyJleHAiOjE2MjY5NzUwNzIsImlhdCI6MTYyNjk3NDQ3MiwianRpIjoiYTExZmFkY2YtYTJkZi00NmNkLTk0OWEtNDdkNzdmNDYxMDMxIiwiaXNzIjoiaHR0cDovL3Rlc3Qta2V5Y2xvYWsvYXV0aC9yZWFsbXMvcHVsc2FyIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImQwN2UxOGIxLTE4YzQtNDZhMC1hNGU0LWE3YTZjNmRiMjFkYyIsInR5cCI6IkJlYXJlciIsImF6cCI6InRlc3QtY2xpZW50IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsImRlZmF1bHQtcm9sZXMtcHVsc2FyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzdWIiOiJzdXBlcnVzZXIiLCJjbGllbnRIb3N0IjoiMTcyLjE3LjAuMSIsImNsaWVudElkIjoidGVzdC1jbGllbnQiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10ZXN0LWNsaWVudCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTcuMC4xIn0.FckQLOD64ZTKmx2uutP75QBpZAqHaqWyEE6jRUXvbSzsiXTAQyz-30zKsUSEjOMJp97NlTy3NZECVo_GdZ7oPcneFdglmFY62btWj-5s6ELcazj-AGQhyt0muGD4VP71xjpjCUpVxhyBIQlltGZLu7Rgw4trfh3LS8YjaY74vGg_BjOzZ8VI4S352lyGOULou7_dRbaeKhv43OfU7e_Y_ro_m_9UaDARypcj3uqSllhZdifA4YbHyaBCCu5eH19GCLtFm3I00PvWkOy3iTyOkkTcayqJ-Vlraf95qCZFN-sooIIU6o8L-wS-Zr7EvkoDJ-II9q49WHJJLIIvnCE2ug","expires_in":600,"refresh_expires_in":0,"token_type":"Bearer","not-before-policy":0,"scope":"email profile"}

Then, you can copy the access_token contents and use it here:

pulsar@pulsar-bastion-85c9b777f6-gt9ct:/pulsar$ bin/pulsar-admin --auth-params "token:eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJDY3c3ZXcwQ0hKMThfbWpCQzYxb2xOSU1wT0d3TkEyd1ZFbHBZLUdzb2tvIn0.eyJleHAiOjE2MjY5NzUwNzIsImlhdCI6MTYyNjk3NDQ3MiwianRpIjoiYTExZmFkY2YtYTJkZi00NmNkLTk0OWEtNDdkNzdmNDYxMDMxIiwiaXNzIjoiaHR0cDovL3Rlc3Qta2V5Y2xvYWsvYXV0aC9yZWFsbXMvcHVsc2FyIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImQwN2UxOGIxLTE4YzQtNDZhMC1hNGU0LWE3YTZjNmRiMjFkYyIsInR5cCI6IkJlYXJlciIsImF6cCI6InRlc3QtY2xpZW50IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsImRlZmF1bHQtcm9sZXMtcHVsc2FyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzdWIiOiJzdXBlcnVzZXIiLCJjbGllbnRIb3N0IjoiMTcyLjE3LjAuMSIsImNsaWVudElkIjoidGVzdC1jbGllbnQiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10ZXN0LWNsaWVudCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTcuMC4xIn0.FckQLOD64ZTKmx2uutP75QBpZAqHaqWyEE6jRUXvbSzsiXTAQyz-30zKsUSEjOMJp97NlTy3NZECVo_GdZ7oPcneFdglmFY62btWj-5s6ELcazj-AGQhyt0muGD4VP71xjpjCUpVxhyBIQlltGZLu7Rgw4trfh3LS8YjaY74vGg_BjOzZ8VI4S352lyGOULou7_dRbaeKhv43OfU7e_Y_ro_m_9UaDARypcj3uqSllhZdifA4YbHyaBCCu5eH19GCLtFm3I00PvWkOy3iTyOkkTcayqJ-Vlraf95qCZFN-sooIIU6o8L-wS-Zr7EvkoDJ-II9q49WHJJLIIvnCE2ug" \
      tenants list
"public"
"pulsar"

Pulsar's Token Based Authentication

This token based authentication relies on a plugin provided by Apache Pulsar using the AuthenticationProviderToken class that ships with Pulsar.

For information on token-based authentication from Apache Pulsar, go here.

For authentication to work, the token-generation keys need to be stored in Kubernetes secrets along with some default tokens (for superuser access).

The chart includes tooling to automatically create the necessary secrets, or you can do this manually.

Automatic generation of secrets for token authentication

Use these settings to enable automatic generation of the secrets and enable token-based authentication:

enableTokenAuth: true
autoRecovery:
  enableProvisionContainer: true

When the provision container is enabled, it will check if the required secrets exist. If they don't exist, it will generate new token keys and use those keys to generate the default set of tokens

The name of the key secrets are:

  • token-private-key
  • token-public-key

Using these keys, it will generate tokens for each role listed in superUserRoles. Based on the default settings, the following secrets will be created to store the tokens:

  • token-superuser
  • token-admin
  • token-proxy
  • token-websocket

Manual secret creation for token authentication

A number of values need to be stored in secrets prior to enabling token-based authentication. First, you need to generate a key-pair for signing the tokens using the Pulsar tokens command:

bin/pulsar tokens create-key-pair --output-private-key my-private.key --output-public-key my-public.key

Note: The names of the files used in this section match the default values in the chart. If you used different names, then you will have to update the corresponding values.

Then you need to store those keys as secrets.

kubectl create secret generic token-private-key \
 --from-file=my-private.key \
 --namespace pulsar
kubectl create secret generic token-public-key \
 --from-file=my-public.key \
 --namespace pulsar

Using those keys, generate tokens with subjects(roles):

bin/pulsar tokens create --private-key file:///pulsar/token-private-key/my-private.key --subject <subject>

You need to generate tokens with the following subjects:

  • admin
  • superuser
  • proxy
  • websocket (only required if using the standalone WebSocket proxy)

Once you have created those tokens, add each as a secret:

kubectl create secret generic token-<subject> \
 --from-file=<subject>.jwt \
 --namespace pulsar

Once you have created the required secrets, you can enable token-based authentication with this setting in the values:

enableTokenAuth: true

TLS

TLS with Client Facing Components

There are many components to consider when enabling TLS for a Pulsar Cluster. To enable TLS for all client facing endpoints, set enableTls: true in the values file and configure certificates. This setting will enable TLS endpoints for the Broker pods, Function Worker pods, and Proxy pods. However, this setting will not configure the proxy or the function worker to use TLS for connections with the broker. You can enable those by configuring tls.proxy.enableTlsWithBroker: true and tls.function.enableTlsWithBroker: true, respectively. Because the function worker only connects to the broker over TLS when authentication is configured, make sure to enable authentication if you'd like the function worker to connect to the broker over TLS.

TLS within all components (zero-trust)

In order to support a zero-trust deployment of Pulsar please view the zero trust example values file here. The example shows the key components necessary for configuring TLS for all connections in Pulsar cluster. Note that you can supply a certificate per component now. Also note that the default values file has documentation for many of the fields related to zero trust.

If you are using Cert Manager, the zero trust example is a complete example. If you are using your own certificates, you'll need to add the correct hostnames to the certificates in order to make hostname verification work. Please see the self-signed-cert-per-component.yaml template to see which hostnames are required for each component.

Hostname Verification

In order for hostname verification to work, you must configure the helm chart to deploy the broker cluster as a StatefulSet. This kind of deployment gives each pod a stable network identifier, which is necessary for hostname verification and the Pulsar Protocol.

To enable hostname verification with upstream servers, set tls.<component>.enableHostnameVerification: true. Note that these settings temporarily default to false for backwards compatibility, but will be updated to default to true in the next major version bump.

Automatically generating certificates using cert-manager

Manually configuring certificate secrets for TLS

To use TLS, you must first create a certificate and store it in the secret defined by tlsSecretName. You can create the certificate like this:

kubectl create secret tls <tlsSecretName> --key <keyFile> --cert <certFile>

The resulting secret will be of type kubernetes.io/tls. The key should not be in PKCS 8 format even though that is the format used by Pulsar. The format will be converted by chart to PKCS 8.

You can also specify the certificate information directly in the values:

# secrets:
  # key: |
  # certificate: |
  # caCertificate: |

This is useful if you are using a self-signed certificate.

For automated handling of publicly signed certificates, you can use a tool such as cert-manager. The following page describes how to set up cert-manager in AWS.

Once you have created the secrets that store the certificate info (or specified it in the values), you can enable TLS in the values:

enableTls: true

OpenID with Starlight for Kafka

To configure OpenID / OAuth2, you can use the values file that includes OpenID support with Starlight for Kafka: dev-values-tls-all-components-and-oauth2.yaml Be sure to provide your appropriate values in the openid section of the values file:

openid:
  enabled: true
  # From token generated in Okta UI or other method:
  allowedIssuerUrls: $ISSUER_URI
  withS4k: true
  allowedAudience: $AUDIENCE

like with these example values:

openid:
  enabled: true
  # From token generated in Okta UI or other method:
  allowedIssuerUrls: https://dev-1111111.okta.com/oauth2/abcd878787
  allowedAudience: api://pulsarClient
  withS4k: true

The chart can be installed as follows:

BASEDIR=/path/to/repo/on/your/local/filesystem
helm install pulsar datastax-pulsar/pulsar --namespace pulsar --values $BASEDIR/pulsar-helm-chart/examples/kafka/dev-values-tls-all-components-and-kafka-and-oauth2.yaml --create-namespace --debug

To test the functionality (with and without TLS) for both token authentication, and for Starlight for Kafka, you can perform the following steps:

  1. Set variables that will be used for subsequent commands (making sure they match the values used in the Helm values file above): Note that these credentials can be obtained from Okta (https://www.youtube.com/watch?v=UQBrecHOXxU&ab_channel=DataStaxDevelopers) or from an equivalent auth provider.
ISSUER_URI="https://dev-1111111.okta.com/oauth2/abcd878787"
AUDIENCE="api://pulsarClient"
SCOPE="pulsar_client_m2m"
AUTH_PARAMS=$(cat <<EOF
{"privateKey":"/pulsar/conf/creds.json","issuerUrl":"$ISSUER_URI","scope":"$SCOPE","audience":"$AUDIENCE"}
EOF
)
CLIENT_ID="your-client-id"
CLIENT_SECRET="your-client-secret"
KAFKA_VERSION="kafka_2.12-3.3.2"
OAUTH_CLIENT="2.10.3.2"

PROXY_HOSTNAME="pulsar-proxy.pulsar.svc.cluster.local"
  1. (Optional for TLS)
# Copy truststore from broker to bastion to simplify tests by first copying to local system. (Make sure you're not still in the bastion.)
kubectl cp pulsar/pulsar-broker-0:/pulsar/tls.truststore.jks ~/Downloads/tls.truststore.jks
# Provide the expected bastion path:
kubectl cp ~/Downloads/tls.truststore.jks pulsar/$(kubectl get pods -o=jsonpath='{.items[?(@.metadata.labels.component=="bastion")].metadata.name}'):/pulsar/tls.truststore.jks 
  1. SSH to bastion, passing variables for convenience:
kubectl exec -it pod/$(kubectl get pods -o=jsonpath='{.items[?(@.metadata.labels.component=="bastion")].metadata.name}') -- env ISSUER_URI=$ISSUER_URI AUDIENCE=$AUDIENCE SCOPE=$SCOPE AUTH_PARAMS=$AUTH_PARAMS CLIENT_ID=$CLIENT_ID CLIENT_SECRET=$CLIENT_SECRET KAFKA_VERSION=$KAFKA_VERSION OAUTH_CLIENT=$OAUTH_CLIENT PROXY_HOSTNAME=$PROXY_HOSTNAME bash
  1. Test Pulsar client with pulsar-perf with token auth against non-TLS endpoint:
bin/pulsar-perf produce --num-messages 1000 -r 1000 --size 1024 --auth_plugin org.apache.pulsar.client.impl.auth.AuthenticationToken --auth-params file:///pulsar/token-superuser-stripped.jwt --service-url pulsar://$PROXY_HOSTNAME:6650/ persistent://public/default/test
  1. Test Pulsar client with pulsar-perf with token auth against TLS endpoint (requires the "Optional for TLS" step, above):
bin/pulsar-perf produce --num-messages 1000 -r 1000 --size 1024 --auth_plugin org.apache.pulsar.client.impl.auth.AuthenticationToken --auth-params file:///pulsar/token-superuser-stripped.jwt --service-url pulsar+ssl://$PROXY_HOSTNAME:6651/ persistent://public/default/test
  1. Configure OIDC credentials (using variables set above)
cat << EOF > /pulsar/conf/creds.json
{"client_id":"$CLIENT_ID","client_secret":"$CLIENT_SECRET","grant_type": "client_credentials"}
EOF

Verify the credentials file was created as expected:

cat /pulsar/conf/creds.json
  1. Test Pulsar client with pulsar-perf with token auth against non-TLS endpoint:
bin/pulsar-perf produce --num-messages 1000 -r 1000 --size 1024 --auth-plugin "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" --auth-params $AUTH_PARAMS --service-url pulsar://$PROXY_HOSTNAME:6650/ persistent://public/default/test
  1. Test Pulsar client with pulsar-perf with token auth against TLS endpoint:
bin/pulsar-perf produce --num-messages 1000 -r 1000 --size 1024 --auth-plugin "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" --auth-params $AUTH_PARAMS --service-url pulsar+ssl://$PROXY_HOSTNAME:6651/ persistent://public/default/test
  1. Test admin endpoints with token auth for non-TLS:
bin/pulsar-admin --auth-plugin "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" --auth-params $AUTH_PARAMS --admin-url http://$PROXY_HOSTNAME:8080/ namespaces policies public/default
  1. Test admin endpoints with token auth for TLS:
bin/pulsar-admin --auth-plugin "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" --auth-params $AUTH_PARAMS --admin-url https://$PROXY_HOSTNAME:8443/ namespaces policies public/default
  1. Configure Kafka client:
mkdir /pulsar/kafka && cd /pulsar/kafka
curl -LOs https://downloads.apache.org/kafka/3.3.2/$KAFKA_VERSION.tgz
tar -zxvf /pulsar/kafka/$KAFKA_VERSION.tgz
cd /pulsar/kafka/$KAFKA_VERSION/libs
curl -LOs "https://github.com/datastax/starlight-for-kafka/releases/download/v$OAUTH_CLIENT/oauth-client-$OAUTH_CLIENT.jar"
cd ..

Verify the files were downloaded as expected:

ls /pulsar/kafka/$KAFKA_VERSION
ls /pulsar/kafka/$KAFKA_VERSION/libs | grep -i "oauth"
  1. Test OpenID/OAuth2 on non-TLS endpoint for Starlight for Kafka (S4K): Setup Kafka producer properties and then run test command:
cat << EOF > /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
bootstrap.servers=pulsar-proxy:9092
compression.type=none
sasl.login.callback.handler.class=com.datastax.oss.kafka.oauth.OauthLoginCallbackHandler
security.protocol=SASL_PLAINTEXT
sasl.mechanism=OAUTHBEARER
sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule \
   required oauth.issuer.url="$ISSUER_URI"\
   oauth.credentials.url="file:///pulsar/conf/creds.json"\
   oauth.audience="$AUDIENCE"\
   oauth.scope="$SCOPE";
EOF

Verify the file looks right:

cat /pulsar/kafka/$KAFKA_VERSION/config/producer.properties

Then, you can run the producer:

cd /pulsar/kafka/$KAFKA_VERSION; bin/kafka-console-producer.sh --bootstrap-server PLAINTEXT://pulsar-proxy:9092 --topic test --producer.config /pulsar/kafka/$KAFKA_VERSION/config/producer.properties

If you want to see the data come through, you can open another CLI tab and use the Pulsar client to subscribe to the topic when you produce the messages via Kafka:

kubectl exec -it pod/$(kubectl get pods -o=jsonpath='{.items[?(@.metadata.labels.component=="bastion")].metadata.name}') -- bash
cd /pulsar
bin/pulsar-client consume persistent://public/default/test --subscription-name test-kafka --num-messages 0

Also, if you want to observe the logs during this process, you can follow them for the proxy and broker, as follows:

kubectl logs pod/$(kubectl get pods -o=jsonpath='{.items[?(@.metadata.labels.component=="proxy")].metadata.name}') --follow
kubectl logs pod/$(kubectl get pods -o=jsonpath='{.items[?(@.metadata.labels.component=="broker")].metadata.name}') --follow

Then, produce messages from the Kafka terminal and observe them come through to the Pulsar consumer.

  1. Test OpenID/OAuth2 on TLS endpoint for S4K: We must setup the Kafka producer a little differently since it requires TLS-specific configurations:
cat << EOF > /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
bootstrap.servers=pulsar-proxy:9093
compression.type=none
ssl.truststore.location=/pulsar/tls.truststore.jks 
security.protocol=SASL_SSL
sasl.login.callback.handler.class=com.datastax.oss.kafka.oauth.OauthLoginCallbackHandler
sasl.mechanism=OAUTHBEARER
# The identification algorithm must be empty
ssl.endpoint.identification.algorithm=
sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule \
   required oauth.issuer.url="$ISSUER_URI"\
   oauth.credentials.url="file:///pulsar/conf/creds.json"\
   oauth.audience="$AUDIENCE"\
   oauth.scope="$SCOPE";
EOF

Then, you can run the command to start the producer:

cd /pulsar/kafka/$KAFKA_VERSION; bin/kafka-console-producer.sh --bootstrap-server SSL://pulsar-proxy:9093 --topic test --producer.config /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
  1. Test S4K with token authentication on non-TLS endpoint:
SUPERUSER_TOKEN=$(</pulsar/token-superuser-stripped.jwt)

# To test token auth on non-TLS endpoint:
cat << EOF > /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
bootstrap.servers=pulsar-proxy:9092
compression.type=none
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule \
   required username="public/default"\
   password="token:$SUPERUSER_TOKEN";
EOF

cd /pulsar/kafka/$KAFKA_VERSION; bin/kafka-console-producer.sh --bootstrap-server PLAINTEXT://pulsar-proxy:9092 --topic test --producer.config /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
  1. Test S4K with token authentication on TLS endpoint:
cat << EOF > /pulsar/kafka/$KAFKA_VERSION/config/producer.properties
bootstrap.servers=pulsar-proxy:9093
compression.type=none
security.protocol=SASL_SSL
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule \
required username="public/default" password="token:$SUPERUSER_TOKEN";
ssl.truststore.location=/pulsar/tls.truststore.jks
# The identification algorithm must be empty
ssl.endpoint.identification.algorithm=
EOF

cd /pulsar/kafka/$KAFKA_VERSION; bin/kafka-console-producer.sh --bootstrap-server SSL://pulsar-proxy:9093 --topic test --producer.config /pulsar/kafka/$KAFKA_VERSION/config/producer.properties

Grafana dashboards for S4K

Additionally, if you want to monitor Grafana dashboards for S4K, you can download them via this command:

cd ~/Downloads; curl -LOs https://raw.githubusercontent.com/datastax/starlight-for-kafka/2.10_ds/grafana/dashboard.json

Then, after you port-forward or otherwise connect to Grafana, you can follow the UI to import the dashboard from this JSON file.

pulsar-helm-chart's People

Contributors

acjohnson avatar cbornet avatar cdbartholomew avatar ddieruf avatar devinbost avatar dlg99 avatar eolivelli avatar filipecaixeta avatar johnsmartco avatar lhotari avatar michaeljmarshall avatar mistertimn avatar mmirelli avatar nadirj avatar nicoloboschi avatar nuriel77 avatar pgier avatar sanderwang avatar zzzming avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pulsar-helm-chart's Issues

Support existing Keycloak instance

Thanks for the OIDC plugin and including a setup for Keycloak in this helm chart!

For those of us who already have existing Keycloak instances, it would be great to be able to leverage those by configuring the Keycloak component to point to our existing instance rather than deploying a new one.

Pod in crashloop โ€˜data/zookeeperโ€™: Permission denied

Hey there,

currently getting a crashloop on zookeeper pod:

[conf/zookeeper.conf] Adding config quorumListenOnAllIPs = true
Current server id 1
Creating data/zookeeper/myid with id = 1
mkdir: cannot create directory โ€˜data/zookeeperโ€™: Permission denied
kubectl get pods -n pulsar   
NAME                                                  READY   STATUS             RESTARTS   AGE
angry-shark-29-grafana-58fbb56d8f-j2ntg               2/2     Running            0          2m34s
angry-shark-29-kube-promet-operator-8bbcdbcf6-8mfpt   1/1     Running            0          2m34s
angry-shark-29-kube-state-metrics-7797486dfd-6xfm6    1/1     Running            0          2m34s
angry-shark-29-prometheus-node-exporter-mbcsk         1/1     Running            0          2m34s
angry-shark-29-prometheus-node-exporter-slxfk         1/1     Running            0          2m34s
angry-shark-29-prometheus-node-exporter-zlwk4         1/1     Running            0          2m34s
prometheus-angry-shark-29-kube-promet-prometheus-0    2/2     Running            0          2m32s
pulsar-autorecovery-59b5cbd74d-xx2qq                  1/1     Running            3          2m34s
pulsar-bastion-7f9656fdd7-czfbn                       1/1     Running            0          2m34s
pulsar-bookkeeper-0                                   0/1     Pending            0          2m59s
pulsar-broker-54cdf98dc9-pqdjd                        0/1     Pending            0          2m59s
pulsar-broker-c97d67cb8-sfd5j                         0/1     Init:0/1           0          2m33s
pulsar-proxy-559687647b-sthqj                         0/2     Pending            0          2m59s
pulsar-proxy-5fcbc8c9bd-h54fx                         0/3     Pending            0          2m33s
pulsar-zookeeper-0                                    0/1     CrashLoopBackOff   4          2m59s

Current HELM Values:

 storageValues = {
        "default_storage": {
          "provisioner": "kubernetes.io/aws-ebs",
          "type": "gp2",
          "fsType": "ext4",
          "extraParams": {
            "iopsPerGB": "10"
          }
        },
      };
const values = 
       {
        "fullnameOverride": "pulsar",
        "dnsName": "pulsar.example.com",
        "enableWaitContainers": "false",
        "rbac": {
          "create": true,
          "clusterRoles": true
        },
        "persistence": true,
        "enableAntiAffinity": false,
        "enableTls": false,
        "enableTokenAuth": false,
        "restartOnConfigMapChange": {
          "enabled": true
        },
        "extra": {
          "function": true,
          "burnell": true,
          "burnellLogCollector": true,
          "pulsarHeartbeat": true,
          "pulsarAdminConsole": true
        },
        "zookeeper": {
          "replicaCount": 1,
          "resources": {
            "requests": {
              "memory": "300Mi",
              "cpu": 0.3
            }
          },
          "configData": {
            "PULSAR_MEM": "\"-Xms300m -Xmx300m -Djute.maxbuffer=10485760 -XX:+ExitOnOutOfMemoryError\""
          }
        },
        "bookkeeper": {
          "replicaCount": 1,
          "resources": {
            "requests": {
              "memory": "512Mi",
              "cpu": 0.3
            }
          },
          "configData": {
            "BOOKIE_MEM": "\"-Xms312m -Xmx312m -XX:MaxDirectMemorySize=200m -XX:+ExitOnOutOfMemoryError\""
          }
        },
        "broker": {
          "component": "broker",
          "replicaCount": 1,
          "ledger": {
            "defaultEnsembleSize": 1,
            "defaultAckQuorum": 1,
            "defaultWriteQuorum": 1
          },
          "resources": {
            "requests": {
              "memory": "600Mi",
              "cpu": 0.3
            }
          },
          "configData": {
            "PULSAR_MEM": "\"-Xms400m -Xmx400m -XX:MaxDirectMemorySize=200m -XX:+ExitOnOutOfMemoryError\""
          }
        },
        "autoRecovery": {
          "resources": {
            "requests": {
              "memory": "300Mi",
              "cpu": 0.3
            }
          }
        },
        "function": {
          "replicaCount": 1,
          "functionReplicaCount": 1,
          "resources": {
            "requests": {
              "memory": "512Mi",
              "cpu": 0.3
            }
          },
          "configData": {
            "PULSAR_MEM": "\"-Xms312m -Xmx312m -XX:MaxDirectMemorySize=200m -XX:+ExitOnOutOfMemoryError\""
          }
        },
        "proxy": {
          "replicaCount": 1,
          "resources": {
            "requests": {
              "memory": "512Mi",
              "cpu": 0.3
            }
          },
          "wsResources": {
            "requests": {
              "memory": "512Mi",
              "cpu": 0.3
            }
          },
          "configData": {
            "PULSAR_MEM": "\"-Xms400m -Xmx400m -XX:MaxDirectMemorySize=112m\""
          },
          "autoPortAssign": {
            "enablePlainTextWithTLS": true
          },
          "service": {
            "autoPortAssign": {
              "enabled": true
            }
          }
        },
        "grafanaDashboards": {
          "enabled": true
        },
        "pulsarAdminConsole": {
          "replicaCount": 1
        },
        "kube-prometheus-stack": {
          "enabled": true,
          "prometheusOperator": {
            "enabled": true
          },
          "grafana": {
            "enabled": true,
            "adminPassword": "***********"
          }
        }
      }

Some help/hints much appreciated

Enable annotations on services

The following services do not support annotations, which mean that on AWS you cannot control the load balancer type used:

  • broker
  • pulsarSql

PulsarHeartBeat and Bastion compnent failed to find "rootCaSecretName"

When TLS is enabled and a customized root ca secrete name (e.g. tls-ss-ca) is provided (see below), PulsarHeartBeat and Bastion components failed to initialize with error "MountVolume.SetUp failed for volume "certs" : secret "tls-ss-ca" not found"

tls:
  ... ... 
   rootCaSecretName: "tls-ss-ca"

Checking the secrets, there is no ca certificate created with the customized name (e.g. 'tls-ss-ca'). However, a ca certificate with the default name 'pulsar-ss-ca' is created:

% kubectl get secrets | grep ss-ca
pulsar-ss-ca                                    kubernetes.io/tls                     3      7m32s

Pulsar admin in bastion does not work

Today I have installed on a vanilla k8s env this helm chart, but I have troubles with using pulsar-admin


(ctool-env) enrico.olivelli@eolivelli-rmbp16 pulsar % kubectl exec $(kubectl get pods -l component=bastion -o jsonpath="{.items[*].metadata.name}") -it -- /bin/bash
root@pulsar-bastion-7489594b85-fxjz7:/pulsar# 
root@pulsar-bastion-7489594b85-fxjz7:/pulsar# 
root@pulsar-bastion-7489594b85-fxjz7:/pulsar# 
root@pulsar-bastion-7489594b85-fxjz7:/pulsar# bin/pulsar-admin tenants list
Warning: Nashorn engine is planned to be removed from a future JDK release

null

Reason: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Connection refused: pulsar-proxy/10.109.252.132:8080

we have two problems here:

  • it does not work: Connection refused: pulsar-proxy/10.109.252.132:8080
  • I am still seeing the "Nashorn engine is planned to be removed from a future JDK release" that has been removed by Ming

Update Ingress API Version

Sample warning when using the Ingress for PulsarSQL:

W0128 16:06:08.502415 22507 warnings.go:70] extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress

Move bookkeeper metadata initialization to it's own job

Currently
bookkeeper shell metaformat --nonInteractive is called every time a bookie is started:

# This initContainer will make sure that the bookkeeper
# metadata is in zookeeper
- name: pulsar-bookkeeper-metaformat
image: "{{ .Values.image.bookkeeper.repository }}:{{ .Values.image.bookkeeper.tag }}"
imagePullPolicy: {{ .Values.image.bookkeeper.pullPolicy }}
command: ["sh", "-c"]
args:
- >
bin/apply-config-from-env.py conf/bookkeeper.conf &&
bin/apply-config-from-env.py conf/bkenv.sh &&
bin/bookkeeper shell metaformat --nonInteractive || true;

bookkeeper shell metaformat command is deprecated since 4.7.0
https://bookkeeper.apache.org/docs/latest/reference/cli/#bookkeeper-shell-metaformat

This command is deprecated since 4.7.0, in favor of using initnewcluster for initializing a new cluster and nukeexistingcluster for nuking an existing cluster.

Consider moving the bookkeeper metadata initialization to it's own job

Cannot start CertManager on latest minikube v1.23.0

I am trying to configure Pulsar with TLS on minikube on Mac, but the default/pulsar-cert-manager-cainjector-564d757c9f-hzpps:cert-manager pod errors with:

I0910 06:45:11.336198 1 request.go:645] Throttling request took 1.0469241s, request: GET:https://10.96.0.1:443/apis/authentication.k8s.io/v1?timeout=32s โ”‚
โ”‚ E0910 06:45:12.194358 1 start.go:151] cert-manager/ca-injector "msg"="Error registering certificate based controllers. Retrying after 5 seconds." "error"="no matches for kind "MutatingWebhookConfigurat โ”‚
โ”‚ Error: error registering secret controller: no matches for kind "MutatingWebhookConfiguration" in version "admissionregistration.k8s.io/v1beta1" โ”‚
โ”‚ Usage: โ”‚
โ”‚ ca-injector [flags]

I have followed the instructions in the README and it used to work with a start k8s installation

Minikube version:

minikube version
minikube version: v1.23.0
commit: 5931455374810b1bbeb222a9713ae2c756daee10

PulsarSQL worker node readiness and liveness probes fail

The readiness and liveness probes fail for the pulsarSQL worker nodes.

For example, from the pod in question:

pulsar@pulsar-sql-worker-84b789f6bc-wtztr:/pulsar/conf$ hostname -i
192.168.14.34

Calling the status endpoint as localhost fails:

pulsar@pulsar-sql-worker-84b789f6bc-wtztr:/pulsar/conf$ curl http://localhost:8090/v1/service/presto
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 404 Not Found</title>
</head>
<body><h2>HTTP ERROR 404 Not Found</h2>
<table>
<tr><th>URI:</th><td>/v1/service/presto</td></tr>
<tr><th>STATUS:</th><td>404</td></tr>
<tr><th>MESSAGE:</th><td>Not Found</td></tr>
<tr><th>SERVLET:</th><td>org.glassfish.jersey.servlet.ServletContainer-5f6e2ad9</td></tr>
</table>

</body>
</html>

As does calling the status endpoint via the pod IP:

pulsar@pulsar-sql-worker-84b789f6bc-wtztr:/pulsar/conf$ curl http://192.168.14.34:8090/v1/service/presto
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 404 Not Found</title>
</head>
<body><h2>HTTP ERROR 404 Not Found</h2>
<table>
<tr><th>URI:</th><td>/v1/service/presto</td></tr>
<tr><th>STATUS:</th><td>404</td></tr>
<tr><th>MESSAGE:</th><td>Not Found</td></tr>
<tr><th>SERVLET:</th><td>org.glassfish.jersey.servlet.ServletContainer-5f6e2ad9</td></tr>
</table>

</body>
</html>

externalDNS version doesn't work with k8s 1.22

The version of externalDNS image used by the chart does not work in k8s 1.22.

The following version works: k8s.gcr.io/external-dns/external-dns:v0.10.2

Also, since the older ingress API versions were removed, the ClusterRole rules needs to be updated to this:

rules:
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get","watch","list"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get","watch","list"]
  - apiGroups: ["networking","networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["get","watch","list"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get","watch","list"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get","watch","list"]

Istio service mesh compatibility

Currently the manner in which jobs start in this helm chart interferes with the use of an istio service mesh.

However, pulsar otherwise would be very compatible with a service mesh and this would reduce complexity for mTLS and ingress routing to a separate aspect of the environment, which is often desirable.

This issue can be reproduced as follows with a basic istio installation. From a new installation:

kubectl create namespace pulsar
kubectl label namespace pulsar istio-injection=enabled
helm upgrade --install  \
   pulsar  datastax-pulsar/pulsar \
  --namespace pulsar \
  --create-namespace 

This will result in a set of initialization jobs that are hung up.

If instead we disable istio in the namespace kubectl label namespace pulsar istio-injection-, install datastax luna pulsar via the helm chart, then re-eanble istio, and cycle the various pods that take place in the data plane, the system works as expected.

This indicates that a set of tweaks to the jobs ( e.g. by setting pod labels sidecar.istio.io/inject=false ) may make this chart compatible with istio.

Jobs observed:

  • pulsar-kube-prometheus-sta-admission-create
  • pulsar-kube-prometheus-sta-admission-patch
  • pulsar-dev-zookeeper-metadata

These jobs will not reach a completed state unless the associated istio-proxy container exits successfully (i.e. shell into the istio-proxy container and run kill -TERM 1). An alternative approach is to add a preStop condition to the main container to call curl -sf -XPOST http://127.0.0.1:15020/quitquitquit which will tell the istio-proxy to exit, or other ideas include a dedicated additional sidecar to manage this. See https://discuss.istio.io/t/best-practices-for-jobs/4968/2 for more.

Fix org.apache.kafka.common.errors.UnknownServerException on ktool deployment

When the deploying the helmchart with values:

              enableAntiAffinity: no
              initialize: true  # ASF Helm Chart
              restartOnConfigMapChange:
                enabled: yes
              image:
                zookeeper:
                  repository: pulsar-repo
                  tag: 2.8.x
                bookie:
                  repository: pulsar-repo
                  tag: 2.8.x
                bookkeeper:
                  repository: pulsar-repo
                  tag: 2.8.x
                autorecovery:
                  repository: pulsar-repo
                  tag: 2.8.x
                broker:
                  repository: pulsar-repo
                  tag: 2.8.x
                proxy:
                  repository: pulsar-repo
                  tag: 2.8.x
                functions:
                  repository: pulsar-repo
                  tag: 2.8.x
                function:
                  repository: pulsar-repo
                  tag: 2.8.x
              extra:
                function: yes
                burnell: no
                burnellLogCollector: no
                pulsarHeartbeat: no
                pulsarAdminConsole: no
                autoRecovery: no
                functionsAsPods: yes
              default_storage:
                existingStorageClassName: server-storage
              volumes:
                data: #ASF Helm Chart
                  storageClassName: existent-storage-class
              zookeeper:
                replicaCount: 3
              bookkeeper:
                replicaCount: 3
              broker:
                component: broker
                replicaCount: 2
                ledger:
                  defaultEnsembleSize: 2
                  defaultAckQuorum:  2
                  defaultWriteQuorum: 2
                service:
                  annotations: {}
                  type: ClusterIP
                  headless: false
                  ports:
                  - name: http
                    port: 8080
                  - name: pulsar
                    port: 6650
                  - name: https
                    port: 8443
                  - name: pulsarssl
                    port: 6651
                  - name: kafkaplaintext
                    port: 9092
                  - name: kafkassl
                    port: 9093
                  - name: kafkaschemareg
                    port: 8001
                kafkaOnPulsarEnabled: true
                kafkaOnPulsar:
                  saslAllowedMechanisms: PLAIN
                  brokerEntryMetadataInterceptors: "org.apache.pulsar.common.intercept.AppendIndexMetadataInterceptor,org.apache.pulsar.common.intercept.AppendBrokerTimestampMetadataInterceptor"
                  kopSchemaRegistryEnable: true
              function:
                replicaCount: 1
                functionReplicaCount: 1
                runtime: "kubernetes"
              proxy:
                replicaCount: 2
                autoPortAssign:
                  enablePlainTextWithTLS: yes
                service:
                  type: ClusterIP
                  autoPortAssign:
                    enabled: yes
                configData:
                  PULSAR_MEM: "\"-Xms400m -Xmx400m -XX:MaxDirectMemorySize=112m\""
                  PULSAR_PREFIX_kafkaListeners: "SASL_PLAINTEXT://0.0.0.0:9092"
                  PULSAR_PREFIX_kafkaAdvertisedListeners: "SASL_PLAINTEXT://pulsar-proxy:9092"
                  PULSAR_PREFIX_saslAllowedMechanisms: PLAIN
                  PULSAR_PREFIX_kafkaProxySuperUserRole: superuser
                  PULSAR_PREFIX_kopSchemaRegistryProxyEnableTls: "false"
                  PULSAR_PREFIX_kopSchemaRegistryEnable: "true"
                  PULSAR_PREFIX_kopSchemaRegistryProxyPort: "8081"
                extensions:
                  enabled: true
                  extensions: "kafka"
                  containerPorts:
                    - name: kafkaplaintext
                      containerPort: 9092
                    - name: kafkassl
                      containerPort: 9093
                    - name: kafkaschemareg
                      containerPort: 8081
                  servicePorts:
                  - name: kafkaplaintext
                    port: 9092
                    protocol: TCP
                    targetPort: kafkaplaintext
                  - name: kafkassl
                    port: 9093
                    protocol: TCP
                    targetPort: kafkassl
                  - name: kafkaschemareg
                    port: 8081
                    protocol: TCP
                    targetPort: kafkaschemareg
              grafanaDashboards:
                enabled: no
              pulsarAdminConsole:
                replicaCount: 0
                service:
                  type: ClusterIP
              grafana: #ASF Helm Chart
                service:
                  type: ClusterIP
              pulsar_manager:
                service: #ASF Helm Chart
                  type: ClusterIP
              kube-prometheus-stack: # Luna Streaming Helm Chart
                enabled: no
                prometheusOperator:
                  enabled: no
                grafana:
                  enabled: no
                  adminPassword: 123
                  service:
                    type: ClusterIP
              pulsarSQL:
                service:
                  type: ClusterIP
              enableTls: no
              enableTokenAuth: no

The following error is thrown by the ktool pod:

[2022-01-01 12:49:53,587] ERROR Failed to start KSQL (io.confluent.ksql.rest.server.KsqlServerMain:66)
io.confluent.ksql.util.KsqlServerException: Could not get Kafka cluster configuration!
	at io.confluent.ksql.services.KafkaClusterUtil.getConfig(KafkaClusterUtil.java:96)
	at io.confluent.ksql.security.KsqlAuthorizationValidatorFactory.isKafkaAuthorizerEnabled(KsqlAuthorizationValidatorFactory.java:81)
	at io.confluent.ksql.security.KsqlAuthorizationValidatorFactory.create(KsqlAuthorizationValidatorFactory.java:51)
	at io.confluent.ksql.rest.server.KsqlRestApplication.buildApplication(KsqlRestApplication.java:724)
	at io.confluent.ksql.rest.server.KsqlRestApplication.buildApplication(KsqlRestApplication.java:637)
	at io.confluent.ksql.rest.server.KsqlServerMain.createExecutable(KsqlServerMain.java:152)
	at io.confluent.ksql.rest.server.KsqlServerMain.main(KsqlServerMain.java:59)
Caused by: org.apache.kafka.common.errors.UnknownServerException: io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: /10.244.4.18:9092

This is resolved by reverting ab5216de64e5868a378a2a08f0ff6efa0f0430ef, as it can be seen by using this "version" of the helmchart. However, a better solution is needed.

Service Annotations in pulsar admin console incorrectly scoped

At this line:

The helm variables name for service annotations is .Values.pulsarAdminConsole.annotations but should be scoped to the service, consistent with other components, as .Values.pulsarAdminConsole.service.annotations

Workaround is to change your values.yaml to match, but it is then inconsistent with standards and the other components of the chart.

Review Port Definitions to Ensure Chart Flexibility

Observation

The current chart has hard coded ports throughout. A good example is the Pulsar Admin Console's nginx configuration. It has hard coded ports for the pulsar proxy service. However, the pulsar proxy service allows for ports to be defined. If a user were to deploy the chart with non-default ports for the proxy service (and possibly other services), the components might not integrate properly.

Solution

Review all hard coded ports. Use the .Values to make those ports configurable. In the case of services, it can be easier to declare target ports using the pod's port names instead of the port numbers. I think using port names, instead of numbers, can make it more readable and reduces the configuration necessary for a service. This feature is described here: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service.

Key duplication in configMaps causing errors on some deployment tools

In these two files I found that there is a key duplication in the configMap:

https://github.com/datastax/pulsar-helm-chart/blob/master/helm-chart-sources/pulsar/templates/broker-deployment/broker-configmap.yaml#L222
https://github.com/datastax/pulsar-helm-chart/blob/master/helm-chart-sources/pulsar/templates/zookeeper/zookeeper-configmap.yaml#L40

For example, if I run helm template . and view zookeeper's configMap output:

apiVersion: v1
kind: ConfigMap
metadata:
  name: "pulsar-broker"
  namespace: nuri-test
  labels:
    app: pulsar
    chart: pulsar-2.0.9
    release: RELEASE-NAME
    heritage: Helm
    component: broker
    cluster: pulsar
data:
  zookeeperServers:
    pulsar-zookeeper-ca:2181
  configurationStoreServers:
    pulsar-zookeeper-ca:2181
  clusterName: pulsar
  allowAutoTopicCreationType: "non-partitioned"
  PULSAR_EXTRA_OPTS: -Dpulsar.log.root.level=info
  PULSAR_GC: -XX:+UseG1GC
  PULSAR_LOG_LEVEL: info
  PULSAR_LOG_ROOT_LEVEL: info
  PULSAR_MEM: -Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g -Dio.netty.leakDetectionLevel=disabled
    -Dio.netty.recycler.linkCapacity=1024 -XX:+ExitOnOutOfMemoryError
  backlogQuotaDefaultRetentionPolicy: producer_exception
  brokerDeduplicationEnabled: "false"
  exposeConsumerLevelMetricsInPrometheus: "false"
  exposeTopicLevelMetricsInPrometheus: "true"
  # Workaround for double-quoted values in old values files
  PULSAR_MEM: -Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g -Dio.netty.leakDetectionLevel=disabled -Dio.netty.recycler.linkCapacity=1024 -XX:+ExitOnOutOfMemoryError
  PULSAR_GC: -XX:+UseG1GC 

The last 2 (PULSAR_MEM and PULSAR_GC) appear twice. This isn't a problem for Helm to handle.

However, for deployment automation tools such as kustomize and FluxCD this presents a problem as they depend on kyaml.

This is a known issue: kubernetes-sigs/kustomize#3480
There's even the chance the error will eventually end up in Helm's newer versions.

I haven't noticed this duplication/workaround on apache's pulsar chart.

Would it be possible to remove the duplication or handle it in a way that will not produce double keys in the configMap?
There might be other instances of the duplication in other configMaps, I haven't gone through all of them.

Thank you.

DNS resolutions errors with Broker host names returned by Pulsar lookups

There's currently a conflicting problem with the Pulsar k8s deployment and how Pulsar load balancing works.

When a Pulsar broker starts, it will register itself as a broker in the internal Pulsar load balancer. Pulsar load balancer might immediately assign new namespace bundles to the broker and the topics might immediately get requests.

The conflicting problem is that DNS resolution for the broker's host name will fail with the current settings until the broker's readiness probe succeeds.

Pulsar might already return the hostname of a specific broker to a client, but the client cannot resolve the DNS name since the broker's readiness probe hasn't passed. This causes extra delays and also bugs when connecting to topics after a load balancing event. Pulsar clients usually backoff and retry. For Admin API HTTP requests, clients might not properly handle errors and for example Pulsar Proxy will fail the request when there's a DNS lookup issue.

solution:
Broker statefulset's service should use publishNotReadyAddresses: true

There's useful information about stateful sets and publishNotReadyAddresses setting:
k8ssandra/cass-operator#18

There's an alternative solution in #198 which is fine for cases where TLS is disabled for brokers. Stable hostnames are required when using TLS to be able to do hostname verification for the certificates.

Missing charts

  1. Using current master branch helmcharts
  2. Download dev-values.yaml
  3. helm install pulsar-hank -n hank-test -f dev-values.yaml ./pulsar/
    Out: Error: found in Chart.yaml, but missing in charts/ directory: kube-prometheus-stack, cert-manager, keycloak

Pulsar Broker metadata initialization should use the given Broker image instead of Zookeeper image

In the chart, Pulsar Broker metadata initialization is called "zookeeperMetadata" which is misleading. It uses the Zookeeper image which is wrong. The Pulsar Broker image should be used for initializing the Pulsar Broker metadata.

image: "{{ .Values.image.zookeeper.repository }}:{{ .Values.image.zookeeper.tag }}"
imagePullPolicy: {{ .Values.image.zookeeper.pullPolicy }}

Configuration .Values.tls.proxy.enableTlsWithBroker and .Values.broker.enableForProxyToBroker are conflicting

.Values.tls.proxy.enableTlsWithBroker:

proxy:
# Applies to connections to standalone function worker, too.
enableTlsWithBroker: false

.Values.broker.enableForProxyToBroker:

broker:
enableForProxyToBroker: false

Similar problem seems to exist with .Values.tls.function.enableTlsWithBroker and .Values.tls.broker.enableForFunctionWorkerToBroker.

Wouldn't it make sense to have .Values.tls.broker.enabled instead?

Release request

Hello,

What is the schedule for releases? We'd like to use a previously patched commit but we're just waiting for the next release.
Thank you again for the continuous patches.

This is the patch we're after.
#141

Thanks!

Error while installing: " unable to build kubernetes objects from release manifest"

Dears,
After following your instructions:

helm repo add datastax-pulsar https://datastax.github.io/pulsar-helm-chart
helm repo update
curl -LOs https://datastax.github.io/pulsar-helm-chart/examples/dev-values.yaml
helm install pulsar -f dev-values.yaml datastax-pulsar/pulsar

I get this:

$ helm install pulsar -f dev-values.yaml datastax-pulsar/pulsar
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(Prometheus.spec): unknown field "probeNamespaceSelector" in com.coreos.monitoring.v1.Prometheus.spec, ValidationError(Prometheus.spec): unknown field "probeSelector" in com.coreos.monitoring.v1.Prometheus.spec, ValidationError(Prometheus.spec): unknown field "shards" in com.coreos.monitoring.v1.Prometheus.spec]

Is there a bug in your templates ?

Regards

Liveness check failed due to the way to deploy broker in Statefulset

  1. Modify broker deploy way from Deployment to Statefulset
  2. Execute the helm install command
  3. Pulsar heartbeat and function pod can not be running due to connection error

Screen Shot 2022-02-16 at 11 12 41 AM

Screen Shot 2022-02-16 at 11 09 18 AM

Screen Shot 2022-02-16 at 11 13 19 AM

Works fine after updating broker.component from broker to brokersts in dev-values.yaml file. Is this the expected way?

Add documentation to disable `kube-prometheus-stack` optional features

Documentation should be added to cover the issue described below.

Whenever the conditional dependency kube-prometheus-stack.enabled is disabled, it does not produce the expected behaviour of disabling all the Prometheus stack components. In fact, each of those should be disabled in the values.yaml, by adding the following:

kube-prometheus-stack:
  enabled: false
  prometheusOperator:
    enabled: false
  grafana:
    enabled: false
    adminPassword: e9JYtk83*4#PM8
  alertmanager:
    enabled: false
  prometheus:
    enabled: false

It should be noted that unless all the Prometheus components are disabled, the helmchart will attempt to install Prometheus CRDs. This might be an issue in cases when the service account used to deploy the cluster does not have enough permissions to install Custom Resources Definitions.

Cannot set existing StorageClass with `existingStorageClassName`.

Problem

I both tried setting existingStorageClassName under global default_storage or under specific volume to an existing StorageClass ebs-pulsar, but the created PVCs are still using the default StorageClass ebs-gp3.

image

image

My custom helm values:

components:
  zookeeper: true
  bookkeeper: true
  autorecovery: true
  broker: true
  functions: true
  proxy: true
  toolset: true
  pulsar_manager: true
monitoring:
  prometheus: false
  grafana: false
volumes:
  persistence: true
default_storage:
  existingStorageClassName: ebs-pulsar
antiAffinity:
  host:
    enabled: true
    mode: required
  zone:
    enabled: true
nodeSelector:
  dedicated: infrastructure
zookeeper:
  volumes:
    data:
      name: data
      size: 40Gi
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
bookkeeper:
  volumes:
    journal:
      name: journal
      size: 20Gi
    ledgers:
      name: ledgers
      size: 100Gi
    ranges:
      name: ranges
      size: 10Gi
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
autorecovery:
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
broker:
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
functions:
  volumes:
    data:
      name: logs
      size: 10Gi
      existingStorageClassName: ebs-pulsar
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
proxy:
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
toolset:
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure
pulsar_manager:
  tolerations:
    - effect: NoSchedule
      key: dedicated
      operator: Equal
      value: infrastructure

Env

Kubernetes: v1.21 in EKS
Helm: v3.3.4
Pulsar Chart: v2.7.6

Allow configuring liveness and readiness probe timeouts

Kubernetes has a default probe timeout of 1 second.
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes

timeoutSeconds: Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1.

The default 1 second timeout causes the probe to intermittently fail. This can cause undesired restarts.

Make the liveness and readiness probe timeouts configurable and set the default value to 5 seconds to prevent undesired restarts.

In the k8s docs it says

"Before Kubernetes 1.20, the field timeoutSeconds was not respected for exec probes: probes continued running indefinitely, even past their configured deadline, until a result was returned."
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes

[Functions] Failed to resolve 'pulsar-broker.mypulsar.svc.cluster.local'

When deploying pulsar with TLS enabled and running a source function the following error is logged in the spawned function:

java.util.concurrent.CompletionException: org.apache.pulsar.client.api.PulsarClientException: java.util.concurrent.CompletionException: java.net.UnknownHostException: Failed to resolve 'pulsar-broker.mypulsar.svc.cluster.local' after 2 queries 
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331) ~[?:?]
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:346) ~[?:?]
	at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:704) ~[?:?]
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506) ~[?:?]
	at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088) ~[?:?]
	at org.apache.pulsar.client.impl.ConnectionPool.lambda$createConnection$10(ConnectionPool.java:226) ~[java-instance.jar:?]
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) ~[java-instance.jar:?]
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) ~[java-instance.jar:?]
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:391) ~[java-instance.jar:?]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[java-instance.jar:?]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[java-instance.jar:?]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[java-instance.jar:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: org.apache.pulsar.client.api.PulsarClientException: java.util.concurrent.CompletionException: java.net.UnknownHostException: Failed to resolve 'pulsar-broker.mypulsar.svc.cluster.local' after 2 queries 
	... 8 more

Repro:

  1. Deploy pulsar with tls and functions enabled (values below)
  2. create a partitioned topic and subscription
  3. generate a source function:
                        bin/pulsar-admin sources create
                        -t data-generator --name data-generator-source
                        --source-config '{"sleepBetweenMessages":"10"}'
                        --destination-topic-name persistent://public/default/test

Values:

enableAntiAffinity: no
enableTls: yes
tls:
  function:
    enableTlsWithBroker: true
    enableHostnameVerification: true
cert-manager:
  enabled: true
createCertificates:
  selfSigned:
    enabled: true
enableTokenAuth: yes
autoRecovery:
  enableProvisionContainer: yes
restartOnConfigMapChange:
  enabled: yes
image:
  zookeeper:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  bookie:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  bookkeeper:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  autorecovery:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  broker:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  proxy:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  functions:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
  function:
    repository: datastaxlunastreaming-all
    tag: 2.7.2_1.1.32
extra:
  broker: false
  brokerSts: true
  function: yes
  burnell: yes
  burnellLogCollector: yes
  pulsarHeartbeat: yes
  pulsarAdminConsole: yes
  functionsAsPods: yes
default_storage:
  existingStorageClassName: server-storage
volumes:
  data: #ASF Helm Chart
    storageClassName: existent-storage-class
zookeeper:
  replicaCount: 3
bookkeeper:
  replicaCount: 3
broker:
  component: broker
  replicaCount: 2
  ledger:
    defaultEnsembleSize: 1
    defaultAckQuorum:  1
    defaultWriteQuorum: 1
function:
  replicaCount: 1
  functionReplicaCount: 1
  runtime: "kubernetes"
proxy:
  disableZookeeperDiscovery: true
  useStsBrokersForDiscovery: true
  replicaCount: 2
  autoPortAssign:
    enablePlainTextWithTLS: yes
  service:
    type: ClusterIP
    autoPortAssign:
      enabled: yes
grafanaDashboards:
  enabled: yes
pulsarAdminConsole:
  replicaCount: 0
  service:
    type: ClusterIP
grafana: #ASF Helm Chart
  service:
    type: ClusterIP
pulsar_manager:
  service: #ASF Helm Chart
    type: ClusterIP
kube-prometheus-stack: # Luna Streaming Helm Chart
  enabled: no
  prometheusOperator:
    enabled: no
  grafana:
    enabled: no
    service:
      type: ClusterIP
pulsarSQL:
  service:
    type: ClusterIP

Add an option to delete PVCs while uninstalling the Helm Chart

While running tests on GKE with Fallout we found out that disks are not released even by deleting the GKE cluster.
This is because the PVC created by the Helm Chart are not deleted when uninstalling the chart.

It would be great to have an option to automatically delete the PVCs

Upgrade Circle CI Base Image

[Action Required] Ubuntu 14.04 machine image deprecation & EOL

We are deprecating Ubuntu 14.04-based machine images on CircleCI in preparation for an EOL on Tuesday, May 31, 2022 to ensure your builds remain secure. For a detailed overview of how this will affect your workflow, read the blog article here.

We will also be conducting temporary brownouts on Tuesday, March 29, 2022, and again on Tuesday, April 26, 2022 during which these images will be unavailable.

We are contacting you because one or more of your projects has a job that either:

does not specify an image (uses machine: true in config)
explicitly uses an Ubuntu 14.04-based image

Jobs that do not specify an image default to using an Ubuntu 14.04-based image.

If you have specified an Ubuntu 14.04-based image or you are using machine: true in your config file, please see our migration guide to upgrade to a newer version of Ubuntu image in order to avoid any service disruption during the brownout & subsequent EOL.

We will also be releasing a CircleCI Ubuntu 22.04 image on April 22nd offering the flexibility to upgrade to the latest LTS version of Ubuntu image before we remove older versions permanently. A beta version of the image will be available March 21st.

superUserRoles shouldn't need to contain the proxy role

Currently the sample "superUserRoles" is superuser,admin,websocket,proxy.

Why does this include all possible roles?

One reason seems to be that the token generation with Burnell uses the "SuperRoles" environment variable with .Values.superUserRoles to generate the tokens.

- name: SuperRoles
value: {{ .Values.superUserRoles }}

https://github.com/datastax/burnell/blob/5a7c261e498ff5b34356b0c164d357e9f3a8b81b/src/workflow/keys-jwt.go#L98

Remove default credentials from values file

There are default credentials for configuring Tardigrade and Grafana in the values file:

tardigrade:
  access: access-key-generated-with-uplink
  accessKey: 2J7EJY4xTK6uHKqnCE4nAhdGfXqy
  secretKey: 4YeYwYdsoFFpvtNFuncWcTVqSTPL
  service:
    port: 7777
    type: ClusterIP

And:

  grafana:
    enabled: true
    # namespaceOverride: "monitoring"
    testFramework:
      enabled: false
    defaultDashboardsEnabled: true
    adminPassword: ZhF9sS8B7PQSTR

These default values should be removed.

Unable to specify loadBalancerIP on Services

I'd like to set an internal static IP to a service with type LoadBalancer, but there is no configuration available to define this.
Could we get a service.loadBalancerIP option for pulsar services so this could be set via helm?

Prepare next release with support for OpenShift deployment

This is an issue to track the tasks for preparing the release with support for OpenShift deployment

Tasks

  • Publish docker image for datastax/burnell
  • Update datastax/burnell docker image tag in values.yaml
  • Publish docker image for datastax/pulsar-heartbeat
  • Update datastax/pulsar-heartbeat docker image tag in values.yaml
  • Publish docker image for datastax/pulsar-admin-console
  • Update pulsar-admin-console docker image tag and make deployment to support rootless image - update helm-chart-sources/pulsar/templates/admin-console/pulsar-admin-console-deployment.yaml: /root/dashboard/dist/config-override.js -> /home/appuser/dashboard/dist/config-override.js
  • Add documentation for OpenShift deployment
  • Add tests for kube-prometheus-stack upgrade to 16.x.x and merge #22 after tests exist
  • Test OpenShift deployment with TLS
  • Add documentation for setting up TLS with OpenShift
  • Test OpenShift monitoring integration where the built-in OpenShift Prometheus operator is used
  • Add documentation for OpenShift monitoring setup

Zookeeper service accessed by shortname

It is only possible to access Zookeeper service via shortname (pulsar-zookeeper-ca:2181)

I understand that this works for DNS resolution since the brokers live in the same namespace and the domain is present in the search option of the /etc/resolv.conf. However, we'd like to avoid having to generate certificates using short-names. Is it possible to add an option to add a full domain for the zookeeper service?

For example something like:
{{ template "pulsar.fullname" . }}-{{ .Values.zookeeper.component }}-ca{{- if .Values.zookeeper.domain -}}.{{ .Values.zookeeper.domain }}{{- end -}}:2281

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.