In this tutorial, you’ll learn how to deploy a highly available Redis instance on Google Kubernetes Engine (GKE) using Pulumi, Helm, and Kubernetes. We'll cover:
Prerequisites
Setting up GCP & GKE via Pulumi
Deploying Redis with the Bitnami Helm chart
Exposing Redis with a LoadBalancer
Validating the Deployment
1. Prerequisites
Before you begin, make sure you have:
A GCP project with billing enabled.
gcloud CLI installed and authenticated.
Pulumi CLI installed.
A local Kubernetes context (you'll dynamically generate one via Pulumi).
Helm installed.
Go ≥1.18 (or your preferred Pulumi language runtime).
2. Setting up GCP & GKE via Pulumi
Create a new Pulumi project (e.g. pulumi new go), then install the GCP and Kubernetes providers:
go get github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/container
go get github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes
Next, implement a provider package to:
Provision a GKE cluster
Generate a kubeconfig
Instantiate a Kubernetes provider
// provider/provider.go
package provider
import (
  "fmt"
  "os/exec"
  "strings"
  "github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/container"
  k8s "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
  "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func SetupProvider(ctx *pulumi.Context) (*k8s.Provider, error) {
  // Provision a GKE cluster
  cluster, err := container.NewCluster(ctx, "my-gke-cluster", &container.ClusterArgs{
    Location:         pulumi.String("<YOUR_REGION>"),
    InitialNodeCount: pulumi.Int(1),
    NodeConfig: &container.ClusterNodeConfigArgs{
      MachineType: pulumi.String("e2-standard-2"),
      OauthScopes: pulumi.StringArray{
        pulumi.String("https://www.googleapis.com/auth/cloud-platform"),
      },
    },
  })
  if err != nil {
    return nil, fmt.Errorf("creating GKE cluster: %w", err)
  }
  // Build kubeconfig dynamically
  kubeconfig := pulumi.All(cluster.Name, cluster.Endpoint, cluster.MasterAuth).ApplyT(
    func(args []interface{}) (string, error) {
      name := args[0].(string)
      endpoint := args[1].(string)
      auth := args[2].(container.ClusterMasterAuth)
      // Retrieve a short-lived access token
      out, err := exec.Command("gcloud", "auth", "print-access-token").Output()
      if err != nil {
        return "", fmt.Errorf("gcloud auth: %w", err)
      }
      token := strings.TrimSpace(string(out))
      return fmt.Sprintf(`
apiVersion: v1
kind: Config
clusters:
- name: %s
  cluster:
    certificate-authority-data: %s
    server: https://%s
contexts:
- name: %s
  context:
    cluster: %s
    user: %s
current-context: %s
users:
- name: %s
  user:
    token: %s
`, name, *auth.ClusterCaCertificate, endpoint,
        name, name, name, name, name, token), nil
    }).(pulumi.StringOutput)
  // Create the Pulumi Kubernetes provider
  k8sProvider, err := k8s.NewProvider(ctx, "k8s", &k8s.ProviderArgs{
    Kubeconfig: kubeconfig,
  })
  if err != nil {
    return nil, fmt.Errorf("creating Kubernetes provider: %w", err)
  }
  return k8sProvider, nil
}
Finally, call this from your main.go:
// main.go
package main
import (
  "iac_staging/provider"
  "iac_staging/redis"
  "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
  pulumi.Run(func(ctx *pulumi.Context) error {
    // Setup GKE + Kubernetes provider
    k8sProvider, err := provider.SetupProvider(ctx)
    if err != nil {
      return err
    }
    // Deploy Redis
    if err := redis.Install(ctx, k8sProvider); err != nil {
      return err
    }
    return nil
  })
}
3. Deploying Redis with the Bitnami Helm Chart
Create a redis package that uses Pulumi’s Helm integration to install the Bitnami Redis chart:
// redis/redis.go
package redis
import (
  "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3"
  k8s "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
  "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func Install(ctx *pulumi.Context, provider *k8s.Provider) error {
  // Replace <YOUR_REDIS_PASSWORD> with a Pulumi secret or config
  redisPassword := pulumi.String("<YOUR_REDIS_PASSWORD>")
  _, err := helm.NewChart(ctx, "redis", helm.ChartArgs{
    Chart:     pulumi.String("redis"),
    Version:   pulumi.String("17.3.11"),
    Namespace: pulumi.String("default"),
    FetchArgs: helm.FetchArgs{
      Repo: pulumi.String("https://charts.bitnami.com/bitnami"),
    },
    Values: pulumi.Map{
      "auth": pulumi.Map{
        "enabled":  pulumi.Bool(true),
        "password": redisPassword,
      },
      "master": pulumi.Map{
        "service": pulumi.Map{
          // Type LoadBalancer will provision a GCP Network LB
          "type": pulumi.String("LoadBalancer"),
        },
        "resources": pulumi.Map{
          "requests": pulumi.Map{
            "cpu":    pulumi.String("100m"),
            "memory": pulumi.String("128Mi"),
          },
          "limits": pulumi.Map{
            "cpu":    pulumi.String("250m"),
            "memory": pulumi.String("256Mi"),
          },
        },
      },
      "replica": pulumi.Map{
        "replicaCount": pulumi.Int(1),
        "resources": pulumi.Map{
          "requests": pulumi.Map{
            "cpu":    pulumi.String("100m"),
            "memory": pulumi.String("128Mi"),
          },
          "limits": pulumi.Map{
            "cpu":    pulumi.String("250m"),
            "memory": pulumi.String("256Mi"),
          },
        },
      },
    },
  }, pulumi.Provider(provider))
  return err
}
4. Exposing Redis with a LoadBalancer
By setting the service.type to LoadBalancer, GKE will automatically provision a GCP Network Load Balancer with an external IP. You can retrieve this IP with:
kubectl --context $(pulumi stack output kubeconfig) \
  get svc redis-master --namespace default -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Tip: You can also configure a static IP in GCP and annotate the chart to use it by adding:
master:
  service:
    annotations:
      networking.gke.io/load-balancer-type: "External"
    loadBalancerIP: "YOUR_RESERVED_STATIC_IP"
5. Validating the Deployment
- Obtain the External IP:
 
EXTERNAL_IP=$(kubectl get svc redis-master \
  --namespace default \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Redis external IP: $EXTERNAL_IP"
- Test Connectivity with redis-cli:
 
redis-cli -h $EXTERNAL_IP -a $REDIS_PASSWORD PING
# Expected: PONG
Conclusion
You’ve now:
Provisioned a GKE cluster on GCP with Pulumi.
Installed Redis using the Bitnami Helm chart via Pulumi.
Exposed Redis publicly (or privately, if you choose a different service.type).
Validated the deployment with redis-cli.
This approach lets you manage your infrastructure and application in a single Pulumi program, ensuring repeatable, version-controlled deployments.
Feel free to drop any questions or improvements in the comments!
              
    
Top comments (0)