Skip to content

Commit 656b587

Browse files
Merge pull request #2521 from jasonrandrews/review
review online boutique app on GKE
2 parents c6f2240 + 2cb875c commit 656b587

File tree

6 files changed

+198
-133
lines changed

6 files changed

+198
-133
lines changed

content/learning-paths/servers-and-cloud-computing/gke-multi-arch-axion/_index.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
---
22
title: From x86 to Arm on GKE - Build, Deploy, and Migrate with Google Axion
3+
34
draft: true
45
cascade:
56
draft: true
67

78
minutes_to_complete: 90
89

9-
who_is_this_for: This learning path is for cloud, platform, and SRE engineers operating Kubernetes on Google Cloud who need a prescriptive path to build multiarchitecture images and migrate services from x86 to Arm (Google Axion) using production‑grade practices.
10+
who_is_this_for: This is an advanced topic for cloud, platform, and site reliability engineers operating Kubernetes on Google Cloud who need a prescriptive path to build multi-architecture images and migrate services from x86 to Arm using Google Axion processors.
1011

1112
learning_objectives:
12-
- Prepare Dockerfiles for multi-architecture builds (minimal, safe edits so services compile and run on amd64 & arm64).
13-
- Create a dual-architecture GKE Standard cluster with two node pools, amd64 and arm64 (Axion-based C4A).
14-
- Build and publish multi-architecture images to Artifact Registry using Docker Buildx (Kubernetes driver) - BuildKit pods run natively on both pools (no QEMU or extra build VMs).
15-
- Deploy to amd64 first, then migrate to arm64 using Kustomize overlays and progressive rollout.
16-
- Optionally automate builds and rollouts end-to-end with Cloud Build and Skaffold.
13+
- Prepare Dockerfiles for multi-architecture builds by adding arm64 support
14+
- Create a dual-architecture GKE standard cluster with two node pools, amd64 and arm64
15+
- Build and publish multi-architecture images to Artifact Registry using Docker Buildx without using QEMU to emulate Arm instructions
16+
- Deploy a Kubernetes application amd64 first, then migrate to arm64 using Kustomize overlays and progressive rollout
17+
- Optionally automate builds and rollouts with Cloud Build and Skaffold
1718

