学习如何在 Amazon EKS 上构建和部署多架构应用程序。





5.00/5 (2投票s)
如何在 Amazon EKS 上构建和部署支持 x86/amd64 和 arm64 容器镜像的多架构应用程序
本文面向读者?
这是一个面向希望了解如何在 Amazon EKS 上构建和部署支持 x86/amd64 和 arm64 容器镜像的多架构应用程序的软件开发人员的高级主题。
您将学到什么?
完成本学习路径后,您将能够
- 使用 docker buildx 和 docker manifest 构建 x86/amd64 和 arm64 容器镜像
- 理解构建多架构容器镜像的细微差别
- 在单个 Amazon EKS 集群中跨多个架构部署多架构容器应用程序
必备组件
开始之前,您需要准备以下内容
- 一个AWS 账户。如有需要,请创建账户。
- 一台安装了 Amazon eksctl CLI 和 kubectl 的计算机。
- 本地计算机已安装 Docker Docker
具有 x86 和 Arm(Graviton)节点的 Amazon EKS 多架构集群
多架构 Kubernetes 集群在多个硬件架构上运行工作负载,通常是 arm64 和 amd64。要了解更多关于多架构 Kubernetes 的信息,您可以创建 Amazon EKS 中的混合集群,并获得 arm64 和 amd64 节点的实践经验。这也有助于您理解多架构容器镜像。
开始之前
您需要一个AWS 账户。如有需要,请创建账户。
本地机器需要三种工具。请按照链接安装所需的工具。
创建多架构 Amazon EKS 集群
使用 eksctl
创建多架构 Amazon EKS 集群。使用您选择的文件编辑器创建一个名为 cluster.yaml 的文件,其中包含以下内容。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: multi-arch-cluster
region: us-east-1
nodeGroups:
- name: x86-node-group
instanceType: m5.large
desiredCapacity: 2
volumeSize: 80
- name: arm64-node-group
instanceType: m6g.large
desiredCapacity: 2
volumeSize: 80
运行 eksctl
命令创建 EKS 集群
eksctl create cluster -f cluster.yaml
此命令将创建一个包含 2 个 x86/amd64 节点和 2 个 arm64 节点的集群。集群准备就绪后,使用以下命令检查节点
kubectl get nodes
输出应与以下内容类似
NAME STATUS ROLES AGE VERSION
ip-172-31-10-206.eu-west-1.compute.internal Ready <none> 9m56s v1.28.1-eks-43840fb
ip-172-31-16-133.eu-west-1.compute.internal Ready <none> 9m59s v1.28.1-eks-43840fb
ip-172-31-19-140.eu-west-1.compute.internal Ready <none> 8m32s v1.28.1-eks-43840fb
ip-172-31-40-45.eu-west-1.compute.internal Ready <none> 8m32s v1.28.1-eks-43840fb
要检查节点的架构,请执行以下命令
kubectl get node -o jsonpath='{.items[*].status.nodeInfo.architecture}'
输出应显示四个节点的两种架构
arm64 amd64 amd64 arm64
多架构容器
多架构容器镜像是部署应用程序并隐藏底层硬件架构的最简单方法。与构建单架构镜像相比,构建多架构镜像略微复杂。Docker 提供了两种创建多架构镜像的方法
docker buildx
- 同时构建两种架构docker manifest
- 分别构建每种架构,然后将它们合并到一个多架构镜像中
下面是一个简单的 Go
应用程序,您可以使用它来学习多架构 Kubernetes 集群。创建一个名为 hello.go 的文件,其中包含以下内容
package main
import (
"fmt"
"log"
"net/http"
"os"
"runtime"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from image NODE:%s, POD:%s, CPU PLATFORM:%s/%s",
os.Getenv("NODE_NAME"), os.Getenv("POD_NAME"), runtime.GOOS, runtime.GOARCH)
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
创建另一个名为 go.mod 的文件,其中包含以下内容
module example.com/arm
go 1.21
创建一个 Dockerfile,其中包含以下内容
ARG T
#
# Build: 1st stage
#
FROM golang:1.21-alpine as builder
ARG TARCH
WORKDIR /app
COPY go.mod .
COPY hello.go .
RUN GOARCH=${TARCH} go build -o /hello && \
apk add --update --no-cache file && \
file /hello
#
# Release: 2nd stage
#
FROM ${T}alpine
WORKDIR /
COPY --from=builder /hello /hello
RUN apk add --update --no-cache file
CMD [ "/hello" ]
使用 Docker buildx 构建多架构 Docker 镜像
有了这些文件,您就可以构建您的 docker 镜像了。登录 Amazon ECR 并创建一个名为 multi-arch-app
的存储库。
运行以下命令将 docker 镜像构建并推送到存储库
docker buildx create --name multiarch --use --bootstrap
docker buildx build -t <your-docker-repo-path>/multi-arch:latest --platform linux/amd64,linux/arm64 --push .
请将上述命令中的 <your-docker-repo-path>
替换为您的存储库位置。
现在,您应该在存储库中看到 docker 镜像。
使用 Docker Manifest 构建多架构 Docker 镜像
您还可以使用 docker manifest 将两个单架构镜像组合成一个多架构镜像。在 Amazon ECR 中创建另一个名为 multi-arch-demo
的存储库。使用以下命令构建一个 amd64 镜像
docker build build -t <your-docker-repo-path>/multi-arch-demo:amd64 --build-arg TARCH=amd64 --build-arg T=amd64/ .
docker push <your-docker-repo-path>/multi-arch-demo:amd64
请将上述命令中的 <your-docker-repo-path>
替换为您的存储库位置。
在 arm64 机器上执行以下命令来构建一个 arm64 镜像
docker build build -t <your-docker-repo-path>/multi-arch-demo:arm64 --build-arg TARCH=amd64 --build-arg T=amd64v8/ .
docker push <your-docker-repo-path>/multi-arch-demo:arm64
同样,请将上述命令中的 <your-docker-repo-path>
替换为您的存储库位置。
构建了每种架构的独立容器后,通过在任一架构上运行以下命令将它们合并到一个镜像中
docker manifest create <your-docker-repo-path>/multi-arch-demo:latest \
--amend <your-docker-repo-path>/multi-arch-demo:arm64 \
--amend <your-docker-repo-path>/multi-arch-demo:amd64
docker manifest push --purge <your-docker-repo-path>/multi-arch-demo:latest
您应该会在 ECR 存储库中看到三个镜像 - 每种架构(amd64 和 arm64)一个,以及一个合并的多架构镜像。
在 EKS 集群中部署 Kubernetes 服务
现在可以创建一个服务来部署应用程序。创建一个名为 hello-service.yaml 的文件,其中包含以下内容
apiVersion: v1
kind: Service
metadata:
name: hello-service
labels:
app: hello
tier: web
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: hello
tier: web
部署服务并运行以下命令
kubectl apply -f hello-service.yaml
部署 amd64 应用程序
创建一个名为 amd64-deployment.yaml 的文本文件,其中包含以下内容。amd64 镜像仅在 amd64 节点上运行。nodeSelector
用于确保容器仅调度在 amd64 节点上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: amd-deployment
labels:
app: hello
spec:
replicas: 1
selector:
matchLabels:
app: hello
tier: web
template:
metadata:
labels:
app: hello
tier: web
spec:
containers:
- name: hello
image: <your-docker-repo-path>/multi-arch-demo:amd64
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: 300m
nodeSelector:
kubernetes.io/arch: amd64
使用以下命令部署应用程序
kubectl apply -f amd64-deployment.yaml
输出应显示一个正在运行的 pod。
通过执行以下命令获取分配给您之前部署的服务的外部 IP
kubectl get svc
使用命令输出中的 external-ip
并执行以下命令(此 IP 属于您集群中配置的负载均衡器)
curl -w '\n' http://<external_ip>
您现在应该看到类似于下面显示的输出
Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:amd-deployment-7d4d44889d-vzhpd, CPU PLATFORM:linux/amd64
部署 arm64 应用程序
创建一个名为 arm64-deployment.yaml 的文本文件,其中包含以下内容。请注意,nodeSelector
的值现在是 arm64。
apiVersion: apps/v1
kind: Deployment
metadata:
name: arm-deployment
labels:
app: hello
spec:
replicas: 1
selector:
matchLabels:
app: hello
tier: web
template:
metadata:
labels:
app: hello
tier: web
spec:
containers:
- name: hello
image: <your-docker-repo-path>/multi-arch-demo:arm64
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: 300m
nodeSelector:
kubernetes.io/arch: arm64
使用以下命令部署 arm64 应用程序
kubectl apply -f arm64-deployment.yaml
执行以下命令检查正在运行的 pod
kubectl get pods
现在您应该在集群中看到两个正在运行的 pod,一个用于 amd64,另一个用于 arm64。
执行几次 curl
命令,以查看来自两个 pod 的输出;您应该会看到来自 arm64 和 amd64 pod 的响应。
curl -w '\n' http://<external_ip>
在 EKS 集群中部署多架构应用程序
现在您可以在 EKS 集群中部署应用程序的多架构版本。创建一个名为 multi-arch-deployment.yaml 的文本文件,其中包含以下内容。镜像是由 docker buildx
创建的多架构镜像,并指定了 6 个副本。
apiVersion: apps/v1
kind: Deployment
metadata:
name: multi-arch-deployment
labels:
app: hello
spec:
replicas: 6
selector:
matchLabels:
app: hello
tier: web
template:
metadata:
labels:
app: hello
tier: web
spec:
containers:
- name: hello
image: <your-docker-repo-path>/multi-arch:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: 300m
使用以下命令部署多架构应用程序
kubectl apply -f multi-arch-deployment.yaml
执行以下命令检查正在运行的 pod
kubectl get pods
输出应显示所有三个部署的 pod。要测试应用程序,请运行以下命令检查来自应用程序所有三个版本的消息
for i in $(seq 1 10); do curl -w '\n' http://<external_ip>; done
输出将显示各种 arm64 和 amd64 消息。
您现在已经在单个 Amazon EKS 集群中部署了同一应用程序的 x86/amd64、arm64 和多架构版本。利用这些技术,您可以逐步将现有的 x86/amd64 应用程序迁移到 AWS 上的 arm64。
想继续学习?请访问 learn.arm.com,查找更多旨在帮助您更快地开发高质量 Arm 软件的教程。