容器化Kubernetes的Node.js REST API
说明
在本教程中,我们将学习如何为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

