容器简介

如果您完全不熟悉容器化工作负载,那么本教程非常适合您。本教程将引导您完成简单应用的设置过程(从源代码到在 GKE 上运行的容器),以向您介绍容器和容器编排。

本教程不要求您具备之前使用任何容器或 Kubernetes 的经验。不过,如果您希望在开始学习本教程之前先大致了解核心 Kubernetes 术语,请参阅开始了解 Kubernetes(或者,如果您偏向于以漫画形式了解 Kubernetes,请参阅我们的 Kubernetes 漫画)。如需查看更详细的资源,请参阅本教程末尾的后续步骤部分。

如果您已熟悉容器和 Kubernetes,可以跳过本教程,直接开始了解 GKE 本身

下载示例代码

  1. 下载 helloserver 源代码:

    git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
    
  2. 切换到示例代码目录:

    cd anthos-service-mesh-samples/docs/helloserver
    

探索多服务应用

示例应用是用 Python 编写的。它包含以下组件,这些组件使用 REST 进行通信:

  • server:一个基本服务器,具有一个 GET 端点 (/),可将“hello world”输出到终端窗口。
  • loadgen:一种将流量发送到 server 的脚本,可配置每秒请求数 (RPS)。

示例应用

从来源运行应用

如需熟悉示例应用,请在 Cloud Shell 中运行它:

  1. sample-apps/helloserver 目录运行 server

    python3 server/server.py
    

    启动时,server 会显示以下内容:

    INFO:root:Starting server...
    
  2. 打开另一个终端窗口,以便向 server 发送请求。如需在 Cloud Shell 中执行此操作,请点击 打开新标签页以打开另一个会话。

  3. 在新终端窗口中,向 server 发送请求:

    curl http://localhost:8080
    

    server 的输出如下所示:

    Hello World!
    
  4. 在同一标签页中,切换到包含 loadgen 脚本的目录:

    cd anthos-service-mesh-samples/docs/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 应用,为 server 生成流量:

    python3 loadgen.py
    

    启动时,loadgen 的输出类似于以下内容:

    Starting loadgen: 2024-10-11 09:49:51.798028
    5 request(s) complete to http://localhost:8080
    
  10. 现在,打开运行 server 的终端窗口。您应该会看到类似如下所示的消息:

    127.0.0.1 - - [11/Oct/2024 09:51:28] "GET / HTTP/1.1" 200 -
    INFO:root:GET request,
    Path: /
    Headers:
    Host: localhost:8080
    User-Agent: python-requests/2.32.3
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    

    从网络的角度来看,整个应用目前在同一主机上运行,这让您可以使用 localhostserver 发送请求。

  11. 要停止 loadgenserver,请在每个终端窗口中按 Ctrl-c

  12. loadgen 终端窗口中,停用虚拟环境:

    deactivate
    

将应用容器化

若要在 GKE 上运行应用,您需要将示例应用的两个组件都打包到容器中。容器是一个软件包,其中包含应用在任何环境中运行所需的所有元素。本教程使用 Docker 将应用容器化。

如需使用 Docker 将应用容器化,您需要一个 DockerfileDockerfile 是一个文本文件,用于定义将应用源代码及其依赖项汇编到容器映像中所需的命令。构建映像后,您可以将其上传到容器注册表,例如 Artifact Registry

本教程的源代码包含一个 Dockerfile 用于 serverloadgen,后者具有构建映像所需的所有命令。以下是 serverDockerfile

FROM python:3.14-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.* /usr/local/lib/

# 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 指令指定 server 侦听端口 8080。此指令不会公开任何端口,但可用作您在运行容器时打开端口 8080 所需的文档。

准备将应用容器化

在将应用容器化之前,您需要为将要使用的工具和服务进行一些设置:

  1. 设置 Google Cloud CLI 的默认 Google Cloud 项目。

    gcloud config set project PROJECT_ID
  2. 设置 Google Cloud CLI 的默认区域。

    gcloud config set compute/region us-central1
    

创建代码库

如需在 Artifact Registry 中为 Docker 容器映像创建新仓库,请执行以下操作:

  1. 确保在Google Cloud 项目中启用 Artifact Registry 服务。

    gcloud services enable artifactregistry.googleapis.com
    
    
  2. 创建 Artifact Registry 代码库:

    gcloud artifacts repositories create container-intro --repository-format=docker \
        --location=us-central1 \
        --description="My new Docker repository"
    
  3. 使用 Google Cloud CLI 设置从 Docker 到 Artifact Registry 之间的身份验证:

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

server 容器化

现在,您可以将应用容器化了。首先,将“hello world”server 容器化,然后将映像推送到 Artifact Registry:

  1. 切换到示例 server 所在的目录:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. 使用 Dockerfile 构建映像:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1 .
    
    • PROJECT_ID 替换为您的 Google Cloud 项目的 ID。

    -t 标志表示 Docker 标记。这是您在部署容器时使用的映像的名称。

  3. 将该映像推送到 Artifact Registry。

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

loadgen 容器化

接下来,以相同的方式将负载生成器服务容器化:

  1. 切换到示例 loadgen 所在的目录:

    cd ../loadgen
    
  2. 构建映像:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1 .
    
  3. 将该映像推送到 Artifact Registry。

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

列出映像

获取代码库中的映像列表,以确认是否已推送映像:

gcloud container images list --repository us-central1-docker.pkg.dev/PROJECT_ID/container-intro

输出应列出您推送的映像名称,类似于以下内容:

NAME
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen

创建 GKE 集群

此时,您可以使用 docker run 命令在 Cloud Shell 虚拟机上运行容器。不过,为了运行可靠的生产工作负载,您需要以更统一的方式管理容器。例如,您需要确保容器在发生故障时会重启,并且需要一种方法来扩容和启动容器的其他实例,以便处理增加的流量。

