部署容器化 Web 应用

本教程介绍如何将 Web 应用打包到 Docker 容器映像中 ,并在 Google Kubernetes Engine (GKE) 集群上运行该容器映像。然后将 Web 应用部署为可随用户需求而扩缩、支持负载平衡的副本集。

目标

  • 将示例 Web 应用打包到 Docker 映像中。
  • 将 Docker 映像上传到 Container Registry。
  • 创建 GKE 集群。
  • 将示例应用部署到集群。
  • 管理部署的自动扩缩。
  • 将示例应用公开发布到互联网。
  • 部署示例应用的新版本。

准备工作

请按照以下步骤启用 Kubernetes Engine API:
  1. 访问 Google Cloud Console 中的 Kubernetes Engine 页面
  2. 创建或选择项目。
  3. 稍作等待,让 API 和相关服务完成启用过程。 此过程可能耗时几分钟。
  4. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

选项 A:使用 Cloud Shell

您可以使用 Cloud Shell 来执行本教程中所述的操作,该环境中预装了本教程中用到的 gclouddockerkubectl 命令行工具。如果使用 Cloud Shell,则无需在工作站上安装这些命令行工具。

如需使用 Cloud Shell,请执行以下操作:

  1. 转到 Google Cloud Console
  2. 点击 Cloud Console 窗口顶部的激活 Cloud Shell 激活 Shell 按钮 按钮。

    一个 Cloud Shell 会话随即会在 Cloud Console 底部的新框内打开,并显示命令行提示符。

    Cloud Shell 会话

选项 B:在本地使用命令行工具

如果您希望在工作站上按照本教程中的说明操作,请按照以下步骤安装必要的工具。

  1. 安装 Cloud SDK,其中包含 gcloud 命令行工具。

  2. 使用 gcloud 命令行工具,安装 Kubernetes 命令行工具。kubectl 用于与 Kubernetes 通信,Kubernetes 是 GKE 集群的集群编排系统:

    gcloud components install kubectl
  3. 在工作站上安装 Docker 社区版 (CE)。您将用它为应用构建容器映像。

  4. 安装 Git 源代码控制工具以从 GitHub 获取示例应用。

构建容器映像

在本教程中,您将部署一个名为 hello-app示例 Web 应用,这是一个用 Go 编写的 Web 服务器,可在端口 8080 上响应所有请求并显示 Hello, World! 消息。

GKE 接受 Docker 映像作为应用部署格式。 在将 hello-app 部署到 GKE 之前,您必须将 hello-app 源代码打包为 Docker 映像。

如需构建 Docker 映像,您需要具有源代码和 Dockerfile。 Dockerfile 中包含有关如何构建该映像的说明。

  1. 通过运行以下命令下载 hello-app 源代码和 Dockerfile:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/hello-app
    
  2. PROJECT_ID 环境变量设置为您的 Google Cloud 项目 ID (project-id)。PROJECT_ID 变量将容器映像与您的项目的 Container Registry 相关联。

    export PROJECT_ID=project-id
    
  3. 确认 PROJECT_ID 环境变量的值正确无误:

    echo $PROJECT_ID
    
  4. hello-app 构建和标记 Docker 映像:

    docker build -t gcr.io/${PROJECT_ID}/hello-app:v1 .
    

    此命令指示 Docker 使用当前目录中的 Dockerfile 构建映像,并使用名称(例如 gcr.io/my-project/hello-app:v1)对其进行标记。gcr.io 前缀是指映像托管在其中的 Container Registry。运行此命令不会上传映像。

  5. 运行 docker images 命令以验证构建是否成功:

    docker images
    
    输出:
    REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
    gcr.io/my-project/hello-app    v1                  25cfadb1bf28        10 seconds ago      54 MB
    