1819
prerequisites:
19-
- A [Google Cloud account](https://console.cloud.google.com/) with billing enabled.
20-
- Cloud Shell access (used as the control plane, includes gcloud, kubectl, and Docker Buildx).
21-
- (Optional if not using Cloud Shell) A Linux/macOS workstation with Docker (Buildx enabled), kubectl, the Google Cloud CLI (gcloud), and Git.
22-
- Basic familiarity with Docker, Kubernetes, and gcloud.
20+
- A [Google Cloud account](https://console.cloud.google.com/) with billing enabled
21+
- A local Linux or macOS computer or Cloud Shell access with Docker, Kubernetes CLI (kubectl), Google Cloud CLI (gcloud), and Git installed
22+
- Basic familiarity with Docker, Kubernetes, and gcloud
2323

2424
author:
2525
- Rani Chowdary Mandepudi
@@ -43,7 +43,7 @@ further_reading:
4343
title: GKE documentation
4444
link: https://cloud.google.com/kubernetes-engine/docs
4545
type: documentation
46-
- resource:
46+
- resource:
4747
title: Create Arm-based clusters and node pools
4848
link: https://cloud.google.com/kubernetes-engine/docs/how-to/create-arm-clusters-nodes
4949
type: documentation

content/learning-paths/servers-and-cloud-computing/gke-multi-arch-axion/cloud-build.md

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
---
2-
title: Automate builds and rollout with Cloud Build & Skaffold
2+
title: Automate builds and rollout with Cloud Build and Skaffold
33
weight: 6
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
77
---
88

9-
Google [**Cloud Build**](https://cloud.google.com/build/docs/set-up) is a managed CI/CD service that runs your containerized build and deploy steps in isolated runners. In this page you'll automate the flow you performed manually: **build multi-arch images, deploy to GKE on amd64, then migrate to arm64**, and print the app's external IP.
9+
Google [**Cloud Build**](https://cloud.google.com/build/docs/set-up) is a managed CI/CD service that runs your containerized build and deploy steps in isolated runners.
1010

11-
## What this pipeline does
12-
- Authenticates Docker to **Artifact Registry**.
13-
- Builds and pushes **amd64 + arm64** images with **Docker Buildx** (QEMU enabled in the runner).
14-
- Connects to your **GKE** cluster.
15-
- Applies the **amd64** Kustomize overlay, verifies pods, then applies the **arm64** overlay and verifies again.
16-
- Prints the **frontend-external** LoadBalancer IP at the end.
11+
In this section, you'll automate the flow you performed manually: build multi-arch images, deploy to GKE on amd64, then migrate to arm64, and print the app's external IP.
1712

13+
## What does this pipeline do?
14+
15+
The pipeline performs the following steps:
16+
17+
- Authenticates Docker to your Artifact Registry
18+
- Builds and pushes amd64 and arm64 images with Docker Buildx, with QEMU enabled in the runner
19+
- Connects to your GKE cluster
20+
- Applies the amd64 Kustomize overlay, verifies pods, then applies the arm64 overlay and verifies pods again
21+
- Prints the frontend-external LoadBalancer IP at the end
1822

1923
{{% notice Tip %}}
20-
Run this from the **microservices-demo** repo root in **Cloud Shell**. Ensure you completed earlier pages (GAR created, images path/tag decided, GKE cluster with amd64 + arm64 node pools, and Kustomize overlays present).
24+
Run this from the microservices-demo repo root in Cloud Shell. Ensure you completed the previous steps.
2125
{{% /notice %}}
2226

23-
## Grant IAM to the Cloud Build service account
27+
## Grant IAM permission to the Cloud Build service account
28+
2429
Cloud Build runs as a per-project service account: `<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`. Grant it the minimal roles needed to build, push, log, and interact with GKE.
2530

31+
Grant the required roles:
32+
2633
```bash
2734
# Uses env vars set earlier: PROJECT_ID, REGION, CLUSTER_NAME, GAR
2835
PROJECT_NUMBER="$(gcloud projects describe "${PROJECT_ID}" --format='value(projectNumber)')"
@@ -37,9 +44,11 @@ gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:
3744
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${CLOUD_BUILD_SA}" --role="roles/logging.logWriter" --condition=None --quiet
3845
```
3946

40-
## Update skaffold.yaml for deploy-only
47+
## Update the Skaffold configuration
48+
49+
Create a `skaffold.yaml` file for Cloud Build. This lets Cloud Build handle image builds and uses Skaffold only to apply the Kustomize overlays.
4150

42-
This will let Cloud Build handle image builds and use Skaffold only to apply the Kustomize overlays.
51+
Create the configuration:
4352

4453
```yaml
4554
# From the repo root (microservices-demo)
@@ -97,9 +106,11 @@ YAML
97106

98107
```
99108

100-
## Create cloudbuild.yaml
109+
## Create a YAML file for Cloud Build
110+
111+
This pipeline installs Docker with Buildx in the runner, enables QEMU, builds two services as examples (extend as desired), connects to your cluster, deploys to amd64, verifies, migrates to arm64, verifies, and prints the external IP. 
101112

102-
This pipeline installs `Docker + Buildx` in the runner, enables QEMU, builds two services as examples (extend as desired), connects to your cluster, deploys to amd64, verifies, migrates to arm64, verifies, and prints the external IP. 
113+
Run the commands to create the `cloudbuild.yaml` file.
103114

104115
```yaml
105116
cat > cloudbuild.yaml <<'YAML'
@@ -239,7 +250,7 @@ In production, add one build step per microservice (or a loop) and enable cachin
239250

240251
## Run the pipeline
241252

242-
From the repo root:
253+
Submit the build from the root of the repository:
243254

244255
```bash
245256
gcloud builds submit --config=cloudbuild.yaml --substitutions=_CLUSTER="${CLUSTER_NAME}",_REGION="${REGION}",_REPO="${GAR}"
@@ -251,4 +262,4 @@ The final step prints in the build description:
251262
Open http://<EXTERNAL-IP> in your browser.
252263
```
253264

254-
Open that URL to load the storefront and confirm the full build - deploy - migrate flow is automated.
265+
Open the URL to load the storefront and confirm the full build, deploy, and migrate flow is automated.

content/learning-paths/servers-and-cloud-computing/gke-multi-arch-axion/gke-build-push.md

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
---
2-
title: Provision a Dual-Arch GKE Cluster and Publish Multi-Arch Images
2+
title: Provision a dual-architecture GKE cluster and publish images
33
weight: 4
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
77
---
88

9-
Now create a **GKE cluster** with **two node pools** (amd64 & arm64), then build and push multi-arch images natively on those node pools. Each architecture uses its own BuildKit pod, and no QEMU emulation is involved.
9+
You are ready to create a GKE cluster with two node pools (amd64 and arm64), then build and push multi-arch images natively on those node pools.
1010

11-
#### Networking (VPC-native / IP aliasing)
11+
Each architecture uses its own BuildKit pod, and no QEMU emulation is required.
1212

13-
GKE uses **VPC-native (IP aliasing)** and requires **two secondary ranges** on the chosen subnet: one for **Pods** and one for **Services**.
14-
- **Default VPC:** Skip this step. GKE will create the secondary ranges automatically.
15-
- **Custom VPC/subnet:** Set variables and add/verify secondary ranges:
13+
## Networking configuration
14+
15+
GKE uses VPC-native (IP aliasing) and requires two secondary ranges on the chosen subnet: one for Pods and one for Services.
16+
17+
For the default VPC, GKE creates the secondary ranges automatically.
18+
19+
Run the commands below in your terminal, adjusting the environment variables as needed for your account:
1620

1721
```bash
1822
# Set/confirm network variables (adjust to your environment)
@@ -29,13 +33,14 @@ gcloud compute networks subnets list --network "${NETWORK}" --regions "${REGION}
2933
# If missing, add two secondary ranges (example CIDRs; ensure no overlap)
3034
gcloud compute networks subnets update "${SUBNET}" --region "${REGION}" --add-secondary-ranges ${POD_RANGE_NAME}=10.8.0.0/14,${SVC_RANGE_NAME}=10.4.0.0/20
3135
```
32-
This avoids users on default VPC accidentally setting NETWORK/SUBNET and passing the wrong flags later.
3336

34-
### Create the GKE cluster
37+
This approach prevents users on the default VPC from accidentally setting NETWORK/SUBNET variables and passing incorrect flags later.
38+
39+
## Create the GKE cluster
3540

36-
Create a GKE Standard cluster with VPC-native (IP aliasing) enabled and no default node pool (you'll add amd64 and arm64 pools next). The command below works for both default and custom VPCs: if NETWORK, SUBNET, and the secondary range variables are unset, GKE uses the default VPC and manages ranges automatically.
41+
Create a GKE Standard cluster with VPC-native (IP aliasing) enabled and no default node pool. You'll add amd64 and arm64 pools in the next step.
3742

38-
Create the cluster with no default node pool and add node pools explicitly.
43+
The command below works for both default and custom VPCs. If the NETWORK, SUBNET, and secondary range variables are unset, GKE uses the default VPC and manages ranges automatically.
3944

4045
```bash
4146
# Cluster vars (reuses earlier PROJECT_ID/REGION/ZONE)
@@ -46,7 +51,7 @@ export CLUSTER_NAME="${CLUSTER_NAME:-gke-multi-arch-cluster}"
4651
gcloud container clusters create "${CLUSTER_NAME}" --region "${REGION}" --enable-ip-alias --num-nodes "1" --machine-type "e2-standard-2" ${NETWORK:+--network "${NETWORK}"} ${SUBNET:+--subnetwork "${SUBNET}"} ${POD_RANGE_NAME:+--cluster-secondary-range-name "${POD_RANGE_NAME}"} ${SVC_RANGE_NAME:+--services-secondary-range-name "${SVC_RANGE_NAME}"}
4752
```
4853

49-
Create an x86 (amd64) pool and an Arm (arm64) pool. Use machine types available in your region (e.g., c4-standard-* for x86 and c4a-standard-* for Axion).
54+
Now create an x86 (amd64) pool and an Arm (arm64) pool. Use machine types available in your region. The commands below use `c4-standard-*` for x86 and `c4a-standard-*` for Axion:
5055

5156
```bash
5257
# amd64 pool (x86)
@@ -67,14 +72,14 @@ kubectl config current-context
6772
kubectl get nodes -o wide
6873
kubectl get nodes -L kubernetes.io/arch
6974
```
70-
You should see nodes for both architectures. In zonal clusters (or when a pool has --num-nodes=1 in a single zone), expect one amd64 and one arm64 node. In regional clusters, --num-nodes is per zone, with three zones you'll see three amd64 and three arm64 nodes.
7175

72-
### Create the Buildx builder on GKE (native, one pod per arch)
76+
You should see nodes for both architectures. In zonal clusters (or when a pool has `--num-nodes=1` in a single zone), expect one amd64 and one arm64 node. In regional clusters, `--num-nodes` is per zone, so with three zones you'll see three amd64 and three arm64 nodes.
7377

74-
Now run a BuildKit pod on an amd64 node and another on an arm64 node. Buildx will route each platform's build to the matching pod - native builds, no emulation.
78+
## Create the Buildx builder on GKE
7579

76-
```bash
80+
Now run a BuildKit pod on an amd64 node and another on an arm64 node. Buildx routes each platform's build to the matching pod. These are native builds with no QEMU emulation.
7781

82+
```bash
7883
# Namespace for BuildKit pods
7984
kubectl create ns buildkit --dry-run=client -o yaml | kubectl apply -f -
8085

@@ -87,14 +92,16 @@ docker buildx create --driver kubernetes --append --name gke-native --driver-opt
8792
# Bootstrap and verify pods
8893
docker buildx inspect gke-native --bootstrap
8994
kubectl -n buildkit get pods -o wide
90-
9195
```
92-
{{% notice Note %}}
93-
You will now have a multi-node Buildx builder named gke-native. Each BuildKit pod is pinned to a specific CPU arch via nodeselector.
94-
{{% /notice %}}
9596

96-
### Build & push all services (multi-arch manifest lists)
97-
Build every service for linux/amd64 and linux/arm64 using the GKE-backed builder:
97+
You now have a multi-node Buildx builder named `gke-native`. Each BuildKit pod is pinned to a specific CPU architecture using node selectors.
98+
99+
## Build and push all services
100+
101+
You can now build all services for `linux/amd64` and `linux/arm64` using the GKE-backed builder.
102+
103+
Run the commands:
104+
98105
```bash
99106
cat << 'EOF' > build-all-multiarch.sh
100107
#!/usr/bin/env bash
@@ -132,23 +139,28 @@ EOF
132139
chmod +x build-all-multiarch.sh
133140
./build-all-multiarch.sh
134141
```
135-
Each :v1 you push is a manifest list that points to two images (one per arch).
136142

137-
### Verify manifest lists and per-arch pulls
143+
Each tag you push is a manifest list that points to two images, one per architecture.
144+
145+
## Verify manifest lists and per-arch pulls
138146

139147
List pushed images:
140148

141149
```bash
142150
gcloud artifacts docker images list "${GAR}"
143151
```
144152

145-
Inspect one tag (should show both platforms):
153+
Inspect one tag to confirm it shows both platforms:
154+
146155
```bash
147156
docker buildx imagetools inspect "${GAR}/adservice:v1"
148157
```
149158

150-
Expected Output:
151-
```
159+
The output is:
160+
161+
```output
152162
Platform: linux/amd64
153163
Platform: linux/arm64
154164
```
165+
166+
You are now ready to prepare the application manifests and deploy the application.

content/learning-paths/servers-and-cloud-computing/gke-multi-arch-axion/gke-deploy.md

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
---
2-
title: Prepare Manifests and Deploy on GKE(migration to arm64)
2+
title: Prepare manifests and deploy on GKE
33
weight: 5
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
77
---
88

9-
Point the app manifests at your Artifact Registry images, add Kustomize overlays to target node architecture, deploy to the x86 (amd64) pool, then migrate the same workloads to the Arm (arm64) pool.
9+
You'll now configure the application manifests to use your Artifact Registry images and create Kustomize overlays for different CPU architectures. This allows you to deploy the same application to both x86 and Arm node pools.
1010

11-
### Prepare deployment manifests
11+
## Prepare deployment manifests
1212

13-
Replace public sample image references with your Artifact Registry path and **tag(:v1)**, then create Kustomize overlays to select nodes by architecture.
13+
Replace sample image references with your Artifact Registry path and tag, then create Kustomize overlays to select nodes by architecture.
1414

15-
#### Point base manifests at your images
15+
### Point base manifests at your images
16+
17+
Replace the image references with your references:
1618

1719
```bash
1820
# Replace the sample repo path with your GAR (from earlier: ${GAR})
@@ -27,13 +29,17 @@ find kustomize/base -name "*.yaml" -type f -exec \
2729
grep -r "${GAR}" kustomize/base/ || true
2830
```
2931

30-
#### Create node-selector overlays (amd64 and arm64)
32+
### Create node-selector overlays
33+
34+
Create node-selector overlays for targeting specific architectures.
35+
36+
First, create the directories:
3137

3238
```bash
3339
mkdir -p kustomize/overlays/amd64 kustomize/overlays/arm64
3440
```
3541

36-
**amd64 overlay**
42+
Create the amd64 overlay:
3743

3844
```bash
3945
cat << 'EOF' > kustomize/overlays/amd64/kustomization.yaml
@@ -53,7 +59,8 @@ cat << 'EOF' > kustomize/overlays/amd64/node-selector.yaml
5359
EOF
5460
```
5561

56-
**arm64 overlay**
62+
Create the arm64 overlay:
63+
5764
```bash
5865
cat << 'EOF' > kustomize/overlays/arm64/kustomization.yaml
5966
resources:
@@ -72,11 +79,13 @@ cat << 'EOF' > kustomize/overlays/arm64/node-selector.yaml
7279
EOF
7380
```
7481

75-
Result: the **base** references your images, and **overlays** control per-arch placement.
82+
You now have updated manifests that reference your container images and Kustomize overlays that target specific CPU architectures.
7683

77-
### Deploy to the x86 (amd64) pool
84+
## Deploy to the x86 (amd64) pool
7885

79-
Render the amd64 Kustomize overlay (adds nodeSelector: kubernetes.io/arch=amd64) and apply it to the cluster. Run from the repository root after updating base manifests to your ${GAR} and setting your kube-context to this cluster.
86+
Render the amd64 Kustomize overlay (adds `nodeSelector: kubernetes.io/arch=amd64`) and apply it to the cluster.
87+
88+
Run from the repository root after updating base manifests and setting your kube-context to this cluster:
8089

8190
```bash
8291
kubectl kustomize kustomize/overlays/amd64 | kubectl apply -f -
@@ -90,43 +99,44 @@ kubectl get pods -o wide
9099
kubectl get pods -o=custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase --no-headers
91100
```
92101

93-
Pods should be scheduled on nodes labelled `kubernetes.io/arch=amd64`.
102+
Pods should be scheduled on nodes labeled `kubernetes.io/arch=amd64`.
94103

95-
### Migrate to the Arm (arm64) pool
104+
## Migrate to the Arm (arm64) pool
96105

97106
Apply the arm64 overlay to move workloads:
98107

99108
```bash
100109
kubectl kustomize kustomize/overlays/arm64 | kubectl apply -f -
101110
```
102111

103-
Verify pods have shifted to arm64 nodes:
112+
Verify pods have moved to arm64 nodes:
104113

105114
```bash
106115
kubectl get pods -o wide
107116
```
108117

109118
You should see pods now running on nodes where `kubernetes.io/arch=arm64`.
110119

111-
### Verify external access
120+
## Verify external access
112121

113122
Get the LoadBalancer IP and open the storefront:
114123

115124
```bash
116125
kubectl get svc frontend-external
117126
```
118127

119-
Expected columns include EXTERNAL-IP:
128+
The output is similar to:
120129

121-
```
130+
```output
122131
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
123132
frontend-external LoadBalancer 10.12.3.45 34.123.45.67 80:31380/TCP 3m
124133
```
125134

126-
Copy the EXTERNAL-IP value, and open it in a new browser tab:
127-
```
135+
Copy the EXTERNAL-IP value and open it in a new browser tab:
136+
137+
```console
128138
http://<EXTERNAL-IP>
129139
```
130140

131-
The microservices storefront should load confirming that your application is accessible and functional on the Arm64 node pool.
141+
The microservices storefront loads, confirming that your application is accessible and functional on the arm64 node pool.
132142

0 commit comments

Comments
 (0)