Q108. 简述 LVS 的三种工作模式(NAT, DR, TUN)的原理和区别。

1. 是什么:LVS(Linux Virtual Server)是一个基于**四层(传输层)**的负载均衡器,通过内核 IPVS 模块把到达 VIP 的请求转发到后端的 Real Server(RS)。三种工作模式 NAT / DR / TUN 的核心区别在于「数据包如何被改写、回包是否经过调度器」。

2. 为什么用它:选型决定架构对网络的改造程度、后端服务器的配置要求和性能上限——DR 模式性能最高但要求后端同网段并做 ARP 抑制;NAT 模式对后端无要求但调度器是瓶颈;TUN 模式适合跨网段/跨机房部署。理解三者才能按场景选对模式。

3. 怎么用它(三种模式原理与区别):

  • NAT(网络地址转换):调度器转发时做 DNAT+SNAT——把请求目标 IP(VIP)改写为选中 RS 的 IP,同时把源 IP 改写为调度器自身 IP;请求和响应都必须经过调度器,调度器成为性能瓶颈。RS 无需特殊配置,只需把默认网关指向调度器。
  • DR(直接路由):调度器只改写目标 MAC 地址(改为选中 RS 的 MAC),IP 报文本身不变(目标仍是 VIP);请求经调度器、响应由 RS 直连客户端返回,吞吐最高。要求 RS 与调度器同一二层网络,且 RS 必须配置 VIP 并做 ARP 抑制(见 Q109)。
  • TUN(IP 隧道):调度器把请求用 IP-in-IP 隧道封装后发给 RS(外层目标为 RS 的 IP),RS 解封装后处理,响应由 RS 直连客户端。不要求二层相邻、可跨网段/机房,但要求 RS 支持隧道并配置隧道接口 + VIP,有封装开销。
模式请求改写回程后端要求性能
NAT改 IP(DNAT+SNAT)必经调度器无特殊要求,网关指向调度器最低(调度器瓶颈)
DR只改 MAC直连客户端同网段 + 配置 VIP + ARP 抑制最高
TUNIP 隧道封装直连客户端支持隧道 + 配置 VIP中(封装开销)
  • 常用调度算法:rr(轮询)、wrr(加权轮询)、lc(最少连接)、wlc(加权最少连接)、sh(源地址哈希);查看/管理规则用 ipvsadm -L -n

4. 使用场景:大流量网站四层负载均衡选 DR;跨机房/跨网段用 TUN;后端无法改造(如 Windows)且规模小时用 NAT。面试关键:三句话对比——NAT 双向改 IP 回程必经调度器;DR 只改 MAC 回程直连客户端、性能最高;TUN 用隧道跨网段、回程直连。生产最常见 DR。


Q109. LVS DR 模式中,为什么要在 Real Server 上配置 VIP 和 ARP 抑制?

1. 是什么:DR 模式下,VIP 会同时配置在调度器和每台 Real Server 的 lo(回环)接口上;ARP 抑制指通过内核参数让 Real Server 对「VIP 的 ARP 请求」不作出应答,保证 VIP 的 ARP 应答只由调度器发出。

2. 为什么用它

  • 为什么配 VIP:DR 只改 MAC 不改 IP,后端收到的请求目标 IP 仍是 VIP。Real Server 若不配置 VIP,内核会认为该包「不是发给我的」而丢弃;把 VIP 绑到 lo:0 上,内核才会接受目标为 VIP 的报文并交给应用处理。
  • 为什么抑制 ARP:客户端/交换机用 ARP 请求查询「VIP 对应的 MAC」。若每台 RS 都对 VIP 的 ARP 请求应答自己的 MAC,就会出现 ARP 抢答——客户端把流量直接发给某台 RS 而非调度器,负载均衡彻底失效,还会造成交换机 MAC 表抖动。必须让 VIP 的 ARP 应答权独占调度器。

3. 怎么用它(Real Server 配置):

# 1) 在回环接口配置 VIP(掩码用 255.255.255.255,避免与调度器同网段地址冲突)
ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 up
# 2) 添加主机路由:目标为 VIP 的包走 lo
route add -host 192.168.1.100 dev lo