在本地运行容器(可选)

  1. 使用本地 Docker 引擎测试容器映像:

    docker run --rm -p 8080:8080 gcr.io/${PROJECT_ID}/hello-app:v1
    
  2. 如果您使用的是 Cloud Shell,请点击网页预览按钮 网页预览按钮,然后选择 8080 端口号。GKE 会在新的浏览器窗口中打开其代理服务的预览网址。

  3. 否则,打开一个新的终端窗口(或 Cloud Shell 标签页)并运行以下命令,以验证容器是否正常工作并以“Hello, World!”响应请求。

    curl http://localhost:8080

    看到成功响应后,您可以在运行 docker run 命令的标签页中按 Ctrl+C 来关闭容器。

将 Docker 映像推送到 Container Registry

您必须将容器映像上传到注册表,以便您的 GKE 集群可以下载并运行该容器映像。在 Google Cloud 中,Container Registry 默认处于启用状态。

  1. 为您正在使用的 Google Cloud 项目启用 Container Registry API

    gcloud services enable containerregistry.googleapis.com
    

  2. 配置 Docker 命令行工具以向 Container Registry 进行身份验证:

    gcloud auth configure-docker
    
  3. 将刚刚构建的 Docker 映像推送到 Container Registry:

    docker push gcr.io/${PROJECT_ID}/hello-app:v1
    

创建 GKE 集群

现在,Docker 映像已存储在 Container Registry 中,接下来创建 GKE 集群来运行 hello-app。GKE 集群由运行 KubernetesCompute Engine 虚拟机实例池组成,Kubernetes 是为 GKE 提供支持的开源集群编排系统。

Cloud Shell

  1. gcloud 工具设置项目 IDCompute Engine 区域选项:

    gcloud config set project $PROJECT_ID
    gcloud config set compute/zone compute-zone

    选择离您最近的可用区。

  2. 创建名为 hello-cluster 的集群:

    gcloud container clusters create hello-cluster
    

    创建 GKE 集群并进行运行状况检查需要几分钟的时间。

  3. 该命令运行完后,请运行以下命令以查看集群的三个工作器虚拟机实例:

    gcloud compute instances list
    
    输出:
    NAME                                           ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
    gke-hello-cluster-default-pool-d8b498d3-0d6r  us-east1-b   e2-medium                   10.142.0.4   35.237.4.149   RUNNING
    gke-hello-cluster-default-pool-d8b498d3-k29m  us-east1-b   e2-medium                   10.142.0.3   34.75.248.193  RUNNING
    gke-hello-cluster-default-pool-d8b498d3-vcrj  us-east1-b   e2-medium                   10.142.0.2   35.196.51.235  RUNNING
    

控制台

  1. 访问 Cloud Console 中的 Google Kubernetes Engine 菜单。

    访问 Google Kubernetes Engine 菜单

  2. 点击 创建

  3. 集群基本信息部分,输入名称 hello-cluster

  4. 通过从下拉菜单中选择 Compute Engine 区域来设置区域

  5. 点击创建。这将创建一个具有 3 个节点的 GKE 集群。

  6. 等待集群创建完成。集群准备就绪后,集群名称旁边会显示一个绿色对勾标记。

将示例应用部署到 GKE

您现在可以将构建的 Docker 映像部署到 GKE 集群。

Kubernetes 将应用表示为 Pod,这是可扩缩的单元,包含一个或多个容器。Pod 是 Kubernetes 中最小的可部署单元。通常,您可以将 Pod 部署为可扩缩并分布在整个集群中的副本集。部署副本集的一种方法是通过 Kubernetes 部署来完成操作。

在本部分中,您将创建一个 Kubernetes Deployment,以便在您的集群上运行 hello-app。此 Deployment 具有副本 (Pod)。一个部署 Pod 仅包含一个容器:即 hello-app Docker 映像。您还将创建一个 HorizontalPodAutoscaler 资源,根据 CPU 负载将 Pod 数量从 3 个扩缩为 1 到 5 个之间。

