WordPress on Kubernetes with GCP and Workload Identity: part 2

WordPress on Kubernetes with GCP and Workload Identity: part 2

Disclaimer: This blog contains opinions about Google technology. While I work at Google, this is my personal blog. Opinions stated here are my own, not those of my company.

Continuing from the previous post, in this second part we will be provisioning Kubernetes objects. Once we are done, this will complete WordPress on Kubernetes with GCP MySQL and Workload Identity sample.

WordPress on Kubernetes

In the last part, we used Config Connector to create GCP objects that we need to power our WordPress site. In this part, we’ll build the Kubernetes side of of our configuration.

Stateful Set

First of all, let’s create a stateful set. As you can see below, it consists of 2 containers. One container is to host WordPress workload, another container is to host SQL proxy. To clarify, I’m omitting non-essential configuration for livenessProbe, readinessProbe and resource limit requests. Please see the full configuration with these sections included here.

Most significantly, there are no secrets that we had to mount to cloudsql-proxy pod. This is part of workload identity “magic”, that propagates these secrets, without having to mount the keys.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: default
  name: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
  serviceName: "wordpress"
  replicas: 1
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      terminationGracePeriodSeconds: 30
      serviceAccountName: sql-wp-ksa-wi
      containers:
      - name: wordpress
        image: wordpress:5.2.2-apache
        imagePullPolicy: IfNotPresent
        env:
        - name: WORDPRESS_DB_HOST
          value: 127.0.0.1:3306
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyRef:
              name: wordpress-cloudsql-db-credentials
              key: username
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: wordpress-cloudsql-db-credentials
              key: password
        ports:
        - containerPort: 80
        volumeMounts:
        - name: wordpress-volume-2
          mountPath: /var/www/html
      - name: cloudsql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.11
        env:
          - name: CONNECTION_NAME
            valueFrom:
              secretKeyRef:
                name: wordpress-cloudsql-db-credentials
                key: connectionName
          - name: PROJECT_ID
            valueFrom:
              secretKeyRef:
                name: wordpress-cloudsql-db-credentials
                key: projectId
        command: ["/cloud_sql_proxy",
                  "-instances=$(PROJECT_ID):$(CONNECTION_NAME)=tcp:3306"]
  volumeClaimTemplates:
    - metadata:
        name: wordpress-volume-2
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 10Gi

K8s Service Account

Next, let’s apply the configuration below. It instantiates a Kubernetes service account. Most importantly, note the annotation that connects it to Google service account. We need this as part of Workload identity setup.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: sql-wp-ksa-wi
  annotations:
    iam.gke.io/gcp-service-account: sql-wp-sa@[PROJECT_ID].iam.gserviceaccount.com

K8s SQL DB Credentials

apiVersion: v1
kind: Secret
metadata:
  name: wordpress-cloudsql-db-credentials
stringData:
  projectId: [PROJECT_ID]
  username: wordpress
  password: change-me
  connectionName: us-central1:wp-db

K8s Service and External Load Balancer

apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: wordpress
---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: wordpress-external
  labels:
    app: wordpress
spec:
  type: LoadBalancer
  ports:
    - port: 80
      name: web
      targetPort: 80
      protocol: TCP
  selector:
    app: wordpress

Workload Identity

To sum up, this is what we created to configure workload identity:

  1. Provision GCP cluster, using Beta create API to configure workload identity namespace
  2. Google Service Account
  3. IAM Policy for Google Service Account – defines permissions that Google Service account has
  4. Workload Identity role for K8s Service Account on Google Service Account
  5. K8s service account with annotation linking it to K8s service account

Once you have these building blocks in place, you no longer need to mount the secrets to use in the pod. For more details, please see Workload Identity documentation.

Applying configuration

To create complete configuration, run kubectl apply on all the resources that we discussed. Finally, run one temporary gcloud step until the gap with policy binding is addressed.

This is it! To summarize, we created WordPress on Kubernetes with GCP and Workload Identity. You can get complete configuration for this sample here.

Leave a Comment