实验目标:
首先起两台实例,部署todo服务,同时对接redis和mysql,并且实现负载均衡
实验步骤:
- 安装docker
- 在腾讯云镜像服务拉取镜像
- 安装nginx(在实例上配置,主要是为了负载均衡)
注意事项:
- 需要进入mysql容器创建 todolist 数据库
- 必须会写脚本同时起100台容器,并且写入nginx的轮询以负载均衡
- 必须会写脚本删除脚本起的容器
- 必须会将日志挂载到本机的同一个文件下(如果题目要求的话)
一键搭建脚本
先在本地实验一下,写个shell脚本去云上
先登录腾讯云
1 2
| docker login ccr.ccs.tencentyun.com --username=100032122665 RootRoot123.
|
然后执行以下脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #!/bin/bash systemctl stop firewalld systemctl disable firewalld # 关闭 SELinux 强制模式,解决 Nginx 502; 因为 SELinux 限制了 Nginx 访问上游服务器或网络资源 setenforce 0 # 删除有风险 # rm -rf /etc/yum.repos.d/*
# 如果用Debian就删除10-25行,反之也是 # --------------------centos ------------------------------------ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.cloud.tencent.com/docker-ce/linux/centos/docker-ce.repo yum makecache yum install epel-release -y
# 注意:如果是Debian,则需要将yum换成apt # 接下来是安装docker yum install -y docker-ce systemctl start docker systemctl enable docker # 安装nginx yum install -y nginx systemctl start nginx systemctl enable nginx # -------------------------------------------------------- #---------------------------- Debian------------------------ sudo apt-get update -y sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.cloud.tencent.com/docker-ce/linux/debian/ \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update -y sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y systemctl start docker systemctl enable docker # --------------------------------------------------------
# 从腾讯云拉取镜像 # 听说这样可以交互密码 echo "$password" | docker login ccr.ccs.tencentyun.com --username=$username --password-stdin docker pull ccr.ccs.tencentyun.com/$user/redis:7.4.0 docker pull ccr.ccs.tencentyun.com/$user/mysql:8.0.39 docker pull ccr.ccs.tencentyun.com/$user/todo:v2
# MySql docker run -d \ -e MYSQL_ROOT_PASSWORD=000000 \ -e MYSQL_DATABASE=todolist \ --name my-mysql \ -p 13306:3306 ccr.ccs.tencentyun.com/troml/mysql:8.0.39 # Redis --requirepass 一定要放在镜像以后 docker run -d \ --name my-redis \ -p 16379:6379 \ ccr.ccs.tencentyun.com/troml/redis:7.4.0 --requirepass 000000 # todo 的配置文件 cat <<EOL > config.ini [service] AppMode = release HttpPort = :3000
[redis] RedisDb = redis RedisAddr = 172.17.0.3:6379 RedisPw = 000000 RedisDbName = 2
[mysql] Db = mysql DbHost = 172.17.0.2 DbPort = 3306 DbUser = root DbPassWord = 000000 DbName = todolist EOL
# Todo 服务 docker run -itd -p 3000:3000 -v ./config.ini:/app/config/config.ini --name todo ccr.ccs.tencentyun.com/troml/todo:v2 curl localhost:3000/api/v1/ping
|
批量起容器的脚本
批量生成脚本(应当琢磨如何简单化),保存变量是必须的,因为最后要去nginx的配置文件里配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #!/bin/bash # 起始端口 base_port=3000 output="" # 启动10个容器 for i in {1..10}; do port=$((base_port + i)) # 启动容器 docker run -d -p $port:3000 -v "$(pwd)/config.ini:/app/config/config.ini" --name "todo-$i" ccr.ccs.tencentyun.com/troml/todo:v2 # 获取容器的IP地址 container_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "todo-$i") # 拼接输出字符串 output+="server $container_ip:3000;\n" done # 最后集中输出所有IP echo -e "$output"
|
批量删除脚本
1 2 3 4 5 6
| #!/bin/bash # 删除名为 todo-1 到 todo-n 的容器 for i in {1..10}; do docker rm -f "todo-$i" echo "Deleted container todo-$i" done
|
配置nginx负载均衡
搭建基础环境基本上在脚本里都能看到,直接开始负载均衡
在本机负载均衡,将利用脚本批量生成10个应用服务容器,利用nginx进行轮询
为问不同端口的todo容器将会回显其主机名,由于主机名不同,达到验证负载均衡成功的目的
如下图:
curl访问

浏览器访问

运行脚本批量生成容器
(注意:新容器端口号要从3001开始)
将生成的容器加入到/etc/nginx/nginx.conf
中
1 2
| vi create.sh bash create.sh
|

修改配置文件
1
| vi /etc/nginx/nginx.conf
|

