|
| 1 | +# Using PGAdapter on Kubernetes |
| 2 | + |
| 3 | +PGAdapter can be used as a sidecar proxy on Kubernetes. This directory contains a small sample |
| 4 | +application that shows how to set this up. |
| 5 | + |
| 6 | +## Creating a GKE cluster |
| 7 | + |
| 8 | +These steps create a GKE cluster where the sample app can be deployed. You can skip these |
| 9 | +steps if you already have a GKE cluster, and instead modify your existing deployment to |
| 10 | +include PGAdapter. |
| 11 | + |
| 12 | +See https://cloud.google.com/kubernetes-engine/docs/deploy-app-cluster for more details on |
| 13 | +how to set up a GKE cluster. |
| 14 | + |
| 15 | +1. Create an Autopilot cluster named example-cluster and update it to use Workload Identity. |
| 16 | + |
| 17 | +```shell |
| 18 | +export PROJECT_ID=<YOUR_PROJECT_ID> |
| 19 | +export REGION=<YOUR_COMPUTE_REGION> |
| 20 | + |
| 21 | +gcloud config set project $PROJECT_ID |
| 22 | +gcloud container clusters create-auto example-cluster \ |
| 23 | + --region=$REGION |
| 24 | +gcloud container clusters update example-cluster \ |
| 25 | + --region=$REGION \ |
| 26 | + --workload-pool=$PROJECT_ID.svc.id.goog |
| 27 | +``` |
| 28 | + |
| 29 | +2. Get authentication credentials for the cluster. |
| 30 | + |
| 31 | +```shell |
| 32 | +gcloud container clusters get-credentials example-cluster \ |
| 33 | + --region $REGION |
| 34 | +``` |
| 35 | + |
| 36 | +This command configures `kubectl` to use the cluster you created. |
| 37 | + |
| 38 | +3. Create a repository and build the sample application |
| 39 | + |
| 40 | +```shell |
| 41 | +gcloud artifacts repositories create example-repo \ |
| 42 | + --repository-format=docker \ |
| 43 | + --location=$REGION \ |
| 44 | + --description="Example Docker repository" |
| 45 | +docker build --platform linux/amd64 \ |
| 46 | + -t ${REGION}-docker.pkg.dev/${PROJECT_ID}/example-repo/example-app . |
| 47 | +``` |
| 48 | + |
| 49 | +4. Authenticate and push the Docker image to Artifact Registry |
| 50 | + |
| 51 | +```shell |
| 52 | +gcloud auth configure-docker ${REGION}-docker.pkg.dev |
| 53 | +docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/example-repo/example-app |
| 54 | +``` |
| 55 | + |
| 56 | +## Setting up a service account |
| 57 | + |
| 58 | +The first step to running PGAdapter in Kubernetes is creating a Google Cloud IAM |
| 59 | +service account (GSA) to represent your application. It is recommended that you create |
| 60 | +a service account unique to each application, instead of using the same service |
| 61 | +account everywhere. This model is more secure since it allows you to limit |
| 62 | +permissions on a per-application basis. |
| 63 | + |
| 64 | +The service account must be granted access to the Cloud Spanner database that the |
| 65 | +application will be connecting to. It is enough to assign the `Cloud Spanner Database User` |
| 66 | +role for this example to the service account. |
| 67 | + |
| 68 | +```shell |
| 69 | +export GSA_NAME=pgadapter-example-gsa |
| 70 | +gcloud iam service-accounts create $GSA_NAME \ |
| 71 | + --description="PGAdapter Example Service Account" \ |
| 72 | + --display-name="PGAdapter Example Service Account" |
| 73 | +gcloud projects add-iam-policy-binding $PROJECT_ID \ |
| 74 | + --member="serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \ |
| 75 | + --role="roles/spanner.databaseUser" |
| 76 | +``` |
| 77 | + |
| 78 | +## Providing the service account to PGAdapter |
| 79 | + |
| 80 | +Next, you need to configure Kubernetes to provide the service account to PGAdapter. |
| 81 | +This example uses GKE's [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) |
| 82 | +for this. This method allows you to bind a [Kubernetes Service Account (KSA)](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) |
| 83 | +to a Google Service Account (GSA). The GSA will then be accessible to applications |
| 84 | +using the matching KSA. |
| 85 | + |
| 86 | +1. Create a Kubernetes Service Account (KSA) |
| 87 | + |
| 88 | +```shell |
| 89 | +export KSA_NAME=pgadapter-example-ksa |
| 90 | +kubectl create serviceaccount $KSA_NAME --namespace default |
| 91 | +``` |
| 92 | + |
| 93 | +2. Enable the IAM binding between your `$GSA_NAME` and `$KSA_NAME`: |
| 94 | + |
| 95 | +```sh |
| 96 | +gcloud iam service-accounts add-iam-policy-binding \ |
| 97 | + --role roles/iam.workloadIdentityUser \ |
| 98 | + --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/$KSA_NAME]" \ |
| 99 | + ${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com |
| 100 | +``` |
| 101 | + |
| 102 | +3. Add an annotation to `$KSA_NAME` to complete the binding: |
| 103 | + |
| 104 | +```sh |
| 105 | +kubectl annotate serviceaccount \ |
| 106 | + $KSA_NAME \ |
| 107 | + iam.gke.io/gcp-service-account=${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com |
| 108 | +``` |
| 109 | + |
| 110 | +## Deploying the application |
| 111 | + |
| 112 | +1. Deploy the example application and PGAdapter to Kubernetes. The script below replaces the |
| 113 | + placeholders in the deployment manifest with your values. |
| 114 | + |
| 115 | +```shell |
| 116 | +export SPANNER_PROJECT_ID=$PROJECT_ID |
| 117 | +export SPANNER_INSTANCE_ID=<YOUR_SPANNER_INSTANCE_ID> |
| 118 | +export SPANNER_DATABASE_ID=<YOUR_SPANNER_DATABASE_ID> |
| 119 | + |
| 120 | +sed -e 's|<YOUR_KSA_NAME>|'"${KSA_NAME}"'|g' \ |
| 121 | + -e 's|<YOUR_REGION>|'"${REGION}"'|g' \ |
| 122 | + -e 's|<YOUR_PROJECT_ID>|'"${PROJECT_ID}"'|g' \ |
| 123 | + -e 's|<YOUR_SPANNER_PROJECT_ID>|'"${SPANNER_PROJECT_ID}"'|g' \ |
| 124 | + -e 's|<YOUR_SPANNER_INSTANCE_ID>|'"${SPANNER_INSTANCE_ID}"'|g' \ |
| 125 | + -e 's|<YOUR_SPANNER_DATABASE_ID>|'"${SPANNER_DATABASE_ID}"'|g' \ |
| 126 | + manifests/example-app-deployment.yaml > manifests/my-app-deployment.yaml |
| 127 | + |
| 128 | +kubectl apply -f manifests/my-app-deployment.yaml |
| 129 | +``` |
| 130 | + |
| 131 | +2. Expose the deployment to the Internet |
| 132 | + |
| 133 | +```shell |
| 134 | +kubectl expose deployment pgadapter-gke-example \ |
| 135 | + --type LoadBalancer --port 80 --target-port 8080 |
| 136 | +``` |
| 137 | + |
| 138 | +## Inspect and view the application |
| 139 | + |
| 140 | +1. Inspect the running Pods by using `kubectl get pods` |
| 141 | + |
| 142 | +```shell |
| 143 | +kubectl get pods |
| 144 | +``` |
| 145 | + |
| 146 | +2. Inspect the pgadapter-gke-example Service by using `kubectl get service` |
| 147 | + |
| 148 | +```shell |
| 149 | +kubectl get service pgadapter-gke-example |
| 150 | +``` |
| 151 | + |
| 152 | +From this command's output, copy the Service's external IP address from the EXTERNAL-IP column. |
| 153 | + |
| 154 | +3. View the output of the application |
| 155 | + |
| 156 | +Use the EXTERNAL-IP address from the previous command. |
| 157 | + |
| 158 | +```shell |
| 159 | +curl http://<EXTERNAL-IP> |
| 160 | +``` |
0 commit comments