# 3) ARP 抑制(关键),一般写入 /etc/rc.local 或 systemd 开机执行
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
  • arp_ignore=1只对本接口地址的 ARP 请求应答。VIP 配置在 lo:0,而 ARP 请求从 eth 接口到达,目标 IP 不是 eth 的地址 → RS 不应答 VIP 的 ARP;
  • arp_announce=2:应答/通信时使用最合适的接口地址,避免用 lo 上的 VIP 作为源地址发出,防止回包源地址异常;
  • 调度器保持默认 ARP 配置(正常应答 VIP),保证客户端把流量只送到调度器。

4. 使用场景:所有 LVS DR 模式部署、排查「请求没进调度器而直接到了某台后端」类故障。面试关键:一句话——配 VIP 是为了「接收目标为 VIP 的报文」(DR 不改 IP),ARP 抑制是为了「防止 RS 抢答 VIP、保证流量只进调度器」;能默写 arp_ignore=1arp_announce=2


Q110. HAProxy 的 mode http 和 mode tcp 有什么区别?

1. 是什么mode 决定 HAProxy 工作的协议层级。mode http 表示 HAProxy 解析 HTTP 协议(七层),mode tcp 表示只做四层转发,原样透传 TCP 报文、不解析内容。

2. 为什么用它:选对 mode 决定「能做多少业务逻辑」与「能转什么协议」——需要按 URL/Host/Cookie 路由、做 HTTP 级健康检查、改写请求头、SSL 卸载等必须用 http 模式;要转发 MySQL/Redis/WebSocket/SSH 等非 HTTP 或需要完全透传的协议必须用 tcp 模式,否则会因解析失败导致转发异常。

3. 怎么用它

  • mode http(七层)
    • 解析 HTTP 请求/响应,支持基于 URL、Host、Header、Cookie、方法、来源 IP 的 ACL 路由;
    • 支持 HTTP 健康检查(option httpchk 探测 URI)、http-request/http-response 改写、重定向、压缩、Cookie 会话保持;
    • 缺点:有协议解析开销,吞吐略低于 tcp;对非 HTTP 协议无效。
  • mode tcp(四层)
    • 只建立/转发 TCP 连接,不解析 payload,任何 TCP 协议(MySQL、Redis、SSH、WebSocket、RDP、TLS 任意内容)都能透传;
    • 性能更高(无解析开销);健康检查只能用 TCP 层探测(server ... check + port);
    • 会话保持只能基于源 IP(stick-tablesrc),无法基于 Cookie。
  • 配置示例(按 frontend 各自指定 mode):
frontend http_front
    bind *:80
    mode http
    use_backend web_back

frontend mysql_front
    bind *:3306
    mode tcp
    use_backend mysql_back
  • 常见混合架构:Web 流量用 mode http,数据库/缓存/长连接用 mode tcp;同一 HAProxy 内不同 frontend 可各自指定。注意:HAProxy 默认即 http 模式

4. 使用场景:Web/API 负载均衡、URL 级路由、HTTPS 卸载用 http 模式;数据库、Redis、SSH、WebSocket、自定义 TCP 协议转发用 tcp 模式。面试关键:核心一句「http 解析 HTTP 能做七层业务逻辑,tcp 只转发四层报文、更通用更快」,并举例「MySQL 必须用 tcp 模式」。


Q111. 如何用 HAProxy 做基于 ACL 的智能路由?

1. 是什么:HAProxy 通过 ACL(访问控制列表) 对请求的字段(域名、URL 路径、Header、Cookie、源 IP、请求方法等)做匹配,再用 use_backend / redirect / http-request 等指令把请求路由到不同后端,实现按规则分流。

2. 为什么用它:一个入口要同时服务多种业务时(按域名/路径分发到不同后端、灰度发布、A/B 测试、按地区分流、接口版本切换),在负载均衡层用 ACL 路由比在应用层做更简单高效,且不侵入业务代码,方便运维直接控制流量。

3. 怎么用它

frontend http_in
    bind *:80
    mode http

    # 1) 定义 ACL:域名 / 路径 / Header / Cookie / 来源 IP / 方法
    acl is_api        hdr(host) -i api.example.com     # 域名
    acl is_static     path_beg /static /images         # 路径前缀
    acl is_admin      path_beg /admin
    acl is_gray       hdr(Cookie) -m sub GRAY=on       # Cookie 含灰度标记
    acl from_beijing  src 114.244.0.0/16               # 来源 IP 段
    acl is_post       method POST

    # 2) 按 ACL 路由(自上而下匹配,第一个命中即生效)
    use_backend api_pool      if is_api
    use_backend static_pool   if is_static
    use_backend gray_app      if is_gray
    use_backend admin_pool    if is_admin
    default_backend default_app              # 兜底

    # 3) 也可做重定向 / 请求改写
    http-request redirect scheme https unless is_api
    http-request set-header X-Region "beijing" if from_beijing

