创建微服务

在本节中,我们将介绍创建 UCS 微服务所需的步骤。UCS 微服务使用 UCS 微服务构建器 CLI (msbuilder) 工具构建。该工具的输入是一个具有特定结构的目录和具有特定名称和格式的文件。该工具的输出是微服务的 UCS 微服务规范,以及可选的微服务使用的容器镜像和基于用例和 UCS 微服务构建器 CLI 工具的输入类型的微服务的 Helm Chart。

有关 UCS 微服务的更多信息,请参阅 - UCS 微服务

有关 msbuilder 输入目录规范,请参阅 - 微服务构建器输入规范

生成脚手架

UCS 微服务构建器 CLI service create 生成新服务的脚手架

$ ucf_ms_builder_cli service create [-h] [-d DESCRIPTION] [-o OUTPUT_DIR] -n NAME -i {container-image,container-config,helm-chart} [-c CHART]

该工具支持为三种类型的输入创建微服务

  • 预构建容器镜像

  • 容器构建配置

  • 预构建 helm charts

预构建容器镜像

当容器镜像已可用于要构建的微服务时,可以使用此选项。使用此方法,该工具将生成

  • 微服务的 Helm chart

  • 微服务的 UCS 微服务规范

要使用此方法,请运行

$ ucf_ms_builder_cli service create -n myservice -d "my service description" -i container-image

此命令将在以下输出目录结构中生成模板微服务

myservice
├── changelog.txt
├── configs
├── endpoints
│   ├── http-api.yaml
│   └── myservice-endpoint-name.yaml
├── LICENSE.txt
├── manifest.yaml
├── manual_compliance_test_results.yaml
├── README.md
├── scripts
└── tests
    └── dev
        ├── app.yaml
        └── params1.yaml

容器构建配置

当必须与微服务一起构建容器镜像时,可以使用此选项。使用此方法,该工具将生成

  • 微服务的容器镜像

  • 微服务的 Helm chart

  • 微服务的 UCS 微服务规范

要使用此方法,请运行

$ ucf_ms_builder_cli service create -n myservice -d "my service description" -i container-config

此命令将在以下输出目录结构中生成模板微服务

myservice
├── changelog.txt
├── configs
├── containers
│   └── cb_config.yaml
├── endpoints
│   ├── http-api.yaml
│   └── myservice-endpoint-name.yaml
├── LICENSE.txt
├── manifest.yaml
├── manual_compliance_test_results.yaml
├── README.md
├── scripts
├── target_x86_64.yaml
└── tests
    └── dev
        ├── app.yaml
        └── params1.yaml

预构建 Helm Chart

当微服务的 helm chart 已可用,但需要创建 UCS 微服务规范时,可以使用此选项。使用此方法,该工具将生成

  • 微服务的 UCS 微服务规范

要使用此方法,请运行

$ ucf_ms_builder_cli service create -n myservice -d "my service description" -i helm-chart -c <helm chart link>

此命令将在以下输出目录结构中生成模板微服务

myservice
├── changelog.txt
├── endpoints
│   ├── http-api.yaml
│   └── myservice-endpoint-name.yaml
├── LICENSE.txt
├── manifest.yaml
├── manual_compliance_test_results.yaml
├── README.md
├── tests
│   └── dev
│       ├── app.yaml
│       └── params1.yaml
└── values.yaml

更新微服务构建器输入

如上一节所示,输入将根据用例和工具的输入类型略有不同。本节将介绍如何更新所有用例的输入目录结构中的文件。

更新 configs

将微服务所需的任何配置文件添加到此目录。此目录中的文件可以包含占位符,这些占位符将被 UCS 应用程序覆盖。

当使用预构建 Helm Chart 时,使用此目录中的文件。

包含占位符的 configs 目录中的文件 app_cfg.yaml 示例

redis:
  host: $egress.redis.address
  port: $egress.redis.port

log_level: 5

