Cloud Service Mesh 是一个功能强大的工具,用于管理和监控分布式应用。如需充分利用 Cloud Service Mesh,最好了解其底层抽象,包括容器和 Kubernetes。本教程介绍如何准备适用于 Cloud Service Mesh 的应用,从源代码到在 GKE 上运行的容器,直到安装 Cloud Service Mesh 之前的内容。
如果您已熟悉 Kubernetes 和服务网格概念,则可以跳过本教程,直接转到 Cloud Service Mesh 安装指南。
目标
- 探索简单多服务“hello world”应用。
- 从来源运行应用
- 将应用容器化。
- 创建一个 Kubernetes 集群。
- 将容器部署到集群。
准备工作
请按照以下步骤启用 Cloud Service Mesh API:- 访问 Google Cloud 控制台中的 Kubernetes Engine 页面。
- 创建或选择项目。
- 稍作等待,让 API 和相关服务完成启用过程。 此过程可能耗时几分钟。
本教程使用 Cloud Shell,其中预配了运行基于 Debian 的 Linux 操作系统的 g1-small Compute Engine 虚拟机 (VM)。
准备 Cloud Shell
使用 Cloud Shell 的优势如下:
- Python 2 和 Python 3 开发环境(包括
virtualenv
)均已设置。 - 本教程中使用的
gcloud
、docker
、git
和kubectl
命令行工具已安装。 您可以选择文本编辑器:
代码编辑器,可通过点击 Cloud Shell 窗口顶部的 来访问。
Emac、Vim 或 Nano,可从 Cloud Shell 中的命令行访问。
In the Google Cloud console, activate Cloud Shell.
At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.
下载示例代码
下载
helloserver
源代码:git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
切换到示例代码目录:
cd anthos-service-mesh-samples/docs/helloserver
探索多服务应用
示例应用是使用 Python 编写的,它有两个使用 REST 进行通信的组件:
server
:一个简单的服务器,具有一个GET
端点/
,可将“hello world”输出到控制台。loadgen
:一种将流量发送到server
的脚本,可配置每秒请求数 (RPS)。
从来源运行应用
如需熟悉示例应用,请在 Cloud Shell 中运行它。
从
sample-apps/helloserver
目录运行server
:python3 server/server.py
启动时,
server
会显示以下内容:INFO:root:Starting server...
打开另一个终端窗口,以便向
server
发送请求。点击 以打开另一个会话。向
server
发送请求:curl http://localhost:8080
server
的响应如下:Hello World!
从下载示例代码的目录中,切换到包含
loadgen
的目录:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
创建以下环境变量:
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5
启动
virtualenv
:virtualenv --python python3 env
激活此虚拟环境:
source env/bin/activate
安装
loadgen
的要求:pip3 install -r requirements.txt
运行
loadgen
:python3 loadgen.py
在启动时,
loadgen
会输出如下消息:Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080
在其他终端窗口中,
server
将如下消息写入控制台:127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 - INFO:root:GET request, Path: / Headers: Host: localhost:8080 User-Agent: python-requests/2.22.0 Accept-Encoding: gzip, deflate Accept: */*
从网络的角度来看,整个应用目前在同一主机上运行。因此,您可以使用
localhost
向server
发送请求。要停止
loadgen
和server
,请在每个终端窗口中输入Ctrl-c
。在
loadgen
终端窗口中,停用虚拟环境:deactivate
将应用容器化
要在 GKE 上运行应用,您需要将示例应用(server
和 loadgen
)打包到容器中。容器可用于打包应用,使其与底层环境隔离。
要将应用容器化,您需要一个 Dockerfile
。Dockerfile
是一个文本文件,用于定义将应用源代码及其依赖项汇编到 Docker 映像 中所需的命令。构建映像后,您可以将其上传到容器注册表,例如 Docker Hub 或 Container Registry。
该示例随附一个 Dockerfile
用于 server
和 loadgen
,后者具有构建映像所需的所有命令。以下是 server
的 Dockerfile
:
FROM python:3-slim as base
命令告知 Docker 将最新的 Python 3 映像用作基础映像。COPY . .
命令会将当前工作目录中的源文件(在本例中为server.py
)复制到容器的文件系统。ENTRYPOINT
定义用于运行容器的命令。在本例中,该命令与您用于通过源代码运行server.py
的命令几乎相同。EXPOSE
命令指定server
侦听端口8080
。此命令不会公开任何端口,但可用作您在运行容器时打开端口8080
所需的文档。
准备将应用容器化
设置以下环境变量。将
PROJECT_ID
替换为您的 Google Cloud 项目的 ID。export PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
您可以在构建 Docker 映像时使用
PROJECT_ID
和GCR_REPO
值标记该 Docker 映像,然后将其推送到您的私有 Container Registry。为 Google Cloud CLI 设置默认 Google Cloud 项目。
gcloud config set project $PROJECT_ID
设置 Google Cloud CLI 的默认可用区。
gcloud config set compute/zone us-central1-b
确保在 Google Cloud 项目中启用 Container Registry 服务。
gcloud services enable containerregistry.googleapis.com
将 server
容器化
切换到示例
server
所在的目录:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
使用之前定义的
Dockerfile
和环境变量构建映像:docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .
-t
标志表示 Docker 标记。这是您在部署容器时使用的映像的名称。将映像推送到 Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
将 loadgen
容器化
切换到示例
loadgen
所在的目录:cd ../loadgen
构建映像:
docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .
将映像推送到 Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1
列出映像
获取代码库中的映像列表,以确认是否已推送映像:
gcloud container images list --repository gcr.io/$PROJECT_ID/asm-ready
该命令将返回您刚刚推送的映像名称:
NAME gcr.io/PROJECT_ID/asm-ready/helloserver gcr.io/PROJECT_ID/asm-ready/loadgen
创建 GKE 集群
您可以使用 docker run
命令在 Cloud Shell 虚拟机上运行这些容器。但在生产环境中,您需要以更统一的方式编排容器。例如,您需要一个可确保容器始终在运行的系统,并且需要一种方法来纵向扩容和启动容器的其他实例,以便处理流量增加。
您可以使用 GKE 运行容器化应用。GKE 是一个容器编排平台,其工作方式是将虚拟机连接到集群。每个虚拟机称为一个节点。GKE 集群由 Kubernetes 开源集群管理系统提供支持。Kubernetes 提供与集群进行交互的机制。
如需创建 GKE 集群,请执行以下操作:
创建集群:
gcloud container clusters create asm-ready \ --cluster-version latest \ --machine-type=n1-standard-4 \ --num-nodes 4
gcloud
命令会在您之前设置的 Google Cloud 项目和可用区中创建一个集群。如需运行 Cloud Service Mesh, 我们建议至少配置 4 个节点 n1-standard-4 机器类型创建集群的命令需要几分钟才能完成。集群准备就绪后,该命令会输出如下消息:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asm-ready us-central1-b 1.13.5-gke.10 203.0.113.1 n1-standard-2 1.13.5-gke.10 4 RUNNING
向
kubectl
命令行工具提供凭据,以便使用它来管理集群:gcloud container clusters get-credentials asm-ready
现在,您可以使用
kubectl
与 Kubernetes 进行通信。例如,您可以运行以下命令来获取节点的状态:kubectl get nodes
该命令会返回节点列表,具体如下:
NAME STATUS ROLES AGE VERSION gke-asm-ready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13
了解关键 Kubernetes 概念
下图显示在 GKE 上运行的应用:
在将容器部署到 GKE 之前,您可能需要查看一些关键 Kubernetes 概念。本教程末尾提供了相关链接,以便您详细了解每个概念。
节点和集群:在 GKE 中,节点是虚拟机。在其他 Kubernetes 平台上,节点可以是物理机或虚拟机。集群是一组可以被视为单个机器的节点,您可以在其中部署容器化应用。
Pod:在 Kubernetes 中,容器在 Pod 中运行。Pod 是 Kubernetes 中的原子单元。Pod 包含一个或多个容器。您将在各自的 Pod 中部署
server
和loadgen
容器。当 Pod 运行多个容器(例如,应用服务器和代理服务器)时,这些容器将作为一个实体进行管理并共享 Pod 资源。Deployment:Deployment 是表示一组相同 Pod 的 Kubernetes 对象。Deployment 会运行分布在集群节点中的 Pod 的多个副本。Deployment 会自动替换失败或无响应的任何 Pod。
Kubernetes 服务:在 GKE 中运行应用代码会更改
loadgen
和server
之间的网络。在 Cloud Shell 虚拟机中运行服务时,您可以使用地址localhost:8080
向server
发送请求。部署到 GKE 后,将 Pod 计划在可用节点上运行。默认情况下,您无法控制 Pod 在哪个节点上运行,因此 Pod 没有稳定的 IP 地址。要获取
server
的 IP 地址,您必须在 Pod 上定义网络抽象(称为 Kubernetes Service)。Kubernetes Service 为一组 Pod 提供稳定的网络端点。有几种类型的 Service。server
使用LoadBalancer
,后者会公开一个外部 IP 地址,以便您可以从集群外部访问server
。Kubernetes 还具有内置 DNS 系统,用于将 DNS 名称(例如
helloserver.default.cluster.local
)分配给 Service。这允许集群内的 Pod 访问具有稳定地址的集群中的其他 Pod。您无法在集群外部(例如通过 Cloud Shell)使用此 DNS 名称。
Kubernetes 清单
从源代码运行应用时,您使用了命令式命令:python3 server.py
命令式意味着以动词为导向:“这样做”。
相比之下,Kubernetes 基于声明式模型运行。这意味着,您无需确切地告知 Kubernetes 做什么,而只需为 Kubernetes 提供所需状态。例如,Kubernetes 会根据需要启动和终止 Pod,以使实际系统状态与所需状态匹配。
您可以在一组清单或 YAML 文件中指定所需状态。YAML 文件包含一个或多个 Kubernetes 对象的规范。
该示例包含 server
和 loadgen
的 YAML 文件。每个 YAML 文件都指定 Kubernetes Deployment 对象和 Service 的所需状态。
服务器
kind
表示对象的类型。metadata.name
指定 Deployment 的名称。- 第一个
spec
字段包含所需状态的说明。 spec.replicas
指定所需 Pod 的数量。spec.template
部分定义 Pod 模板。Pod 的规范中包含image
字段,该字段是从 Container Registry 中拉取的映像的名称。
Service 的定义如下:
LoadBalancer
:客户端向网络负载平衡器的 IP 地址发送请求,网络负载平衡器具有稳定的 IP 地址,并且可从集群外部访问。targetPort
:回想一下,Dockerfile
中的EXPOSE 8080
命令不会实际公开任何端口。您可以公开端口8080
,以便访问集群外部的server
容器。在这种情况下,hellosvc.default.cluster.local:80
(简称:hellosvc
)映射到helloserver
Pod IP 的端口8080
。port
:这是在发送请求时集群中的其他服务使用的端口号。
负载生成器
loadgen.yaml
中的 Deployment 对象类似于 server.yaml
。一个显著区别是 Deployment 对象包含一个名为 env
的部分。此部分定义 loadgen
所需的环境变量,此变量是您在从来源运行应用时设置的。
由于 loadgen
不接受传入请求,因此将 type
字段设置为 ClusterIP
。此类型提供集群中的服务可以使用的稳定 IP 地址,但不会向外部客户端公开 IP 地址。
将容器部署到 GKE
切换到示例
server
所在的目录:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
通过文本编辑器打开
server.yaml
。将
image
字段中的名称替换为您的 Docker 映像的名称。image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。保存并关闭
server.yaml
。将 YAML 文件部署到 Kubernetes:
kubectl apply -f server.yaml
成功后,该命令会返回以下内容:
deployment.apps/helloserver created service/hellosvc created
切换到
loadgen
所在的目录。cd ../loadgen
通过文本编辑器打开
loadgen.yaml
。将
image
字段中的名称替换为您的 Docker 映像的名称。image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。保存并关闭
loadgen.yaml
,然后关闭文本编辑器。将 YAML 文件部署到 Kubernetes:
kubectl apply -f loadgen.yaml
成功后,该命令会返回以下内容:
deployment.apps/loadgenerator created service/loadgensvc created
检查 Pod 的状态:
kubectl get pods
该命令将返回如下状态:
NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s
从
loadgen
Pod 获取应用日志。将POD_ID
替换为之前输出中的标识符。kubectl logs loadgenerator-POD_ID
获取
hellosvc
的外部 IP 地址:kubectl get service
此命令的响应类似于下列内容:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hellosvc LoadBalancer 10.81.15.158 192.0.2.1 80:31127/TCP 33m kubernetes ClusterIP 10.81.0.1 <none> 443/TCP 93m loadgensvc ClusterIP 10.81.15.155 <none> 80/TCP 4m52s
向
hellosvc
发送请求。将EXTERNAL_IP
替换为hellosvc
的外部 IP 地址。curl http://EXTERNAL_IP
已准备好迎接 Cloud Service Mesh
现在,您已将应用部署到 GKE。loadgen
可以使用 Kubernetes DNS (hellosvc:80
) 向 server
发送请求,而您可以使用外部 IP 地址向 server
发送请求。虽然 Kubernetes 向您提供许多功能,但缺少服务的一些相关信息:
- 服务如何交互?服务之间是什么关系?流量如何在服务之间流动?您知道
loadgen
向server
发送请求,但假设您不熟悉应用。您不能通过查看 GKE 上正在运行的 Pod 的列表来回答这些问题。 - 指标:
server
响应传入请求需要多长时间?每秒有多少请求 (RPS) 进入server
?是否有任何错误响应? - 安全信息:是
loadgen
与server
普通HTTP
或 mTLS 之间的流量吗?
Cloud Service Mesh 可以解决这些问题。Cloud Service Mesh 是 Google Cloud 管理的开源 Istio 项目版本。Cloud Service Mesh 的工作方式是在每个 Pod 中放置一个 Envoy 边车代理。Envoy 代理会拦截应用容器的所有入站和出站流量。这意味着 server
和 loadgen
均会获取 Envoy Sidecar 代理,并且从 loadgen
到 server
的所有流量均由 Envoy 代理进行调解。这些 Envoy 代理之间的连接构成服务网格。此服务网格架构在 Kubernetes 上提供一个控制层。
由于 Envoy 代理在其自己的容器中运行,因此您可以在 GKE 集群上安装 Cloud Service Mesh,而无需对应用代码进行任何实质更改。不过,您可采用几个关键方法准备好使用 Cloud Service Mesh 进行应用插桩:
- 所有容器的服务:
server
和loadgen
Deployment 都附加 Kubernetes 服务。即使未收到任何入站请求的loadgen
也有服务。 - 服务中的端口必须命名:尽管 GKE 允许您
定义未命名的服务端口时,Cloud Service Mesh 需要您提供一个
端口名称
该端口的协议与端口的协议相匹配。在 YAML 文件中,
server
的端口命名为http
,因为server
使用HTTP
通信协议。如果service
使用的是gRPC
,则应将端口命名为grpc
。 - 部署加标签:这有助于您使用 Cloud Service Mesh 流量管理功能,例如在同一服务的不同版本之间拆分流量。
安装 Cloud Service Mesh
访问 Cloud Service Mesh 安装指南,并按照说明操作在您的集群上安装 Cloud Service Mesh。
清理
为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。
要清理,请删除 GKE 集群。删除集群会删除构成容器集群的所有资源,例如计算实例、磁盘和网络资源。
gcloud container clusters delete asm-ready
后续步骤
详细了解本教程中使用的技术:
详细了解这些工具:
详细了解 Kubernetes 概念: