(四)将容器部署到Azure上的Kubernetes

目录

构建Node.js应用程序

Docker容器

使用Azure容器注册表

部署到Kubernetes

下一步


上一篇文章中,我们研究了如何将我们的云原生应用程序扩展到Azure Kubernetes服务,并让Azure DevOps同时自动构建和部署应用程序和基础架构。

在本文中,我们通过构建一个容器化的node.js应用程序组件来更进一步。我们首先为我们的Functions构建一个简单的Node.js前端,然后使用Docker将应用程序容器化并将其放入我们自己的私有容器注册表中。最后,我们将容器添加到Kubernetes集群中的pod。

在本文结束时,我们会将无服务器Azure Functions和更传统的Node.js应用程序的应用程序组件捆绑到一个代码存储库中,并使用Azure DevOps进行部署。

构建Node.js应用程序

在开始使用Docker构建容器之前,让我们使用Express.js框架构建一个简单的Node.js前端应用程序。在这个项目中,我们只是构建了一个简单的页面来从我们的函数中检索任务列表,但您可以随时进一步扩展它。

首先,我们在代码库中创建一个名为NodeServer的新文件夹。在这个文件夹中,我们运行以下命令来设置我们的应用程序:

  • npm init
  • npm install express
  • npm install axios

这三个命令初始化我们的应用程序以及安装我们需要托管网页 (Express)和从我们的API(Axios)检索数据的两个包。完成后,创建一个名为app.js的新文件并输入以下代码:

const express = require('express')
const axios = require('axios').default;
const app = express()
const port = 3001

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

app.get('/', function (req, res) {

    try {
        const response = axios({
            method: 'get',
            url: 'https://tsfunctionexample.azurewebsites.net/api/ListTasks',
            data: { username: 'testuser' }
        }).then(function (response){
            var returnPage = "<html><body><h1>Task List</h1>";
            if(response.status = '200'){
                returnPage += '<table style="width:100%"><tr><th>Username</th><th>Task ID</th><th>Task Name</th><th>Due Date</th></tr>';
                response.data.results.forEach(element => {
                    returnPage += '<tr><td>' + element.username + '</td><td>' + element.taskID + '</td><td>' + element.name + '</td><td>' + element.dueDate + '</td></tr>';
                });
                returnPage += '</table>';
            } else {
                returnPage += '<p>Error - No Tasks Found</p>';
            }
            returnPage += '</body></html>';
            console.log(response);
            res.send(returnPage);
        });
    } catch (error) {
        console.error(error);
    }
});

