0%

Docker Swarm 集群探索笔记

前言

学校服务器要负载均衡,根据隔壁 TARI TARI 所说,就要搞双 Nginx 冗余服务器,加上两个后端服务器用来跑 PHP 程序,同时将学校服务器的程序都跑在 Docker 上以便管理,根据 U2 推荐,使用 Swarm 进行集群搭建,一共准备六台服务器。

由于是第一次使用 Docker Swarm,操作起来并不熟练,如果文章有哪里出现错误和问题麻烦大佬们在评论区指出,谢谢 QvQ

参考资料:https://www.jianshu.com/p/df744c4e375ehttps://www.jianshu.com/p/028b40ca4f2a

注:本篇文章由 TARI TARI 和 果果 共同创作

开始

先别管那么多,只要你是 CentOS,防火墙先安排上,不然服务从外面(指 Docker 外面)是连不通的。(一个个端口关太鬼麻烦了,先把防火墙关了以便后续操作,这玩意坑了老久)

# 可以把防火墙关了。不过建议一个个端口关,会安全点
systemctl stop firewalld

如果你用 iptable 前方左转 Google

准备材料

  • Docker_Master
  • CentOS7-Worker-Haproxy * 2
  • CentOS-Worker-Web * 2
  • Ubuntu-Worker-DB

给各台主机修改 Hostname

为避免主机在之后的操作中难以识别的情况,先给每台主机修改 Hostname,确保主机名唯一

安装 Docker

参考资料:https://docs.docker.com/install/linux/docker-ce/centos/

在 CentOS 的五台服务器上运行(嫌麻烦的用 Ansible)

yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo  https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io

Ubuntu 的参考这个资料 https://docs.docker.com/install/linux/docker-ce/ubuntu/

来都来了,那顺便把 docker-compose 给安排了吧

参考资料:https://docs.docker.com/compose/install/

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

对 Swarm 主机进行初始化

执行命令前,给 Master 主机防火墙开启 2377(tcp)端口

给其余的节点主机和 Master 主机开启 7946(tcp & udp)、4789(udp)端口

同时做作地把 80、443 端口打开以免之后出现的问题

参考资料:

https://www.digitalocean.com/community/tutorials/how-to-configure-the-linux-firewall-for-docker-swarm-on-ubuntu-16-04

https://docs.docker.com/engine/swarm/swarm-tutorial/#open-protocols-and-ports-between-the-hosts

firewall-cmd --zone=public --add-port=2377/tcp --permanent # 其他节点对 Master 的访问
firewall-cmd --zone=public --add-port=7946/tcp --permanent # 允许节点间的 Docker 相互通信 
firewall-cmd --zone=public --add-port=7946/udp --permanent
firewall-cmd --zone=public --add-port=4789/udp --permanent # 网络交换
firewall-cmd --reload

# 各主机可能还需要开启的端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --reload

在 Swarm 主机上,执行命令

[root@localhost ~]# docker swarm init --advertise-addr <IP Address> --listen-addr <IP Address>:<Port>
Swarm initialized: current node (xxxxxxxxxxxxxx) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token Balabalabalabala <IP Address>:<Port>

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

然后在其他主机(节点)上运行这段命令,就是中间 docker swarm join 这行

给节点贴标签

特定节点办特定事,给节点都贴上标签

docker node update --label-add role=web Backend_1
docker node update --label-add role=web Backend_2

部署 Portainer

为了方便观察和管理,这里用了 portainer

在 Master 主机上,放置 docker-compose.yml

version: "3"

services:
  portainer:
    container_name: "portainer"
    image: portainer/portainer:latest
    ports:
        - "9000:9000/tcp"
    volumes:
        - "/var/run/docker.sock:/var/run/docker.sock"
    environment:
      TZ: 'Asia/Shanghai'
    restart: always

运行 docker-compose up -d ,打开 http://xxx.xxx.xx.xxx:9000 进行配置

新建一个内网使用

docker默认网段 10.* , 然后本机如果是 10.*,则 docker 里 IP 可能会和咱内网冲突,导致无法访问到内网其他设备。 为了更方便管理,于是新建一个空闲网段

docker network create -d overlay --subnet=192.168.0.0/24 --attachable WordPress

之后在docker-compose.yml 里面加入改网段就好了

Docker Stack 的启动