backend api_pool
    balance roundrobin
    server api1 10.0.0.11:8080 check
    server api2 10.0.0.12:8080 check
  • 常用匹配类型:hdr(host)(域名)、path_beg / path_end / path_reg(路径)、-i(忽略大小写)、-m sub(包含子串)、src(源 IP)、method(方法)、hdr(Cookie)(Cookie)、req.ssl_sni(TLS SNI,七层按证书域名);
  • 路由优先级:use_backend 按配置顺序自上而下匹配第一个为 true 的规则,全部不命中走 default_backend
  • 灰度/AB 可配合 stick-table + set-var 做基于 Cookie 或用户维度的会话保持。

4. 使用场景:多域名/多业务统一入口、静态资源与动态接口分流、灰度发布与 AB 测试、按地域/线路分流、接口版本路由。面试关键:流程是「定义 ACL → use_backend 分流 → default_backend 兜底」;掌握 hdr(host)path_begsrchdr(Cookie) 四种匹配,并说清 use_backend 是「自上而下、第一个匹配生效」。


Q112. Keepalived 的原理是什么?VRRP 协议是如何工作的?

1. 是什么:Keepalived 是一个高可用软件,核心基于 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议,RFC 3768):把多台机器虚拟成一个「虚拟路由器」,共享一个虚拟 IP(VIP),通过主备选举 + 心跳 + 故障自动切换实现服务高可用。

2. 为什么用它:单台服务器(或负载均衡器)是单点故障,宕机即业务中断。Keepalived/VRRP 让多台节点共用一个 VIP,正常情况下 VIP 绑定在主节点,主节点故障时备节点「接管」VIP 继续服务,客户端无感知(IP 不变),把故障恢复从人工几十分钟降到秒级自动切换

3. 怎么用它(VRRP 工作原理):

  • 虚拟路由器组:多个真实设备组成一个虚拟路由器,对外表现为一个虚拟路由器,拥有虚拟 MAC00-00-5e-00-01-xx)和 VIP;
  • 角色选举:一个 Master + 多个 Backup,按优先级(priority,默认 100) 选举,优先级高者为 Master,同优先级 IP 大者优先;
  • 心跳通告:Master 周期性(默认 1s,advert_int)向组播地址 224.0.0.18 发送 VRRP Advertisement 通告报文;
  • 故障切换:Backup 连续 3 × advert_int(默认 3s)收不到通告,即判定 Master 故障,优先级最高的 Backup 抢占成为新 Master,把 VIP 绑定到自己的接口并开始发送通告
  • 抢占模式preempt(默认)Master 恢复后抢回 VIP;nopreempt 关闭抢占,避免切换抖动;
  • Keepalived 扩展:在 VRRP 之外增加健康检查vrrp_script + track_script)——监控服务/进程/端口,脚本失败则降低本机优先级或主动让出,比纯 VRRP「只看心跳」更可靠。
# /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
    state MASTER            # 备机写 BACKUP
    interface eth0          # 承载 VIP 的网卡
    virtual_router_id 51    # 组内所有节点必须一致
    priority 100            # 主 100,备 90
    advert_int 1            # 通告间隔 1s
    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }
    track_script {
        chk_nginx           # 脚本失败则本节点降级让位
    }
}

4. 使用场景:负载均衡器高可用(LVS/HAProxy + Keepalived)、数据库主从 VIP、应用网关双机。面试关键:先讲「多节点虚拟成一个虚拟路由器、共用一个 VIP」,再答 VRRP 三机制——组播心跳(224.0.0.18、1s 一次)、优先级选举 Master、连续 3 个周期收不到通告就切换;补充 Keepalived 的 vrrp_script 健康检查是其比纯 VRRP 更实用的地方。


Q113. 如何实现 Keepalived 的脑裂监测和处理?

1. 是什么:脑裂(Split-Brain)指主备节点同时认为自己是 Master、都绑定了 VIP,导致同一 VIP 被两台机器同时响应,流量被分散、会话/数据状态不一致,是高可用集群最危险的状态之一。

2. 为什么用它:VRRP 靠「组播心跳 + 超时」判定对方故障。当心跳链路本身出问题(网卡故障、交换机端口隔离、网络拥塞、防火墙拦截组播)而双方服务都正常时,备节点会误以为主节点挂了而抢 VIP,产生脑裂。必须能检测并处理,否则 VIP 冲突引发的故障比单机宕机更严重(数据双写、路由混乱)。

