文章目录
测试环境
VM PRO 17
虚拟机centos Centos Linux 7 (Core)
Kernel 3.10.0-327.10.1.e17.x86_64 on an x86_64
连接类型 NAT 子网地址192.168.127.0
创建macvlan 网络
当前虚拟机ip 是 192.168.127.128,docker如何创建一个centos系统 ip是192.168.127.x呢
主要有两种方法:使用 macvlan 网络驱动(推荐)或创建自定义的 bridge 网络。但优先推荐 macvlan。
网关验证
ip route | grep default
我网关是192.168.127.2
查看网卡名字
ip addr
我的网卡是eno16777736
老内核记得开混杂模式
sudo ip link set eno16777736 promisc on
1)创建 macvlan 网络
执行以下命令,请务必将 --subnet, --gateway, -o parent 这三个参数替换为你自己的网络信息。
bash
# 请根据你的实际网络环境修改以下参数
docker network create -d macvlan \
--subnet=192.168.127.0/24 \
--gateway=192.168.127.2 \
-o parent=eno16777736 \
macvlan_net
一、先验证你刚才创建的 macvlan 网络是否成功
查看所有 Docker 网络
bash
docker network ls
你会看到 macvlan_net 说明创建成功。
查看 macvlan 详细配置
bash
docker network inspect macvlan_net
里面会显示:
- subnet: 192.168.127.0/24
- gateway: 192.168.127.2
- parent: eno16777736
二、如果要删除(重建用)
删除 macvlan 网络
bash
docker network rm macvlan_net
删除后再用 docker network ls 确认消失即可。
三、重新创建
bash
docker network create -d macvlan \
--subnet=192.168.127.0/24 \
--gateway=192.168.127.2 \
-o parent=eno16777736 \
macvlan_net
四、启动一个容器 指定同网段IP 测试
我们用最简单的 alpine 镜像测试。
启动容器(指定IP:192.168.127.120)
bash
docker run -d \
--name macvlan_test \
--network macvlan_net \
--ip 192.168.127.120 \
alpine sleep 3600
五、最终验证:容器是否真的在同网段
进入容器查看 IP
bash
docker exec -it macvlan_test ifconfig
# 或者
docker exec -it macvlan_test ip addr
在 局域网其他机器 ping 这个IP
在你电脑/另一台服务器执行:
ping 192.168.127.120
注意:Linux 内核限制,宿主机 ping 不通容器 ,但局域网其他设备一定能通。
六、用完清理
bash
docker stop macvlan_test
docker rm macvlan_test
全套命令速查
bash
sudo ip link set eno16777736 promisc on
# 查看
docker network ls
docker network inspect macvlan_net
# 删除
docker network rm macvlan_net
# 创建
docker network create -d macvlan --subnet=192.168.127.0/24 --gateway=192.168.127.2 -o parent=eno16777736 macvlan_net
# 启动测试容器
docker run -d --name macvlan_test --network macvlan_net --ip 192.168.127.120 alpine sleep 3600
# 进入容器查看IP
docker exec -it macvlan_test ifconfig
ip设计
进入正题,我们先设计一下ip地址
nginx+keepalived+nacos集群
nacos集群ip地址 192.168.127.121,192.168.127.122,192.168.127.123
nginx+keepalived集群ip地址 192.168.127.131,192.168.127.132
keepalived VIP地址 192.168.127.141
mysql ip地址 192.168.127.130
创建nacos集群
Nacos 集群必须外部数据库 这里用MySQL 8.0
创建 MySQL 容器(Nacos 集群必须使用外部数据库)
启动 MySQL 并挂载数据(推荐指定版本,好像不能高过8.0.22,老版本nacos会有版本兼容问题)
bash
docker pull mysql:8.0
docker run -d \
--name mysql-nacos \
--network macvlan_net \
--ip 192.168.127.130 \
--restart=always \
-e MYSQL_ROOT_PASSWORD=root123 \
-e MYSQL_DATABASE=nacos_config \
-e MYSQL_USER=nacos \
-e MYSQL_PASSWORD=nacos123 \
mysql:8.0 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
验证 MySQL 容器运行状态
bash
docker ps | grep mysql-nacos
docker exec -it mysql-nacos mysql -uroot -proot123
show databases;
show grants for nacos@'%';
# 退出mysql
exit
拉一下nacos,这里用的v2.4.0的镜像,这里没开鉴权好像,里面自带sql没有user
bash
# docker pull nacos/nacos-server:v2.4.0
# 拉取国内镜像
docker pull nacos-registry.cn-hangzhou.cr.aliyuncs.com/nacos/nacos-server:v2.4.0
# 重命名为官方名称(后续启动不用改命令)
docker tag nacos-registry.cn-hangzhou.cr.aliyuncs.com/nacos/nacos-server:v2.4.0 nacos/nacos-server:v2.4.0
# 1. 临时启动 nacos 2.4.0
docker run -d --name nacos-temp nacos/nacos-server:v2.4.0
# 2. 把内置的 mysql-schema.sql 复制到宿主机
docker cp nacos-temp:/home/nacos/conf/mysql-schema.sql ./nacos-mysql-2.4.0.sql
# 导入数据库
docker exec -i mysql-nacos mysql -uroot -proot123 nacos_config < nacos-mysql-2.4.0.sql
# 3. 删除临时容器
docker rm -f nacos-temp
三、启动 Nacos 集群(3 节点)
创建配置目录并编写 application.properties
bash
mkdir nacos-cluster && cd nacos-cluster
创建配置文件(注意节点不共用,记得修改nacos.server.ip):
bash
cat > application.properties <<EOF
# 基础配置
server.port=8848
nacos.mode=cluster
spring.datasource.platform=mysql
# MySQL 配置(保留你的修复参数)
db.num=1
db.url.0=jdbc:mysql://192.168.127.130:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
db.user.0=nacos
db.password.0=nacos123
# ==================== 集群核心修复(关键!) ====================
# Nacos 2.X 集群节点列表(必须带 7848 端口,raft 通信端口)
nacos.member.list=192.168.127.121:7848,192.168.127.122:7848,192.168.127.123:7848
# 固定自身IP(macvlan 必须加,让节点知道自己是谁)
# 注意:启动哪个节点,就把这个IP改成对应节点的!!
nacos.server.ip=192.168.127.121
# 其他基础配置
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=180000
nacos.naming.empty-service.clean.period-time-ms=180000
server.tomcat.accesslog.enabled=true
EOF
启动三个 Nacos 节点,增加重启策略与 JVM 限制
bash
# 节点1 (192.168.127.121)
sed -i 's/nacos.server.ip=.*/nacos.server.ip=192.168.127.121/' application.properties
docker run -d \
--name nacos1 \
--network macvlan_net \
--ip 192.168.127.121 \
--restart=always \
-e JVM_XMS=512m -e JVM_XMX=512m -e JVM_XMN=256m \
-e NACOS_SERVERS="192.168.127.121:8848,192.168.127.122:8848,192.168.127.123:8848" \
-v $(pwd)/application.properties:/home/nacos/conf/application.properties \
nacos/nacos-server:v2.4.0
# 节点2 (192.168.127.122)
sed -i 's/nacos.server.ip=.*/nacos.server.ip=192.168.127.122/' application.properties
docker run -d \
--name nacos2 \
--network macvlan_net \
--ip 192.168.127.122 \
--restart=always \
-e JVM_XMS=512m -e JVM_XMX=512m -e JVM_XMN=256m \
-e NACOS_SERVERS="192.168.127.121:8848,192.168.127.122:8848,192.168.127.123:8848" \
-v $(pwd)/application.properties:/home/nacos/conf/application.properties \
nacos/nacos-server:v2.4.0
# 节点3 (192.168.127.123)
sed -i 's/nacos.server.ip=.*/nacos.server.ip=192.168.127.123/' application.properties
docker run -d \
--name nacos3 \
--network macvlan_net \
--ip 192.168.127.123 \
--restart=always \
-e JVM_XMS=512m -e JVM_XMX=512m -e JVM_XMN=256m \
-e NACOS_SERVERS="192.168.127.121:8848,192.168.127.122:8848,192.168.127.123:8848" \
-v $(pwd)/application.properties:/home/nacos/conf/application.properties \
nacos/nacos-server:v2.4.0
验证 Nacos 集群状态
浏览器访问任意节点:http://192.168.127.121:8848/nacos/index.html,
默认账号密码 nacos/nacos(我这里没开鉴权)
进入"集群管理"→"节点列表",应显示三个节点为 UP

