将语言检测容器部署到 Azure Kubernetes 服务

了解如何部署语言检测容器。 此过程说明如何创建本地 Docker 容器,将容器推送到自己的专用容器注册表,在 Kubernetes 群集中运行容器,以及在 Web 浏览器中对其进行测试。

先决条件

此过程要求必须在本地安装和运行多个工具。

  • 使用 Azure 订阅。 如果没有 Azure 订阅,可在开始前创建一个试用帐户
  • 适用于操作系统的 Git,以便克隆此过程中使用的示例
  • Azure CLI
  • Docker 引擎并验证 Docker CLI 是否可在控制台窗口中工作。
  • kubectl
  • 具有适当定价层的 Azure 资源。 并非所有定价层都适用于此容器:
    • 仅具有 F0 或标准定价层的语言资源。
    • 具有 S0 定价层的 Azure AI 服务资源

运行示例

此过程加载并运行 Azure AI 服务容器示例以进行语言检测。 该示例有两个容器,一个用于客户端应用程序,另一个用于 Azure AI 服务容器。 我们会将这两个映像都推送到 Azure 容器注册表。 这些映像推送到自己的注册表后,请创建 Azure Kubernetes 服务来访问这些映像和运行容器。 容器在运行时,请使用 kubectl CLI,监视容器性能。 使用 HTTP 请求访问客户端应用程序,并查看结果。

A diagram showing the conceptual idea of running a container on Kubernetes

示例容器

该示例有两个容器映像,一个用于前端网站。 第二个映像是可返回检测到的文本语言(区域性)的语言检测容器。 完成后,这两个容器都可以从外部 IP 进行访问。

语言前端容器

此网站相当于自己的进行语言检测终结点的请求的客户端应用程序。 完成此过程后,使用 http://<external-IP>/<text-to-analyze> 在浏览器中访问网站容器,即可获得检测到的字符串语言。 此 URL 的一个示例为 http://132.12.23.255/helloworld!。 浏览器中的结果为 English

语言容器

在此特定过程中,任何外部访问请求都可以访问语言检测容器。 容器未以任何方式更改,因此标准的特定于的 Azure AI 服务容器的语言检测 API 可供使用。

