容器服务化方向的一些探索

本文参考使用Docker打造自己的云平台编写

本文基于 Docker Swarm Mode 实现容器化,虽然目前 k8s 更火一些,但实在是太重了,以后再折腾。
使用 traefik 来实现反向代理、负载均衡,traefik 还自带了服务发现、后端断路器、健康检查等,相当于是自带服务发现的 nginx。当然它还支持其他的容器编排工具如,服务发现工具如 Consul。
使用 Portainer 来管理 Docker 容器,可以兼容 Docker Swarm 模式。

Docker 的安装就不说了。装完初始化 Swarm 模式。

1
$ docker swarm init

先设置一下环境变量。

1
$ export DOCKER_DEV_PATH=/usr/local/src/docker-dev

日志文件都会统一存到 ${DOCKER_DEV_PATH}/logs。

traefik

新建一个编排文件 traefik.yml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: '3.3'
services:
reverse-proxy:
image: traefik:1.7-alpine
command: --web --docker --docker.domain=cloud-labs.io --docker.watch --docker.swarmmode=true --loglevel=INFO --accesslog --accesslog.filepath=/logs/access.log --traefiklog --traefiklog.filepath=/logs/traefik.log
deploy:
mode: replicated
replicas: 1
labels:
- traefik.enable=true
- traefik.backend=traefik
- traefik.frontend.rule=Host:monitor.cloud-labs.io
- traefik.port=8080
- traefik.docker.network=traefik_proxy
networks:
- proxy
ports:
- 8081:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${DOCKER_DEV_PATH}/logs/traefik:/logs
- /dev/null:/traefik.toml
networks:
proxy:

简单解释下 labels 中配置的含义

1
2
3
4
traefik.backend 后端
traefik.frontend.rule 前端规则,满足此规则转发给后端
traefik.port 后端端口 8080 是 traefik web 后台端口
traefik.docker.network 指定网络

更多可用 labels 可用看该Traefik 文档

因为在腾讯云上做的测试没有域名备案,映射了8081端口到80。

部署traefik

1
$ docker stack deploy -c traefik.yml traefik

完成后访问 monitor.cloud-labs.io:8081 就可以进入 traefik 的后台界面了(当然这个域名是要绑host的)。

Portainer

Portainer是一个轻量级的Docker环境管理UI。

新建一个编排文件 portainer.yml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3.3'
services:
server:
image: portainer/portainer
command: -H unix:///var/run/docker.sock
networks:
- traefik_proxy
deploy:
labels:
- traefik.enable=true
- traefik.backend=portainer
- traefik.frontend.rule=Host:console.cloud-labs.io
- traefik.docker.network=traefik_proxy
- traefik.port=9000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer:/data
networks:
traefik_proxy:
external: true
volumes:
portainer:

部署

1
$ docker stack deploy -c portainer.yml portainer

访问 console.cloud-labs.io:8081 就可以管理 Docker 了。

部署一个PHP服务

php服务部署其实还是有些麻烦的。一般前端起nginx将php请求转发到php-fpm,这个时候用的是FastCGI协议。但是目前traefik不支持FastCGI协议,估计以后也不会支持,所以php和nginx要一块部署。如下配置文件。
新建一个编排文件 nginx_php_web.yml,其中包含nginx和php。

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.3'
services:
nginx:
image: nginx:latest
volumes:
- ${DOCKER_DEV_PATH}/logs/nginx:/data/logs/nginx
- ${DOCKER_DEV_PATH}/test_code/php:/code
- ./site.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- traefik_proxy
deploy:
mode: replicated
replicas: 2
labels:
- traefik.backend=nginx
- traefik.frontend.passHostHeader=true
- traefik.frontend.rule=Host:domain.cloud-labs.io
- traefik.docker.network=traefik_proxy
- traefik.port=80
php:
image: php:5.5.38-fpm
volumes:
- ./php.ini:/usr/local/etc/php/php.ini
- ./php-fpm.conf:/usr/local/etc/php-fpm.conf
- ./www.conf:/usr/local/etc/php-fpm.d/www.conf
- ${DOCKER_DEV_PATH}/test_code/php:/code
- ${DOCKER_DEV_PATH}/logs/php:/data/logs/php
networks:
- traefik_proxy
deploy:
mode: replicated
replicas: 3
labels:
- traefik.enable=false
networks:
traefik_proxy:
external: true

部署

1
$ docker stack deploy -c nginx_php_web.yml nginx_php_web

访问 domain.cloud-labs.io:8081 可以看到服务已经起来了。
但是这种方式会有问题

  • 因为请求是从traefik直接到nginx,做健康检查的话只能在nginx上写规则,这样会有问题。除非将nginx和php构建到一个镜像中,但是这又违反了docker的初衷。
  • 经过traefik->nginx->php 性能也会应该有所损耗。

另一种方式通过php的swoole扩展起一个http服务,直接将请求转发过去。

建一个Dockerfile,build一个带swoole的php镜像。这里用了最新的php版本。

1
2
3
4
5
FROM php:7.3.8-cli
RUN pecl channel-update pecl.php.net
# 从pecl安装扩展
RUN pecl install swoole-4.4.0 \
&& docker-php-ext-enable swoole
1
$ docker build -t php7.3.8_swoole4.4.0 . > build.log &

很简单没有遇见任何问题。

再建一个编排文件 php_web.yml。

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
version: '3.3'
services:
swoole_http:
image: php7.3.8_swoole4.4.0:latest
command: php /code/httpServ.php 8888
volumes:
- ${DOCKER_DEV_PATH}/test_code/php:/code
- ${DOCKER_DEV_PATH}/logs/swoole:/data/logs/swoole
networks:
- traefik_proxy
deploy:
mode: replicated
replicas: 2
labels:
- traefik.backend=swoole_http
- traefik.frontend.passHostHeader=true
- traefik.frontend.rule=Host:domain.cloud-labs.io
- traefik.docker.network=traefik_proxy
- traefik.port=8888
- traefik.backend.healthcheck.hostname=domain.cloud-labs.io
- traefik.backend.healthcheck.port=8888
- traefik.backend.healthcheck.path=/healthcheck.php
- traefik.backend.healthcheck.interval=5s
networks:
traefik_proxy:
external: true

其中做了健康检查每五秒一次。httpServ.php的内容整理完发到github上了,文末有说明。
部署起来。

1
2
$ docker stack rm nginx_php_web
$ docker stack deploy -c php_web.yml php_web

效果

traefik 界面

Portainer 界面

跑是跑起来了,但还有些问题。

  • docker swarm目前只是单节点
  • 容器日志、监控处理的不太好
  • 压力测试也没有做
  • 没有关联CI/CD

坑挖的有点多慢慢填吧。。

文中所有配置文件都整理完发到github上了,地址 https://github.com/zyh94946/docker-dev