如何将容器映像中的应用部署到GKE集群
涉及操作
- 使用 Cloud Build 将应用封装到容器映像中。
- 在 Google Kubernetes Engine (GKE) 中创建一个集群。
- 将容器映像部署到该集群。
准备工作
- 登录您的 Google Cloud 账号。如果您没有 Google Cloud 账号,可以选择创建一个 Google账号来继续操作。新客户还可获享 $300 赠金,用于运行、测试和部署工作负 载。
- 创建或选择一个项目。
- 检测并确保您的项目已启用结算功能。
- 启用 Artifact Registry, Cloud Build, and Google Kubernetes Engine API。
- 安装 Google Cloud CLI,如果您之前安装了 gcloud CLI,请确保通过运行 gcloud components update 获得最新版本。
- 使用 gcloud 安装 kubectl,用于管理Kubernetes(即 GKE 使用的集群编排系统)
- 创建或选择一个应用
相关操作
使用 Cloud Build 将应用容器化
- 如需将应用容器化,请在与源文件相同的目录中创建一个名为 Dockerfile 的
新文件,并将以下内容复制到此文件中:
Go# Use the offical Go image to create a build artifact. # This is based on Debian and sets the GOPATH to /go. # https://hub.docker.com/_/golang FROM golang:1.22.0 as builder WORKDIR /app # Initialize a new Go module. RUN go mod init quickstart-go # Copy local code to the container image. COPY *.go ./ # Build the command inside the container. RUN CGO_ENABLED=0 GOOS=linux go build -o /quickstart-go # Use a Docker multi-stage build to create a lean production image. # https://docs.docker.com/develop/develop-images/multistage-build/#use-mul ti-stage-builds FROM gcr.io/distroless/base-debian11 # Change the working directory. WORKDIR / # Copy the binary to the production image from the builder stage. COPY --from=builder /quickstart-go /quickstart-go # Run the web service on container startup. USER nonroot:nonroot ENTRYPOINT ["/quickstart-go"]
Node.js# Use the official lightweight Node.js 16 image. # https://hub.docker.com/_/node FROM node:21-slim # Create and change to the app directory. WORKDIR /usr/src/app # Copy application dependency manifests to the container image. # A wildcard is used to ensure both package.json AND package-lock.json are copied. # Copying this separately prevents re-running npm install on every code change. COPY package*.json ./ # Install production dependencies. RUN npm install --omit=dev # Copy local code to the container image. COPY . ./ # Run the web service on container startup. CMD [ "npm", "start" ]
再添加一个 .dockerignore 文件,以确保本地文件不会影响容器的构建过程:
Dockerfile README.md node_modules npm-debug.log
Python# Use the official lightweight Python image. # https://hub.docker.com/_/python FROM python:3.12-slim # Copy local code to the container image. ENV APP_HOME /app WORKDIR $APP_HOME COPY . ./ # Install production dependencies. RUN pip install Flask gunicorn # Run the web service on container startup. Here we use the gunicorn # webserver, with one worker process and 8 threads. # For environments with multiple CPU cores, increase the number of workers # to be equal to the cores available. CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
再添加一个 .dockerignore 文件,以确保本地文件不会影响容器的构建过程:
Dockerfile README.md *.pyc *.pyo *.pyd __pycache__
C## Use Microsoft's official lightweight .NET images. FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /app # Install production dependencies. # Copy csproj and restore as distinct layers. COPY *.csproj ./ RUN dotnet restore # Copy local code to the container image. COPY . ./ # Build a release artifact. RUN dotnet publish -c Release -o out # Run the web service on container startup in a lean production image. FROM mcr.microsoft.com/dotnet/aspnet:6.0 WORKDIR /app COPY --from=build /app/out . # Start the .dll (will have the same name as your .csproj file) ENTRYPOINT ["dotnet", "helloworld-gke.dll"]
再添加一个 .dockerignore 文件,以确保本地文件不会影响容器的构建过程:
Dockerfile README.md **/obj/ **/bin/
PHP# Use the official PHP 7.4 image. # https://hub.docker.com/_/php FROM php:8.2-apache # Copy local code to the container image. COPY index.php /var/www/html/ # Use port 8080 in Apache configuration files. RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf # Configure PHP for development. # Switch to the production php.ini for production operations. # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" # https://hub.docker.com/_/php#configuration RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
再添加一个 .dockerignore 文件,以确保本地文件不会影响容器的构建过程:
Dockerfile README.md vendor
- 获取 Google Cloud 项目 ID:
gcloud config get-value project
- 在本快速入门中,您需要将容器存储在 Artifact Registry 中,并从注册表中将其部署到
集群。运行以下命令,在集群所在的位置创建名为 hello-repo 的仓库:
gcloud artifacts repositories create hello-repo \ --project=PROJECT_ID \ --repository-format=docker \ --location=us-central1 \ --description="Docker repository"
替换以下值: 是您的 Google Cloud 项目 ID
- 使用 Cloud Build 构建容器映像,此行为类似于运行 docker build 和 docker
push,但构建是在 Google Cloud 上进行的:
gcloud builds submit \ --tag us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke .
创建 GKE 集群
GKE 集群是作为单个 GKE 集群运行的一组托管式 Compute Engine 虚拟机。
- 创建集群。
gcloud container clusters create-auto helloworld-gke \ --location us-central1
- 验证您有权访问该集群。以下命令会列出您的容器集群中已启动并运行的节点,
并表明您有权访问该集群。
kubectl get nodes
部署到 GKE
如需将该应用部署到您创建好的 GKE 集群,您需要用到两个 Kubernetes 对象。
- 一个 Deployment 对象,用来定义您的应用。
- 一个 Service 对象,用来定义如何访问您的应用。
部署应用
该应用具有一个前端服务器,用于处理 Web 请求。您可以在名为 deployment.yaml 的新文 件中定义运行该前端所需的集群资源。这些资源通过一个 Deployment 对象来描述。您可以使 用 Deployment 来创建和更新 ReplicaSet 以及与其关联的 Pod。
- 在与其他文件相同的目录中创建 deployment.yaml 文件,然后复制以下内容。在文
件中替换以下值:
- $GCLOUD_PROJECT 是您的 Google Cloud 项目 ID
- $LOCATION 是代码库位置,例如 us-central1。
apiVersion: apps/v1 kind: Deployment metadata: name: helloworld-gke spec: replicas: 1 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello-app # Replace $LOCATION with your Artifact Registry location (e.g., us-west1). # Replace $GCLOUD_PROJECT with your project ID. image: $LOCATION-docker.pkg.dev/$GCLOUD_PROJECT/hello-repo/helloworld-gke:lates t # This app listens on port 8080 for web traffic by default. ports: - containerPort: 8080 env: - name: PORT value: "8080" resources: requests: memory: "1Gi" cpu: "500m" ephemeral-storage: "1Gi" limits: memory: "1Gi" cpu: "500m" ephemeral-storage: "1Gi"
- 将资源部署到集群:
kubectl apply -f deployment.yaml
- 跟踪 Deployment 的状态:
kubectl get deployments
如果所有 AVAILABLE 部署都为 READY,则表示 Deployment 已完成。
NAME READY UP-TO-DATE AVAILABLE AGE helloworld-gke 1/1 1 1 20s
如果 Deployment 有误,请再次运行 kubectl apply -f deployment.yaml,更新 Deployment 以纳入任何更改。
- Deployment 完成后,您可以查看 Deployment 创建的 Pod:
kubectl get pods
部署Service
Service 提供对一组 Pod 的单一访问点。尽管您可以访问单个 Pod,但 Pod 是临时性 的,只有使用一个 Service 地址才能进行可靠的访问。在您的 Hello World 应用中,名 为“hello”的 Service 定义了一个负载均衡器,用于通过一个 IP 地址访问多个 hello-app Pod。此 Service 在 service.yaml 文件中定义。
- 请在与其他源文件相同的目录中创建一个名为 service.yaml 的文件,并在此
文件中添加以下内容:
# The hello service provides a load-balancing proxy over the hello-app # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will # create an external HTTP load balancer. apiVersion: v1 kind: Service metadata: name: hello spec: type: LoadBalancer selector: app: hello ports: - port: 80 targetPort: 8080
这些 Pod 与使用 Pod 的 Service 是分别定义的。Kubernetes 使用标签来选择 服务指向的 Pod。利用标签,您既可以让一个 Service 指向来自不同副本集的多 个 Pod,也可以让多个 Service 指向同一个 Pod。
- 创建 Hello World Service:
kubectl apply -f service.yaml
- 获取服务的外部 IP 地址:
kubectl get services
分配 IP 地址最多可能需要 60 秒的时间。外部 IP 地址列在 hello Serivce 的 EXTERNAL-IP 列下。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello LoadBalancer 10.22.222.222 35.111.111.11 80:32341/TCP 1m kubernetes ClusterIP 10.22.222.1 none 443/TCP 20m
查看已部署的应用
现在,您已经部署好了在 GKE 上运行 Hello World 应用所需的全部资源。
使用在上一步中获取的外部 IP 地址在网络浏览器中加载应用,并查看正在运行的应用:
http://EXTERNAL-IP
或者,您可以对 Service 的外部 IP 地址进行 curl 调用:
curl EXTERNAL_IP
输出显示以下内容:
Hello World!
清理
为避免因本页中使用的资源导致您的 Google Cloud 账号产生费用,请按照以下步骤操作。
您需要为集群中运行的 Compute Engine 实例和 Container Registry 中的容器映像付费。
删除项目
删除 Google Cloud 项目后,系统会停止对该项目中使用的所有资源计费。
- 在 Google Cloud 控制台中,进入管理资源页面。
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关闭以删除项目。
删除集群
如果您想保留项目,只删除本教程中使用的资源,请删除您的集群和映像。
如需使用 Google Cloud CLI 删除集群,请为您使用的模式运行以下命令:
gcloud container clusters delete helloworld-gke \
--location us-central1
如需删除 Artifact Registry 代码库中的映像,请运行以下命令:
gcloud artifacts docker images delete \
us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke