使用 Istio 将 ASP.NET Core 应用部署到 Google Kubernetes Engine(第 1 部分)

1. 概览

ASP.NET Core 是一个开源的跨平台框架,可让您使用 C# 编程语言构建基于云和联网的现代应用。

Kubernetes 是一个开源系统,用于自动部署、扩缩和管理容器化应用。Istio 是一个用于连接、保护、管理和监控服务的开放式框架。

在本实验的第一部分中,您需要将一个简单的 ASP.NET Core 应用部署到在 Google Kubernetes Engine (GKE) 上运行的 Kubernetes,并将其配置为由 Istio 管理。

在本实验的第二部分,您将进一步探索 Istio 的功能,例如指标、跟踪、动态流量管理、故障注入等。

学习内容

  • 如何创建 ASP.NET Core 应用并将其打包到 Docker 容器中。
  • 如何使用 Google Kubernetes Engine (GKE) 创建 Kubernetes 集群。
  • 如何在 GKE 上的 Kubernetes 集群上安装 Istio。
  • 如何部署 ASP.NET Core 应用并将其流量配置为由 Istio 管理。

所需条件

您打算如何使用本教程?

仅阅读教程内容 阅读并完成练习

如何评价您的 Google Cloud Platform 使用体验?

<ph type="x-smartling-placeholder"></ph> 新手 中级 熟练

2. 设置和要求

自定进度的环境设置

  1. 登录 Cloud 控制台,然后创建一个新项目或重复使用现有项目。 如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

96a9c957bc475304

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

请记住项目 ID,它在所有 Google Cloud 项目中都是唯一的名称(上述名称已被占用,您无法使用,抱歉!)。它稍后将在此 Codelab 中被称为 PROJECT_ID

  1. 接下来,您需要在 Cloud 控制台中启用结算功能,才能使用 Google Cloud 资源。

运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。请务必按照“清理”部分部分,其中会指导您如何关停资源,以免产生超出本教程范围的结算费用。Google Cloud 的新用户符合参与 300 美元的免费试用计划的条件。

启动 Cloud Shell

虽然 Google Cloud 可以通过笔记本电脑远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在 Google Cloud 中运行的命令行环境。

激活 Cloud Shell

  1. 在 Cloud Console 中,点击激活 Cloud Shell4292cbf4971c9786

bce75f34b2c53987.png

如果您以前从未启动过 Cloud Shell,系统会显示一个中间屏幕(非首屏)来介绍 Cloud Shell。如果是这种情况,请点击继续(此后您将不会再看到此通知)。一次性屏幕如下所示:

70f315d7b402b476

预配和连接到 Cloud Shell 只需花几分钟时间。

fbe3a0674c982259.png

这个虚拟机装有您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证。只需使用一个浏览器或 Google Chromebook 即可完成本 Codelab 中的大部分(甚至全部)工作。

在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设置为您的项目 ID:

  1. 在 Cloud Shell 中运行以下命令以确认您已通过身份验证:
gcloud auth list

命令输出

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目:
gcloud config list project

命令输出

[core]
project = <PROJECT_ID>

如果不是上述结果,您可以使用以下命令进行设置:

gcloud config set project <PROJECT_ID>

命令输出

Updated property [core/project].

3. 在 Cloud Shell 中创建 ASP.NET Core 应用

在 Cloud Shell 提示符中,您可以通过检查 dotnet 命令行工具的版本来验证其是否已安装。此命令应输出已安装的 dotnet 命令行工具的版本:

dotnet --version

接下来,创建一个新的 ASP.NET Core Web 框架应用。

dotnet new mvc -o HelloWorldAspNetCore

系统会创建一个项目并恢复其依赖项。您应该会看到如下所示的消息:

Restore completed in 11.44 sec for HelloWorldAspNetCore.csproj.

Restore succeeded.

4. 运行 ASP.NET Core 应用

我们很快就可以运行应用了。前往应用文件夹。

