1. 简介
运行网站和应用并非易事。
意外出现意外、服务器崩溃、需求增加会让更多的资源被利用,在不停机的情况下进行更改却既复杂又压力重。
想象一下,有一款工具可以帮助您完成所有这些工作,甚至能让您实现自动化!有了 GKE,这一切都不可能变得简单易行!在此 Codelab 中,您将扮演开发者的角色,他们为一家虚构的公司 Fancy Store 运营电子商务网站。由于存在扩缩和服务中断问题,您需将应用部署到 GKE!
下面安排练习来反映普通云开发者的体验:
- 创建 GKE 集群。
- 创建 Docker 容器。
- 将容器部署到 GKE。
- 通过服务公开容器。
- 将容器扩容为多个副本。
- 修改网站。
- 在不停机的情况下发布新版本。
架构图
学习内容
- 如何创建 GKE 集群
- 如何创建 Docker 映像
- 如何将 Docker 映像部署到 Kubernetes
- 如何在 Kubernetes 上扩缩应用
- 如何在 Kubernetes 上执行滚动更新
前提条件
- 拥有创建项目管理员权限的 Google 账号,或具有 Project-Owner 角色的项目
- 对 Docker 和 Kubernetes 有基本的了解(如果您没有基本的了解,请立即查看 Docker 和 Kubernetes)。
2. 环境设置
自定进度的环境设置
如果您还没有 Google 账号,则必须先创建一个。登录 Google Cloud 控制台并创建一个新项目。
请注意,项目 ID 是所有 Google Cloud 项目中的唯一名称(很抱歉,上述名称已被占用,您无法使用!)。稍后我们将使用 PROJECT_ID
来指代它。
接下来,您需要在 Cloud 控制台中启用结算功能,才能使用 Google Cloud 资源。Google Cloud 的新用户有资格获享$300 免费试用。如果您不是新用户,也无需担心,因为您学习此 Codelab 所需的费用应该不会超过几美元。不过,如果您使用更多资源或让它们保持运行状态,此 Codelab 可能会花费更多费用(请参阅最后的“清理”部分)。如需了解详情,请参阅价格。
Cloud Shell
虽然您可以使用笔记本电脑远程操作 Google Cloud 和 GKE,但您将在此 Codelab 中使用 Cloud Shell(一种在云端运行的命令行环境)。
基于 Debian 的这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证。这意味着在本 Codelab 中,您只需要一个浏览器(没错,它适用于 Chromebook)。
- 如需从 Cloud Console 激活 Cloud Shell,只需点击激活 Cloud Shell(预配和连接到环境仅需花费一些时间)。
在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设置为您的 PROJECT_ID
。
gcloud auth list
命令输出
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
命令输出
[core] project = <PROJECT_ID>
如果出于某种原因未设置项目,只需发出以下命令即可:
gcloud config set project <PROJECT_ID>
正在查找您的 PROJECT_ID
?检查您在设置步骤中使用的 ID,或在 Cloud Console 信息中心查找该 ID:
默认情况下,Cloud Shell 还会设置一些环境变量,这对您日后运行命令可能会很有用。
echo $GOOGLE_CLOUD_PROJECT
命令输出
<PROJECT_ID>
- 最后,设置默认可用区和项目配置。
gcloud config set compute/zone us-central1-f
您可以选择各种不同的可用区。如需了解详情,请参阅地区和可用区。
3. 创建 GKE 集群
现在,您已经有了工作的开发者环境,接下来需要一个 GKE 集群来部署您的网站!在创建集群之前,您需要确保已启用正确的 API。运行以下命令以启用容器 API:
gcloud services enable container.googleapis.com
现在,您可以创建集群了!按照以下步骤创建一个名为 fancy-cluster 且包含 3 个节点的集群:
gcloud container clusters create fancy-cluster --num-nodes 3
集群可能需要几分钟才能完成创建。之后,运行以下命令并查看集群的三个工作器虚拟机 (VM) 实例:
gcloud compute instances list
输出:
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS gke-fancy-cluster-default-pool-ad92506d-1ng3 us-east4-a n1-standard-1 10.150.0.7 XX.XX.XX.XX RUNNING gke-fancy-cluster-default-pool-ad92506d-4fvq us-east4-a n1-standard-1 10.150.0.5 XX.XX.XX.XX RUNNING gke-fancy-cluster-default-pool-ad92506d-4zs3 us-east4-a n1-standard-1 10.150.0.6 XX.XX.XX.XX RUNNING
您还可以在 Cloud 控制台中查看集群和相关信息。点击左上角的菜单按钮,向下滚动到 Kubernetes Engine,然后点击“集群”。您应该会看到名为 fancy-cluster 的集群。
恭喜!您已创建自己的第一个集群!
4. 克隆源代码库
由于这是一个现有网站,您只需从代码库克隆源代码,即可专注于创建 Docker 映像并部署到 GKE。
运行以下命令,将源代码库克隆到 Cloud Shell 实例,并将其更改为相应的目录。您还将安装 Node.js 依赖项,以便在部署应用之前对其进行测试。
cd ~ git clone https://github.com/googlecodelabs/monolith-to-microservices.git cd ~/monolith-to-microservices ./setup.sh
这会克隆代码库、更改目录并安装在本地运行应用所需的依赖项。该脚本可能需要几分钟时间才能运行完毕。
进行尽职调查并测试您的应用。运行以下命令以启动 Web 服务器:
cd ~/monolith-to-microservices/monolith npm start
输出:
Monolith listening on port 8080!
您可以点击 Cloud Shell 菜单中的网页预览图标,然后选择在端口 8080 上预览来预览应用。
这应该会打开一个新窗口,您可以在其中查看 Fancy 商店的实际展示情况!
您可以在查看网站后关闭该窗口。在终端窗口中按 Control+C
(Windows 或 Mac)停止 Web 服务器进程。
5. 使用 Cloud Build 创建 Docker 容器
现在,您的源文件已准备就绪,是时候对应用进行 Docker 化了!
通常,您必须采取两个步骤,包括构建 Docker 容器并将其推送到注册表以存储 GKE 从中提取的映像。但是,您可以使用 Cloud Build 创建 Docker 容器并将映像放入 Container Registry,只需一个命令,即可让工作更轻松!(如需查看手动创建并推送 Docker 文件的过程,请参阅 Container Registry 快速入门。)
Cloud Build 会压缩目录中的文件,并将其移至 Cloud Storage 存储分区。然后,构建流程从存储分区中获取文件,并使用 Dockerfile 运行 Docker 构建流程。由于您为 Docker 映像指定了 --tag
标志,并将主机指定为 gcr.io
,因此生成的 Docker 映像将被推送到 Container Registry。
首先,您需要运行以下命令来启用 Cloud Build API:
gcloud services enable cloudbuild.googleapis.com
启用 API 后,在 Cloud Shell 中运行以下命令以启动构建流程:
cd ~/monolith-to-microservices/monolith gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 .
此过程需要几分钟的时间,但完成后,您可以在终端中看到以下输出:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ID CREATE_TIME DURATION SOURCE IMAGES STATUS 1ae295d9-63cb-482c-959b-bc52e9644d53 2019-08-29T01:56:35+00:00 33S gs://<PROJECT_ID>_cloudbuild/source/1567043793.94-abfd382011724422bf49af1558b894aa.tgz gcr.io/<PROJECT_ID>/monolith:1.0.0 SUCCESS
如需查看构建记录或实时观察构建过程,您可以访问 Cloud 控制台。点击左上角的菜单按钮,向下滚动到“Ci/CD”,然后点击“Cloud Build”,最后点击“历史记录”。在这里,您可以看到您之前 build 的列表,但应该只显示您自己创建的 build。
如果您点击“Build id”,就可以查看该构建的所有详细信息,包括日志输出。
在“构建详情”页面上,您可以通过点击“构建信息”部分中的“映像名称”来查看创建的容器映像。
6. 将容器部署到 GKE
现在,您已对您的网站进行了容器化并将容器推送到了 Container Registry,接下来可以将其部署到 Kubernetes 了!
如需在 GKE 集群上部署和管理应用,您必须与 Kubernetes 集群管理系统进行通信。您通常使用 kubectl 命令行工具执行此操作。
Kubernetes 将应用表示为 Pod,这是表示一个容器(或一组紧密耦合的容器)的单元。Pod 是 Kubernetes 中最小的可部署单元。在这里,每个 Pod 仅包含您的单体式应用容器。
如需部署应用,您需要创建一个 Deployment。Deployment 会管理应用的多个副本(称为副本),并安排这些副本在集群中的各个节点上运行。在这种情况下,Deployment 将仅运行应用的一个 Pod。Deployment 通过创建 ReplicaSet 来确保这一点。ReplicaSet 负责确保指定数量的副本始终保持运行状态。
kubectl create deployment
命令会使 Kubernetes 在具有 1 个副本的集群上创建一个名为 monolith 的 Deployment。
运行以下命令以部署应用:
kubectl create deployment monolith --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0
验证部署
如需验证 Deployment 是否已成功创建,请运行以下命令(Pod 状态可能需要一些时间才会变为“正在运行”):
kubectl get all
输出:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-htm7z 1/1 Running 0 6m21s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 24h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 1 1 1 1 20m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 1 1 1 20m
该输出会显示以下内容。您可以看到当前 Deployment您的 ReplicaSet,所需 Pod 数量为 1以及正在运行的 Pod看起来您已经成功创建了所有内容!
如需逐个查看您的资源,您可以运行以下命令:
# Show pods kubectl get pods # Show deployments kubectl get deployments # Show replica sets kubectl get rs #You can also combine them kubectl get pods,deployments
若要了解 Kubernetes 的全部优势,您可以模拟服务器崩溃,删除 Pod,然后看看会发生什么!
复制上一个命令中的 Pod 名称,然后运行以下命令将其删除:
kubectl delete pod/<POD_NAME>
如果速度足够快,您可以运行上一个命令以再次查看所有 Pod,您应该会看到两个 Pod,一个正在终止,另一个正在创建或运行:
kubectl get all
输出:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-2bxts 1/1 Running 0 4s pod/monolith-7d8bc7bf68-htm7z 1/1 Terminating 0 9m35s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 24h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 1 1 1 1 24m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 1 1 1 24m
为什么会发生这种情况?ReplicaSet 发现 Pod 正在终止并触发新 Pod 以保持所需的副本数。稍后,您将了解如何进行扩缩,以确保运行多个实例,从而在某个实例出现故障时,用户不会看到任何停机问题!
7. 公开 GKE 部署
您已将应用部署到 GKE,但无法在集群外部访问该应用。默认情况下,您无法从互联网访问您在 GKE 上运行的容器,因为这些容器没有外部 IP 地址。您必须通过 Service 资源明确向来自互联网的流量公开应用。Service 为应用的 Pod 提供网络和 IP 支持。GKE 会为您的应用创建外部 IP 和负载平衡器(需要付费)。
运行以下命令,在互联网上公开您的网站:
kubectl expose deployment monolith --type=LoadBalancer --port 80 --target-port 8080
输出:
service/monolith exposed
访问服务
GKE 会将外部 IP 地址分配给 Service 资源,而不是 Deployment。如果要查找 GKE 为应用预配的外部 IP,可以使用 kubectl get service 命令检查 Service:
kubectl get service
输出:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE monolith 10.3.251.122 203.0.113.0 80:30877/TCP 3d
确定应用的外部 IP 地址后,请复制该地址。将浏览器指向该网址(例如 http://203.0.113.0),以检查您的应用是否可访问。
您应该会看到之前测试的同一网站!恭喜!您的网站完全在 Kubernetes 上运行!
8. 扩缩 GKE 部署
现在,您已经在 GKE 中有一个正在运行的应用实例,并已将其公开给互联网,您的网站已经变得非常受欢迎!您需要一种方法来将应用扩展到多个实例,以便处理流量。了解如何将应用扩展到最多三个副本。
运行以下命令,将部署扩展到三个副本:
kubectl scale deployment monolith --replicas=3
输出:
deployment.apps/monolith scaled
验证规模化部署
如需验证 Deployment 是否已成功扩缩,请运行以下命令:
kubectl get all
输出:
NAME READY STATUS RESTARTS AGE pod/monolith-7d8bc7bf68-2bxts 1/1 Running 0 36m pod/monolith-7d8bc7bf68-7ds7q 1/1 Running 0 45s pod/monolith-7d8bc7bf68-c5kxk 1/1 Running 0 45s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 25h service/monolith LoadBalancer 10.27.253.64 XX.XX.XX.XX 80:32050/TCP 6m7s NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/monolith 3 3 3 3 61m NAME DESIRED CURRENT READY AGE replicaset.apps/monolith-7d8bc7bf68 3 3 3 61m
您应该会看到三个 Pod 实例正在运行。另请注意,Deployment 和 ReplicaSet 所需的计数值现在为 3。
9. 更改网站
您的营销团队要求您更改网站首页。他们认为,应该向员工说明您的公司和您实际销售的产品,这样才能提供更多信息。在本部分中,您将在首页添加一些文字,让营销团队满意!我们的某位开发者似乎已经使用文件名“index.js.new
”创建了更改。您可以将该文件复制到 index.js
,这样您所做的更改就会生效。按照以下说明进行适当更改。
运行以下命令,将更新后的文件复制到正确的文件名,然后输出其内容以验证更改:
cd ~/monolith-to-microservices/react-app/src/pages/Home mv index.js.new index.js cat ~/monolith-to-microservices/react-app/src/pages/Home/index.js
最终代码应如下所示:
/* Copyright 2019 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import React from "react"; import { makeStyles } from "@material-ui/core/styles"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; const useStyles = makeStyles(theme => ({ root: { flexGrow: 1 }, paper: { width: "800px", margin: "0 auto", padding: theme.spacing(3, 2) } })); export default function Home() { const classes = useStyles(); return ( <div className={classes.root}> <Paper className={classes.paper}> <Typography variant="h5"> Fancy Fashion & Style Online </Typography> <br /> <Typography variant="body1"> Tired of mainstream fashion ideas, popular trends and societal norms? This line of lifestyle products will help you catch up with the Fancy trend and express your personal style. Start shopping Fancy items now! </Typography> </Paper> </div> ); }
您更新了 React 组件,但需要构建 React 应用以生成静态文件。运行以下命令,构建 React 应用并将其复制到单体式应用公共目录:
cd ~/monolith-to-microservices/react-app npm run build:monolith
现在您的代码已更新,接下来您需要重新构建 Docker 容器并将其发布到 Container Registry。您可以使用与之前相同的命令,但这次您将更新版本标签!
运行以下命令,使用更新后的映像版本 2.0.0 触发新的 Cloud Build:
cd ~/monolith-to-microservices/monolith #Feel free to test your application npm start gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 .
在终端窗口中按 Control+C
(Windows 或 Mac)停止 Web 服务器进程。
在下一部分中,您将使用该映像在不停机的情况下更新应用。
10. 零停机更新网站
更改已完成,营销团队对您的更新感到满意!是时候在不中断用户的情况下更新网站了。请按照以下说明更新您的网站。
GKE 的滚动更新可确保您的应用保持正常运行且可用,即使系统将所有运行副本中的旧容器映像实例替换为新容器映像也是如此。
通过命令行,您可以告诉 Kubernetes,您想将 Deployment 的映像更新为新版本:
kubectl set image deployment/monolith monolith=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0
输出:
deployment.apps/monolith image updated
验证部署
您可以通过运行以下命令来验证 Deployment 更新:
kubectl get pods
输出:
NAME READY STATUS RESTARTS AGE monolith-584fbc994b-4hj68 1/1 Terminating 0 60m monolith-584fbc994b-fpwdw 1/1 Running 0 60m monolith-584fbc994b-xsk8s 1/1 Terminating 0 60m monolith-75f4cf58d5-24cq8 1/1 Running 0 3s monolith-75f4cf58d5-rfj8r 1/1 Running 0 5s monolith-75f4cf58d5-xm44v 0/1 ContainerCreating 0 1s
您会看到系统创建三个新 Pod,旧 Pod 正在关停。您可以按年龄分辨哪些是新的,哪些是旧的。最终,您只会再次看到三个 Pod,也就是三个更新后的 Pod。
如需验证您的更改,请再次导航到负载平衡器的外部 IP,您会发现您的应用已经更新。
运行以下命令列出服务,如果您忘记了 IP 地址,请查看:
kubectl get svc
您的网站应显示您添加到首页组件的文字!
11. 清理
删除 Git 代码库
cd ~ rm -rf monolith-to-microservices
删除 Container Registry 映像
注意:如果您创建了其他版本,也可以使用相同的语法来删除这些映像。此 Codelab 假定您只有两个标记。
# Delete the container image for version 1.0.0 of our monolith gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --quiet # Delete the container image for version 2.0.0 of our monolith gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 --quiet
从 Cloud Storage 中删除 Cloud Build 制品
注意:如果您将 Cloud Build 用于此 Codelab 以外的工件,则必须手动从 Cloud Storage 存储分区 gs://<PROJECT_ID>_cloudbuild/source
中删除您的源代码。
# The following command will take all source archives from all builds and delete them from cloud storage # Run this command to print all sources: # gcloud builds list | awk 'NR > 1 {print $4}' gcloud builds list | awk 'NR > 1 {print $4}' | while read line; do gsutil rm $line; done
删除 GKE 服务
kubectl delete service monolith kubectl delete deployment monolith
删除 GKE 集群
gcloud container clusters delete fancy-cluster
注意:此命令可能需要一些时间。
12. 恭喜!
您在 GKE 上部署、扩缩并更新了您的网站。现在,您已拥有使用 Docker 和 Kubernetes 的经验!