运维常见面试题_06_LVS、keepalived等高可用技术与docker容器化
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 抑制 | 最高 |
| TUN | IP 隧道封装 | 直连客户端 | 支持隧道 + 配置 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=1 与 arp_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-table按src),无法基于 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_beg、src、hdr(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 工作原理):
- 虚拟路由器组:多个真实设备组成一个虚拟路由器,对外表现为一个虚拟路由器,拥有虚拟 MAC(
00-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. 怎么用它:
- 脑裂检测:
- 看 VIP 归属:
ip addr show eth0看 VIP 是否同时出现在两台机器上; - 看 Keepalived 状态:
systemctl status keepalived/ 日志journalctl -u keepalived -f,两台都出现Entering MASTER STATE即脑裂; - 第三方探针:从第三台机器(监控主机)
ping/arping VIP,若 VIP 的 MAC 在主机 A、B 的 MAC 之间来回跳变,判定脑裂; - 脚本监测:定时脚本检查「本机是 MASTER 且能 ping 通对端存活、且对端也持有 VIP」即判定脑裂。
- 看 VIP 归属:
- 处理手段:
- 仲裁隔离(fencing/STONITH):脑裂时通过带外手段(IPMI/iLO 远程关机、云厂商 API)强制关闭对方节点或杀掉对方 keepalived,保证只剩一台持有 VIP;
- 本机让位:检测到脑裂后本机关闭 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. 是什么:COPY 和 ADD 都是把构建上下文中的文件复制进镜像的指令;CMD 和 ENTRYPOINT 都用于指定容器启动时执行的命令。两组指令功能相近但语义不同,是 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) |
| 密度 | 一台可跑几十上百个 | 一台通常几个 |
| 安全隔离 | 相对弱(共享内核) | 强 |
减少镜像体积的方法:
- 多阶段构建(最有效):构建阶段用带编译器的镜像,运行阶段只 COPY 产物到精简镜像(
FROM golang AS builder+FROM alpine); - 选择精简基础镜像:
alpine(约 5MB)替代debian/ubuntu;纯静态二进制可用scratch(空镜像); - 合并 RUN + 清理缓存:一条 RUN 用
&&串联,装完包即删包管理缓存(rm -rf /var/lib/apt/lists/*)、临时文件; .dockerignore:排除.git、node_modules、测试、日志等无用文件,减小构建上下文;- 不带调试/编译工具:运行时不需要 gcc、make、vim 等;Java 用 JRE 而非 JDK;
- 静态编译/精简二进制:Go 等静态编译产物体积小;必要时
upx压缩; - 分层顺序:不变的高频层放前面、变化大的放后面,最大化利用层缓存,减少重复拉取。
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 端口映射」这条链路。
更多推荐
所有评论(0)