Cloud Shell

  1. 为您的 hello-app Docker 映像创建 Kubernetes 部署。

    kubectl create deployment hello-app --image=gcr.io/${PROJECT_ID}/hello-app:v1
    
  2. 将部署副本的基准数量设置为 3。

    kubectl scale deployment hello-app --replicas=3
    
  3. 为您的部署创建一个 HorizontalPodAutoscaler 资源。

    kubectl autoscale deployment hello-app --cpu-percent=80 --min=1 --max=5
    
  4. 如需查看已创建的 Pod,请运行以下命令:

    kubectl get pods
    
    输出:
    NAME                         READY   STATUS    RESTARTS   AGE
    hello-app-784d7569bc-hgmpx   1/1     Running   0          10s
    hello-app-784d7569bc-jfkz5   1/1     Running   0          10s
    hello-app-784d7569bc-mnrrl   1/1     Running   0          15s
    

控制台

  1. 访问 Cloud Console 中的 Google Kubernetes Engine“工作负载”菜单。

    访问“工作负载”菜单

  2. 在“工作负载”菜单中,点击部署

  3. 在出现的“创建部署”窗口中,点击现有容器映像

  4. 使用下拉菜单,点击您推送到 Container Registry 的 hello-app 映像。

  5. 点击查看 YAML。这将打开一个 YAML 配置文件,该文件表示将要部署到集群中的两个 Kubernetes API 资源:一个部署资源,以及一个用于该部署资源的 HorizontalPodAutoscaler 资源。

  6. 点击部署

  7. 等待部署 Pod 准备就绪。在 GKE 集群部署 3 个 hello-app Pod 时,会出现蓝色的旋转轮;然后在 Pod 成功部署后,会出现绿色的对勾标记。

  8. 通过导航到 Kubernetes Engine,然后导航到工作负载,等待 Pod 准备就绪。点击 hello-app 并向下滚动到托管 Pod 部分以查看 3 个 hello-app Pod。

将示例应用公开发布到互联网

虽然 Pod 确实具有单独分配的 IP 地址,但这些 IP 地址只能从集群内部访问。此外,GKE Pod 设计是临时的,可根据扩缩需求启动或关闭。当 Pod 因错误而崩溃时,GKE 会自动重新部署该 Pod,并且每次都会为 Pod 分配新的 IP 地址。

这意味着对于任何部署,与活跃 Pod 组对应的 IP 地址集是动态的。我们需要一种方法来执行以下操作:1) 将 Pod 组合成一个静态主机名,以及 2) 将集群外的一组 Pod 公开发布到互联网。

Kubernetes 服务可同时解决这两个问题。 这些服务会将 Pod 组合成一个静态 IP 地址,并且可从集群内的任何 Pod 进行访问。 GKE 还会为该静态 IP 地址分配 DNS 主机名,例如:hello-app.default.svc.cluster.local

GKE 中的默认服务类型为 ClusterIP,其中服务将获得只能从集群内部访问的 IP 地址。 如需在集群外部公开 Kubernetes 服务,请创建 LoadBalancer 类型的服务。此类型的服务会为可通过互联网访问的一组 Pod 生成外部负载平衡器 IP 地址。

在本部分中,您将使用 LoadBalancer 类型的 Service 将 hello-app Deployment 公开发布到互联网。

Cloud Shell

  1. 使用 kubectl expose 命令为 hello-app 部署生成 Kubernetes 服务。

    kubectl expose deployment hello-app --name=hello-app-service --type=LoadBalancer --port 80 --target-port 8080
    

    此处,--port 标志指定在负载平衡器上配置的端口号,--target-port 标志指定 hello-app 容器正在侦听的端口号。

  2. 运行以下命令以获取 hello-app-service 的服务详情。

    kubectl get service
    
    输出:
    NAME                 CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
    hello-app-service    10.3.251.122    203.0.113.0     80:30877/TCP     10s
    
  3. EXTERNAL_IP 地址复制到剪贴板(例如:203.0.113.0)。