查看报错的命令
1
| tail -f /var/log/nginx/access.log /var/log/nginx/error.log
|
接下来,只需要访问我们虚拟机的80
端口,即可实现轮询-负载均衡


配置nginx容错机制
难免会有容器出现问题,这时候就需要用到容错机制
容错机制介绍
Failover(失效转移):如果主服务器出问题,自动切换到备用服务器,让系统继续运行。例如:如果数据库服务器崩溃,备用的服务器会接管工作。
场景应用:你可以使用 proxy_next_upstream
指定在特定错误条件(如超时、错误代码)下,转移到其他服务器:
1 2 3 4 5 6 7 8 9
| upstream server_list { server 172.17.0.5:3000 max_fails=1 fail_timeout=500ms; server 172.17.0.6:3000 max_fails=1 fail_timeout=500ms; }
location / { proxy_pass http: proxy_next_upstream error timeout invalid_header http_502 http_503 http_504; }
|
Failfast(快速失败):一旦发现错误,立即停止操作,不做多余的尝试。这样可以更快地发现问题,并马上切换到其他解决方案或服务器。
场景应用:适用于需要快速失败的系统,不希望长时间等待,快速转移到下一个可用服务:
1 2 3 4 5
| location / { proxy_pass http://server_list; proxy_connect_timeout 100ms; # 如果连接超过100毫秒未建立,立即失败 proxy_read_timeout 300ms; # 如果读取响应超过300毫秒,立即失败 }
|
Failback(失效恢复):当主服务器修复好后,系统会自动从备用服务器切换回主服务器,恢复到最初的状态。
Nginx 本身并没有专门的 failback
机制,但配合健康检查模块或使用商业版的 Nginx Plus可以实现这种功能。当上游服务器恢复健康时,Nginx 可以自动将流量再次转移回去。也可以通过外部监控工具来检测服务器健康状态,并动态调整 Nginx 的上游服务器配置。
Failsafe(失效安全):即使系统出错,也会确保安全运行,尽量减少损失或危险。例如:红绿灯出故障时会全亮红灯,而不是继续让车子通过,确保安全。
场景应用:在所有上游服务器失败时,提供一个安全的降级机制或错误页面
1 2 3 4 5
| error_page 502 = /fallback.html;
location /fallback.html { root /usr/share/nginx/html; }
|
根据我的需求,我需要在某个服务器挂掉以后,nginx必须快速做出反应请求到下一台服务器,因此本次选择Failfast(快速失败)
因为和之前的记录中断了,首先展示本次用到的上游服务器

修改nginx配置文件

1 2
| proxy_connect_timeout 100ms; # 如果连接超过100毫秒未建立,立即失败 proxy_read_timeout 300ms; # 如果读取响应超过300毫秒,立即失败
|
用一个脚本验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import requests import time
url = "http://192.168.100.201"
for i in range(10): try: response = requests.get(url) print(f"请求 {i+1} 的返回值: {response.text}") except requests.RequestException as e: print(f"请求 {i+1} 失败: {e}")
|
长连接
在使用脚本验证失效服务之前,发现一个奇怪的现象
注意:图片标反了

原因是由于长连接的存在,所以有复用的现象
如果keepalive_timeout=0,那么第一个请求还没结束,nginx就给切掉了,下一个请求来了还是在这个容器里面
如果keepalive_timeout=65,那么第一个请求不管它多久,我们的容器就会为它服务65秒,下一个请求来了就会轮询到下一台
- **
keepalive_timeout=0
**:
- 当
keepalive_timeout
设置为 0 时,每次请求都可能建立一个全新的连接,这意味着负载均衡器能够均匀地将请求分配到不同的容器上。因此,你在这种情况下成功地轮询到了 10 台机器。
- **
keepalive_timeout=65
**:
- 当
keepalive_timeout
设置为 65 秒时,HTTP 连接可能在多个请求之间复用。如果客户端在同一个连接上发送多个请求,负载均衡器不会重新分配这些请求,而是保持使用同一个后端服务器。因此,返回的容器主机名看起来没有明显的轮询规律,且多个请求可能被同一个容器处理。
解释:
- Keepalive Connection:HTTP keepalive 允许客户端与服务器保持持久连接,在同一个连接上发送多个请求。这减少了建立新连接的开销,但会导致请求可能多次被同一个服务器处理。
- 轮询模式失效:当连接复用时,负载均衡器不会参与后续请求的重新分配。因此你看到某些容器多次响应同样的请求。
长连接65 再关掉了一个服务器
1
| docker stop 1febd25736e3
|

再次轮询

在腾讯云上实操
创建一个私有网络
<013>
<014>
购买两台实例
<016>
<017>
直接按上述步骤,搭建起所需要的服务
搭建方案:在两台实例上安装nginx
,和``todo、redis、mysql`,并且在每个实例上都起多台实例
注意:Debian的nginx配置文件如下
<018>
购买负载均衡