最近有个项目需要进行扩容,之前是直接jar包运行,通过nginx进行负载均衡。搭架子倒是简单,但是每次更新很麻烦,这次正好一并换掉。
成型后大概的拓扑图:
| 路径 | |
|---|---|
| http://traefik | traefik dashboard |
| http://edu | 后台页面 |
| http://edu/api/admin | 后台接口 |
| http://edu/portainer/ | portainer dashboard |
准备三台机器,server-201(192.168.68.201),server-202(192.168.68.202),server-203(192.168.68.203),系统为ubuntu24.04,均已安装docker 官方文档
1.初始化docker swarm和网络
开放swarm所需要的端口:Getting started with Swarm mode | Docker Docs
- 2377/tcp 集群间管理通信
- 7946 tcp/udp 节点间通信
- 4789 udp 用于overlay网络
其他端口:
- 9001 tcp portainer-agent
firewall-cmd --zone=public --permanent --add-port={2377/tcp,7946/tcp,7946/udp,4789/tcp,9001/tcp}
# 重新加载使开放端口生效
firewall-cmd --reload
规划server-201为manager,202和203为node
初始化集群:Create a swarm | Docker Docs
# 201上执行 成功后会打印join集群的token
docker swarm init --advertise-addr 192.168.68.201:2377 --listen-addr 192.168.68.201:2377
# 202 203分别执行 token记得替换成上面打印的结果
docker swarm join --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c 192.168.68.201:2377
查看集群节点,在201上执行:
docker node ls
总共三个节点,201为manager
网络
traefik和portainer agent都需要在同一网络下才能发现,规划两个overlay网络:
- app_net:所有需要traefik代理的服务都在这个网络
- portainer_agent_network:只用来服务portainer agent
在201上执行:
# --attachable标记的网络才能在创建后继续加入容器
docker network create --driver overlay --attachable portainer_agent_network
docker network create --driver overlay --attachable app_net
查看网络:
2.部署portainer+traefik+nginx
不直接映射portainer和nginx,通过traefik代理。规划的访问路径:
- portainer:http://edu/portainer/ (注意不是http://edu/portainer)
- traefik: http://traefik
- nginx: http://edu (nginx只代理静态页面)
注意:
- edu和traefik只是我自定义的host,需要在本地配置hosts,真实环境换成实际的域名即可
# windows:C:\Windows\System32\drivers\etc\hosts linux: /etc/hosts
192.168.68.201 edu
192.168.68.201 traefik
- traefik也可以使用二级目录 http://edu/traefik 来进行访问,不过配置要麻烦一些,感兴趣的参考: Allow to add path prefix for both api and dashboard endpoints · Issue #5853 · traefik/traefik
创建目录用来挂载容器数据:
cd /root
mkdir traefik nginx portainer
# traefik配置文件
touch /root/traefik/traefik.yml
# nginx 配置和静态目录
touch /root/nginx/nginx.conf
mkdir /root/nginx/html/admin
# portainer目录
mkdir /root/portainer
traefik.yml:官方模板
global:
checkNewVersion: true
sendAnonymousUsage: true
entryPoints:
web:
address: :80
websecure:
address: :443
accessLog:
filePath: /log/log.txt
api:
dashboard: true
providers:
# 开启docker代理
docker: {}
# 开启swarm代理
swarm:
endpoint: "unix:///var/run/docker.sock"
nginx.conf:根据自己项目配置
user root;
worker_processes 1;
worker_rlimit_nofile 1024;
events {
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
server_tokens off;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
server {
listen 80;
server_name edu.host;
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' *;
add_header 'Access-Control-Allow-Headers' *;
add_header Strict-Transport-Security "max-age=31536000";
client_max_body_size 150m;
client_body_buffer_size 20m;
location / {
alias /usr/share/nginx/html/admin/;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}
}
2.1 docker compose部署(推荐)
services:
traefik:
container_name: traefik
restart: always
image: traefik:v3.2.0
networks:
- app_net
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/traefik/traefik.yml:/etc/traefik/traefik.yml
labels:
- "traefik.http.routers.traefik.rule=Host(`traefik`)" # 通过traefik访问
- "traefik.http.routers.traefik.service=api@internal" # 指定的服务
- "traefik.http.middlewares.traefik-auth.basicauth.users=traefik:$$apr1$$q1UDMg1q$$MgKSNFf4U94se9zeJ7nfS1" # dashboard鉴权一下
- "traefik.http.routers.traefik.middlewares=traefik-auth@docker" #指定鉴权中间件到traefik路由上
portainer:
container_name: portainer
restart: always
image: portainer/portainer-ce
networks:
- app_net
- portainer_agent_network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/portainer:/data
labels:
- "traefik.http.routers.portainer.rule=Host(`edu`)&&PathPrefix(`/portainer`)" # 通过 /portainer 子路径 访问
- "traefik.http.services.portainer.loadbalancer.server.port=9000" #指定访问的端口
- "traefik.http.middlewares.portainer-stripprefix.stripprefix.prefixes=/portainer" # 中间件 代理后删除 /portainer 路径
- "traefik.http.routers.portainer.middlewares=portainer-stripprefix@docker" # 指定中间件到portainer路由上
- "traefik.docker.network=app_net" # portainer有两个网络 指定traefik使用app_net网络进行代理
nginx:
container_name: nginx
restart: always
image: nginx
networks:
- app_net
volumes:
- /root/nginx/html:/usr/share/nginx/html:ro
- /root/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
labels:
- "traefik.http.routers.nginx.rule=Host(`edu`) && !PathPrefix(`/api`)&&!PathPrefix(`/portainer`)" # 匹配 edu 和非 /api开头的路径
- "traefik.http.services.nginx.loadbalancer.server.port=80" #指定访问的端口 80
networks:
app_net:
external: true # 外部网络,即网络已经创建好了
portainer_agent_network:
external: true
docker compose up -d
注意:这里traefik配置了认证,具体参考Traefik BasicAuth Documentation | Traefik | v3.2,hash后的密码中$需替换为$$
输入输入用户名密码后即可访问控制台
访问http://edu/portainer/ 进入portainer dashboard,设置用户名密码后添加docker swarm环境:
跟随页面指引,创建portainer-agent服务,通过portainer监控docker swarm集群:
# 201上执行
docker service create \
--name portainer_agent \
--network portainer_agent_network \
-p 9001:9001/tcp \
--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 \
--label="traefik.enable=false"\
portainer/agent
# --label="traefik.enable=false" 不让traefik管理portainer agent,否则traefik会一直打印错误日志
http://edu 访问nginx代理页面
2.2 单独部署(不建议)
2.2.1部署portainer
# 创建portainer overlay网络
docker network create --driver overlay --attachable portainer_agent_network
# 拉取镜像
docker pull portainer/portainer-ce
docker pull portainer/agent
# 挂载portainer数据目录
mkdir portainer
# 启动portainer
docker run -d -p 8000:8000 -p 9000:9000 \
--name=portainer \
--network=app_net \
--restart=always \
--label="traefik.http.routers.portainer.rule=PathPrefix(\`/portainer\`)&& !PathPrefix(\`/api\`)" \
--label="traefik.http.services.portainer.loadbalancer.server.port=9000" \
--label="traefik.http.middlewares.portainer-stripprefix.stripprefix.prefixes=/portainer" \
--label="traefik.http.routers.portainer.middlewares=portainer-stripprefix@docker" \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ./portainer:/data \
portainer/portainer-ce
# portainer-agent
docker service create \
--name portainer_agent \
--network portainer_agent_network \
-p 9001:9001/tcp \
--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 \
--label="traefik.enable=false"\
portainer/agent
访问192.168.68.201:9000进入portainer dashboard,给portainer容器添加portainer_agent_network网络,才能访问到portainer-agent,进行docker swarm集群管理
2.2.2.部署traefik
# 全部在201上操作
# 拉取镜像
docker pull traefik:v3.2.0
# 新建配置文件 https://github.com/traefik/traefik/blob/master/traefik.sample.yml
docker run -d -p 80:80 \
--name=traefik --network=app_net \
-v /root/traefik/traefik.yml:/etc/traefik/traefik.yml \
-v /var/run/docker.sock:/var/run/docker.sock \
--label="traefik.http.routers.traefik.rule=Host(\`traefik\`)" \
--label="traefik.http.routers.traefik.service=api@internal" \
--label="traefik.http.middlewares.traefik-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/" \
--label="traefik.http.routers.traefik.middlewares=traefik-auth@docker" \
traefik:v3.2.0
# 只映射80端口 dashboard由traefik自身代理
2.2.3.部署nginx
docker run -d \
--name=nginx \
--network=app_net \
--restart=always \
--label="traefik.http.routers.nginx.rule=Host(\`edu\`) && !PathPrefix(\`/api\`)" \
--label="traefik.http.services.nginx.loadbalancer.server.port=80" \
-v /root/nginx/html:/usr/share/nginx/html:ro \
-v /root/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx
# !PathPrefix在这里会报错 最后是直接在portainer中创建的nginx容器
3.部署portainer-agent
通过portainer监控docker swarm集群
# 启动portainer-agent
docker service create \
--name portainer_agent \
--network portainer_agent_network \
-p 9001:9001/tcp \
--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 \
--label="traefik.enable=false"\
portainer/agent
# --label="traefik.enable=false" 不让traefik管理portainer agent,否则后台一直打印错误日志
4.部署service
登录portainer后台可以直接新增service,注意需要选择app_net才能使treafik访问到,添加对应的service label:
也可以在201上直接创建服务:
#部署edu-admin服务
docker service create \
--replicas 3 \
--network=app_net \
--label="traefik.http.routers.edu-admin.rule=Host(\`edu\`) && PathPrefix(\`/api/admin\`)" \
--label="traefik.http.services.edu-admin.loadbalancer.server.port=8080" \
--label="traefik.docker.network=app_net" \
--env spring.redis.host=192.168.68.203 \
--env spring.profiles.active=dev \
--name=admin admin
启动成功后访问swagger :http://edu/api/admin/doc.html