如果我们简单地逐步执行此代码,首先我们加载Express并启动它侦听端口3001。然后我们使用该.get()函数侦听URL的根或主页以获取get请求。收到此信息后,我们使用Axios调用我们的List tasks API(我们的托管在https://tsfunctionexample.azurewebsites.net/api/ListTasks),使用之前的用户名“testuser”作为主体有效负载。

当响应返回时,我们遍历列表中的所有结果,将它们格式化为一个简单的HTML表,然后返回它们。如果我们保存这个文件,现在尝试使用命令运行我们的代码node app.js,我们会看到从我们的函数返回的任务列表。

值得注意的是,如果您有一段时间没有使用您的功能,此页面可能需要一些时间才能返回。这是因为函数在一段时间未使用时需要时间来预热。

从这里,我们可以添加用于发布、删除和获取特定任务的附加功能,但是,让我们看看如何将这个应用程序容器化。

Docker容器

Docker使您能够将应用程序及其所有依赖项打包到一个容器中。这包括操作系统的基本版本(通常是Linux)、任何依赖项(例如Node和npm)、您的应用程序及其所需的库。

容器是应用程序的运行实例,蓝图是构建容器的配置。让我们为我们当前的应用程序构建一个蓝图,并在本地运行容器进行测试。确保您已安装并准备好Docker

首先,创建一个名为Dockerfile的新文件来制作我们的容器蓝图。打开此文件并使用以下代码:

FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3001
CMD [ "node", "app.js"]

大多数容器蓝图应该非常简单并遵循类似的模式。第一行定义了我们正在构建的源镜像,在本例中是Node 14版镜像。

接下来,我们指定在此镜像中的何处可以找到我们的应用程序代码。因为这个源镜像同时包含Node和npm,我们可以通过复制我们现有的包文件并运行npm install来安装我们所有的依赖项。

接下来,我们通过将当前本地目录复制到当前工作目录来复制我们的应用程序代码。

最后,我们允许容器打开3001端口并使用CMD运行Node并指定我们的apps.js作为参数。

在我们构建和运行我们的Docker镜像之前,我们还应该创建一个忽略文件,这样我们的本地调试和包就不会被复制。为此,请创建文件.dockerignore和以下内容:

node_modules
npm-debug.log

完成后,我们现在使用以下命令构 Docker镜像

docker build -t <username>/node-server .

Docker遍历并编译所有必需的组件并将其保存到本地注册表。您可以使用命令docker images查看本地注册表中的所有镜像

 

一旦我们在本地注册表中有我们的Docker镜像,我们现在启动一个容器来使用以下命令运行它:

docker run -p 80:3001 <username>/node-server

此命令使用-d repository/image-name运行镜像,但还指定应使用参数-p将来自端口80的任何流量重定向到容器上的端口3001 。当我们现在运行命令docker ps时,我们应该看到我们的容器在转发端口的情况下运行。

当我们打开Web浏览器访问http://localhost时,应该会显示我们的任务管理器应用程序。

使用Azure容器注册表

因此,我们使用Docker将我们的应用程序容器化,容器镜像位于我们的本地注册表中,Docker可以在本地构建和运行容器。现在让我们构建容器镜像并将其存储在Azure容器注册表中,以便AKS可以托管容器。首先,我们需要通过打开Azure门户、转到命令shell并键入以下命令来创建容器注册表:

az acr create --resource-group TSFunctionTutorial --name tsfunctionRegistry --sku Basic

一旦我们的容器注册表存在,我们现在可以向我们的基础设施管道添加另一个步骤来构建我们的容器镜像。

为了访问Docker注册表,我们通过在Azure DevOps中打开项目、选择项目设置并打开服务连接来创建额外的服务主体。

单击新建服务连接,从连接选项中选择Docker注册表,然后从订阅中找到Azure容器注册表。

设置服务主体后,我们打开管道并编辑我们在上一篇文章中创建的任务管理器管道。

在Deploy Infrastructure阶段下,在Deploy AKS Cluster作业下使用以下代码添加新作业:

- stage: BuildContainer
  displayName: Build Container
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: Docker@2
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: tsfunctionnodeserver
        dockerfile: '**/Dockerfile'
        containerRegistry: TSFunctionRegistry

此作业是使用该Docker@2任务构建和推送我们的镜像的单个步骤。此处的关键输入是Docker镜像(存储库)的名称、Docker文件的位置以及我们创建的容器注册表的名称。保存并提交更改,然后管道运行以构建和部署应用程序组件。

完成后,当我们转到Azure门户中的容器注册表并查看存储库时,我们应该会看到等待部署的docker镜像

部署到Kubernetes

现在我们的Docker镜像已经构建并在注册表中,我们可以设置一个选项来将我们的容器部署到集群。

首先,我们需要为我们的集群创建另一个服务连接。

转到Project Settings,然后转到Service Connections,然后创建一个到Kubernetes的新服务连接。选择Azure订阅选项、AKS群集和默认命名空间。我们将服务连接称为TSFunctionCluster,稍后我们将使用它。

现在我们已经创建了一个服务主体,我们需要创建清单文件来部署我们的容器。

使用以下代码创建一个名为manifests的新目录和一个名为deployment.yaml的新文件:

apiVersion : apps/v1
kind: Deployment
metadata:
  name: tsfunctionnodeserver 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tsfunctionnodeserver
  template:
    metadata:
      labels:
        app: tsfunctionnodeserver 
    spec:
      containers:
        - name: tsfunctionnodeserver 
          image: tsfunctionregistry.azurecr.io/tsfunctionnodeserver
          ports:
          - containerPort: 80

这将部署我们的容器,对其可以消耗的资源没有真正的限制,并在端口80上打开。 接下来,我们使用以下代码创建一个service.yaml文件:

apiVersion: v1
kind: Service
metadata:
    name: tsfunctionnodeserver
spec:
    type: LoadBalancer
    ports:
    - port: 80
    selector:
        app: tsfunctionnodeserver

该组件将网络添加到我们的容器中,以便我们可以从集群外部访问它。

我们还需要向我们的管道添加另外两个阶段来配置Kubernetes密钥并从ACR中提取镜像。在BuildContainer阶段之后将以下代码添加到azure-pipelines.yaml文件中:

- stage: DeployContainer
  displayName: Deploy Container
  jobs:
  - job: Deploy
    displayName: Deploy Container
    pool:
      vmImage:  $(vmImageName)
    steps:
    - task: KubernetesManifest@0
      inputs:
        action: 'createSecret'
        kubernetesServiceConnection: 'TSFunctionCluster'
        namespace: 'default'
        secretType: 'dockerRegistry'
        secretName: 'tsfunction-access'
        dockerRegistryEndpoint: 'TSFunctionRegistry'
    - task: KubernetesManifest@0
      inputs:
        action: 'deploy'
        kubernetesServiceConnection: 'TSFunctionCluster'
        namespace: 'default'
        manifests: |
                $(Build.SourcesDirectory)/manifests/deployment.yaml
                $(Build.SourcesDirectory)/manifests/service.yaml
        containers: 'tsfunctionnodeserver'
        imagePullSecrets: 'tsfunction-access'

此阶段的第一个任务是创建从存储库中提取容器镜像所需的密钥。它使用Docker注册服务连接和Kubernetes服务连接进行链接访问。

第二个任务使用两个清单文件将镜像部署到集群上的容器中。

保存这些文件并签入您的更改以运行管道。部署管道后,当您在Azure门户中打开集群时,单击工作负载,然后单击Pod,您应该会看到一个以tsfunctionnodeserver开头的Pod。当您单击此pod并复制IP地址时,您应该能够使用它来访问您的任务管理前端应用程序。

下一步

通过本系列,我们使用无服务器Azure Functions和容器化Node.js应用程序组件的组合构建了一个简单的任务管理应用程序。我们所有的代码、基础结构配置和管道配置都存储在Git存储库中,作为Azure DevOps的一部分。

您可以通过使用单页应用程序(SPA)构建前端、添加安全性和完全自动化部署来进一步开发此应用程序。通读本系列文章并了解Azure与其他云工具结合使用时的功能后,您现在可以构建和部署自己独特的无服务器应用程序。

了解有关在Azure上使用Kubernetes的更多信息,请浏览Kubernetes Bundle |Microsoft AzureAzure上的动手Kubernetes |微软Azure

Deploying Containers to Kubernetes on Azure - CodeProject

Guess you like

Origin blog.csdn.net/mzl87/article/details/121162900