3. 怎么用它

  • 脑裂检测
    1. 看 VIP 归属ip addr show eth0 看 VIP 是否同时出现在两台机器上;
    2. 看 Keepalived 状态systemctl status keepalived / 日志 journalctl -u keepalived -f,两台都出现 Entering MASTER STATE 即脑裂;
    3. 第三方探针:从第三台机器(监控主机)ping / arping VIP,若 VIP 的 MAC 在主机 A、B 的 MAC 之间来回跳变,判定脑裂;
    4. 脚本监测:定时脚本检查「本机是 MASTER 且能 ping 通对端存活、且对端也持有 VIP」即判定脑裂。
  • 处理手段
    1. 仲裁隔离(fencing/STONITH):脑裂时通过带外手段(IPMI/iLO 远程关机、云厂商 API)强制关闭对方节点或杀掉对方 keepalived,保证只剩一台持有 VIP;
    2. 本机让位:检测到脑裂后本机关闭 VIP(systemctl stop keepalived 或 down 接口),保留健康节点;备机脚本示例:
#!/bin/bash
# 备机上:若对端仍存活(能 ping 通)而本机却成了 Master → 脑裂,本机让位
if ping -c 3 -W 1 <对端IP> >/dev/null 2>&1; then
    systemctl stop keepalived
    exit 1
fi
exit 0
3. **降低误判概率(配置层面)**:`advert_int` 调大容错窗口、开启 `nopreempt` 避免抖动、心跳与业务走独立网卡/多路径、防火墙放行组播 `224.0.0.18`(协议号 112);
4. **应用层兜底**:数据库等关键场景用**分布式锁/仲裁**(etcd、ZooKeeper)决定谁真正持权,不能只依赖 VRRP。

4. 使用场景:双机高可用集群巡检、故障演练、脑裂告警处置。面试关键:先说成因「心跳链路故障导致备机误抢 VIP」,再答检测三招「看 VIP 是否双绑定、看日志是否双 MASTER、从第三方节点探测 VIP 的 MAC 跳变」,最后答处理「仲裁/隔离杀掉一方 + 调大超时窗口 + 核心场景用分布式锁兜底」。


Q114. 如何用 LVS + Keepalived 搭建高可用的负载均衡集群?

1. 是什么:LVS 负责把流量分发到后端 Real Server(负载均衡),Keepalived 负责为调度器提供高可用(两台调度器共用一个 VIP,主故障自动漂移)并同时做后端 RS 的健康检查,组合成「调度器双机热备 + 后端多台可水平扩展」的完整高可用负载均衡集群。

2. 为什么用它:单台 LVS 调度器是单点故障;且 IPVS 本身不做后端健康检查。Keepalived 一石二鸟——既用 VRRP 保证调度器 VIP 漂移,又通过 virtual_server 里对每个 real_server 的 TCP/HTTP 探测,把故障 RS 自动从转发列表摘除,实现「调度器高可用 + 后端自动摘除」两个目标,是 LVS 架构的标准配套。

3. 怎么用它(DR 模式为例,两台调度器 + 多台 RS):

  • 架构:Master 调度器 192.168.1.11 / Backup 调度器 192.168.1.12 + 两台以上 Real Server 192.168.1.21/22(跑 Nginx/Web)+ 虚拟 IP 192.168.1.100
  • RS 端配置:每台 RS 配置 VIP 到 lo:0 + ARP 抑制(见 Q109);
  • Keepalived 配置(两台调度器,仅 state/priority 不同):
# /etc/keepalived/keepalived.conf(Master,Backup 改 state=BACKUP、priority=90)
global_defs {
    router_id LVS_MASTER
}
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }
}
# 用 Keepalived 定义 LVS 转发规则 + RS 健康检查
virtual_server 192.168.1.100 80 {
    delay_loop 6               # 每 6 秒检查一次 RS
    lb_algo wrr                # 加权轮询
    lb_kind DR                 # 工作模式
    persistence_timeout 50     # 会话保持 50s
    protocol TCP
    real_server 192.168.1.21 80 {
        weight 1
        TCP_CHECK { connect_timeout 3; connect_port 80 }
    }
    real_server 192.168.1.22 80 {
        weight 2
        TCP_CHECK { connect_timeout 3; connect_port 80 }
    }
}
  • 切换流程:Master 宕机 → Backup 3s 未收到通告 → 抢占 VIP → Keepalived 在新 Master 上重建 virtual_server 的 IPVS 规则 → 继续转发;恢复后按 preempt/nopreempt 决定是否抢回;
  • 验证ipvsadm -L -n 看 IPVS 规则与 RS 状态(ActiveConn、故障 RS 被摘除);ip addr show eth0 看 VIP 在哪台;拔掉 Master 网线测试 VIP 秒级漂移;
  • 注意:RS 侧必须做 ARP 抑制(见 Q109),保证流量永远进调度器的 VIP。