timeout: $params.timeout

configs 目录中的文件 app_cfg.yaml 将挂载到微服务包含的容器中的 /opt/configs/app_cfg.yaml,并使用实际值更新占位符。

当构建和部署包含此微服务(连接了 redis 出口端点并且 timeout 参数设置为 10)的应用程序时,文件 /opt/configs/app_cfg.yaml 将挂载到微服务包含的容器,其内容如下

redis:
  host: redis-svc
  port: 6739

log_level: 5

timeout: 10

更新 scripts

将微服务所需的任何脚本文件添加到此目录。

当使用预构建 Helm Chart 时,使用此目录中的文件。

例如,scripts 目录中名为 run.sh 的文件将挂载到微服务包含的容器中的 /opt/scripts/run.sh,内容完全相同。

容器构建 配置文件添加到 containers

对于必须与微服务一起构建的任何容器,将 容器构建 配置文件添加到 containers 目录并进行更新。

当使用预构建 Helm Chart 或使用预构建容器镜像时,使用此目录中的文件。

更新 endpoints

每个入口/出口端点的端点定义文件可以根据 UCS MS 规范添加到 endpoints 目录下。文件名必须是 <endpoint-name>.<ext>。文件的扩展名和内容将取决于端点的方案。

有关端点定义文件的内容、格式和文件名的更多详细信息,请参阅 UCS 端点方案

更新 manual_compliance_test_results.yaml

开发人员必须按照 UCS 微服务合规性 中的规定运行手动合规性检查,并在 manual_compliance_test_results.yaml 中将各个合规性规则的结果(布尔值)更新为 true / false

添加测试

tests 目录包含 UCS 应用程序,这些应用程序基本上是微服务的测试。测试应用程序遵循 UCS 应用程序图文件规范 - UCS Tools 应用程序

这些测试理想情况下应该作为一个整体测试微服务,即微服务的 helm chart 是否正常工作,而不是微服务内部运行的应用程序的单元测试。

例如,它可以测试通过微服务端点访问 API 是否有效,当应用程序通过 Kubernetes 容器化和部署时,通过使用已知输入和相应的已知输出调用 API,应用程序是否正常工作。

如果正在构建的微服务依赖于其他微服务,则这些其他微服务可以替换为存根微服务或更简单的功能等效微服务,以在测试时消除对其他微服务的依赖。

更新 values.yaml

仅当使用预构建 Helm Chart 时,才使用此文件。

它采用标准 Helm values.yaml 的形式,并包含必须覆盖的预构建 helm chart 的值。该文件可以包含 $params$egress$secrets 占位符,这些占位符将在构建和部署应用程序时替换为实际值。

当使用预构建 Helm Chart 类型生成脚手架时,values.yaml 从 helm chart 中拉取并放置在此处。微服务开发人员可以修剪和更新该文件,仅保留那些需要被微服务或使用微服务的应用程序覆盖的值。

例如,当为 helm chart 生成脚手架时,values.yaml 可能如下所示

applicationSpecs:
  myservice-deployment:
    apptype: stateless
    containers:
      myservice-container:
        env:
        - name: REDIS_ENDPOINT
          value: redis-svc:6379
        command:
        - sleep
        - '1000'
        image:
          repository: ubuntu
          tag: latest
        ports:
        - containerPort: 1000
          name: http
    restartPolicy: Always
    securityContext:
      runAsGroup: 1000
      runAsUser: 1000
    services:
      myservice-service:
        ports:
        - name: http-api
          port: 1000
image:
  pullPolicy: IfNotPresent
imagePullSecrets: []
ingress:
  enabled: false

微服务开发人员可以更新它以删除不需要覆盖的值,并添加 $params$egress 等占位符

applicationSpecs:
  myservice-deployment:
    apptype: stateless
    containers:
      myservice-container:
        env:
        - name: REDIS_ENDPOINT
          value: $egress.redis.address:$egress.redis.port
        command:
        - sleep
        - '1000'
        image:
          repository: ubuntu
          tag: $params.stringToEcho