GKE 可以帮助您满足这些需求。GKE 是一个容器编排平台,其工作方式是将虚拟机连接到集群。每个虚拟机称为一个节点。GKE集群由Kubernetes 开源集群管理系统提供支持Kubernetes为用户提供了与集群进行交互的机制

如需在 GKE 上运行容器,您需要先创建集群,然后连接到该集群:

  1. 创建集群:

    gcloud container clusters create-auto container-intro
    

    gcloud 命令会在您之前设置的默认 Google Cloud 项目和区域中创建一个集群。

    创建集群的命令需要几分钟才能完成。集群准备就绪后,输出类似于以下内容:

     NAME: container-intro
     LOCATION: us-central1
     MASTER_VERSION: 1.30.4-gke.1348000
     MASTER_IP: 34.44.14.166
     MACHINE_TYPE: e2-small
     NODE_VERSION: 1.30.4-gke.1348000
     NUM_NODES: 3
     STATUS: RUNNING
    
  2. kubectl 命令行工具提供凭据,以便使用它来管理集群:

    gcloud container clusters get-credentials container-intro
    

检查 Kubernetes 清单

从源代码运行应用时,您使用了命令式命令:python3 server.py

命令式意味着以动词为导向:“这样做”。

相比之下,Kubernetes 基于声明式模型运行。这意味着,您无需确切地告知 Kubernetes 做什么,而只需为 Kubernetes 提供所需状态。例如,Kubernetes 会根据需要启动和终止 Pod,以使实际系统状态与所需状态匹配。

您可以在名为清单的文件中指定所需状态。清单以 YAML 或 JSON 等语言编写,包含一个或多个 Kubernetes 对象的规范。

该示例包含 serverloadgen 各自的清单。每个清单都指定了 Kubernetes Deployment 对象(用于管理以 Kubernetes Pod 形式打包的容器运行)和 Service(用于为 Pod 提供 IP 地址)的所需状态。Pod 是您可以在 Kubernetes 中创建和管理的最小可部署计算单元,包含一个或多个容器。

下图显示在 GKE 上运行的应用:

在 GKE 上运行的容器化应用

如需详细了解 Pod、Deployment 和 Service,请参阅开始学习 Kubernetes 或本页末尾的资源。

服务器

首先,我们来看看“hello world”server 的清单:

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

此清单包含以下字段:

  • kind 表示对象的类型。
  • metadata.name 指定 Deployment 的名称。
  • 第一个 spec 字段包含所需状态的说明。
  • spec.replicas 指定所需 Pod 的数量。
  • spec.template 部分定义 Pod 模板。Pod 的规范中包含 image 字段,该字段是从 Artifact Registry 中拉取的映像的名称。在下一步中,您会将此映像更新为您刚刚创建的新映像。

hellosvc Service 的定义如下:

apiVersion: v1
kind: Service
metadata:
  name: hellosvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: helloserver
  type: LoadBalancer
  • 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。一个显著区别是 loadgen Deployment 的 Pod 规范包含一个名为 env 的字段。此部分定义 loadgen 所需的环境变量,此变量是您在从来源运行应用时设置的。

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

由于 loadgen 不接受传入请求,因此将 type 字段设置为 ClusterIP。此类服务提供集群中的实体可以使用的稳定 IP 地址,但不会向外部客户端公开 IP 地址。

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

将容器部署到 GKE

如需部署容器,您可以使用 kubectl 应用可指定所需状态的清单。

部署 server

  1. 切换到示例 server 所在的目录:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Cloud Shell Editor(或您喜欢的文本编辑器)中打开 server.yaml

  3. image 字段中的名称替换为您的 Docker 映像的名称。

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

    请将 PROJECT_ID 替换为您的 Google Cloud 项目 ID。

    • 如果您使用的是 Cloud Shell 编辑器,系统会自动保存该文件。点击打开终端,返回终端窗口。
    • 如果您使用的是 Cloud Shell 中的文本编辑器,请保存并关闭 server.yaml
  4. 将清单部署到 Kubernetes:

    kubectl apply -f server.yaml
    

    输出类似于以下内容:

    deployment.apps/helloserver created
    service/hellosvc created
    

部署 loadgen

  1. 切换到 loadgen 所在的目录。

    cd ../loadgen
    
  2. 像之前一样,在文本编辑器中打开 loadgen.yaml

  3. image 字段中的名称替换为您的 Docker 映像的名称。

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

    请将 PROJECT_ID 替换为您的 Google Cloud 项目 ID。

    • 如果您使用的是 Cloud Shell 编辑器,系统会自动保存该文件。点击打开终端,返回终端窗口。
    • 如果您使用的是 Cloud Shell 中的文本编辑器,请保存并关闭 loadgen.yaml
  4. 将清单部署到您的集群:

    kubectl apply -f loadgen.yaml
    

    成功后,该命令会返回以下内容:

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

验证您的部署

将清单部署到集群后,验证容器是否已成功部署:

  1. 检查集群中 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
    
  2. loadgen Pod 获取应用日志。将 POD_ID 替换为之前输出中的负载生成器 Pod 标识符。

    kubectl logs POD_ID
    
  3. 获取 hellosvc 的外部 IP 地址:

    kubectl get service hellosvc
    

    输出类似于以下内容:

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    hellosvc     LoadBalancer   10.81.15.158   192.0.2.1       80:31127/TCP   33m
    
  4. hellosvc 发送请求。将 EXTERNAL_IP 替换为 hellosvc 的外部 IP 地址。

    curl http://EXTERNAL_IP
    

    您应该会看到来自服务器的“Hello World!”消息。