对于此容器,该 API 是进行语言检测的 POST 请求。 与所有 Azure AI 容器一样,你可以从该容器的托管 Swagger 信息 (http://<external-IP>:5000/swagger/index.html) 了解有关该容器的详细信息。

端口 5000 是用于 Azure AI 容器的默认端口。

创建 Azure 容器注册表服务

若要将容器部署到 Azure Kubernetes 服务,需要能够访问容器映像。 创建自己的 Azure 容器注册表服务以托管映像。

  1. 登录 Azure CLI

    az login
    
  2. 创建名为 cogserv-container-rg 的资源组来保存此过程中创建的每一个资源。

    az group create --name cogserv-container-rg --location chinanorth
    
  3. 使用名字后加 registry 这一格式(如 pattyregistry)创建自己的 Azure 容器注册表。 请勿在名称中使用短划线或下划线字符。

    az acr create --resource-group cogserv-container-rg --name pattyregistry --sku Basic
    

    保存结果,以获取 loginServer 属性。 这将是托管容器地址的一部分,稍后将在 language.yml 文件中使用。

    az acr create --resource-group cogserv-container-rg --name pattyregistry --sku Basic
    
    {
        "adminUserEnabled": false,
        "creationDate": "2019-01-02T23:49:53.783549+00:00",
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/cogserv-container-rg/providers/Microsoft.ContainerRegistry/registries/pattyregistry",
        "location": "chinanorth",
        "loginServer": "pattyregistry.azurecr.io",
        "name": "pattyregistry",
        "provisioningState": "Succeeded",
        "resourceGroup": "cogserv-container-rg",
        "sku": {
            "name": "Basic",
            "tier": "Basic"
        },
        "status": null,
        "storageAccount": null,
        "tags": {},
        "type": "Microsoft.ContainerRegistry/registries"
    }
    
  4. 登录容器注册表。 需登录后才能将映像推送到注册表。

    az acr login --name pattyregistry
    

获取网站 Docker 映像

  1. 此过程中使用的示例代码位于 Azure AI 容器示例存储库中。 克隆存储库以生成示例的本地副本。

    git clone https://github.com/Azure-Samples/cognitive-services-containers-samples
    

    如果存储库已在本地计算机上,请在 \dotnet\Language\FrontendService 目录中查找网站。 该网站用作客户端应用程序,可调用语言检测容器中托管的语言检测 API。

  2. 为网站生成 Docker 映像。 运行以下命令时,确保控制台位于 Dockerfile 所在的\FrontendService 目录中:

    docker build -t language-frontend -t pattiyregistry.azurecr.io/language-frontend:v1 .
    

    若要在容器注册表上跟踪版本,请添加具有版本格式的标记,如 v1

  3. 将映像推送到容器注册表。 这可能需要几分钟的时间。

    docker push pattyregistry.azurecr.io/language-frontend:v1
    

    如果收到 unauthorized: authentication required 错误,请使用 az acr login --name <your-container-registry-name> 命令登录。

    该过程完成后,结果应类似于以下内容:

    The push refers to repository [pattyregistry.azurecr.io/language-frontend]
    82ff52ee6c73: Pushed
    07599c047227: Pushed
    816caf41a9a1: Pushed
    2924be3aed17: Pushed
    45b83a23806f: Pushed
    ef68f6734aa4: Pushed
    v1: digest: sha256:31930445deee181605c0cde53dab5a104528dc1ff57e5b3b34324f0d8a0eb286 size: 1580
    

获取语言检测 Docker 映像

  1. 将 Docker 映像的最新版本拉取到本地计算机上。 这可能需要几分钟的时间。 如果有此容器的较新版本,请将值从 1.1.006770001-amd64-preview 更改到较新版本。

    docker pull mcr.microsoft.com/azure-cognitive-services/language:1.1.006770001-amd64-preview
    
  2. 使用容器注册表标记图像。 查找最新版本,如果有更新的版本,请替换版本 1.1.006770001-amd64-preview

    docker tag mcr.microsoft.com/azure-cognitive-services/language pattiyregistry.azurecr.io/language:1.1.006770001-amd64-preview
    
  3. 将映像推送到容器注册表。 这可能需要几分钟的时间。

    docker push pattyregistry.azurecr.io/language:1.1.006770001-amd64-preview
    

获取容器注册表凭据

需要执行以下步骤来获取所需信息,以便将容器注册表与稍后此过程中要创建的 Azure Kubernetes 服务进行连接。

  1. 创建服务主体。

    az ad sp create-for-rbac
    

    为步骤 3 中代理人参数 <appId> 的保存结果 appId 值。 为下一节中 client-secret 参数 <client-secret> 保存 password

    {
      "appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "displayName": "azure-cli-2018-12-31-18-39-32",
      "name": "http://azure-cli-2018-12-31-18-39-32",
      "password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
    
  2. 获取容器注册表 ID。

    az acr show --resource-group cogserv-container-rg --name pattyregistry --query "id" --o table
    

    为下一步中范围参数值 <acrId> 保存输出。 输出如下所示:

    /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/cogserv-container-rg/providers/Microsoft.ContainerRegistry/registries/pattyregistry
    

    为本节中步骤 3 保存完整值。

  3. 若要授予 AKS 群集使用容器注册表中存储的映像的适当访问权限,请创建角色分配。 将 <appId><acrId> 替换为在前两个步骤中收集的值。

    az role assignment create --assignee <appId> --scope <acrId> --role Reader
    

创建 Azure Kubernetes 服务

  1. 创建 Kubernetes 群集。 所有参数值都来自前一部分,name 参数除外。 选择一个名称,指明其创建者及其用途,例如 patty-kube

    az aks create --resource-group cogserv-container-rg --name patty-kube --node-count 2  --service-principal <appId>  --client-secret <client-secret>  --generate-ssh-keys
    

    这个步骤可能需要几分钟的时间。 结果为:

    {
      "aadProfile": null,
      "addonProfiles": null,
      "agentPoolProfiles": [
        {
          "count": 2,
          "dnsPrefix": null,
          "fqdn": null,
          "maxPods": 110,
          "name": "nodepool1",
          "osDiskSizeGb": 30,
          "osType": "Linux",
          "ports": null,
          "storageProfile": "ManagedDisks",
          "vmSize": "Standard_DS1_v2",
          "vnetSubnetId": null
        }
      ],
      "dnsPrefix": "patty-kube--65a101",
      "enableRbac": true,
      "fqdn": "patty-kube--65a101-341f1f54.hcp.chinanorth.azmk8s.io",
      "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/cogserv-container-rg/providers/Microsoft.ContainerService/managedClusters/patty-kube",
      "kubernetesVersion": "1.9.11",
      "linuxProfile": {
        "adminUsername": "azureuser",
        "ssh": {
          "publicKeys": [
            {
              "keyData": "ssh-rsa AAAAB3NzaC...ohR2d81mFC
            }
          ]
        }
      },
      "location": "chinanorth",
      "name": "patty-kube",
      "networkProfile": {
        "dnsServiceIp": "10.0.0.10",
        "dockerBridgeCidr": "172.17.0.1/16",
        "networkPlugin": "kubenet",
        "networkPolicy": null,
        "podCidr": "10.244.0.0/16",
        "serviceCidr": "10.0.0.0/16"
      },
      "nodeResourceGroup": "MC_patty_chinanorth",
      "provisioningState": "Succeeded",
      "resourceGroup": "cogserv-container-rg",
      "servicePrincipalProfile": {
        "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "keyVaultSecretRef": null,
        "secret": null
      },
      "tags": null,
      "type": "Microsoft.ContainerService/ManagedClusters"
    }
    

    服务已创建,但还没有网站容器或语言检测容器。

  2. 获取 Kubernetes 群集的凭据。

    az aks get-credentials --resource-group cogserv-container-rg --name patty-kube
    

将业务流程定义加载到 Kubernetes 服务中

本部分使用 kubectl CLI 与 Azure Kubernetes 服务通信

  1. 在加载业务流程定义之前,请检查 kubectl 是否有权访问节点

    kubectl get nodes
    

    响应如下所示:

    NAME                       STATUS    ROLES     AGE       VERSION
    aks-nodepool1-13756812-0   Ready     agent     6m        v1.9.11
    aks-nodepool1-13756812-1   Ready     agent     6m        v1.9.11
    
  2. 复制以下文件并将其命名为 language.yml。 该文件含有一个 service 部分和一个 deployment 部分,各自用于两种容器类型,即 language-frontend 网站容器和 language 检测容器。

# A service which exposes the .net frontend app container through a dependable hostname: http://language-frontend:5000
apiVersion: v1
kind: Service
metadata:
  name: language-frontend
  labels:
    run: language-frontend
spec:
  selector:
    app: language-frontend
  type: LoadBalancer
  ports:
  - name: front
    port: 80
    targetPort: 80
    protocol: TCP
---
# A deployment declaratively indicating how many instances of the .net frontend app container we want up
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: language-frontend
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: language-frontend
    spec:
      containers:
      - name: language-frontend
        image: # < URI of the Frontend App image >
        ports:
        - name: public-port
          containerPort: 80
        livenessProbe:
          httpGet:
            path: /status
            port: public-port
          initialDelaySeconds: 30
          timeoutSeconds: 1
          periodSeconds: 10
      imagePullSecrets:
        - name: # < Name of the registry secret providing access to the frontend image >
      automountServiceAccountToken: false
---
# A service which exposes the cognitive-service containers through a dependable hostname: http://language:5000
apiVersion: v1
kind: Service
metadata:
  name: language
  labels:
    run: language
spec:
  selector:
    app: language
  type: LoadBalancer
  ports:
  - name: language
    port: 5000
    targetPort: 5000
    protocol: TCP
---
# A deployment declaratively indicating how many instances of the cognitive-service container we want up
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: language
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: language
    spec:
      containers:
      - name: language
        image: # < URI of the Language Image >
        ports:
        - name: public-port
          containerPort: 5000
        livenessProbe:
          httpGet:
            path: /status
            port: public-port
          initialDelaySeconds: 30
          timeoutSeconds: 1
          periodSeconds: 10
        args:
            - "eula=accept"
            - "apikey=" # < API Key for the Language Service >
            - "billing=" # < Language billing endpoint URI >

      imagePullSecrets:
        - name: # < Name of the registry secret providing access to the Language image >

      automountServiceAccountToken: false
  1. 根据下表更改 language.yml 的语言前端部署行,以添加自己的容器注册表映像名称、客户端密码和语言服务设置。

    语言前端部署设置 用途
    第 32 行
    image 属性
    容器注册表中的前端映像的映像位置
    <container-registry-name>.azurecr.io/language-frontend:v1
    第 44 行
    name 属性
    映像的容器注册表机密,在上一节中称为 <client-secret>
  2. 根据下表更改 language.yml 的语言部署行,以添加自己的容器注册表映像名、客户端密码和语言服务设置。

    语言部署设置 用途
    第 78 行
    image 属性
    容器注册表中语言映像的映像位置
    <container-registry-name>.azurecr.io/language:1.1.006770001-amd64-preview
    第 95 行
    name 属性
    映像的容器注册表机密,在上一节中称为 <client-secret>
    第 91 行
    apiKey 属性
    语言服务资源密钥
    第 92 行
    billing 属性
    语言服务资源的计费终结点。
    https://api.cognitive.azure.cn/text/analytics/v2.1

    由于 apiKey 和账单终结点已设置为 Kubernetes 业务流程定义的一部分,因此网站容器无需了解这些内容或将其作为请求的一部分传递。 网站容器按其业务流程协调程序名称 language 引用语言检测容器。

  3. 从创建和保存 language.yml 的文件夹中加载此示例的业务流程定义文件。

    kubectl apply -f language.yml
    

    响应为:

    service "language-frontend" created
    deployment.apps "language-frontend" created
    service "language" created
    deployment.apps "language" created
    

获取容器的外部 IP

对于这两个容器,请验证 language-frontendlanguage 服务是否正在运行,并获取外部 IP 地址。

kubectl get all
NAME                                     READY     STATUS    RESTARTS   AGE
pod/language-586849d8dc-7zvz5            1/1       Running   0          13h
pod/language-frontend-68b9969969-bz9bg   1/1       Running   1          13h

NAME                        TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
service/kubernetes          ClusterIP      10.0.0.1      <none>          443/TCP          14h
service/language            LoadBalancer   10.0.39.169   104.42.172.68   5000:30161/TCP   13h
service/language-frontend   LoadBalancer   10.0.42.136   104.42.37.219   80:30943/TCP     13h

NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/language            1         1         1            1           13h
deployment.extensions/language-frontend   1         1         1            1           13h

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/language-586849d8dc            1         1         1         13h
replicaset.extensions/language-frontend-68b9969969   1         1         1         13h

NAME                                DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/language            1         1         1            1           13h
deployment.apps/language-frontend   1         1         1            1           13h

NAME                                           DESIRED   CURRENT   READY     AGE
replicaset.apps/language-586849d8dc            1         1         1         13h
replicaset.apps/language-frontend-68b9969969   1         1         1         13h

如果服务的 EXTERNAL-IP 显示为挂起,请重新运行该命令,直到显示 IP 地址,然后再转到下一步。

测试语言检测容器

打开浏览器并导航到上一节中 language 容器的外部 IP:http://<external-ip>:5000/swagger/index.html。 可以使用 API 的 Try it 功能来测试语言检测终结点。

A screenshot showing the container's swagger documentation

测试客户端应用程序容器

使用以下格式将浏览器中的 URL 更改为 language-frontend 容器的外部 IP:http://<external-ip>/helloworldhelloworld 的英文区域性文本预测为 English

清理资源

群集操作完成后,请删除 Azure 资源组。

az group delete --name cogserv-container-rg

后续步骤

Azure AI 容器