更新文档

微服务构建器工具接受四种文档

  • README.md - 有关微服务的详细信息。由 service create 命令生成的模板具有多个部分,例如详细描述、使用信息、性能 KPI、支持的平台和部署要求、已知问题等。微服务开发人员必须根据需要填写这些部分中的信息。

  • LICENSE.txt - 包含微服务中使用的任何第三方软件的许可证文本。这包括容器内运行的应用程序中使用的第三方软件的许可证,以及添加到容器文件系统的任何第三方软件包的许可证。

  • changelog.txt - 当前版本与以前版本相比的更改列表。

更新 Manifest 文件 manifest.yaml

manifest.yaml 包含用于描述微服务、helm chart 实现和容器构建配置详细信息的信息。

为三个用例生成的模板 manifest 略有不同。本节将介绍如何更新第一个用例(即 预构建容器镜像)的 manifest 文件,然后描述其他用例的差异(如果适用)。

以下是为 预构建容器镜像 用例生成的模板 manifest.yaml 文件示例

type: msapplication
specVersion: 2.5.0
name: ucf.svc.myservice
chartName: myservice
description: default description
version: 0.0.1
tags: []
keywords: []

publish: false

egress-endpoints:
  - name: myservice-endpoint-name
    description: Short description of endpoint
    protocol: TCP # Or UDP
    scheme: asyncio # Or grpc / rtsp / asyncio / none
    mandatory: True # Or False
    data-flow: in-out # Or in or out

ingress-endpoints:
  - name: http-api
    description: Short description of http-api ingress endpoint
    scheme: http
    data-flow: in-out # Or in or out

secrets:
  - name: some-secret-name
    description: Description for the secret
    mandatory: True
    mountPath: /secrets
    fileName: someSecretFileName

params:
  stringToEcho: someString
  #> type: string
  #> enum_values: someString, someOtherString
  #> description: String to echo in init container
  timeToSleep: 1000000
  #> type: integer
  #> maximum: 2000000
  #> minimum: 1000000
  #> description: String to echo in init container
  #> flags: mandatory

metrics:
- portName: metrics # Name of pod container port which implements prometheus metrics
  path: /metrics    # HTTP path where metrics are available

  # List of metrics exported by the microservice endpoint and their details
  details:
  - name: latency
    description: Average latency of handling HTTP requests in milliseconds
    labels: [request-type]
    # recommendedMin: 5  # Optional
    # recommendedMax: 50  # Optional

  # Optional. Selector for pods that implement the metrics endpoint
  # podSelectorLabels:
  #   app: myservice-myservice-deployment

# Files and directories will be mounted with prefix /opt/ext-files/
externalFiles:
- name: some-config.yaml # File will be available in containers at /opt/ext-files/some-config.yaml
  description: Some Configuration file
  mandatory: True
  isDirectory: False

tests:
  - name: dev-params1
    app: tests/dev/app.yaml
    params: tests/dev/params1.yaml
    ciTrigger: false
    timeout: 10
    duration: 10
    installPreReqs: true  # Wether to install foundational services
    namespace: default  # Kubernetes namespace
    gpuNodeLabels: ""
    watchAllPods: true # OR set to false and set list of pods to watch below
    watchPods:
    - <pod-name-regex>
    testerPods:  # At least one tester pod is required
    - name: testpod1  # Name of the test pod
      startSignature: <START>  # Signature to look for in the logs indicating start of tests. Regex is accepted
      endSignature: <END>  # Signature to look for in the logs indicating end of tests. Regex is accepted
      errorSignatures:  # Signatures that indicate test failures.  Regex is accepted
      - <REGEX1>
      - <REGEX2>


