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

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

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

$ docker swarm init

先设置一下环境变量。

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

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

traefik

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

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 中配置的含义

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

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

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

部署traefik

$ docker stack deploy -c traefik.yml traefik

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

Portainer

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

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

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:

部署

$ 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。

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

部署

$ 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版本。

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
$ docker build -t php7.3.8_swoole4.4.0 . > build.log &

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

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

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上了,文末有说明。 部署起来。

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

效果

traefik 界面

Portainer 界面

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

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

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

文中所有配置文件当时整理到了 docker-dev 仓库,目前该仓库已经不可访问。