使用 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 的功能,例如指标、跟踪、动态流量管理、故障注入等。

学习内容

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

所需条件

您打算如何使用本教程?

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

您如何评价自己在 Google Cloud Platform 方面的经验水平?

新手水平 中等水平 熟练水平

2. 设置和要求

自定进度的环境设置

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

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

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

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

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

启动 Cloud Shell

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

激活 Cloud Shell

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

bce75f34b2c53987.png

如果您以前从未启动过 Cloud Shell,将看到一个中间屏幕(非首屏),描述它是什么。如果是这种情况,请点击继续(您将永远不会再看到它)。一次性屏幕如下所示:

70f315d7b402b476.png

预配和连接到 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

再次利用 Cloud Shell 的网页预览功能:

2015-11-03 17:20:22 的屏幕截图.png

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

f579a9baedc108a9.png

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

现在,映像已按预期运行,您可以将其推送到 Google Container Registry,这是一个私有代码库,用于存储您的 Docker 映像,可从每个 Google 云项目(也可从 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 边车注入到服务的每个 pod 中。

为此,您需要为用于微服务的命名空间(“default”)启用边车注入。为此,请应用标签:

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 控制平面、入站网关和出站网关(您可以将其视为“面向互联网其余部分的边车代理”),分别命名为 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>

Ingress 网关的类型为 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 控制平面。处理代理边车的配置和编程、服务发现、证书分发和边车注入
  • ingress gateway:处理来自集群外部的入站请求。
  • egress gateway:处理向集群外部端点发出的出站请求。

8. 部署应用

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

Deployment 和 Service

首先,使用您惯用的编辑器(vim, nano,emacs 或 Cloud Shell 的代码编辑器)创建一个 aspnetcore.yaml 文件,并为应用定义 Kubernetes 部署和服务:

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 和 Service 标准,不包含任何特定于 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

网关和 VirtualService

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

网关用于为 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