DEV Community

suin
suin

Posted on

Deploying Helm Charts to Multiple Kubernetes Clusters with Cluster API's HelmChartProxy

In this article, I'll introduce you to HelmChartProxy, a powerful feature of Cluster API that enables bulk deployment of Helm charts across multiple Kubernetes clusters.

Introduction

When managing multiple Kubernetes clusters, you often need to deploy the same Helm charts across different environments. Traditionally, this meant running Helm commands individually for each cluster. However, with Cluster API's HelmChartProxy, you can now streamline this process with bulk deployments.

We'll explore:

  • Bulk deployment to all clusters
  • Targeted deployment using labels
  • Deployment from private registries

Setting Up the Test Environment

Prerequisites

  • Docker (16GB+ memory recommended)
  • kubectl
  • kind
  • clusterctl

1. Creating the Management Cluster

First, let's create a management cluster using kind. Create the following configuration file:

# kind-cluster-with-extramounts.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  ipFamily: dual
nodes:
- role: control-plane
  extraMounts:
    - hostPath: /var/run/docker.sock
      containerPath: /var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

Create the cluster using this configuration:

kind create cluster --config kind-cluster-with-extramounts.yaml
Enter fullscreen mode Exit fullscreen mode

2. Setting Up Cluster API

Install Cluster API on the management cluster:

export CLUSTER_TOPOLOGY=true
clusterctl init --infrastructure docker --addon helm
Enter fullscreen mode Exit fullscreen mode

Wait for all components to be ready:

kubectl wait --for=condition=Available --timeout=300s -n capi-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-bootstrap-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-control-plane-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capd-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n caaph-system deployments --all
Enter fullscreen mode Exit fullscreen mode

3. Creating Workload Clusters

We'll create two clusters named "muscat" and "delaware":

# Generate manifest for muscat cluster
clusterctl generate cluster muscat \
  --flavor development \
  --kubernetes-version v1.28.0 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  > muscat.yaml

# Generate manifest for delaware cluster
clusterctl generate cluster delaware \
  --flavor development \
  --kubernetes-version v1.28.0 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  > delaware.yaml

# Create the clusters
kubectl apply -f muscat.yaml
kubectl apply -f delaware.yaml
Enter fullscreen mode Exit fullscreen mode

Get the kubeconfig files:

clusterctl get kubeconfig muscat > muscat-kubeconfig.yaml
clusterctl get kubeconfig delaware > delaware-kubeconfig.yaml
Enter fullscreen mode Exit fullscreen mode

4. Setting Up CNI

Install Calico on both clusters:

# Install Calico on muscat
kubectl --kubeconfig=muscat-kubeconfig.yaml apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml

# Install Calico on delaware
kubectl --kubeconfig=delaware-kubeconfig.yaml apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
Enter fullscreen mode Exit fullscreen mode

Deploying with HelmChartProxy

Deploying to All Clusters

Let's look at an example of deploying nginx to all clusters:

# helm-chart-proxy-nginx.yaml
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: nginx
spec:
  clusterSelector: {} # Empty selector means "select all clusters"
  repoURL: oci://registry-1.docker.io/bitnamicharts
  chartName: nginx
  version: "18.2.5"
  releaseName: nginx
  namespace: nginx
  options:
    waitForJobs: true
    atomic: true
    wait: true
    timeout: 5m
    install:
      createNamespace: true
  valuesTemplate: |-
    service:
      type: NodePort
Enter fullscreen mode Exit fullscreen mode

Deploy and verify:

# Deploy nginx
kubectl apply -f helm-chart-proxy-nginx.yaml

# Wait for HelmReleaseProxy to be ready
kubectl wait --for=condition=Ready --timeout=300s helmreleaseproxy --all

# Check pods on muscat
kubectl --kubeconfig=muscat-kubeconfig.yaml get pods -n nginx

# Check pods on delaware
kubectl --kubeconfig=delaware-kubeconfig.yaml get pods -n nginx
Enter fullscreen mode Exit fullscreen mode

Targeted Deployment Using Labels

You can deploy to specific clusters using labels:

# helm-chart-proxy-nginx.yaml
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: nginx
spec:
  clusterSelector:
    matchLabels:
      use-nginx: "true"  # Only deploy to clusters with this label
  # ... (other settings remain the same)
Enter fullscreen mode Exit fullscreen mode

Usage:

# Deploy nginx
kubectl apply -f helm-chart-proxy-nginx.yaml

# Label the muscat cluster
kubectl label cluster muscat use-nginx=true

# Check deployment status
kubectl get helmreleaseproxy -A

# Verify nginx is running on muscat
kubectl --kubeconfig=muscat-kubeconfig.yaml get pods -n nginx

# Verify nginx is not running on delaware
kubectl --kubeconfig=delaware-kubeconfig.yaml get pods -n nginx
Enter fullscreen mode Exit fullscreen mode

Deploying from Private Registries

Let's use GitHub Container Registry as an example:

  1. Create a GitHub Personal Access Token (needs read:packages permission)

  2. Set up registry credentials:

# Create config.json with base64 encoded credentials
echo -n "YOUR_GITHUB_USERNAME:YOUR_GITHUB_TOKEN" | base64 > auth.txt

cat > config.json << EOF
{
  "auths": {
    "ghcr.io": {
      "auth": "$(cat auth.txt)"
    }
  }
}
EOF

# Create the secret
kubectl create secret generic github-creds \
  --from-file=config.json \
  -n caaph-system
Enter fullscreen mode Exit fullscreen mode
  1. Create HelmChartProxy for private charts:
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: private-chart
spec:
  clusterSelector: {}
  repoURL: oci://ghcr.io/YOUR_GITHUB_USERNAME
  chartName: YOUR_CHART_NAME
  version: "0.1.0"
  credentials:
    secret:
      name: github-creds
      namespace: caaph-system
    key: config.json
  # ... (other settings)
Enter fullscreen mode Exit fullscreen mode

Conclusion

HelmChartProxy significantly simplifies the process of deploying Helm charts across multiple clusters. Key benefits include:

  • Reduced operational overhead through bulk deployments
  • Flexible deployment control using labels
  • Support for private registries

If you're managing multiple Kubernetes clusters, consider incorporating HelmChartProxy into your workflow. It can greatly streamline your Helm chart deployment process and make your multi-cluster management more efficient.

Top comments (0)