4. 使用场景:大流量门户/电商四层负载均衡、需要 RS 水平扩容且调度器不宕机的生产架构。面试关键:说清分工「Keepalived 管 VIP 漂移 + 管 RS 健康检查,LVS 管流量分发」;能默写 virtual_server + real_server + TCP_CHECK 三段配置;强调 RS 必须配 ARP 抑制、两台调度器仅 priority 不同。


Q115. 如何用 HAProxy + Keepalived 搭建高可用的负载均衡集群?

1. 是什么:用两台 HAProxy 做四/七层负载均衡(mode tcp/mode http),Keepalived 提供 VIP 漂移实现双机热备,HAProxy 自身通过 server ... check 做后端健康检查,组合成「HAProxy 双机热备 + 后端自动摘除」的高可用负载均衡集群。

2. 为什么用它:HAProxy 功能强大(七层 ACL 路由、健康检查、会话保持)但自身是单点,且没有内置 VIP 漂移能力;Keepalived/VRRP 恰好补上这块,让 VIP 在主备 HAProxy 间自动切换,客户端始终访问同一 VIP,实现秒级故障转移。

3. 怎么用它

  • 架构:HAProxy Master 192.168.1.11 + Backup 192.168.1.12 + 多台后端 Web 192.168.1.21/22 + VIP 192.168.1.100;两台 HAProxy 配置保持一致;
  • Keepalived 配置(用 vrrp_script 检测 HAProxy 存活,保证「HAProxy 挂了就切 VIP」,比纯 VRRP 更可靠):
# 两台机器 keepalived.conf,仅 state/priority 不同
vrrp_script chk_haproxy {
    script "/usr/bin/killall -0 haproxy"   # 检测 haproxy 进程存活,返回 0 为健康
    interval 2          # 每 2 秒检测
    fall 2              # 连续 2 次失败判定不健康
    rise 2              # 连续 2 次成功恢复健康
}
vrrp_instance VI_1 {
    state MASTER        # 备机 BACKUP
    interface eth0
    virtual_router_id 51
    priority 100        # 备机 90
    advert_int 1
    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }
    track_script {
        chk_haproxy     # haproxy 挂掉则优先级降低,VIP 漂移到备机
    }
}
  • HAProxy 配置:与单机 HAProxy 相同,前端 frontend + 后端 server ... check;开启 option httpchk 做 HTTP 层健康检查:
backend web_servers
    mode http
    balance roundrobin
    option httpchk GET /healthz
    server web1 192.168.1.21:80 check inter 3s fall 2 rise 2
    server web2 192.168.1.22:80 check inter 3s fall 2 rise 2
  • 切换流程:Master 的 HAProxy 或整机故障 → chk_haproxy 失败使优先级降低 → Backup 抢占 VIP → 客户端新连接进入 Backup 的 HAProxy 继续转发;
  • 验证ip addr show 看 VIP 漂移;killall -0 haproxy 不返回值验证脚本;curl -I http://192.168.1.100/ 验证 VIP 可访问;
  • 注意:两台 HAProxy 的配置与证书需保持一致(rsync/git 发布同步);已建立的 TCP/WebSocket 长连接切换后需重连,业务要支持重连。

4. 使用场景:Web/API 七层负载均衡高可用、需要按 URL/域名路由又要求 VIP 不中断的企业网关。面试关键:核心是「Keepalived 用 vrrp_script 检测 HAProxy 存活、挂了降级让 VIP 漂移;HAProxy 自己用 option httpchk + check 做后端健康检查」;能对比 LVS+Keepalived(四层、virtual_server 管 RS)与 HAProxy+Keepalived(四/七层、frontend/backend 管后端)的差异。

Q116. 描述一个完整的电商网站高可用架构(从 DNS 到后端 DB)。