控制台

  1. 访问 Cloud Console 中的 Google Kubernetes Engine“工作负载”菜单。

    访问“工作负载”菜单

  2. 点击 hello-app

  3. 在“部署详情”页面中,点击公开

  4. 在“公开部署”菜单中,将目标端口设置为 8080。 这是 hello-app 容器侦听的端口。

  5. 确保已选择 Load balancer 作为服务类型

  6. 点击公开以生成用于 hello-app 的 Kubernetes 服务,该服务名为 hello-app-service

  7. 等待外部负载平衡器完成创建。Google Cloud Console 中会显示蓝色旋转轮图标。负载平衡器准备就绪后,您将被重定向到 hello-app-service 的服务详情页面。

  8. 向下滚动到外部端点字段,然后将地址复制到剪贴板。

现在,hello-app Pod 已通过 Kubernetes 服务公开发布到互联网,您可以打开新的浏览器标签页,然后导航到先前复制到剪贴板中的服务 IP 地址。您会看到一条 Hello, World! 消息以及一个 Hostname 字段。Hostname 对应于向浏览器传送 HTTP 请求的三个 hello-app Pod 中的一个。

部署示例应用的新版本

在本部分中,您将通过构建新的 Docker 映像并将其部署到 GKE 集群,来将 hello-app 升级到新版本。

GKE 的滚动更新功能让您可以在不停机的情况下更新部署。在滚动更新期间,GKE 集群将逐步将现有 hello-app Pod 替换为包含新版本的 Docker 映像的 Pod。在更新期间,负载平衡器服务仅将流量路由到可用的 Pod。

  1. 返回到 Cloud Shell,现在您已在其中克隆了 hello 应用源代码和 Dockerfile。 更新 main.go 文件中的函数 hello() 以报告新版本 2.0.0

  2. 构建并标记新的 hello-app Docker 映像。

    docker build -t gcr.io/${PROJECT_ID}/hello-app:v2 .
    
  3. 将映像推送到 Container Registry。

    docker push gcr.io/${PROJECT_ID}/hello-app:v2
    

现在,您可以更新 hello-app Kubernetes 部署来使用新的 Docker 映像。

Cloud Shell

  1. 通过更新映像,对现有部署进行滚动更新:

    kubectl set image deployment/hello-app hello-app=gcr.io/${PROJECT_ID}/hello-app:v2
    
  2. 运行 v1 映像的 Pod 停止运行后,系统会启动运行 v2 映像的新 Pod。

    watch kubectl get pods
    
    输出:
    NAME                        READY   STATUS    RESTARTS   AGE
    hello-app-89dc45f48-5bzqp   1/1     Running   0          2m42s
    hello-app-89dc45f48-scm66   1/1     Running   0          2m40s
    
  3. 在单独的标签页中,再次导航到 hello-app-service 外部 IP。您现在应该看到 Version 被设置为 2.0.0.

控制台

  1. 访问 Cloud Console 中的 Google Kubernetes Engine“工作负载”菜单。

    访问“工作负载”菜单

  2. 点击 hello-app

  3. 操作下,点击滚动更新

  4. 在出现的窗口中,将映像字段设置为 gcr.io/[YOUR_PROJECT_ID]/hello-app:v2

  5. 点击更新以开始滚动更新。

  6. 返回到 hello-app 的部署视图,然后向下滚动到有效修订版本。 您现在应该看到两个修订版本:1 和 2。修订版本 1 对应于您之前创建的初始部署。修订版本 2 是您刚刚执行的滚动更新。

  7. 片刻之后,刷新页面。在托管 Pod 下,hello-app 的所有副本现在均对应于修订版本 2。

  8. 在单独的标签页中,再次导航到 hello-app-service 外部 IP。您现在应该看到 Version 被设置为 2.0.0.

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

  1. 删除 Service:此步骤将取消并释放为 Service 创建的 Cloud Load Balancer:

    kubectl delete service hello-app-service
  2. 删除集群:此步骤将删除构成集群的资源,如计算实例、磁盘和网络资源:

    gcloud container clusters delete hello-cluster
  3. 删除容器映像:此操作会删除推送到 Container Registry 的 Docker 映像。

     gcloud container images delete gcr.io/${PROJECT_ID}/hello-app:v1  --force-delete-tags --quiet
     gcloud container images delete gcr.io/${PROJECT_ID}/hello-app:v2  --force-delete-tags --quiet
    

后续步骤