这里用到 metowolf/docker-lemp

放在 Master 机器上

同样,我也不知道这个是不是正确的食用方法,稍微改改

(此处 /var/www 放在 /home 是因为机器上分区就给 /home 挂了个较大容量的分区,不知道怎么想的(小声

(同时 /etc/php-fpm 就直接栽到 /etc 文件夹,避免其他人上来不知道丢哪了

version: '3.2'

services:
  php-fpm:
    image: metowolf/php:latest
    volumes:
      - /etc/php-fpm/php-fpm.ini:/usr/local/etc/php-fpm.ini
      - /etc/php-fpm/crontabs:/etc/crontabs
      - /home/www:/var/www
    networks:
      - WordPress
    deploy:
      mode: global
      placement:
         constraints:
            - node.labels.role==web
      restart_policy:
         condition: any
    environment:
      ENABLE_CRONTAB: "true"
      TZ: Asia/Shanghai

  nginx:
    image: metowolf/nginx:latest
    volumes:
      - /var/log/nginx:/var/log/nginx
      - /etc/nginx/nginx.conf:/etc/nginx/nginx.conf
      - /etc/nginx/conf.d:/etc/nginx/conf.d
      - /etc/nginx/ssl:/etc/nginx/ssl
      - /home/www:/var/www
    networks:
      - WordPress
    deploy:
      mode: global
      placement:
         constraints:
            - node.labels.role==web
      restart_policy:
         condition: any
    environment:
      ENABLE_CRONTAB: "true"
      TZ: Asia/Shanghai
    depends_on:
      - php-fpm

networks:
  WordPress:
    external: true

输入

docker stack deploy -c docker-compose.yml Web_Backend

给 role 为 web 的两个节点分配任务

注:这么分配完了以后,由于 nginx.conf 写的是请求 php-fpm:9000 ,php-fpm 此时有两个host,所以nginx会选择性地去请求这两个其中的一个

注注:这里不用分配 80 和 443 端口,nginx 和 haproxy 的沟通通过 swarm 网络,将 haproxy 和 nginx 放在同一个 swarm 网络即可

然后到此时我感觉我 swarm 的用法是不是搞错了(小声嘀咕

部署Haproxy

在 Master 主机上,放置 docker-compose.yml

version: "3.0"

services:

  haproxy:
    image: haproxytech/haproxy-alpine
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    dns:
      - 127.0.0.11
    volumes:
      - /var/www:/var/www
      - /etc/haproxy:/usr/local/etc/haproxy
    networks:
      - WordPress
    deploy:
      mode: global
      placement:
         constraints:
            - node.labels.role==haproxy
      restart_policy:
         condition: any
    environment:
      ENABLE_CRONTAB: "true"
      TZ: Asia/Shanghai

networks:
  WordPress:
    external: true

haproxy 服务器上

注意 用证书要把两个证书合并

-----BEGIN RSA PRIVATE KEY-----

-----END RSA PRIVATE KEY-----

-----BEGIN CERTIFICATE-----

-----END CERTIFICATE-----

可以在控制台运行

cat domain.crt domain.key | tee cert.pem

合并证书。

mkdir /etc/haproxy
touch /etc/haproxy/haproxy.cfg

# /etc/haproxy/haproxy.cfg 内容如下
global
    daemon
    log          fd@2 local2
    chroot /usr/local/etc/haproxy
    tune.ssl.default-dh-param 2048


​ # 此处理论上不需要,因为 Docker 默认解析的主机名就是127.0.0.11,如果实在无法解析到 nginx 就加上这段吧
​ ########docker 主机名解析##############
​ resolvers docker
​ nameserver dns1 127.0.0.11:53
​ resolve_retries 3
​ timeout resolve 1s
​ timeout retry 1s
​ hold other 10s
​ hold refused 10s
​ hold nx 10s
​ hold timeout 10s
​ hold valid 10s
​ hold obsolete 10s

########default##############
defaults
log global
mode http
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.1
option redispatch
retries 3
option redispatch
maxconn 2000
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000

########frontend配置##############
frontend www
  bind *:80
  bind *:443 ssl crt /usr/local/etc/haproxy/ssl/cert.pem
  #隐藏HAProxy版本信息
  stats hide-version
  mode http
  option httpclose
  option forwardfor
  rspidel ^Server.*
  redirect scheme https if !{ ssl_fc }
  # 利用单一连接处理多条客户端请求,从而实现性能提升
  option http-server-close
  default_backend web-backend

########backend配置##############
#指定一个名为web-backend的backend
backend web-backend
  mode http
  balance roundrobin
  cookie SERVERID insert indirect nocache
  server-template nginx 3 nginx:80 check resolvers docker inter 1000

docker pull haproxytech/haproxy-alpine
docker node update --label-add role=haproxy HaProxy_1
docker stack deploy -c docker-compose.yml HaProxy_1

配置 Nginx 进行自我缓存(不建议)

参考资料:https://juejin.im/post/5af38e0c518825670c45ef6e (作者:我是leon)

本来是可以用 HaProxy + Vanish 来搭建缓存服务器的,闲太麻烦就直接用 nginx 搞了(

在 nginx.conf 中添加以下设置

proxy_connect_timeout 10;
proxy_read_timeout 180;
proxy_send_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 96k;
proxy_temp_file_write_size 96k;
proxy_temp_path /var/www/nginx/temp;
proxy_cache_path /var/www/nginx/cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=10g;

(这里为了能够外部调用删除缓存写在 PHP 和 nginx 的公共目录下

部署 Syncthing

参考文档:https://github.com/linuxserver/docker-syncthing

注意:此处不能按照此方法用swarm分配任务,或者你在 docker-compose 单独写两个 services 也行,并且将两个 services 分别分配到不同的端口,否则连接到 Syncthing 控制台时将会产生混乱。

原因:这里分配完端口后,会向 swarm 网络的所有节点打开端口,然后在任意节点上尝试连接该端口就会自动转发到对应的节点上。

为了让两台 Web 服务器的文件同步,同时也方便查看,这里使用 syncthing

先给所有服务器创建 /etc/syncthing 文件夹

我本来是想用 swarm 派的,结果发现创建完了以后,一台服务器的syncthing GUI总是喜欢去连接一下另一台,另一台总是喜欢去连接一下这台,瞎搞

编辑 docker-compose.yml

version: "3"
services:
  syncthing:
    image: linuxserver/syncthing
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - UMASK_SET=<022>
    volumes:
      - /etc/syncthing:/config
      - /var/www:/sync/www
      - /etc/php-fpm:/sync/php-fpm
      - /etc/nginx:/sync/nginx
    ports:
      - 8384:8384
      - 22000:22000
      - 21027:21027/udp
    restart: always

安装WordPress

配置 nginx, 先把 原来的 https 证书搬过来,换上

解析 网站根目录至 /var/www/wordpress

虽然物理主机上网站根目录的 /home/www 目录下, 但 docker 里的逻辑卷于 /var/www/

配置 nfs

此处配置 nfs 以便文件同步(?)

# /etc/fstab 增加
server_ip:server_dir  client_dir nfs rw  0 0

rsync 同步

(注:如果上面 Syncthing 不好用的话那还是用这个吧(

主服务器 以及 从服务器文件

# 详情可参考 https://tari0510.github.io/2019/07/15/ansible-shell/ rsync部分
# 从服务器已经配置好, 主服务器执行以下命令即可
sh /usr/local/inotify/rsync.sh &

数据库服务器允许新ip访问

如果是通过更换 ip 的方式迁移数据库这一步就不需要了

时间同步

https://blog.csdn.net/a_drjiaoda/article/details/89674468

yum -y install ntp ntpdate
ntpdate 0.asia.pool.ntp.org
hwclock --systohc

关闭所有 debug 信息

配置好 nginx 把域名解析到新服务器ip应该问题不大了。

乱七八糟的问题

ailed to chown socket at step GROUP: No such process

解决方法:

添加docker用户组

groupadd docker

# 如果出现 groupadd: cannot open /etc/group ,可能文件被加锁了,解文件锁就好了
chattr -i /etc/group

Haproxy dns 解析问题

Docker-Swarm/Untitled.png

这里理论上是不应该出现的,出现这个问题先去看一下 开始 / 对 Swarm 主机进行初始化 这里是否配置正确

先进容器试试能不能 ping 通nginx,如果不能,关掉防火墙。

也有可能是 haproxy 版本问题,好像 ≤ 1.6 是没有 dns 解析功能的。

还是无法解决右转 Google