1. 是什么:一个生产级电商网站高可用架构是一条完整的访问链路:DNS → CDN → 四层负载均衡(LVS)→ 七层负载均衡(Nginx/HAProxy)→ 应用服务 → 缓存 → 数据库 → 对象/文件存储,每一层都有冗余与容灾设计,任意一层单点故障不影响整体服务。

2. 为什么用它:电商对可用性要求极高(大促、秒杀、支付),任何单点环节故障都会导致交易中断或资金风险;分层 + 每层冗余 + 缓存兜底,能把故障面控制在局部、把热点流量挡在入口,是支撑高并发与高可用的业界标准架构。

3. 怎么用它(自顶向下的分层设计):

① DNS(智能解析):按地域/运营商解析到不同机房入口,多 A 记录 + 短 TTL,故障可摘除
② CDN:静态资源(图片/JS/CSS/详情页)就近缓存,回源到 OSS/源站,减轻源站压力
③ 四层负载均衡:LVS(DR 模式)+ Keepalived 双机,VIP 漂移秒级切换,按 IP/端口转发
④ 七层负载均衡:Nginx/HAProxy 集群 + Keepalived,按 URL/域名路由、限流、HTTPS 卸载
⑤ 应用服务层:Web/API 应用多副本 + 无状态化设计 + 水平扩展 + 服务注册发现
⑥ 缓存层:Redis(主从 + 哨兵/Cluster)缓存热点数据与会话,扛住 80%+ 读流量
⑦ 数据库层:MySQL 主从读写分离 + MHA/MGR 高可用 + 分库分表(按业务/用户分片)
⑧ 文件/对象存储:图片/视频放 OSS + CDN 分发,不占应用服务器磁盘
⑨ 消息队列:订单创建、通知等异步化(Kafka/RabbitMQ),大促削峰填谷
⑩ 监控与容灾:全链路监控(Prometheus/Grafana + 链路追踪)、多机房/两地三中心、定期故障演练

关键设计点:

  • 无状态化:应用层不存 Session(放 Redis),任何一台机器可随意增删,支撑水平扩展;
  • 每层高可用:LB 双机、应用多副本、Redis 主从哨兵、MySQL 主从自动切换,消灭单点;
  • 缓存防护:防缓存穿透/击穿/雪崩——热点数据永不过期 + 互斥锁重建、缓存空值、限流降级;
  • 大促削峰:MQ 异步削峰 + 限流(令牌桶)+ 本地缓存 + 数据库异步落单;
  • 数据安全:主从 + 半同步 + 备份恢复演练;支付走独立通道与风控。

4. 使用场景:系统架构设计题、从零搭建高并发电商平台、架构评审。面试关键:按「DNS → CDN → 四层 LB → 七层 LB → 应用 → 缓存 → DB → 存储」逐层讲,每层说清「用什么 + 怎么高可用 + 故障怎么兜底」;重点强调「无状态应用 + 每层冗余 + 缓存兜底 + 异步削峰」四个设计思想,能画出链路并解释每层选型理由。

Q117. Dockerfile 中 COPY 和 ADD 指令的区别?CMD 和 ENTRYPOINT 的区别和联系?

1. 是什么COPYADD 都是把构建上下文中的文件复制进镜像的指令;CMDENTRYPOINT 都用于指定容器启动时执行的命令。两组指令功能相近但语义不同,是 Dockerfile 高频考点。

2. 为什么用它:用错 COPY/ADD 会带来镜像体积膨胀或非预期的行为(ADD 自动解压、URL 下载);用错 CMD/ENTRYPOINT 会导致「容器启动命令被覆盖」或「参数被吞掉」的差异。理解语义才能写出行为可预期的镜像。

3. 怎么用它

COPY vs ADD

  • COPY:只负责把文件/目录从构建上下文复制进镜像,语义单一明确,推荐优先使用
  • ADD:在 COPY 基础上多了两个隐式行为——① 源是本地 tar 压缩包.tar/.tar.gz/.tgz)时自动解压;② 源可以是 URL(会自动下载)。这些隐式行为容易造成「非预期的文件差异」和镜像变大;
  • 实践建议:普通文件复制一律用 COPY;需要自动解压本地归档时才用 ADD不要用 ADD 下载 URL(应使用 RUN curl/wget + 清理,可控体积且能处理失败)。
COPY ./app /usr/src/app                # 复制目录
ADD ./files.tar.gz /opt/               # 自动解压 files.tar.gz 到 /opt/
COPY --from=builder /app/dist /usr/share/nginx/html   # 多阶段构建复制产物

