Docker 安装 Webdis

前言

Webdis 是一个非常简单的 Web 服务器,专门为 Redis 提供 HTTP 接口,使用 hiredis、jansson、libevent、http-parser 等组件。下面将介绍 Docker 安装部署 Webdis 与 Redis,由于篇幅有限不会详细介绍部署过程,但会给出 Docker 相关的主要配置内容。如需更详细的教程内容,可参考 Webdis Github 上的说明文档。

软件环境

环境名称版本
docker-ce18.09.3
docker-compose1.24.0-rc1
linux 发行版 CentOS Linux release 7.6.1810 (Core)

Webdis 镜像的 DockerFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from debian:stretch

MAINTAINER clay<clay@gmail.com>

RUN cp /etc/apt/sources.list /etc/apt/backup.sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch main non-free contrib" > /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian-security stretch/updates main" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list

RUN apt-get -y update && apt-get -y upgrade
RUN apt-get -y install apt-utils vim net-tools telnet git curl wget make gcc libevent-dev
RUN apt-get -y autoclean && apt-get -y autoremove

ENV version 0.1.4

WORKDIR /usr/local

RUN wget --no-check-certificate https://github.com/nicolasff/webdis/archive/$version.tar.gz -O webdis-$version.tar.gz
RUN tar -xvzf webdis-$version.tar.gz
RUN cd webdis-$version && make && make install && cd ..
RUN rm -rf webdis-$version.tag.gz

WORKDIR /usr/local/webdis-$version

EXPOSE 7379

CMD /usr/local/bin/webdis /etc/webdis.prod.json && bash

构建 Webdis 镜像

1
2
3
4
5
6
7
8
# 创建DockerFile
# touch Dockerfile-Webdis

# 将上述内容写入到DockerFile中
# vim Dockerfile-Webdis

# 构建Webdis镜像
# docker build -f Dockerfile-Webdis -t clay/webdis:0.1.4 .

Redis 的配置文件

Redis 配置文件中的主要内容(redis.conf)如下:

1
2
3
4
5
# 注释掉下面这一行,不绑定任何主机IP
# bind 127.0.0.1

# 设置Redis密码
requirepass C6v8TMQv@oc%4HkznfKJ5jy&zBUencAL

Webdis 的配置文件

Webdis 配置文件(webdis.prod.json)的完整内容如下,具体的 ACL 规则可参考 Github 上的说明文档。考虑到服务器安全,下面配置了 Http Auth 的用户名和密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"redis_host": "172.89.0.2",
"redis_port": 6379,
"redis_auth": "C6v8TMQv@oc%4HkznfKJ5jy&zBUencAL",

"http_host": "0.0.0.0",
"http_port": 7379,
"threads": 4,

"daemonize": false,

"database": 0,

"acl": [
{
"disabled": ["DEBUG", "FLUSHDB", "FLUSHALL", "GET", "SET", "DEL"]
},
{
"http_basic_auth": "admin:123456",
"enabled": ["DEBUG", "GET", "SET", "DEL"]
}
],

"verbosity": 3,
"logfile": "/var/log/webdis.log"
}

Docker-Compose 的配置文件

使用 Docker-Compose 管理容器,其中 docker-compose.yml 配置文件的完整内容如下(包括 Redis、Webdis)。具体的数据卷挂载目录,需要根据自己的实际情况进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: "3.5"

services:
redis:
image: redis:5.0.4-stretch
container_name: redis-5.0.4
privileged: false
ports:
- 6379:6379
networks:
redis-network:
ipv4_address: 172.89.0.2
volumes:
- '/container/redis/data:/data'
- '/container/redis/redis.conf:/usr/local/etc/redis/redis.conf'
command: redis-server /usr/local/etc/redis/redis.conf

webdis:
image: clay/webdis:0.1.4
container_name: webdis
privileged: false
depends_on:
- redis
networks:
redis-network:
ipv4_address: 172.89.0.3
ports:
- 7379:7379
volumes:
- '/container/wedis/webdis.log:/var/log/webdis.log'
- '/container/wedis/webdis.prod.json:/etc/webdis.prod.json'

networks:
redis-network:
name: redis-network
driver: bridge
ipam:
config:
- subnet: 172.89.0.0/24

创建并启动 Docker 容器

1
2
3
4
5
6
7
8
9
10
11
# 进入docker-compose.yml配置文件所在的目录
# cd docker-compose-dir

# 以后台方式启动Redis、Webdis容器
# docker-compose up -d

# 查看容器的启动情况
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ebd5cac7fee9 clay/webdis:0.1.4 "/bin/sh -c '/usr/lo…" 14 minutes ago Up 14 minutes 0.0.0.0:7379->7379/tcp webdis
9a1feb971d1c redis:5.0.4-stretch "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 0.0.0.0:6379->6379/tcp redis-5.0.4

