为Istio准备应用程序


Istio是连接,保护和监视分布式应用程序的便捷工具。 Istio使用各种技术来大规模启动和管理软件,包括用于包装应用程序代码的容器和用于部署的依赖项,以及用于管理这些容器的Kubernetes。 因此,要使用Istio,您必须知道在没有 Istio的情况下具有基于这些技术的多种服务的应用程序如何工作。 如果您已经了解这些工具和概念,请随时跳过本指南,直接转到在Google Kubernetes Engine(GKE)上安装Istio在GKE扩展程序上安装Istio


这是一个循序渐进的指南,在其中我们将介绍从源代码到GKE上的容器的整个过程,以便您通过示例了解这些技术的基本概念。 您还将看到Istio如何利用这些技术。 假定您对容器,Kubernetes,服务网格或Istio一无所知。


任务


在本指南中,您将完成以下任务:


  1. 探索带有多个服务的简单hello world应用程序。
  2. 从源代码运行应用程序。
  3. 将应用程序包装在容器中。
  4. 创建一个Kubernetes集群
  5. 将容器部署到群集。

开始之前


按照说明启用Kubernetes Engine API:


  1. 转到Google Cloud Platform控制台中的Kubernetes Engine页面
  2. 创建或选择一个项目。
  3. 等待API和相关服务打开。 这可能需要几分钟。
  4. 确保为Google Cloud Platform项目配置了结算方式。 了解如何启用结算

在本指南中,您可以使用Cloud Shell,它可以具有基于Debian的Linux或Linux或macOS计算机的Google Compute Engine中准备g1小型虚拟机。


选项A:使用Cloud Shell


使用Cloud Shell的好处:


  • 完全定制了Python 2和Python 3开发环境(包括virtualenv )。
  • 我们将使用的gclouddockergitkubectl命令行工具已经安装。
  • 您可以从以下几种文本编辑器中进行选择:
    1. 使用 Cloud Shell窗口顶部的编辑图标打开的代码编辑器
    2. 从Cloud Shell中的命令行打开的Emacs,Vim或Nano。

要使用Cloud Shell


  1. 转到GCP控制台。
  2. 单击GCP控制台窗口顶部的“ 激活Cloud Shell”按钮。


GCP控制台的底部在新窗口中,使用命令行打开Cloud Shell会话。



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


如果要在装有Linux或macOS的计算机上工作,则需要配置和安装以下组件:


  1. 设置Python 3和Python 2开发环境


  2. 使用gcloud命令行工具 安装Cloud SDK


  3. 安装kubectl ,这是用于Kubernetes的命令行工具。


    gcloud components install kubectl 

  4. 安装Docker Community Edition(CE) 。 您将使用docker命令行工具为示例应用程序创建容器映像。


  5. 安装Git版本控制工具以通过GitHub获取示例应用程序。



下载示例代码


  1. 下载helloserver源代码:


     git clone https://github.com/GoogleCloudPlatform/istio-samples 

  2. 转到示例代码目录:


     cd istio-samples/sample-apps/helloserver 


探索多服务应用程序


该示例应用程序是用Python编写的,由与REST交互的两个组件组成:


  • 服务器 :具有一个GET端点/的简单服务器,该控制台在控制台上显示“ hello world”。
  • loadgen :一个脚本,它将流量发送到服务器 ,每秒可配置的请求数。


从源代码运行应用程序


要了解示例应用程序,请在Cloud Shell或计算机上运行它。
1)在istio-samples / sample-apps / helloserver目录中,运行server


 python3 server/server.py 

服务器启动时,将显示以下内容:


 INFO:root:Starting server... 

2)打开另一个终端窗口,以将请求发送到服务器 。 如果您使用的是Cloud Shell,请单击添加图标以打开另一个会话。
3)向服务器发送请求:


 curl http://localhost:8080 

服务器答案:


 Hello World! 

4)从下载示例代码的目录中,转到包含loadgen的目录:


 cd YOUR_WORKING_DIRECTORY/istio-samples/sample-apps/helloserver/loadgen 

5)创建以下环境变量:


 export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5 

6)运行virtualenv


 virtualenv --python python3 env 

7)激活虚拟环境:


 source env/bin/activate 

8)设置loadgen的要求:


 pip3 install -r requirements.txt 

9)运行loadgen


 python3 loadgen.py 

启动时, loadgen将显示以下消息:


 Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080 