cd HelloWorldAspNetCore

最后,运行应用。

dotnet run --urls=http://localhost:8080

该应用随即便开始监听端口 8080。

Hosting environment: Production
Content root path: /home/atameldev/HelloWorldAspNetCore
Now listening on: http://[::]:8080
Application started. Press Ctrl+C to shut down.

如需验证该应用是否正在运行,请点击右上角的网页预览按钮,然后选择“在端口 8080 上预览”。

Capture.PNG

您会看到默认的 ASP.NET Core 网页:

f579a9baedc108a9.png

确认应用正在运行后,按 Ctrl+C 关闭应用。

5. 将 ASP.NET Core 应用打包到 Docker 容器中

接下来,准备好您的应用,使其以容器的形式运行。第一步是定义容器及其内容。

在应用的基本目录中,创建一个 Dockerfile 来定义 Docker 映像。

touch Dockerfile

使用您喜爱的编辑器(vim, nano,emacs 或 Cloud Shell 的代码编辑器)将以下代码添加到 Dockerfile

# Use Microsoft's official build .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-sdk/
FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine 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 . ./
WORKDIR /app

# Build a release artifact.
RUN dotnet publish -c Release -o out

# Use Microsoft's official runtime .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-aspnet/
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# Make sure the app binds to port 8080
ENV ASPNETCORE_URLS http://*:8080

# Run the web service on container startup.
ENTRYPOINT ["dotnet", "HelloWorldAspNetCore.dll"]

Dockerfile 中包含的一项重要配置是应用监听传入流量 (8080) 的端口。这是通过设置 ASPNETCORE_URLS 环境变量实现的,ASP.NET Core 应用使用该变量确定要监听的端口。

保存此Dockerfile。现在,我们来构建映像:

docker build -t gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-dotnet:v1 .

此操作完成后(下载和提取所有内容需要一些时间),您可以看到映像已构建并保存到本地:

docker images

REPOSITORY                             TAG   
gcr.io/yourproject-XXXX/hello-dotnet   v1            

使用以下命令在本地测试映像,该命令将在端口 8080 上从新创建的容器映像在本地运行 Docker 容器:

docker run -p 8080:8080 gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-dotnet:v1

再次充分利用 CloudShell 的网页预览功能:

2015 年 11 月 3 日 17:20:22 的屏幕截图.png

您应该会在新标签页中看到默认的 ASP.NET Core 网页。

f579a9baedc108a9.png

确认应用可在 Docker 容器本地正常运行后,您可以通过 Ctrl-> C 停止正在运行的容器。

现在映像按预期运行,接下来您可以将它推送到 Google Container Registry,这是一个私有代码库,用于存储 Docker 映像,该代码库可从每个 Google Cloud 项目(以及从 Google Cloud Platform 外部访问)进行访问:

docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-dotnet:v1

如果一切进展顺利,一段时间后,您应该能够看到 Container Registry 部分中列出的容器映像。此时,您已经有一个项目范围的 Docker 映像可用,Kubernetes 可以访问和编排该映像,几分钟后您就会看到。

73558f3a54ce1c0c.png

如果您想浏览存储在 Google Cloud Storage 中的容器映像,可以点击以下链接:https://console.cloud.google.com/storage/browser/(得到的完整链接应采用以下格式:https://console.cloud.google.com/project/PROJECT_ID/storage/browser/)。

6. 使用 Istio 创建 Kubernetes/GKE 集群

首先,确保已启用 Kubernetes Engine API:

gcloud services enable container.googleapis.com

创建 Kubernetes 集群。如果愿意,您可以将区域更改为附近的某个区域:

gcloud container clusters create hello-istio \
  --cluster-version=latest \
  --machine-type=n1-standard-2 \
  --num-nodes=4 \
  --region europe-west1

请稍等片刻,我们正在为您设置集群。它将显示在 Google Cloud Platform 控制台的 Kubernetes Engine 部分中。