CMD vs ENTRYPOINT(区别和联系):

  • ENTRYPOINT:容器不可被覆盖的主命令;docker run 镜像 参数 中的「参数」会追加到 ENTRYPOINT 后面(作为它的参数);
  • CMD:提供默认命令/参数,可被 docker run 的命令完全覆盖;若存在 ENTRYPOINT,CMD 作为 ENTRYPOINT 的默认参数
  • 联系/组合:最佳实践是 ENTRYPOINT 固定主程序 + CMD 提供默认参数docker run 镜像 --flag 追加的就是 ENTRYPOINT 的参数;
  • exec 形式 vs shell 形式:exec 形式(["cmd","arg"]不经过 shell,容器 PID 1 直接是程序,能正确接收 SIGTERM/SIGINT 优雅退出(推荐);shell 形式(cmd arg)经 /bin/sh -c 执行,PID 1 是 sh,会吞掉信号导致容器不能优雅关闭。
ENTRYPOINT ["nginx"]           # 主程序固定
CMD ["-g", "daemon off;"]      # 默认参数,docker run 可覆盖
# docker run nginx        → 执行 nginx -g "daemon off;"
# docker run nginx -v     → 执行 nginx -v(CMD 被覆盖,ENTRYPOINT 保留)

4. 使用场景:编写任何生产 Dockerfile、面试考察镜像构建与容器启动行为。面试关键:COPY=纯复制、ADD=COPY+自动解压(+URL),「能用 COPY 不用 ADD」;ENTRYPOINT 不可覆盖、CMD 可覆盖,组合是「主程序 + 默认参数」;exec 形式优于 shell 形式(信号与 PID 1 问题)。

根据图片内容,提取的表格信息如下:

指令作用执行时机示例
FROM指定基础镜像,构建的起点构建时FROM eclipse-temurin:17-jre-alpine
WORKDIR设置容器内的工作目录,后续命令在该目录下执行构建时WORKDIR /app
COPY将构建上下文中的文件/目录复制到镜像内构建时COPY target/app.jar /app/app.jar
RUN在构建过程中执行命令,通常用于安装依赖构建时RUN apt-get update && apt-get install -y curl
CMD指定容器启动时执行的默认命令(可被 docker run 覆盖)容器启动时CMD ["java", "-jar", "app.jar"]
USER切换运行用户,用于以非root身份运行容器构建时RUN addgroup -g 1001 app && adduser -u 1001 -G app app
USER app

键区分:RUN是构建镜像时执行的命令,CMD是容器启动时执行的命令,两者执行时机完全不同。


Q118. Docker 和虚拟机的本质区别是什么?如何减少 Docker 镜像的体积?

1. 是什么:本质区别在共享 vs 独占内核:Docker 容器与宿主机共享操作系统内核,只做进程级隔离(命名空间 Namespace + 资源限制 Cgroups),镜像是分层文件系统;虚拟机每台 VM 运行独立的完整操作系统(含自己的内核),由 Hypervisor 虚拟出整台硬件,隔离更强但开销大。

2. 为什么用它:理解区别才能正确选型——容器轻量、秒级启动、密度高,适合微服务与弹性伸缩;虚拟机隔离更强(内核级隔离),适合异构操作系统、安全要求高、运行不可信代码的场景。镜像体积直接影响构建速度、拉取时间、存储成本与启动速度,必须掌握瘦身方法。

3. 怎么用它(区别 + 瘦身方法):

Docker vs 虚拟机对比

维度Docker 容器虚拟机
内核共享宿主机内核(无独立内核)每台独立内核(KVM/Hyper-V 等)
隔离进程级(Namespace + Cgroups)硬件级(CPU/内存/磁盘全虚拟)
启动秒级分钟级
资源占用小(MB 级,仅进程+依赖)大(GB 级,含完整 OS)
密度一台可跑几十上百个一台通常几个
安全隔离相对弱(共享内核)

减少镜像体积的方法:

  1. 多阶段构建(最有效):构建阶段用带编译器的镜像,运行阶段只 COPY 产物到精简镜像(FROM golang AS builder + FROM alpine);
  2. 选择精简基础镜像alpine(约 5MB)替代 debian/ubuntu;纯静态二进制可用 scratch(空镜像);
  3. 合并 RUN + 清理缓存:一条 RUN 用 && 串联,装完包即删包管理缓存(rm -rf /var/lib/apt/lists/*)、临时文件;
  4. .dockerignore:排除 .gitnode_modules、测试、日志等无用文件,减小构建上下文;
  5. 不带调试/编译工具:运行时不需要 gcc、make、vim 等;Java 用 JRE 而非 JDK;
  6. 静态编译/精简二进制:Go 等静态编译产物体积小;必要时 upx 压缩;
  7. 分层顺序:不变的高频层放前面、变化大的放后面,最大化利用层缓存,减少重复拉取。

4. 使用场景:镜像构建规范、CI/CD 加速、K8s 部署调优。面试关键:本质区别一句话「容器共享宿主机内核做进程级隔离,虚拟机有独立内核做硬件级隔离」;瘦身按「多阶段构建 → alpine/scratch → 合并 RUN + 清缓存 → .dockerignore」顺序讲,突出多阶段构建是关键手段。


Q119. Docker 宿主机磁盘空间不足,如何清理?解释 docker0 网桥的工作原理。

1. 是什么:这是两个独立问题——① 宿主机磁盘被 Docker 数据(镜像、容器层、数据卷、构建缓存、容器日志)占满时的清理方法;② docker0 是 Docker 安装时自动创建的默认虚拟网桥(Linux Bridge),容器通过它实现与宿主机的网络通信。

2. 为什么用它:磁盘占满是 Docker 运维最高频问题——反复拉镜像、长期构建残留 build cache、不轮转的容器日志都会吞磁盘,且容器运行中断面大,必须能安全清理;理解 docker0 才能解释「容器为何能互相通信、能出外网、与宿主机如何互通」,也是排查容器网络问题的基础。

3. 怎么用它

磁盘清理

# 1) 看磁盘占用构成
docker system df            # 镜像/容器/卷/构建缓存各占多少
du -sh /var/lib/docker/*    # 直接看 Docker 数据目录(默认路径)

# 2) 一键清理(核心命令)
docker system prune -a --volumes   # 清理停止容器、无用网络、悬空/无引用镜像、未用卷、构建缓存
docker image prune -a              # 只清理未被容器引用的镜像
docker container prune             # 清理已停止的容器
docker volume prune                # 清理未被使用的数据卷(删除不可恢复,确认后再用)
docker builder prune               # 清理构建缓存(通常占大头)

# 3) 定位异常占用:容器 stdout 日志
docker ps -a                        # 找残留停止容器
find /var/lib/docker/containers -name '*-json.log' -size +100M -ls   # 大日志
echo "" > $(docker inspect --format='{{.LogPath}}' <容器名>)            # 清空指定容器日志

# 4) 配置层防护:daemon.json 配置日志轮转,避免日志无限增长
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

常用习惯:定期执行 docker system prune -af(不带 --volumes 更安全,避免误删数据卷);删除数据卷前确认没有容器/业务在用

docker0 网桥工作原理

  • 本质:Docker 启动时在宿主机创建虚拟网桥 docker0(默认网段 172.17.0.0/16),它就是一个运行在宿主机的二层交换机,容器网卡都接入它;
  • 容器侧:每个容器有一对 veth 虚拟网卡(成对出现)——一端在容器内(eth0,配 172.17.0.x/16),另一端挂到 docker0 网桥上;
  • 容器互通:同一宿主机上接入 docker0 的容器通过网桥二层直接互通(同网段),互不经过 NAT;
  • 出外网:容器访问宿主机之外时,数据包经 docker0 转给宿主机内核,由iptables NAT(MASQUERADE) 把容器源 IP 伪装成宿主机 IP 发出,回包再 NAT 回容器;
  • 入站(端口映射)docker run -p 8080:80 通过 iptables DNAT 把宿主机 8080 端口流量转发到容器 80 端口;
  • 自定义网络docker network create 可创建自定义 bridge 网络,容器间可用容器名做 DNS 解析,比默认 docker0 更方便服务发现;默认 bridge 不支持容器名解析(需 --link)。

4. 使用场景:磁盘告警应急、定期清理脚本、容器网络故障排查(容器互相不通/出不了网)。面试关键:清理题答「docker system df 看占用 → docker system prune 清理 → 定位大日志 → daemon 配置日志轮转」,强调 build cache 和容器日志常是主凶;网桥题讲清「docker0 是虚拟网桥,容器 veth 接入它,同机容器二层互通,出外网靠 NAT,进容器靠 DNAT 端口映射」这条链路。

更多推荐