Skip to content

Commit 95cad50

Browse files
Merge pull request #2518 from ranimandepudi/add-multi-arch-learning-path
KubeCon Demo: From x86 to Arm on GKE - Build, Deploy, and Migrate with Google Axion
2 parents 2a896e1 + 8eb8f72 commit 95cad50

File tree

8 files changed

+871
-1
lines changed

8 files changed

+871
-1
lines changed

assets/contributors.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,6 @@ Mohamad Najem,Arm,,,,
105105
Ruifeng Wang,Arm,,,,
106106
Zenon Zhilong Xiu,Arm,,zenon-zhilong-xiu-491bb398,,
107107
Zbynek Roubalik,Kedify,,,,
108-
Ayoub Bourjilat,AC6,Bourjilat,ayoub-bourjilat-a55b58165/,,https://www.ac6.fr/en/
108+
Rani Chowdary Mandepudi, Arm,,,,
109+
Ayoub Bourjilat,Ac6,Bourjilat,ayoub-bourjilat-a55b58165/,,https://www.ac6.fr/en/
109110
Yahya Abouelseoud,Arm,,,,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
title: From x86 to Arm on GKE - Build, Deploy, and Migrate with Google Axion
3+
draft: true
4+
cascade:
5+
draft: true
6+
7+
minutes_to_complete: 90
8+
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 multi‑architecture images and migrate services from x86 to Arm (Google Axion) using production‑grade practices.
10+
11+
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.
17+
18+
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.
23+
24+
author:
25+
- Rani Chowdary Mandepudi
26+
27+
### Tags
28+
skilllevels: Advanced
29+
subjects: Containers and Virtualization
30+
armips:
31+
- Neoverse
32+
operatingsystems:
33+
- Linux
34+
tools_software_languages:
35+
- Kubernetes
36+
- GKE
37+
- Skaffold
38+
- Cloud Build
39+
40+
41+
further_reading:
42+
- resource:
43+
title: GKE documentation
44+
link: https://cloud.google.com/kubernetes-engine/docs
45+
type: documentation
46+
- resource:
47+
title: Create Arm-based clusters and node pools
48+
link: https://cloud.google.com/kubernetes-engine/docs/how-to/create-arm-clusters-nodes
49+
type: documentation
50+
51+
52+
53+
54+
55+
### FIXED, DO NOT MODIFY
56+
# ================================================================================
57+
weight: 1 # _index.md always has weight of 1 to order correctly
58+
layout: "learningpathall" # All files under learning paths have this same wrapper
59+
learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content.
60+
---
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# ================================================================================
3+
# FIXED, DO NOT MODIFY THIS FILE
4+
# ================================================================================
5+
weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation.
6+
title: "Next Steps" # Always the same, html page title.
7+
layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing.
8+
---
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
title: Automate builds and rollout with Cloud Build & Skaffold
3+
weight: 6
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
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.
10+
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.
17+
18+
19+
{{% 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).
21+
{{% /notice %}}
22+
23+
## Grant IAM to the Cloud Build service account
24+
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.
25+
26+
```bash
27+
# Uses env vars set earlier: PROJECT_ID, REGION, CLUSTER_NAME, GAR
28+
PROJECT_NUMBER="$(gcloud projects describe "${PROJECT_ID}" --format='value(projectNumber)')"
29+
CLOUD_BUILD_SA="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"
30+
31+
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${CLOUD_BUILD_SA}" --role="roles/cloudbuild.builds.builder" --condition=None --quiet
32+
33+
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${CLOUD_BUILD_SA}" --role="roles/container.developer" --condition=None --quiet
34+
35+
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${CLOUD_BUILD_SA}" --role="roles/artifactregistry.writer" --condition=None --quiet
36+
37+
gcloud projects add-iam-policy-binding "${PROJECT_ID}" --member="serviceAccount:${CLOUD_BUILD_SA}" --role="roles/logging.logWriter" --condition=None --quiet
38+
```
39+
40+
## Update skaffold.yaml for deploy-only
41+
42+
This will let Cloud Build handle image builds and use Skaffold only to apply the Kustomize overlays.
43+
44+
```yaml
45+
# From the repo root (microservices-demo)
46+
[ -f skaffold.yaml ] && cp skaffold.yaml "skaffold.yaml.bak.$(date +%s)"
47+
cat > skaffold.yaml <<'YAML'
48+
49+
# Copyright 2021 Google LLC
50+
#
51+
# Licensed under the Apache License, Version 2.0 (the "License");
52+
# you may not use this file except in compliance with the License.
53+
# You may obtain a copy of the License at
54+
#
55+
# http://www.apache.org/licenses/LICENSE-2.0
56+
#
57+
# Unless required by applicable law or agreed to in writing, software
58+
# distributed under the License is distributed on an "AS IS" BASIS,
59+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
60+
# See the License for the specific language governing permissions and
61+
# limitations under the License.
62+
63+
apiVersion: skaffold/v3
64+
kind: Config
65+
metadata:
66+
name: app
67+
manifests:
68+
kustomize:
69+
paths:
70+
- kustomize/base
71+
deploy:
72+
kubectl: {}
73+
profiles:
74+
- name: deploy-amd
75+
patches:
76+
- op: replace
77+
path: /manifests/kustomize/paths/0
78+
value: kustomize/overlays/amd64
79+
- name: migrate-arm
80+
patches:
81+
- op: replace
82+
path: /manifests/kustomize/paths/0
83+
value: kustomize/overlays/arm64
84+
---
85+
apiVersion: skaffold/v3
86+
kind: Config
87+
metadata:
88+
name: loadgenerator
89+
requires:
90+
- configs: [app]
91+
manifests:
92+
rawYaml:
93+
- ./kubernetes-manifests/loadgenerator.yaml
94+
deploy:
95+
kubectl: {}
96+
YAML
97+
98+
```
99+
100+
## Create cloudbuild.yaml
101+
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. 
103+
104+
```yaml
105+
cat > cloudbuild.yaml <<'YAML'
106+
107+
# Copyright 2020 Google LLC
108+
#
109+
# Licensed under the Apache License, Version 2.0 (the "License");
110+
# you may not use this file except in compliance with the License.
111+
# You may obtain a copy of the License at
112+
#
113+
# http://www.apache.org/licenses/LICENSE-2.0
114+
#
115+
# Unless required by applicable law or agreed to in writing, software
116+
# distributed under the License is distributed on an "AS IS" BASIS,
117+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
118+
# See the License for the specific language governing permissions and
119+
# limitations under the License.
120+
121+
# [START cloudbuild_microservice_demo_cloudbuild]
122+
123+
# This configuration file is used to build and deploy the app into a
124+
# GKE cluster using Google Cloud Build.
125+
#
126+
# PREREQUISITES:
127+
# - Cloud Build service account must have role: "Kubernetes Engine Developer"
128+
129+
# USAGE:
130+
# GCP zone and GKE target cluster must be specified as substitutions
131+
# Example invocation:
132+
# `gcloud builds submit --config=cloudbuild.yaml --substitutions=_ZONE=us-central1-b,_CLUSTER=demo-app-staging .`
133+
134+
substitutions:
135+
_REGION: ${REGION}
136+
_CLUSTER: ${CLUSTER_NAME}
137+
_REPO: ${GAR}
138+
139+
options:
140+
machineType: "N1_HIGHCPU_8"
141+
logging: CLOUD_LOGGING_ONLY
142+
timeout: "7200s"
143+
144+
steps:
145+
# 1) Authenticate Docker to Artifact Registry
146+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk
147+
entrypoint: bash
148+
args:
149+
- -ceu
150+
- |
151+
echo "Auth to GAR..."
152+
gcloud auth configure-docker "$(echo "${_REPO}" | awk -F/ '{print $1}')" --quiet
153+
154+
# 2) Build and push multi-arch images (examples: adservice, cartservice)
155+
- name: gcr.io/google.com/cloudsdktool/google-cloud-cli:stable
156+
entrypoint: bash
157+
env:
158+
- DOCKER_BUILDKIT=1
159+
- CLOUDSDK_CORE_DISABLE_PROMPTS=1
160+
args:
161+
- -ceu
162+
- |
163+
apt-get update && apt-get install -y docker.io curl
164+
mkdir -p ~/.docker/cli-plugins/
165+
curl -sSL https://github.com/docker/buildx/releases/download/v0.14.0/buildx-v0.14.0.linux-amd64 \
166+
-o ~/.docker/cli-plugins/docker-buildx
167+
chmod +x ~/.docker/cli-plugins/docker-buildx
168+
169+
# Start Docker daemon in the runner
170+
dockerd > /var/log/dockerd.log 2>&1 &
171+
timeout 30 sh -c 'until docker info >/dev/null 2>&1; do sleep 1; done'
172+
173+
# Enable QEMU for cross-arch builds and create builder
174+
docker run --privileged --rm tonistiigi/binfmt --install all
175+
docker buildx create --name multi --use || true
176+
docker buildx inspect --bootstrap
177+
178+
# Build and push multi-arch images
179+
docker buildx build --platform linux/amd64,linux/arm64 \
180+
-t "${_REPO}/adservice:v1" \
181+
src/adservice --push
182+
183+
docker buildx build --platform linux/amd64,linux/arm64 \
184+
-t "${_REPO}/cartservice:v1" \
185+
src/cartservice/src --push
186+
187+
# 3) Connect kubectl to the target cluster
188+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
189+
entrypoint: bash
190+
args:
191+
- -ceu
192+
- |
193+
gcloud container clusters get-credentials "${_CLUSTER}" --region "${_REGION}"
194+
195+
# 4) Deploy to amd64 node pool
196+
- name: gcr.io/k8s-skaffold/skaffold:v2.16.1
197+
id: deploy-amd
198+
entrypoint: bash
199+
args:
200+
- -ceu
201+
- |
202+
skaffold deploy --filename=skaffold.yaml --config loadgenerator -p deploy-amd
203+
204+
# 5) Verify pods on amd64
205+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk:latest
206+
entrypoint: bash
207+
args:
208+
- -ceu
209+
- |
210+
echo "Pods on amd64:"
211+
kubectl get pods -o wide
212+
213+
# 6) Migrate to arm64 node pool
214+
- name: gcr.io/k8s-skaffold/skaffold:v2.16.1
215+
id: migrate-arm
216+
entrypoint: bash
217+
args:
218+
- -ceu
219+
- |
220+
skaffold deploy --filename=skaffold.yaml --config loadgenerator -p migrate-arm
221+
222+
# 7) Verify pods on arm64 and print the external IP
223+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk:latest
224+
entrypoint: bash
225+
args:
226+
- -ceu
227+
- |
228+
echo "Pods on arm64:"
229+
kubectl get pods -o wide
230+
echo "Fetching external IP for the frontend service..."
231+
IP=$(kubectl get svc frontend-external -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
232+
echo "Open http://$${IP} in your browser."
233+
YAML
234+
```
235+
236+
{{% notice Note %}}
237+
In production, add one build step per microservice (or a loop) and enable caching. The example above builds two images for brevity, mirroring the manual steps you completed earlier. 
238+
{{% /notice %}}
239+
240+
## Run the pipeline
241+
242+
From the repo root:
243+
244+
```bash
245+
gcloud builds submit --config=cloudbuild.yaml --substitutions=_CLUSTER="${CLUSTER_NAME}",_REGION="${REGION}",_REPO="${GAR}"
246+
```
247+
248+
The final step prints in the build description:
249+
250+
```
251+
Open http://<EXTERNAL-IP> in your browser.
252+
```
253+
254+
Open that URL to load the storefront and confirm the full build - deploy - migrate flow is automated.

0 commit comments

Comments
 (0)