---
spec:
  - name: myservice-deployment
    type: ucf.k8s.app.deployment
    parameters:
      apptype: stateless

  - name: myservice-init-container
    type: ucf.k8s.initcontainer
    parameters:
      image: ubuntu
      imagePullPolicy: IfNotPresent
      args: [echo, $params.stringToEcho]
  - name: "myservice-container"
    type: ucf.k8s.container
    parameters:
      image:
        repository: ubuntu
        tag: "latest"
      command: ["sleep", "$params.timeToSleep"]
      ports:
      - containerPort: 0 # <PORT>
        name: http
      startupProbe:
        httpGet:
          path: /healthz
          port: http
        failureThreshold: 30
        periodSeconds: 10
      livenessProbe:
        httpGet:
          path: /healthz
          port: http
      readinessProbe:
        exec:
          command:
          - cat
          - /tmp/healthy
        initialDelaySeconds: 5
        periodSeconds: 5

  - name: myservice-service
    type: ucf.k8s.service
    parameters:
      annotations:
        test-svc-annotation: annotation-value
      labels:
        test-svc-label: label-value
      ports:
      - port: 0 # <OUT_PORT>
        name: http-api
      #externalTrafficPolicy: # Cluster / Local. Allowed when service type is NodePort or LoadBalancer

根据 manifest 规范更新以下部分

规范

微服务的实现(即它的 helm chart)可以在 spec 字段下指定。作为 UCS 微服务构建器工具 的一部分,微服务实现必须使用可组合组件完成。

当使用预构建 Helm Chart 时,必须省略此部分。MSBuilder 忽略此字段,因为它不构建微服务 helm chart。

组件

组件定义了微服务实现的一小部分,例如容器、服务、卷。可以使用以下命令查看可用组件列表

$ ucf_ms_builder_cli component list
List of available components:
=============================
ucf.appspec.app.workload
ucf.appspec.defaultVolumeMount
ucf.k8s.app.deployment
ucf.k8s.configmap
ucf.k8s.container
ucf.k8s.imagepullsecret
ucf.k8s.initcontainer
ucf.k8s.podAnnotations
ucf.k8s.podLabels
ucf.k8s.podSecurityContext
ucf.k8s.pvc
ucf.k8s.restartPolicy
ucf.k8s.service
ucf.k8s.volume
...

要查看有关组件的详细信息,请运行

$ ucf_ms_builder_cli component info -c ucf.k8s.service
type:        ucf.k8s.service
description: Service
properties:
                 pod: (string ), Service pod. [Mandatory:False]
               ports: (array  ), An explanation about the purpose of this instance. [Mandatory:True]
                        port: (integer), Service port. [Mandatory:True]
                        name: (string ), Name for service port (this is used as endpoint name) [Mandatory:False]
                  targetPort: (['string', 'integer']), Target port number or name. [Mandatory:False]
                    nodePort: (integer), Target port number or name. [Mandatory:False]
                       range: (integer), Range of ports. 0-<range - 1> will be added added to port/targetPort/nodePort [Mandatory:False]
                type: (string ), Service type [Mandatory:False, Allowed Values:{ ClusterIP, NodePort }]
externalTrafficPolicy: (string ), Route external traffic to node-local or cluster-wide endpoints [Mandatory:False, Allowed Values:{ Cluster, Local }]
        nameOverride: (boolean), Enable to set service name as set as <appname>-<service-name> [Mandatory:False]
    fullNameOverride: (boolean), Enable to set service name as set as <service-name> [Mandatory:False]
          extraSpecs: (object ), Extra specs to set on the service [Mandatory:False]
         annotations: (object ), Annotations to set on the service [Mandatory:False]
              labels: (object ), Labels to set on the service [Mandatory:False]

常用组件

下表列出了常用组件及其用途

组件

用途

ucf.appspec.defaultVolumeMount

添加默认 volumeMount。此 volumeMount 将添加到 pod 中的所有容器/initContainer

ucf.appspec.ingress

添加入口资源

ucf.k8s.app.deployment

