前言
学校服务器要负载均衡,根据隔壁 TARI TARI 所说,就要搞双 Nginx 冗余服务器,加上两个后端服务器用来跑 PHP 程序,同时将学校服务器的程序都跑在 Docker 上以便管理,根据 U2 推荐,使用 Swarm 进行集群搭建,一共准备六台服务器。
由于是第一次使用 Docker Swarm,操作起来并不熟练,如果文章有哪里出现错误和问题麻烦大佬们在评论区指出,谢谢 QvQ
参考资料:https://www.jianshu.com/p/df744c4e375e、https://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://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 解析问题
这里理论上是不应该出现的,出现这个问题先去看一下 开始 / 对 Swarm 主机进行初始化 这里是否配置正确
先进容器试试能不能 ping 通nginx,如果不能,关掉防火墙。
也有可能是 haproxy 版本问题,好像 ≤ 1.6 是没有 dns 解析功能的。
还是无法解决右转 Google