补充检查 gRPC 端口(Nacos 2.x 依赖):
docker exec nacos1 netstat -tulpn | grep -E "9848|9849"
构建 nginx + keepalived
创建构建目录
mkdir nginx-keepalived && cd nginx-keepalived
文件 1:Dockerfile
因为这虚拟机的centos内核很老了,这里用alpine:3.18,没有用最新的
bash
cat > Dockerfile <<EOF
FROM alpine:3.18
RUN apk add --no-cache nginx keepalived bash
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
EOF
文件 2:nginx.conf(反向代理到 Nacos 集群)
bash
cat > nginx.conf <<'NEOF'
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream nacos_cluster {
server 192.168.127.121:8848;
server 192.168.127.122:8848;
server 192.168.127.123:8848;
}
server {
listen 80;
location /nacos {
proxy_pass http://nacos_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
return 302 /nacos;
}
}
}
NEOF
文件 3:entrypoint.sh(VIP 配置去掉子网掩码)
我遇到点PID BUG先这么解决吧
bash
cat > entrypoint.sh <<'EOF'
#!/bin/bash
set -e
# 1. 准备目录
mkdir -p /etc/keepalived
# 2. 生成 Keepalived 配置(简化版,去掉 global_defs 里的 pid_file)
cat > /etc/keepalived/keepalived.conf <<KEEP
global_defs {
# 跳过检查源地址,适合容器环境
vrrp_skip_check_adv_addr
# 禁止严格模式(否则容易因为网卡问题报错)
# vrrp_strict <-- 注释掉这行
}
vrrp_instance VI_1 {
state ${KEEPALIVED_STATE:-MASTER}
interface eth0
virtual_router_id 51
priority ${KEEPALIVED_PRIORITY:-100}
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.127.141
}
}
KEEP
# 3. 【关键】清理所有 Keepalived 可能存放 PID 的路径
# 不管它想往哪写,先把可能的地方都删了
echo "Cleaning up possible PID files..."
rm -f /var/run/keepalived.pid
rm -f /run/keepalived.pid
rm -f /tmp/keepalived.pid
rm -rf /run/keepalived/
mkdir -p /run/keepalived/ # 有些版本会尝试往这个目录写
echo "Testing nginx configuration..."
nginx -t
echo "Starting nginx..."
nginx
echo "Starting keepalived..."
# 增加 --vrrp 来明确只启动 VRRP 功能,减少复杂度
exec keepalived --dont-fork --log-console --release-vips --vrrp
EOF
chmod +x entrypoint.sh
构建镜像,这里network用宿主机的dns
bash
docker build --network=host -t nginx-keepalived-nacos .
# docker build --no-cache --network=host -t nginx-keepalived-nacos .
启动两个高可用节点(增加 --privileged 和重启策略)
bash
# 主节点
docker run -d \
--name nginx-kp1 \
--network macvlan_net \
--ip 192.168.127.131 \
--privileged \
--restart=always \
-e KEEPALIVED_STATE=MASTER \
-e KEEPALIVED_PRIORITY=100 \
nginx-keepalived-nacos
# 备节点
docker run -d \
--name nginx-kp2 \
--network macvlan_net \
--ip 192.168.127.132 \
--privileged \
--restart=always \
-e KEEPALIVED_STATE=BACKUP \
-e KEEPALIVED_PRIORITY=90 \
nginx-keepalived-nacos
查看日志
docker logs nginx-kp1 --tail 60
docker logs nginx-kp2 --tail 60
通过 VIP 访问 Nacos
在局域网任意设备浏览器访问:http://192.168.127.141/nacos
应出现 Nacos 登录页,并能正常登录即可。
查看 VIP 所在位置
bash
docker exec nginx-kp1 ip addr show eth0 | grep 192.168.127.141 # MASTER 应有
# inet 192.168.127.141/32 scope global eth0
docker exec nginx-kp2 ip addr show eth0 | grep 192.168.127.141 # BACKUP 应无
测试故障转移
docker stop nginx-kp1
稍等 2~3 秒,再次访问 http://192.168.127.141/nacos 仍然可用。
检查 VIP 已漂移到备机:
docker exec nginx-kp2 ip addr show eth0 | grep 192.168.127.141
恢复主节点并观察 VIP 抢回:
docker start nginx-kp1
稍后 VIP 会自动回到 nginx-kp1
docker exec nginx-kp1 ip addr show eth0 | grep 192.168.127.141
PS:Keepalived双主模式
如果要做双主模式改一下keepalived.conf配置就好,不做过多展开了
bash
cat > entrypoint.sh <<'EOF'
#!/bin/bash
set -e
# 默认值设置
# 实例 1 (默认配置)
STATE_1=${KEEPALIVED_STATE:-MASTER}
PRIORITY_1=${KEEPALIVED_PRIORITY:-100}
VIP_1=${KEEPALIVED_VIP_1:-192.168.127.141}
# 实例 2 (双主新增配置)
# 如果没设置 STATE_2,默认不启动实例 2 (保持向后兼容单主模式)
STATE_2=${KEEPALIVED_STATE_2:-}
PRIORITY_2=${KEEPALIVED_PRIORITY_2:-90}
VIP_2=${KEEPALIVED_VIP_2:-192.168.127.142}
# 1. 准备目录
mkdir -p /etc/keepalived
# 2. 生成 Keepalived 配置
cat > /etc/keepalived/keepalived.conf <<KEEP
global_defs {
vrrp_skip_check_adv_addr
}
# ------------ VRRP 实例 1 ------------
vrrp_instance VI_1 {
state ${STATE_1}
interface eth0
virtual_router_id 51
priority ${PRIORITY_1}
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
${VIP_1}
}
}
KEEP
# ------------ VRRP 实例 2 (双主模式) ------------
# 只有当设置了 KEEPALIVED_STATE_2 环境变量时才追加这一段配置
if [ -n "$STATE_2" ]; then
cat >> /etc/keepalived/keepalived.conf <<KEEP2
vrrp_instance VI_2 {
state ${STATE_2}
interface eth0
virtual_router_id 52 # 注意:ID 必须与实例 1 不同
priority ${PRIORITY_2}
advert_int 1
authentication {
auth_type PASS
auth_pass 1234 # 密码可以相同
}
virtual_ipaddress {
${VIP_2}
}
}
KEEP2
fi
# 3. 清理 PID
echo "Cleaning up possible PID files..."
rm -f /var/run/keepalived.pid /run/keepalived.pid /tmp/keepalived.pid
rm -rf /run/keepalived/ && mkdir -p /run/keepalived/
echo "Testing nginx configuration..."
nginx -t
echo "Starting nginx..."
nginx
echo "Starting keepalived (Dual Master Mode)..."
# 注意:去掉了 --vrrp 参数,因为现在有多个实例需要管理
exec keepalived --dont-fork --log-console --release-vips
EOF
chmod +x entrypoint.sh
重新构建
bash
# 停止删除旧容器
docker stop nginx-kp1 nginx-kp2
docker rm nginx-kp1 nginx-kp2
# 重新构建镜像 (因为改了 entrypoint.sh)
docker build --network=host -t nginx-keepalived-nacos-active-active .
启动docker
bash
docker run -d \
--name nginx-kp1 \
--network macvlan_net \
--ip 192.168.127.131 \
--privileged \
--restart=always \
-e KEEPALIVED_STATE=MASTER \
-e KEEPALIVED_PRIORITY=100 \
-e KEEPALIVED_VIP_1=192.168.127.141 \
-e KEEPALIVED_STATE_2=BACKUP \
-e KEEPALIVED_PRIORITY_2=90 \
-e KEEPALIVED_VIP_2=192.168.127.142 \
nginx-keepalived-nacos-active-active
docker run -d \
--name nginx-kp2 \
--network macvlan_net \
--ip 192.168.127.132 \
--privileged \
--restart=always \
-e KEEPALIVED_STATE=BACKUP \
-e KEEPALIVED_PRIORITY=90 \
-e KEEPALIVED_VIP_1=192.168.127.141 \
-e KEEPALIVED_STATE_2=MASTER \
-e KEEPALIVED_PRIORITY_2=100 \
-e KEEPALIVED_VIP_2=192.168.127.142 \
nginx-keepalived-nacos-active-active
查看节点 1 (kp1):
docker logs nginx-kp1 --tail 30
你会看到:
VRRP_Instance(VI_1) Entering MASTER STATE (拿到 .141)
VRRP_Instance(VI_2) Entering BACKUP STATE (待命 .142)
查看节点 2 (kp2):
docker logs nginx-kp2 --tail 30
你会看到:
VRRP_Instance(VI_1) Entering BACKUP STATE (待命 .141)
VRRP_Instance(VI_2) Entering MASTER STATE (拿到 .142)
两URL都可以访问了