CURL 命令测试 Webdis 与 Redis 是否正常工作

1
2
3
4
5
6
7
8
9
10
11
# 写入key
# curl http://127.0.0.1:7379/SET/hello/world -u admin:123456
{"SET":[true,"OK"]}

# 获取key
# curl http://127.0.0.1:7379/GET/hello -u admin:123456
{"GET":"world"}

# 删除key
# curl http://127.0.0.1:7379/DEL/hello -u admin:123456
{"DEL":1}

NodeJS 代码测试 Webdis 与 Redis 是否正常工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var request = require('request');
var username = "admin";
var password = "123456";
var url = 'http://127.0.0.1:7379/GET/hello';
var auth = "Basic " + new Buffer(username + ":" + password).toString("base64");

request({
url: url,
headers: {
"Authorization": auth
}
},
function(error, response, body) {
if (error) {
console.log(error);
return;
}
if (response.statusCode == 200) {
console.log("result: " + body);
} else {
console.log("code: " + response.statusCode);
}
}
);

WebSocket 与 Pub/Sub 的支持

Webdis 默认不启用 WebSocket 与 Pub/Sub 的支持,如需要相关功能,可以参考以下的步骤进行操作。官方声明 Websocket 与 Pub/Sub 功能是实验性的,生产环境慎用。经过反复测试,按照下面的步骤进行操作,JavaScript 代码依然无法连接 WebSocket、Pub/Sub 服务,后续再想办法解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 连接上面创建的webdis容器
# docker run -it webdis /bin/bash

# 进入webdis的tests目录
# cd /usr/local/webdis-0.1.4/tests

# tests目录结构介绍
|-- Makefile
|-- README.tests
|-- basic.py # 单元测试脚本
|-- bench.sh # 压测脚本
|-- limits.py
|-- pubsub.c # pub/sub支持
|-- websocket.c # websocket支持
`-- websocket.html # websocket的html5测试页面

# 编译websocket、pub/sub的代码
# make

# 查看websocket命令的使用方法
$ ./websocket -h
Usage: ./websocket [options]
Options are:
-h host (default = "127.0.0.1")
-p port (default = 7379)
-c threads (default = 4)
-n count (number of messages per thread, default = 100000)
-v (verbose)

# 启动websocket服务,其中127.0.0.1是webdis服务的IP,7379是webdis服务的端口
$ ./websocket -h 127.0.0.1 -p 7379 -v

# 查看pubsub命令的使用方法
$ ./pubsub -h
Usage: ./pubsub [options]
Options are:
-h host (default = "127.0.0.1")
-p port (default = 7379)
-r readers (default = 450)
-w writers (default = 10)
-c channels (default = 1)
-n messages (number of messages to read in total, default = 100000)

# 启动pub/sub服务,其中127.0.0.1是webdis服务的IP,7379是webdis服务的端口
# 经测试,pub/sub服务的启动会导致webdis服务意外停止,原因暂时未知
$ ./pubsub -h 127.0.0.1 -p 7379

JavaScript 代码测试 WebSocket 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function testJSON() {
var jsonSocket = new WebSocket("ws://127.0.0.1:7379/.json");
jsonSocket.onopen = function() {

console.log("JSON socket connected!");
jsonSocket.send(JSON.stringify(["SET", "hello", "world"]));
jsonSocket.send(JSON.stringify(["GET", "hello"]));
};
jsonSocket.onmessage = function(messageEvent) {
console.log("JSON received:", messageEvent.data);
};
}

testJSON();

JavaScript 代码测试 Pub/Sub 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var previous_response_length = 0
xhr = new XMLHttpRequest()
xhr.open("GET", "http://127.0.0.1:7379/SUBSCRIBE/hello", true);
xhr.onreadystatechange = checkData;
xhr.send(null);

function checkData() {
if(xhr.readyState == 3) {
response = xhr.responseText;
chunk = response.slice(previous_response_length);
previous_response_length = response.length;
console.log(chunk);
}
};

Webdis 的 SSL 支持

Webdis 官方默认不支持 SSL,如果需要 SSL 的支持,可以使用 Nginx 作为反向代理服务器,即配置 Nginx 的代理与 SSL 证书,然后将请求转发给 Webdis,这样就可以提高 Webdis 连接的安全性。Nginx 的示例配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 18379;
# Webdis的IP与端口
server_name 172.89.0.3:7379;

# SSL证书
ssl on;
ssl_certificate /usr/local/nginx/cert/example.cn.crt;
ssl_certificate_key /usr/local/nginx/cert/example.cn.key;

# SSL性能调优
ssl_session_timeout 10m;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;

location / {
# 代理
proxy_pass http://$server_name;
}
}

1
2
# 使用CURL命令测试Nginx的代理与SSL配置是否正确,其中example.com是绑定了SSL证书的域名
# curl https://example.com:18379/GET/hello -u admin:123456