使用 Node.js 和 Docker 构建高质量的微服务

2016-11-13 Frank 服务器

[TOC]

1. Nodejs快速部署

1.1 删除不用的镜像

docker rmi <Image ID>
docker rmi <name:tag>

1.2 拉取镜像,创建Dockerfile文件

docker pull alpine:edge
cd ~
mkdir docker_web_app
cd docker_web_app
vim Dockerfile

1.3 准备程序

两个文件package.json, app.js:

{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "Zhangpc <zhangpc@tenxcloud.com>",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.13.3"
}
}
// app.js
'use strict';

const express = require('express')

// Constants
const PORT = 8080

// App
const app = express()
app.get('/', function (req, res) {
res.send('Hello world\n')
})

app.listen(PORT)
console.log('Running on http://localhost:' + PORT)

1.4 编辑Dockerfile文件

# Dockerfile.alpine-mini
FROM index.tenxcloud.com/docker_library/alpine:edge

# Create app directory and bundle app source
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app

# Install node.js and app dependencies
RUN echo '@edge http://nl.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories \
&& apk update && apk upgrade \
&& apk add --no-cache nodejs-lts@edge \
&& npm install \
&& npm uninstall -g npm \
&& rm -rf /tmp/* \
&& rm -rf /root/.npm/

# Expose port
EXPOSE 8080

CMD [ "node", "app.js" ]

1.5 执行以下命令进行构建:

docker build -t frank/docker_web_app:alpine .

网络原因,如果构建失败了不妨再来一次。

1.6 运行

docker run -d --name hello -p 8081:8080 frank/docker_web_app:alpine

1.7 测试

curl localhost:8000

2. 使用 Kong 构建 API gateway

2.1 Docker 中运行 Kong

启动数据库容器,以 postgres 为例

docker run -d --name kong-database \
      -p 5432:5432 \
      -e "POSTGRES_USER=kong" \
      -e "POSTGRES_DB=kong" \
      postgres:9.4

启动 Kong

docker run -d --name kong \
      --link kong-database:kong-database \
      -e "KONG_DATABASE=postgres" \
      -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
      -e "KONG_PG_HOST=kong-database" \
      -p 8000:8000 \
      -p 8443:8443 \
      -p 8001:8001 \
      -p 7946:7946 \
      -p 7946:7946/udp \
      kong

检查 Kong 是否运行正常

Kong 启动以后,会监听 8000 和 8001 两个端口。其中 8001 作为 Admin API Server

curl http://127.0.0.1:8001

2.2 Kong 高可用

可以通过 Nginx 或者 Kubernetes 实现 Kong 高可用,开启高可用后,系统的典型构架如下:

使用 Nginx 实现高可用可参考以下脚本:

upstream backend {
ip_hash;
    server 192.168.1.1:8000;
    server 192.168.1.2:8000;
    server 192.168.1.3:8000;
    }
server {
listen  8000;
# ssl     on;
# ssl_certificate      /etc/nginx/conf.d/server.cert;
# ssl_certificate_key  /etc/nginx/conf.d/server.key;
location / {
    #设置主机头和客户端真实地址,以便服务器获取客户端真实IP
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #禁用缓存
    proxy_buffering off;
    #反向代理的地址
    proxy_pass https://backend;
}
location /status {
    stub_status on;
    auth_basic "NginxStatus";
}
}

2.3 Kong Plugin 使用举例

Kong 依赖于 Cassandra 或 PostgreSQL,但 Kong Server 自己维护 cache,只有 Plugin 需要使用额外的数据库,下面以 key-authentication 为例说明如何给 API 增加 Authentication:

准备

创建一个 hello world 服务(监听端口 8889),假设宿主机 IP 为 192.168.1.4。

docker run -d --name=hello -p 8889:80 index.tenxcloud.com/tenxcloud/hello-world

将 hello world API 添加到 Kong:(由于Kong运行在容器中,upstream_url 不能使用 localhost)。

curl -i -X POST \
    --url http://localhost:8001/apis/ \
    --data 'name=hello' \
    --data 'upstream_url=http://192.168.1.4:8889' \
    --data 'request_host=hello-world'

如果运行成功, 执行以下脚本,能够看到 Kong 的 Response 头信息和 hello world 页面。

curl -i -X GET \
    --url http://localhost:8000/ \
    --header 'Host: hello-world'

使用 APIKey 进行身份认证

为特定API 添加权限验证:

curl -X POST http://localhost:8000/apis/{api}/plugins \
--data "name=key-auth"

这里 {api} 必须是 API 的 ID 或 Name,这里以 hello 为例。

添加成功以后,可以执行以下脚本查看该 API 的插件:

curl -X GET http://localhost:8001/apis/hello/plugins

此时,我们再次运行以下脚本 ,会得到 401 Unauthorized 的结果:

root@ubuntu:~# curl -i -X GET \
--url http://localhost:8000/ \
--header 'Host: hello-world'
HTTP/1.1 401 Unauthorized
Date: Mon, 10 Oct 2016 07:56:54 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Server: kong/0.9.2
{"message":"No API key found in headers or querystring"}

增加 Consumer,并为Consumer 增加 apiToken

不管使用 Key 进行身份认证,还是实现 Client 粒度的限速,都需要一个 Consumer ID 。

Consumer 本质上与 用户 是一个概念。Consumer ID 与 API Token 配合使用,实现身份认证的功能;还可以与 Rate limiting 配合使用,实现对特定用户限速的功能。

Consumer 的相关操作参考 API 文档 Consumer Object(https://getkong.org/docs/0.9.x/admin-api/#consumer-object)。

增加名为 test 的 Consumer:

root@ubuntu:~# # add consumer "test"
root@ubuntu:~# curl -X POST http://localhost:8001/consumers/ \
--data "username=test" \
--data "custom_id=id_test"
{"custom_id":"id_test","username":"test","created_at":1478075521563,"id":"2bbd5f40-f4f3-456d-9695-2e1466633615"}

为 consumer “test” 增加一个 api key:

root@ubuntu:~# # add api key for consumer "test"
root@ubuntu:~# curl -X POST http://localhost:8001/consumers/test/key-auth \
--data 'key=my-customized-key'
{"created_at":1478075713267,"consumer_id":"2bbd5f40-f4f3-456d-9695-2e1466633615","key":"my-customized-key","id":"b9e4db78-2e1a-43d0-8a22-01b889b47952"}

测试生成的 api key 是否正确:

root@ubuntu:~# # check whether api key is valid or not
root@ubuntu:~# curl -i -X GET \
--url http://localhost:8000/ \
--header "Host: hello-world" \
--header "apiKey: b9e4db78-2e1a-43d0-8a22-01b889b47952"
HTTP/1.1 200 OK
...
...
...

最后推荐一个UI管理程序
kong-dashboard

参考:

标签: docker nodejs

发表评论 登录

Top