在另一个终端窗口中, 服务器向控制台显示以下消息:


 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: */* 

从网络角度来看,整个应用程序都在同一主机(本地计算机或Cloud Shell虚拟机)上运行。 因此,您可以使用localhost将请求发送到server
10)要停止loadgenserver ,请在每个终端窗口中输入Ctrl-c
11)在loadgen终端窗口中,禁用虚拟环境:


 deactivate 

将应用程序包装在容器中


要在GKE上运行该应用程序,您需要将示例应用程序服务器 - 服务器loadgen-打包容器中 。 容器是打包应用程序以使其与环境隔离的一种方式。


要将应用程序打包在容器中,您需要一个DockerfileDockerfile是一个文本文件,定义用于将应用程序源代码及其依赖项构建到Docker映像中的命令。 构建后,将映像上传到容器注册表,例如Docker Hub或Container Registry


该示例已经具有用于服务器loadgenDockerfile ,以及用于组装映像的所有必需命令。 以下是服务器Dockerfile


 FROM python:3-slim as base FROM base as builder RUN apt-get -qq update \ && apt-get install -y --no-install-recommends \ g++ \ && rm -rf /var/lib/apt/lists/* # Enable unbuffered logging FROM base as final ENV PYTHONUNBUFFERED=1 RUN apt-get -qq update \ && apt-get install -y --no-install-recommends \ wget WORKDIR /helloserver # Grab packages from builder COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/ # Add the application COPY . . EXPOSE 8080 ENTRYPOINT [ "python", "server.py" ] 

  • FROM python:3-slim as base命令可以告诉Docker使用最新的Python 3映像作为基础。
  • COPY团队 将源文件复制到容器文件系统中的当前工作目录(在本示例中,仅是server.py )。
  • ENTRYPOINT定义用于启动容器的命令。 在我们的例子中,此命令与用于从源代码运行server.py的命令几乎相同。
  • EXPOSE命令指示服务器正在侦听端口8080 。 该命令不提供端口 。 这是在容器启动时打开端口8080所需的某种文档。

准备应用程序容器化


1)设置以下环境变量。 用您的GCP项目标识符替换PROJECT_ID


 export PROJECT_ID="PROJECT_ID" 

 export GCR_REPO="preparing-istio" 

使用PROJECT_IDGCR_REPO值,您可以在收集Docker映像并将其发送到私有Container Registry时对其进行标记。


2)为gcloud命令行工具设置默认的GCP项目。


 gcloud config set project $PROJECT_ID 

3)设置gcloud命令行工具的默认区域。


 gcloud config set compute/zone us-central1-b 

4)确保GCP项目中包含Container Registry服务。


 gcloud services enable containerregistry.googleapis.com 

集装箱化服务器


  1. 切换到服务器示例所在的目录:


     cd YOUR_WORKING_DIRECTORY/istio-samples/sample-apps/helloserver/server/ 

  2. 使用先前定义的Dockerfile和环境变量构建映像:


     docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 . 


-t选项代表Docker标签。 这是您在部署容器时使用的映像的名称。


  1. 将图像发送到容器注册表:
     docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 

集装箱装载机


1)转到loadgen示例所在的目录:


 cd ../loadgen 

2)组装图片:


 docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 . 

3)将图片发送到Container Registry:


 docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 

查看图像列表


浏览存储库中的图像列表,并确保已发送图像:


 gcloud container images list --repository gcr.io/$PROJECT_ID/preparing-istio 

该命令显示刚发送的图像的名称:


 NAME gcr.io/PROJECT_ID/preparing-istio/helloserver gcr.io/PROJECT_ID/preparing-istio/loadgen 

创建一个GKE集群


可以使用docker run命令在Cloud Shell虚拟机或计算机上运行这些容器。 但是在生产环境中,您需要一种对容器进行集中编排的方法。 例如,我们需要一个确保容器始终运行的系统,并且需要一种方法来在流量增加时放大并启动其他容器实例。


您可以使用GKE运行容器应用程序。 GKE是对虚拟机进行集群的容器编排平台。 每个虚拟机称为主机。 GKE集群基于开源集群管理系统Kubernetes。 Kubernetes提供了与集群交互的机制。


创建一个GKE集群:


1)创建一个集群:


 gcloud container clusters create istioready \ --cluster-version latest \ --machine-type=n1-standard-2 \ --num-nodes 4 

gcloud命令在GCP项目和您指定的默认区域中创建一个istioready群集。 要启动Istio,建议您至少有4个节点和一台n1-standard-2虚拟机。


该团队将创建一个集群几分钟。 集群就绪后,该命令将发出类似的消息


2)在kubectl命令行工具中指定凭据以使用它来管理集群:


 gcloud container clusters get-credentials istioready 

3)现在您可以通过kubectl与Kubernetes进行通信了。 例如,使用以下命令,您可以找到节点的状态:


 kubectl get nodes 

该命令显示节点列表:


 NAME STATUS ROLES AGE VERSION gke-istoready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-istoready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-istoready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-istoready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13 

Kubernetes的关键概念


该图显示了GKE上的应用程序:



在将容器部署到GKE之前,请查看Kubernetes的关键概念。 如果您想了解更多信息,请在最后找到链接。


  • 节点和集群 。 在GKE中,节点是虚拟机。 在其他Kubernetes平台上,主机可以是计算机或虚拟机。 群集是节点的集合,可以将它们视为一个整体,并在其中部署容器化的应用程序。
  • 豆荚 。 在Kubernetes中,容器在pod中运行。 Kubernetes中的Pod是不可分割的单元。 吊舱可容纳一个或多个容器。 您将服务器容器loadgen容器部署在单独的容器中。 当Pod中有多个容器时(例如,应用程序服务器和代理服务器 ),这些容器将作为单个对象进行管理并共享Pod的资源。
  • 部署 。 在Kubernetes中,部署是一个对象,该对象是相同pod的集合。 部署运行分布在集群节点上的多个Pod副本。 部署会自动替换失败或不响应的Pod。
  • Kubernetes服务 。 在GKE中运行应用程序代码时, loadgen服务器之间的连接会更改。 在Cloud Shell虚拟机或计算机上启动服务时,您向localhost:8080服务器发送了请求。 部署到GKE后,pod将在可用节点上运行。 默认情况下,您无法控制正在运行的主机Pod,因此Pod没有永久IP地址。
    要获取服务器的IP地址,您需要在Pod顶部定义网络抽象。 这就是Kubernetes服务 。 Kubernetes服务为一组Pod提供了一个永久端点。 有几种类型的服务服务器使用LoadBalancer ,该负载提供一个外部IP地址以从群集外部与服务器联系。
    Kubernetes还具有一个集成的DNS系统,该系统为服务分配DNS名称(例如helloserver.default.cluster.local )。 因此,群集中的Pod与群集中其他Pod在固定地址进行通信。 无法在群集外部(例如在Cloud Shell或计算机上)使用DNS名称。

Kubernetes清单


从源代码启动应用程序时,您使用了命令式python3命令


server.py


命令式隐含了动词:“做”。


Kubernetes使用声明性模型 。 这意味着我们不会告诉Kubernetes到底需要做什么,而是要描述所需的状态。 例如,Kubernetes会根据需要启动和停止Pod,因此系统的实际状态是所需的。


您可以在清单或YAML文件中指定所需的状态。 YAML文件包含一个或多个Kubernetes对象的规范。


该示例包含用于serverloadgen的YAML文件。 每个YAML文件都指示部署对象和Kubernetes服务的所需状态。


server.yaml


 apiVersion: apps/v1 kind: Deployment metadata: name: helloserver spec: selector: matchLabels: app: helloserver replicas: 1 template: metadata: labels: app: helloserver spec: terminationGracePeriodSeconds: 5 restartPolicy: Always containers: - name: main image: gcr.io/google-samples/istio/helloserver:v0.0.1 imagePullPolicy: Always 

  • kind指示对象的类型。
  • metadata.name指示部署的名称。
  • 第一字段规范包含对所需状态的描述。
  • spec.replicas指示所需的豆荚数量。
  • spec.template部分定义了pod模板。 在pod规范中,有一个image字段,其中指示要从Container Registry中提取的图像的名称。

服务定义如下:


 apiVersion: v1 kind: Service metadata: name: hellosvc spec: type: LoadBalancer selector: app: helloserver ports: - name: http port: 80 targetPort: 8080 

  • LoadBalancer :客户端将请求发送到负载平衡器的IP地址,该地址具有固定的IP地址,并且可以从群集外部访问。
  • targetPort :您还记得, Dockerfile中的EXPOSE 8080命令没有提供端口。 您提供端口8080,以便可以从群集外部访问服务器容器。 在我们的例子中, hellosvc.default.cluster.local:80 (短名称: hellosvc )对应于helloserver容器IP地址的端口8080
  • port :这是集群中其他服务将发送请求的端口号。

loadgen.yaml


loadgen.yaml中的部署对象类似于server.yaml 。 区别在于部署对象包含一个env部分。 它定义了loadgen所需的环境变量以及您从源代码启动应用程序时设置的环境变量。


 apiVersion: apps/v1 kind: Deployment metadata: name: loadgenerator spec: selector: matchLabels: app: loadgenerator replicas: 1 template: metadata: labels: app: loadgenerator spec: terminationGracePeriodSeconds: 5 restartPolicy: Always containers: - name: main image: gcr.io/google-samples/istio/loadgen:v0.0.1 imagePullPolicy: Always env: - name: SERVER_ADDR value: "http://hellosvc:80/" - name: REQUESTS_PER_SECOND value: "10" resources: requests: cpu: 300m memory: 256Mi limits: cpu: 500m memory: 512Mi 

由于loadgen不接受传入请求, 因此type字段指定了ClusterIP 。 此类型提供了群集中的服务可以使用的固定IP地址,但是未向外部客户端提供此IP地址。


 apiVersion: v1 kind: Service metadata: name: loadgensvc spec: type: ClusterIP selector: app: loadgenerator ports: - name: http port: 80 targetPort: 8080 

在GKE中部署容器


1)转到服务器示例所在的目录:


 cd YOUR_WORKING_DIRECTORY/istio-samples/sample-apps/helloserver/server/ 

2)在文本编辑器中打开server.yaml
3)将image字段中的名称替换为Docker映像的名称。


 image: gcr.io/PROJECT_ID/preparing-istio/helloserver:v0.0.1 

PROJECT_ID替换为GCP项目的标识符。
4)保存并关闭server.yaml
5)在Kubernetes中展开YAML文件:


 kubectl apply -f server.yaml 

成功完成后,该命令将发出以下代码:


 deployment.apps/helloserver created service/hellosvc created 

6)转到loadgen所在的目录:


 cd ../loadgen 

7)在文本编辑器中打开loadgen.yaml
8)将image字段中的名称替换为Docker映像的名称。


 image: gcr.io/PROJECT_ID/preparing-istio/loadgenv0.0.1 

PROJECT_ID替换为GCP项目的标识符。
9)保存并关闭loadgen.yaml ,关闭文本编辑器。
10)在Kubernetes中展开YAML文件:


 kubectl apply -f loadgen.yaml 

成功完成后,该命令将发出以下代码:


 deployment.apps/loadgenerator created service/loadgensvc created 

11)检查炉膛状态:


 kubectl get pods 

该命令显示状态:


 NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s 

12)从loadgen pod中提取应用程序日志。 用上一个答案中的标识符替换POD_ID


 kubectl logs loadgenerator-POD_ID 

13)获取外部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 

14)向hellosvc发送请求:将EXTERNAL_IP替换为hellosvc的外部IP地址。


 curl http://EXTERNAL_IP 

抢劫伊斯蒂奥


您已经有一个应用程序部署到GKE。 loadgen可以使用Kubernetes DNS( hellosvc:80 )将请求发送到服务器 ,并且您可以使用外部IP地址将请求发送到服务器 。 尽管Kubernetes具有许多功能,但是缺少有关服务的一些信息:


  • 服务如何相互作用? 服务之间是什么关系? 服务之间的流量如何? 您知道loadgen将请求发送到服务器 ,但可以想象您对应用程序一无所知。 为了回答这些问题,我们查看了GKE中运行的炉床清单。
  • 指标服务器对传入请求的响应时间为多长时间? 每秒有多少个请求发送到服务器? 它会给出错误消息吗?
  • 安全信息loadgen服务器之间通信是否仅通过HTTPmTLS进行

Istio回答了所有这些问题。 为此,Istio在每个吊舱中放置一个Envoy边车代理。 Envoy代理拦截到应用程序容器的所有传入和传出流量。 这意味着服务器loadgen接收Envoy sidecar代理,并且从loadgen服务器的所有流量都通过Envoy代理。


Envoy代理之间的连接形成服务网格。 服务网格体系结构提供了对Kubernetes的控制层。



一旦Envoy代理在其容器中执行,就可以在几乎不更改应用程序代码的情况下将Istio安装在GKE群集的顶部。 但是您做了一些工作来准备使用Istio进行管理的应用程序:


  • 所有容器的服务。 服务器loadgen部署由Kubernetes服务链接。 甚至不接收传入请求的loadgen都有服务。
  • 服务中的端口必须具有名称。 尽管可以在GKE中保留服务端口的名称 ,但Istio仍需要根据其协议指定端口名称 。 在YAML文件中, 服务器的端口称为http,因为服务器使用HTTP协议 。 如果服务使用gRPC ,则将端口命名为grpc
  • 部署已标记。 因此,您可以使用Istio的流量管理功能,例如,在同一服务的各个版本之间共享流量。

安装Istio


有两种安装Istio的方法。 您可以在GKE扩展上启用Istio在群集上 安装Istio的开源版本 。 使用GKE上的Istio,您可以在GKE集群生命周期中轻松管理Istio的安装和升级。 如果您需要最新版本的Istio或对Istio控制面板的配置进行更多控制,请安装开源版本,而不是GKE扩展上的Istio。 要决定采用哪种方法,请阅读GKE上的文章Istio吗?


选择一个选项,研究适当的手册,然后按照说明在群集上安装Istio。 如果要在新部署的应用程序中使用Istio,请为默认名称空间启用sidecar嵌入


清洁用品


为确保本指南中使用的资源不会从您的Google Cloud Platform帐户中扣除,请在安装Istio并使用示例应用程序时删除容器群集。 这将删除所有群集资源,例如计算实例,磁盘和网络资源。


接下来是什么?


Source: https://habr.com/ru/post/zh-CN469515/


All Articles