定义部署工作负载及其类型(例如 statelessstatefuljobcronjobdaemonsetstatic-pod

ucf.k8s.configmap

向微服务添加 configmap

ucf.k8s.container

向微服务 pod/pod 模板添加容器

ucf.k8s.dnsPolicy

为微服务 pod/pod 模板设置 DNS 策略

ucf.k8s.initcontainer

向微服务 pod/pod 模板添加 initContainer

ucf.k8s.podAnnotations

在 pod/pod 模板上设置注释

ucf.k8s.podLabels

在 pod/pod 模板上设置自定义标签

ucf.k8s.podSecurityContext

为 pod/pod 模板设置 securityContext

ucf.k8s.pvc

为微服务添加 PVC 资源

ucf.k8s.restartPolicy

为 pod/pod 模板设置重启策略

ucf.k8s.service

向以下项添加 Kubernetes 服务

ucf.k8s.volume

向 pod/pod 模板添加卷

向规范添加组件

组件必须作为列表添加到 spec 下,并附带其参数。参数值必须遵循组件的参数模式,可以使用如上所示的 component info 命令查看该模式。占位符 $params$egress$secrets 可用于参数值中,分别引用参数、出口端点和密钥。这些占位符保留在构建的微服务 helm chart 中,但在应用程序构建期间被替换。

添加带有占位符的组件的示例是

spec:
  - name: myservice-deployment
    type: ucf.k8s.app.deployment
    parameters:
      apptype: stateless

  - name: "myservice-container"
    type: ucf.k8s.container
    parameters:
      image:
        repository: ubuntu
        tag: "latest"
      env:
      - name: HTTP_API_CA_CERT_PATH
        value: $secrets.ca-cert.path
      command: ["curl", "$egress.http-api.address:$egress.http-api.port",
        "--connect-timeout", $params.connectTimeout, "--cacert", $(HTTP_API_CA_CERT_PATH)]
      startupProbe:
        httpGet:
          path: /healthz
          port: http
        failureThreshold: 30
        periodSeconds: 10
      livenessProbe:
        httpGet:
          path: /healthz
          port: http
      readinessProbe:
        exec:
          command:
          - cat
          - /tmp/healthy
        initialDelaySeconds: 5
        periodSeconds: 5

注意

对于规范中定义的组件,参数必须遵守每种类型特定的组件模式,如上所示。

在一个 yamldoc 中只能指定一种工作负载类型(例如 statelessstatefuljobcronjobdaemonsetstatic-pod)。要向微服务添加多种工作负载类型(例如两个 stateless(即 Deployment)),请执行以下操作

---
spec:
- name: app-deployment-1
  type: ucf.k8s.app.deployment
  parameters:
    apptype: stateless
...
---
spec:
- name: app-deployment-2
  type: ucf.k8s.app.deployment
  parameters:
    apptype: stateless
...

使用容器构建器配置

对于使用 容器构建 选项来构建容器以及微服务,请修改 ucf.k8s.containerucf.k8s.initcontainer 组件的 image 参数,以指定容器构建器配置文件路径。路径相对于 manifest.yaml 文件。例如

spec:
- name: myservice-init-container
  type: ucf.k8s.initcontainer
  parameters:
    image:
      config_path: containers/init-container.yaml
    ...
- name: myservice-container
  type: ucf.k8s.container
  parameters:
    image:
      config_path: containers/app-container.yaml
    ...

模板容器构建器配置文件在 containers/cb_config.yaml 生成。必须至少进行以下更改才能使配置正常工作。

  • 更新 base_image

  • 更新 local_copy_filesstage_copy_files 或完全删除它们

  • 更新 http_archives 或完全删除

  • docker_build 下更新 image_name 到将要上传镜像的位置。

构建微服务

一旦微服务构建器工具的输入准备就绪,就可以使用以下命令构建微服务

$ ucf_ms_builder_cli service build -d <msbuilder-input-dir>
$ ucf_ms_builder_cli service build -d myservice/
2022-12-05 14:54:13,927 - Registry - INFO - Building: myservice/
2022-12-05 14:54:15,943 - MsBuilder - INFO - Helm chart generated in myservice/output/helm
2022-12-05 14:54:15,962 - MsBuilder - INFO - MS spec generated in myservice/output/msspec
2022-12-05 14:54:17,034 - MsBuilder - WARNING - Mandatory compliance checks failed. Check myservice/output/compliance_test_logs.txt for more information
2022-12-05 14:54:17,176 - MsBuilder - INFO - MS spec generated in myservice/output/msspec
2022-12-05 14:54:17,185 - MsBuilder - INFO - Building test application 'dev-params1'
2022-12-05 14:54:17,327 - MsBuilder - INFO - Syncing any missing service versions to cache...
2022-12-05 14:54:17,329 - MsBuilder - INFO - Validating application ...
2022-12-05 14:54:17,335 - MsBuilder - INFO - Building application myservice-dev-params1-0.0.1 ...
2022-12-05 14:54:17,671 - MsBuilder - INFO - Application compliance report generated at myservice/output/tests/dev-params1/compliance_report.json
2022-12-05 14:54:17,758 - MsBuilder - INFO - Application Helm Chart generated in myservice/output/tests/dev-params1
2022-12-05 14:54:17,759 - MsBuilder - INFO - Tests generated in myservice/output/tests
2022-12-05 14:54:17,902 - Registry - INFO - Generating service helm chart package...
2022-12-05 14:54:17,993 - Registry - INFO - Generating test helm chart packages...
2022-12-05 14:54:18,152 - MsBuilder - INFO - Added microservice 'ucf.svc.myservice:0.0.1' to local repository

如果使用 容器构建 选项,则必须添加额外的参数 -t <target-file>

$ ucf_ms_builder_cli service build -d myservice/ -t myservice/target_x86_64.yaml

示例目标文件 <msbuilder-input-dir>/target_x86_64.yaml 及其以下内容作为模板微服务生成的一部分添加

---
platform:
  arch: x86_64
  os: linux
  distribution: ubuntu_22.04
compute:
  cuda: 11.8
  tensorrt: 8.5.1
  cudnn: 8.6.0
  deepstream: 6.2
  triton: null
  vpi: 2.1.6

如果需要,可以使用以下命令手动上传工具构建的容器镜像

.. code-block:: text

$ docker images # 列出所有镜像并找到使用工具构建的镜像 $ docker push <image>

注意

如果镜像在本地 docker 缓存中,则某些 Kubernetes 配置将无法拉取镜像,因为 Kubernetes 可能有自己的容器运行时实例正在运行,并且不使用本地 docker 缓存。在这种情况下,必须将容器镜像推送到 Kubernetes 可以从中拉取镜像的容器注册表中。如果需要指向新的存储库,则必须在 manifest 文件中进行相应的更改。当使用 Microk8s 时,可以使用其内置注册表:https://microk8s.io/docs/registry-built-in

构建输出

构建微服务会根据用例生成以下输出

  • 微服务的 UCS 微服务规范

  • Helm Chart - 适用于 预构建容器镜像容器构建 用例

  • 容器镜像 - 适用于 容器构建 用例

  • 测试应用程序 Helm Chart - 适用于 manifest.yaml 中提到的每个测试

  • 微服务的 合规性报告

  • 合规性检查日志<msbuilder-input-dir>/output/compliance_test_logs.txt 生成

一旦微服务成功构建,它将自动添加到本地存储库,并准备好在 UCS 应用程序中使用。

可以使用 查看微服务信息 查看有关构建的微服务的信息。

有关合规性的更多信息,请参阅 UCS 微服务合规性。微服务开发人员可以参考 <msbuilder-input-dir>/output/compliance_test_logs.txt 中的日志文件,了解任何合规性失败的原因。