操作系统均为centos8
介绍
基于docker swarm构建一套可以快速伸缩的应用系统。我们的系统并非是微服务架构,考虑到微服务需要的面对的挑战(分布式事务等)太多了,我们仅仅是多个单体服务,服务间的调用很少,服务间均衡负载使用docker的service实现。
构建目标
可视化管理集群,网关统一输出API,日志统一处理,存储统一处理,网关流量监控,故障转移。
准备工作
准备工作的内容需要为每台机器都执行一遍。
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
安全起见,生产环境建议保留防火墙,只开放需要的端口。
修改DNS
vi /etc/resolv.conf
nameserver修改为114.114.114.114
修改Hostname
给每台机器重新设置一下hostname,node-1、node-2、…..node8
hostnamectl set-hostname node-1 --static
关闭selinux
vim /etc/selinux/config
#重启服务器
reboot
安装docker-ce
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y yum-utils device-mapper-persistent-data lvm2
dnf makecache
dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
# centos8默认自带podman,因此会冲突,需要加上参数自动替换
dnf install docker-ce docker-ce-cli --allowerasing
# 验证一下是否安装成功
docker version
# 开机自启
systemctl enable docker
修改docker配置文件
vim /etc/docker/daemon.json
配置内容:
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn"
],
"dns":["114.114.114.114"]
}
主要是加速docker镜像拉取。
资源划分
管理节点
管理节点必须是奇数个
- 172.16.113.4
- 172.16.113.5
- 172.16.113.6
工作节点
- 172.16.113.7
- 172.16.113.8
- 172.16.113.9
网关节点
- 172.16.113.10
- 172.16.113.11
运维节点
- 172.16.113.12
初始化swarm集群
我们在172.16.113.4
上执行初始化命令
docker swarm init --listen-addr 0.0.0.0:2377 --cert-expiry 87600h0m0s --task-history-limit 1
然后我们在每个工作节点、运维节点、网关节点上运行
# 该命令在初始化完成后会打印在控制台中,后续也可以在管理节点上执行docker swarm join-token worker来获取
docker swarm join --token SWMTKN-1-5ua3tzuqsglxry0kwb7tg3b2mtiqfg40dwt3na0zwa322tkdfn-03essdmekuv68m4s9l7kv6rud 172.16.113.4:2377
然后我们在剩下的每个管理节点上运行
# 在管理节点上运行docker swarm join-token manager来获取
docker swarm join --token SWMTKN-1-5ua3tzuqsglxry0kwb7tg3b2mtiqfg40dwt3na0zwa322tkdfn-c25ey7vpenvhz4glf8vegnj26 172.16.113.4:2377
验证集群
# 在管理节点上,应该列出6个节点
docker node ls
部署Portainer-ce
Portainer我们不需要安装成集群,我们安装到运维节点上。
创建网络
在运维节点上
docker network create \
--driver overlay \
--attachable \
--subnet 10.12.0.0/24 \
portainer_agent_network
安装portainer-ce
docker run -d \
-p 8000:8000 \
-p 9000:9000 \
--name=portainer \
--network=portainer_agent_network \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /data/portainer:/data \
portainer/portainer-ce
安装portainer-agent
docker service create \
--name portainer_agent \
--network portainer_agent_network \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
配置portainer-ce
用浏览器打开运维节点IP:9000
,登录完成后,如下配置即可。
部署traefik网关
创建应用网络
在管理节点上运行
docker network create \
--driver overlay \
--attachable \
--subnet 10.100.0.0/24 \
application_net
创建配置文件
################################################################
#
# Configuration sample for Traefik v2.
#
# For Traefik v1: https://github.com/traefik/traefik/blob/v1.7/traefik.sample.toml
#
################################################################
################################################################
# Global configuration
################################################################
[global]
checkNewVersion = true
sendAnonymousUsage = true
################################################################
# Entrypoints configuration
################################################################
# Entrypoints definition
#
# Optional
# Default:
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
################################################################
# Traefik logs configuration
################################################################
# Traefik logs
# Enabled by default and log to stdout
#
# Optional
#
[log]
# Log level
#
# Optional
# Default: "ERROR"
#
# level = "DEBUG"
# Sets the filepath for the traefik log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
filePath = "log/traefik.log"
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format = "json"
################################################################
# Access logs configuration
################################################################
# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
#
[accessLog]
# Sets the file path for the access log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
filePath = "/log/log.txt"
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format = "json"
################################################################
# API and dashboard configuration
################################################################
# Enable API and dashboard
[api]
# Enable the API in insecure mode
#
# Optional
# Default: false
#
insecure = true
# Enabled Dashboard
#
# Optional
# Default: true
#
dashboard = true
################################################################
# Ping configuration
################################################################
# Enable ping
[ping]
# Name of the related entry point
#
# Optional
# Default: "traefik"
#
# entryPoint = "traefik"
################################################################
# Docker configuration backend
################################################################
# Enable Docker configuration backend
[providers.docker]
# Docker server endpoint. Can be a tcp or a unix socket endpoint.
#
# Required
# Default: "unix:///var/run/docker.sock"
#
swarmMode = true
endpoint = "ssh://root@172.16.113.4"
network = "application_net"
# Default host rule.
#
# Optional
# Default: "Host(`{{ normalize .Name }}`)"
#
# defaultRule = "Host(`{{ normalize .Name }}.docker.localhost`)"
# Expose containers by default in traefik
#
# Optional
# Default: true
#
# exposedByDefault = false
#
#
#[metrics]
# [metrics.influxDB]
# address = "influxdb:8089"
# protocol = "udp"
# database = "traefik"
注意:配置文件中的endpoint应该任意2个管理节点的ip,这里利用ssh保障docker access api的安全。
SSH免密登录配置
每个管理节点都需要支持ssh免密登录,然后把公钥存放到网关节点上,这样网关节点就不需要密码就能ssh到管理节点上。免密登录的配置请自己查资料了。
创建traefik容器
在2台网关节点上都要运行,创建2个网关入口,以保障高可用(可以使用keepalived来实现vIP漂移)。
docker run -d -p 81:8080 -p 80:80 \
-v /data/traefik/conf/traefik.toml:/etc/traefik/traefik.toml \
--name=traefik \
--network=application_net \
-v /root/.ssh:/root/.ssh \
traefik:v2.4.8
到这一步,portainer上应该可以看到运行traefik的容器了。
这步很关键!(安装ssh)
目前traefik其实还没正确连接到swarm集群。ok! 我们在portainer上进入traefik的容器,然后运行
apk update
apk add openssh
等待安装完成后,traefik就能自动连接上swarm集群,至此集群和网关就搭建完成了。
部署应用
这里使用nginx来充当应用。 在任何一台管理节点上运行
docker service create \
--replicas 10 \
--publish 8080:80 \
--network=application_net \
--label="traefik.http.routers.nginx-service.rule=Host(\`nb.io\`)" \
--label="traefik.http.services.nginx-service.loadbalancer.server.port=80" \
--name nginx nginx
Host
中的nb.io
实际应该换成自己的域名,没有域名自己想办法吧,可以使用docker镜像sameersbn/bind
搭建一个私有dns服务器。
等待完成后,我们可以在traefik的webUI上看到:
现在你可以访问
nb.io
来访问nginx服务集群了。
约束应用部署的节点
现在在swarm集群中部署服务,服务的容器会跑到运维节点和网关节点,其实这不是我们想要的。
给节点打标签
在portainer的swarm菜单下为每个节点进行打标签,或者使用命令,该命令需要在管理节点执行
docker node update —label-add role=application node-1
docker node update —label-add role=application node-2
docker node update —label-add role=application node-3
docker node update —label-add role=application node-4
docker node update —label-add role=application node-5
docker node update —label-add role=application node-6
docker node update —label-add role=gateway node-7
docker node update —label-add role=gateway node-8
docker node update —label-add role=sys node-9
调整服务创建命令
docker service create \
--replicas 10 \
--publish 8080:80 \
--network=application_net \
--constraint 'node.labels.role == application' \
--label="traefik.http.routers.nginx-service.rule=Host(\`nb.io\`)" \
--label="traefik.http.services.nginx-service.loadbalancer.server.port=80" \
--name nginx nginx
现在应用服务只会部署在node-1到node-6
节点了。
总结
部署的方式多种多样,traefik,portainer也可以以service的方式部署,这个还是看实际情况吧,这里是直接启容器的。