容器化Kubernetes的Node.js REST API

时间:2020-01-09 10:34:23  来源:igfitidea点击:

说明

在本教程中,我们将学习如何为Express REST API构建Node.js Docker镜像,并将其部署到Kubernetes。我们还将学习如何安全地存储敏感的后端凭据,并远离应用程序源代码。

1构建Express REST API

以下内容将向我们展示如何基于Chris Sevilleja编写的"使用Node和Express 4构建RESTful API"来构建Express REST API。该应用程序的目的是演示如何在Kubernetes中构建和部署Express应用程序Docker镜像

最重要的是,我们将学习如何正确处理环境设置,例如数据库凭据。

在项目目录中,创建一个package.json文件。本教程将使用以下内容,它将安装Express,Body Parser和Mongoose的软件包。

// package.json

{
   "name": "express-api",
   "version": "1.0.0",
   "description": "An example Node.js Express API",
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "Hyman@localhost",
   "license": "ISC",
   "dependencies": {
     "body-parser": "^1.19.0",
     "express": "^4.17.1",
     "mongoose": "^5.5.11"
   }
 }

使用NPM安装express-api的依赖项

npm install

在同一目录中创建一个名为config.js的文件。该文件将包含我们所有应用程序的环境配置。

// config.js

export function = {
  app: {
    port: process.env.PORT || 3000,
  },
  db: {
    username: process.env.DB_USERNAME || '',
    password: process.env.DB_PASSWORD || '',
    host: process.env.DB_HOST || '',
    database: expressapi
  } 
}

请注意,大多数值是通过环境变量设置的。这样做是为了使应用程序与每种环境完全脱钩,从而使我们可以在任何地方部署应用程序。

然后分别由Kubernetes Secrets或者Kubernetes ConfigMaps设置这些值,分别用于敏感和不敏感设置。例如,数据库密码应存储为机密,而数据库主机可以存储在configMap中。

创建路线

const express = require('express');
const book   = require('./bookController');
const router = express.Router();

router.use('/book', book);

module.export = router;

建立模型

// bookModel.js

const mongoose = require('mongoose');

var bookSchema = mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  published: {
    type: Date
  }
});

var Book = module.exports = mongoose.model('book', bookSchema);

创建一个控制器

// bookController.js

Book = require('./bookModel');

exports.index = function (req, res) {
  Book.get(function (err, books) {
    if (err) {
      res.json({
        status: "error",
        message: err
      });
    }
    res.json({
      status: "Success"
      data: books
    });
  });
};

现在创建index.js文件。

// index.js

const express    = require('express');
const bodyParser = require('body-parser');
const routes     = require('./routes');
const config     = require('./config');

const app        = express();

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

router.get('/', function(req, res) {
     res.json({ message: 'hooray! welcome to our api!' });   
});
 
app.use('/api', routes);

app.listen(config.app.port);
console.log('Express API running on port ' + config.app.port);

2构建Docker镜像

本教程中构建的镜像将基于Node的官方文档来进行dockerizing node.js应用程序。

在项目目录中,创建一个名为Dockerfile的新文件。我们构建的Docker镜像将基于官方的Node镜像。

FROM node:12

RUN apt update \
    && apt update upgrade -y
RUN apt install -y \
    nginx

WORKDIR /app

COPY app/package.json /app/package.json
COPY app/index.js /app/index.js
COPY app/config.js /app/config.js

COPY nginx/nginx.conf /etc/nginx.conf

RUN npm install
CMD ['startup.sh']

3在Kubernetes ConfigMap中存储配置

ConfigMap是Kubernetes中的资源类型,可用于存储容器的配置。然后可以将配置作为环境变量或者文件挂载,这最适合应用程序。

例如,该配置可以表示为Java Springboot应用程序的属性文件,也可以表示为Node.js应用程序的环境变量。

为Node.js API创建一个新的清单,名为expressapi-configmap.yml。

触摸expressapi-configmap.yml

向其添加以下配置。这些将用于我们API中的数据库主机和数据库名称。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: expressapi-config
data:
  mongodb_host: db.prod.theitroad.com
  mongodb_database: expressapi_prod

现在,使用kubectl apply命令在Kubernetes集群中创建ConfigMap资源。如果资源已经存在,将对其进行更新。

kubectl apply -f expressapi-configmap.yml