e46fd9c6ee82bcc4.png

对于此 Codelab,我们将从 istio.io 下载并安装 Istio。还有其他安装选项,包括适用于 GKE 的 Istio 插件Anthos Service Mesh。此步骤之后的应用步骤适用于所有 Istio 安装。

我们先下载 Istio 客户端和示例。Istio 发布页面提供了适用于多个操作系统的下载工件。在本例中,我们可以使用便捷的命令下载并提取适用于当前平台的最新版本:

curl -L https://istio.io/downloadIstio | sh -

该脚本将告诉您已下载的 Istio 版本:

Istio has been successfully downloaded into the istio-1.8.1 folder on your system.

安装目录包含示例应用和 istioctl 客户端二进制文件。切换到该目录:

cd istio-1.8.1

复制并粘贴提供的命令,将 bin 目录添加到 PATH,以便您可以使用 istioctl

export PATH="$PATH:/home/<YOURHOMEID>/istio-1.8.1/bin"

检查您的集群是否已准备好使用 Istio,以验证 istioctl 是否可用:

istioctl x precheck

您应该会看到如下消息:Install Pre-Check passed! The cluster is ready for Istio installation.

使用演示配置文件安装 Istio:

istioctl install --set profile=demo

Istio 现已安装在您的集群中。

自动 Sidecar 注入

要开始使用 Istio,您无需对应用进行任何更改。当您配置和运行服务时,Envoy Sidecar 会自动注入该服务的每个 Pod。

为此,您需要为用于微服务的命名空间(“默认”)启用 Sidecar 注入。您可以通过应用标签来实现此目的:

kubectl label namespace default istio-injection=enabled

如需验证标签是否已成功应用,请运行以下命令:

kubectl get namespace -L istio-injection

输出结果会确认已为默认命名空间启用 Sidecar 注入:

NAME              STATUS   AGE    ISTIO-INJECTION
default           Active   3m     enabled
istio-system      Active   63s    disabled
...

7. 验证安装

Istio 提供三项服务:istiod 控制平面,以及入站流量和出站流量网关(您可以将它们视为“互联网其余部分的 Sidecar 代理”),这些服务分别命名为 istio-ingressgatewayistio-egressgateway

kubectl get svc -n istio-system

输出的内容应如下所示:

NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     AGE
istio-egressgateway    ClusterIP      10.55.252.182   <none>
istio-ingressgateway   LoadBalancer   10.55.250.185   35.233.118.42
istiod                 ClusterIP      10.55.253.217   <none>

入站网关的类型为 LoadBalancer,因此可通过互联网访问;其他的则只需从集群内访问即可。

接下来,确保已部署相应的 Kubernetes Pod,并且所有容器都已启动并运行:

kubectl get pods -n istio-system

当所有 Pod 都处于运行时,您可以继续操作。

NAME                                    READY   STATUS
istio-egressgateway-674988f895-m6tk4    1/1     Running
istio-ingressgateway-6996f7dcc8-7lvm2   1/1     Running
istiod-6bf5fc8b64-j79hj                 1/1     Running
  • istiod:Istio 控制平面。处理代理 Sidecar 的配置和编程、服务发现、证书分发和 Sidecar 注入
  • ingress gateway:处理从集群外部传入的请求。
  • egress gateway::处理发送到集群外部端点的传出请求。

8. 部署应用

现在您已确认 Istio 已安装并且正在运行,接下来您可以部署 ASP.NET Core 应用了。

部署和服务

首先,使用您喜爱的编辑器(vim, nano,emacs 或 Cloud Shell 的代码编辑器)创建一个 aspnetcore.yaml 文件,然后为应用定义 Kubernetes Deployment 和 Service:

apiVersion: v1
kind: Service
metadata:
  name: aspnetcore-service
  labels:
    app: aspnetcore
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: aspnetcore
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aspnetcore-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aspnetcore
      version: v1
  template:
    metadata:
      labels:
        app: aspnetcore
        version: v1
    spec:
      containers:
      - name: aspnetcore
        image: gcr.io/YOUR-PROJECT-ID/hello-dotnet:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

该文件的内容是用于部署应用的标准 Deployment 和服务,不包含任何 Istio 特有的内容。

使用 kubectl 将服务部署到默认命名空间:

kubectl apply -f aspnetcore.yaml
service "aspnetcore-service" created
deployment.extensions "aspnetcore-v1" created

验证 Pod 是否正在运行:

kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
aspnetcore-v1-6cf64748-mddb   2/2       Running   0          34s

Gateway 和 VirtualService

如需允许入站流量到达网格,您需要创建网关VirtualService

网关为 HTTP/TCP 流量配置负载平衡器,通常在网格边缘运行,以便为应用启用入站流量。VirtualService 定义的规则用于控制服务请求在 Istio 服务网格中路由的方式。

创建 aspnetcore-gateway.yaml 文件来定义网关:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: aspnetcore-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

创建一个 aspnetcore-virtualservice.yaml 文件来定义 VirtualService:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aspnetcore-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - aspnetcore-gateway
  http:
  - route:
    - destination:
        host: aspnetcore-service

运行 kubectl 命令,使用以下命令部署网关:

kubectl apply -f aspnetcore-gateway.yaml

该命令会生成以下输出:

gateway.networking.istio.io "aspnetcore-gateway" created

接下来,运行以下命令来部署 VirtualService:

kubectl apply -f aspnetcore-virtualservice.yaml

该命令会生成以下输出:

virtualservice.networking.istio.io "aspnetcore-virtualservice" created

验证一切是否正在运行:

kubectl get gateway
NAME                      AGE
aspnetcore-gateway   28s
kubectl get virtualservice
NAME                             AGE
aspnetcore-virtualservice   33s

恭喜!您刚刚部署了一个已启用 Istio 的应用。接下来,您会看到使用中的应用。

9. 测试应用

您最终可以看到该应用的实际运行情况。您需要获取网关的外部 IP 和端口。它列在 EXTERNAL-IP 下:

kubectl get svc istio-ingressgateway -n istio-system

将外部 IP 和端口导出到 GATEWAY_URL 变量:

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')

export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

使用 curl 测试应用。服务应以 200 作为响应代码进行响应:

curl -o /dev/null -s -w "%{http_code}\n" http://${GATEWAY_URL}/

或者,您也可以打开浏览器,前往 http://<gatewayurl> 以查看应用:

f579a9baedc108a9.png

10. 恭喜!

您刚刚为在 Google Kubernetes Engine (GKE) 上运行的 Kubernetes 部署了一个简单的 ASP.NET Core 应用,并将其配置为由 Istio 管理。

您可能想知道“Istio 有什么优势?”。好问题!目前为止,让 Istio 管理此应用还没有任何优势。在本实验的第二部分中,我们将进一步探索 Istio 的功能,例如指标、跟踪、动态流量管理、服务可视化和故障注入。

后续步骤

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。

11. 清理

如果您不想继续本实验的第二部分,可以删除该应用并卸载 Istio,也可以直接删除 Kubernetes 集群。

删除应用

如需删除应用,请执行以下操作:

kubectl delete -f aspnetcore-gateway.yaml
Kubectl delete -f aspnetcore-virtualservice.yaml
kubectl delete -f aspnetcore.yaml

如需确认该应用已不复存在,请执行以下操作:

kubectl get gateway 
kubectl get virtualservices 
kubectl get pods

卸载 Istio

如需删除 Istio,请执行以下操作:

kubectl delete -f install/kubernetes/istio-demo-auth.yaml

如需确认 Istio 是否已消失,请运行以下命令:

kubectl get pods -n istio-system

删除 Kubernetes 集群

gcloud container clusters delete hello-istio