在Kubernetes秘密中存储3个秘密

与ConfigMaps不同,机密用于存储敏感信息。这是我们将用于存储凭据,ssh密钥,TLS密钥和证书以及应用程序使用的任何其他敏感数据的资源类型。

机密存储为Base64编码的字符串。为了存储我们的数据库用户名和密码,我们需要将其转换为base64. 使用以下命令执行此操作。

echo -n 'db-user' | base64
ZGItdXNlcg==
echo -n 'super-secret-password' | base64
c3VwZXItc2VjcmV0LXBhc3N3b3Jk

记下两个命令输出的base64编码的字符串。这些值将被插入Express API的Kubernetes机密中。

创建一个名为expressapi-secrets.yml的新文件

触摸expressapi-secrets.yml

将以下内容添加到文件中。请记住,对db_username和db_password键使用我们自己的base64编码的字符串。

---
apiVersion: v1
kind: Secret
metadata:
  name: expressapi-secret
data:
  mongodb_username: ZGItdXNlcg==
  mongodb_password: c3VwZXItc2VjcmV0LXBhc3N3b3Jk

使用kubectl apply命令在Kubernetes中创建秘密资源。

kubectl apply -f expressapi-secrets.yml

Base64没有加密,因此我们应该将此文件存储在安全的地方。或者更好的是,一起删除键值。这使我们可以保留键名,并提供一种以后可以轻松更新值的机制。

4为Node.js API创建部署

部署是一种扩展和更新无状态容器Pod的机制。由于我们的Express API不会维护状态,因此我们为其创建了一个部署资源,该资源随后将生成一个copySetSet资源。

副本集是控制器控制窗格副本的工具,它可以替换发生故障的窗格,放大或者缩小窗格。

创建一个名为expressapi-deployment.js的新文件

touch expressapi-deployment.js

向其中添加以下内容。该部署清单将创建Express API的3个副本。这些副本将基于本教程前面创建的theitroad / expressapi:1.0.0 Docker镜像。

apiVersion: v1
kind: Deployment
metadata:
  name: expressapi
  labels:
    app: expressapi
spec:
  replicas: 3
  selector:
    matchLabels:
      app: expressapi
  template:
    metadata:
      labels:
        app: expressapi
    spec:
      containers:
        - name: expressapi
          image: theitroad/expressapi:1.0.0
          env:
            - name: MONGODB_HOST
              valueFrom:
                configMapKeyRef:
                  name: expressapi-configmap
                  key: mongodb_host
            - name: MONGODB_DATABASE
              valueFrom:
                configMapKeyRef:
                  name: expressapi-configmap
                  key: mongodb_database
            - name: MONGODB_USER
              valueFrom:
                secretKeyRef:
                  name: expressapi-secret
                  key: mongodb_username
            - name: MONGODB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: expressapi-secret
                  key: mongodb_password

请注意然后env键下的值。从ConfigMap中获取的值由configMapKeyRef键引用,而秘密由secretKeyRef键引用。

我们从ConfigMap中获取数据库连接信息,并从Secret中获取数据库凭据。这样,任何新创建的Express API pod都可以连接到Mongo数据库。

5公开Node.js部署

要将Express API公开,我们需要为其创建服务资源。我们创建服务资源是因为Pod是短暂的,整个状态都是临时的。吊舱一经销毁,其IP地址即被吊销,新的吊舱将获得另一个地址。

服务是静态的,不是短暂的。因此,它们非常适合用作端点。 Pod通过标签添加到服务资源,该标签是使用服务上的选择器和Pod清单上的元数据名称设置的。

创建一个名为expressapi-service.yml的新文件。

触摸expressapi-service.yml

向其中添加以下内容。

apiVersion: v1
kind: Service
metadata:
  name: expressapi-service
spec:
  type: LoadBalancer
  selector:
    app: expressapi
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000

我们为我们的服务分配了LoadBalancer类型,这将导致Kubernetes正在运行的云平台上提供计算负载平衡器。然后,平衡器将在清单中设置的协议上公开端口。

选择器键被分配了expressapi,它映射到Deployment元数据名称值。只有与该标签匹配的豆荚才会添加到服务上。

使用kubetcl apply命令创建新的服务资源。

kubectl apply -f expressapi-service.yml

6扩展Node.js API