背景
Docker 已經(jīng)是現(xiàn)代運(yùn)維和開發(fā)的基礎(chǔ)設(shè)施,但在生產(chǎn)環(huán)境中使用 Docker,由于環(huán)境的復(fù)雜性和容器的特殊性,很多在物理機(jī)或虛擬機(jī)上不會出的問題在容器環(huán)境下會集中爆發(fā)。本篇從實(shí)際生產(chǎn)故障中提煉出 10 個最容易踩的坑,每個坑都給出真實(shí)的現(xiàn)象描述、原理說明、排查命令和修復(fù)方案。
這些坑覆蓋了鏡像管理、容器生命周期、網(wǎng)絡(luò)配置、存儲管理、安全加固、監(jiān)控告警等 Docker 使用中最常見的領(lǐng)域。
坑一:Docker 存儲空間耗盡(Disk Full)
現(xiàn)象
容器無法啟動,日志報錯no space left on device
docker ps報錯Cannot connect to the Docker daemon
df -h顯示/var/lib/docker所在磁盤使用率 100%
寫入文件時報 "No space left on device"
原理
Docker 的存儲驅(qū)動(overlay2、devicemapper、btrfs、zfs)默認(rèn)把鏡像層、容器層、日志、構(gòu)建緩存都放在/var/lib/docker下。如果這個分區(qū)沒有獨(dú)立mount,或者根分區(qū)空間有限,容器日志、鏡像、build 緩存很容易把它撐滿。
排查命令
# 查看 Docker 數(shù)據(jù)目錄所在磁盤的使用情況 df -h /var/lib/docker # 查看 Docker 占用的磁盤空間分布 docker system df # 詳細(xì)看各部分占用 docker system df -v # 查看容器日志大小 ls -lh /var/lib/docker/containers/*/*-json.log # 查看 overlay2 層的實(shí)際占用 du -sh /var/lib/docker/overlay2/*
修復(fù)方案
# 1. 清理懸空鏡像(沒有 tag 的鏡像)
docker image prune -a
# 2. 清理構(gòu)建緩存
docker builder prune -a
# 3. 清理所有未使用的資源(鏡像、容器、網(wǎng)絡(luò)、構(gòu)建緩存)
docker system prune -a --volumes
# 4. 限制容器日志大小(需要修改 docker daemon 配置或 docker-compose)
# 方法一:全局限制(修改 /etc/docker/daemon.json)
# {
# "log-driver": "json-file",
# "log-opts": {
# "max-size": "100m",
# "max-file": "3"
# }
# }
# 5. 手動清理容器日志(臨時方案,不推薦但緊急時可用)
# 先停止容器,截斷日志文件,再啟動
> /var/lib/docker/containers//*-json.log
預(yù)防措施
把/var/lib/docker放在獨(dú)立分區(qū)或 LVM 邏輯卷
配置容器日志輪轉(zhuǎn)(max-size+max-file)
定期清理鏡像和構(gòu)建緩存
監(jiān)控磁盤使用率,超過 80% 告警
坑二:容器內(nèi)時間與宿主機(jī)時間不一致
現(xiàn)象
容器內(nèi)date命令輸出和宿主機(jī)差 8 小時
程序日志時間戳和實(shí)際時間不符
數(shù)據(jù)庫寫入的時間差了 8 小時
證書有效期計算錯誤
原理
容器默認(rèn)使用宿主機(jī)的 kernel,沒有自己的時區(qū)設(shè)置。如果宿主機(jī)是 CST(UTC+8),但容器沒有正確掛載時區(qū)文件,就會使用 UTC 時間。
排查命令
# 查看宿主機(jī)時間 date # 查看容器內(nèi)時間 dockerexecdate # 檢查容器是否掛載了時區(qū)文件 docker inspect | grep -A 20"Mounts"
修復(fù)方案
方案一:運(yùn)行時掛載時區(qū)文件
docker run -v /etc/timezone:/etc/timezone:ro -v /etc/localtime:/etc/localtime:ro nginx
方案二:設(shè)置環(huán)境變量(部分基礎(chǔ)鏡像支持)
docker run -e TZ=Asia/Shanghai nginx
方案三:docker-compose 方式
services: app: image:my-app:latest environment: TZ:"Asia/Shanghai" volumes: -/etc/timezone:/etc/timezone:ro -/etc/localtime:/etc/localtime:ro
方案四:Dockerfile 中設(shè)置時區(qū)(基礎(chǔ)鏡像構(gòu)建時)
FROMubuntu:20.04 RUNapt-get update && apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo"Asia/Shanghai"> /etc/timezone
坑三:容器內(nèi)無法解析 DNS(內(nèi)網(wǎng)域名)
現(xiàn)象
宿主機(jī)能 ping 通redis-master,容器內(nèi) ping 不通
curl http://nginx在宿主機(jī)正常,容器內(nèi)失敗
容器能解析公網(wǎng) DNS(curl baidu.com正常),但無法解析內(nèi)網(wǎng)域名
跨容器通信時報could not resolve host
原理
Docker 默認(rèn)使用內(nèi)置的 DNS 服務(wù)(地址 127.0.0.11),這個 DNS 服務(wù)知道容器通過--link或docker network建立的內(nèi)部域名,但不知道宿主機(jī)網(wǎng)絡(luò)中的自定義 DNS 記錄(如公司內(nèi)網(wǎng) DNS 服務(wù)器上的redis-master.internal)。
排查命令
# 查看容器 DNS 配置 dockerexeccat /etc/resolv.conf # 查看容器網(wǎng)絡(luò)模式 docker inspect | grep -A 10"NetworkSettings" # 從容器內(nèi)測試 DNS dockerexec nslookup nginx dockerexec dig nginx # 查看宿主機(jī) DNS 配置 cat /etc/resolv.conf
修復(fù)方案
方案一:使用--dns指定 DNS 服務(wù)器
docker run --dns 192.168.1.53 nginx
方案二:docker-compose 配置 DNS
services: app: image:my-app:latest dns: -192.168.1.53 -8.8.8.8 networks: -my-net networks: my-net: driver:bridge ipam: config: -subnet:172.20.0.0/16
方案三:配置 daemon.json 全局 DNS
{
"dns": ["192.168.1.53","8.8.8.8"]
}
注意:修改 daemon.json 需要systemctl restart docker才能生效,會影響所有容器。
坑四:容器進(jìn)程被OOMKilled
現(xiàn)象
docker ps顯示容器退出了
docker logs
docker inspect
宿主機(jī)dmesg | grep -i oom或journalctl | grep -i oom有記錄
原理
容器的內(nèi)存限制由 Linux cgroup 控制。當(dāng)容器內(nèi)的進(jìn)程試圖申請超過 limit 的內(nèi)存時,Linux 會觸發(fā) OOM Killer 選擇容器內(nèi)的一個進(jìn)程殺掉。如果進(jìn)程沒有處理 SIGKILL 信號,容器會直接退出。
排查命令
# 檢查容器退出狀態(tài) docker inspect| grep -E"OOMKilled|ExitCode|State" # 查看容器內(nèi)存使用峰值 docker stats --no-stream # 查看容器內(nèi)存限制 docker inspect | grep -A 5"Memory" # 在宿主機(jī)上查看 cgroup 內(nèi)存統(tǒng)計 cat /sys/fs/cgroup/memory/docker/ /memory.usage_in_bytes cat /sys/fs/cgroup/memory/docker/ /memory.limit_in_bytes # 查看宿主機(jī) OOM 日志 dmesg | grep -i"out of memory" dmesg | grep -i"killed process" journalctl | grep -i oom | tail -20
修復(fù)方案
# 1. 緊急:提高內(nèi)存限制重新啟動容器 docker run --memory=1g my-app:latest # 2. docker-compose 方式 # docker-compose.yml services: app: image: my-app:latest mem_limit: 1g mem_reservation: 512m # 3. 如果是 Java 應(yīng)用,確保 JVM 堆內(nèi)存 <= 容器內(nèi)存 limit # JVM 堆外內(nèi)存(native、direct buffer、mmap)也需要考慮 # 建議 JVM -Xmx 設(shè)置為容器 limit 的 75-80% docker run -e JAVA_OPTS="-Xmx768m"?--memory=1g my-java-app # 4. 如果是正常業(yè)務(wù)增長,考慮水平擴(kuò)展(多容器實(shí)例)
預(yù)防措施
設(shè)置合理的內(nèi)存 limit,不要設(shè)置得過高或過低
Java/Node.js 等有自己內(nèi)存管理的應(yīng)用,要明確設(shè)置堆內(nèi)存
配置監(jiān)控告警:內(nèi)存使用率超過 80% limit 時告警
在宿主機(jī)部署 OOM 告警腳本
坑五:容器無法訪問外網(wǎng),但宿主機(jī)正常
現(xiàn)象
ping baidu.com在宿主機(jī)正常,容器內(nèi)不通
curl https://google.com在宿主機(jī)正常,容器內(nèi)超時
容器間通信正常(同一個 bridge 網(wǎng)絡(luò)內(nèi))
從容器內(nèi)訪問宿主機(jī) IP 正常,但訪問其他 IP 不通
原理
這種情況通常是 Docker 的包過濾(iptables/IPVS)或網(wǎng)絡(luò) MTU 問題導(dǎo)致的。常見原因:
MTU 不匹配:容器默認(rèn)使用 docker0 網(wǎng)橋的 MTU(默認(rèn) 1500),如果宿主機(jī)網(wǎng)卡的 MTU 是 9000(jumbo frame),路徑 MTU 發(fā)現(xiàn)可能失敗
iptables 規(guī)則被意外修改:Docker 會自動添加 iptables NAT 規(guī)則,如果被清理,容器無法通過 NAT 訪問外網(wǎng)
宿主機(jī)開啟了數(shù)據(jù)包轉(zhuǎn)發(fā)但 Docker 沒正確配置
代理設(shè)置:宿主機(jī)走了代理但容器沒有
排查命令
# 檢查容器網(wǎng)絡(luò)連通性(按順序測試) dockerexecping 8.8.8.8 # 測試 IP 層連通性 dockerexec ping baidu.com # 測試 DNS 解析 dockerexec curl -v https://google.com # 測試應(yīng)用層 # 檢查宿主機(jī) iptables NAT 規(guī)則 iptables -t nat -L -n | grep DOCKER # 檢查 Docker 網(wǎng)橋配置 ip addr show docker0 ip route show # 檢查 MTU ip link show eth0 docker network inspect bridge | grep -i mtu # 抓包分析 tcpdump -i docker0 -n host 8.8.8.8
修復(fù)方案
MTU 問題:
# 方法一:啟動容器時指定 MTU
docker run --network=host --mtu=9000 my-app
# 方法二:修改 daemon.json 全局配置
# /etc/docker/daemon.json
{
"mtu": 9000
}
iptables 規(guī)則被清理:
# 重置 Docker 的 iptables 規(guī)則 iptables -t nat -F iptables -t filter -F systemctl restart docker # Docker 重啟后會自動添加正確的 iptables 規(guī)則
代理問題:
# 檢查宿主機(jī)代理 echo$http_proxy echo$https_proxy # 容器內(nèi)設(shè)置代理(如果宿主機(jī)走了代理) docker run -e HTTP_PROXY=http://host.docker.internal:7890 my-app
坑六:刪除容器后數(shù)據(jù)丟失
現(xiàn)象
重新部署容器后,之前寫入的數(shù)據(jù)找不到了
數(shù)據(jù)庫容器重啟后變成空庫
配置文件修改后,重啟容器又恢復(fù)成默認(rèn)配置
原理
默認(rèn)情況下,容器內(nèi)的文件系統(tǒng)是「寫時復(fù)制」(copy-on-write)的,容器刪除后,這一層也跟著沒了。容器內(nèi)的數(shù)據(jù)默認(rèn)不會持久化到宿主機(jī)。除非使用:
數(shù)據(jù)卷(Volume):存儲在/var/lib/docker/volumes/
綁定掛載(Bind Mount):直接映射宿主機(jī)的目錄
tmpfs mount:存在內(nèi)存中
排查命令
# 查看容器的掛載信息 docker inspect| grep -A 20"Mounts" # 查看數(shù)據(jù)卷列表 docker volume ls # 查看數(shù)據(jù)卷詳情 docker volume inspect # 檢查宿主機(jī)上的數(shù)據(jù)卷路徑 ls -la /var/lib/docker/volumes/ /_data
修復(fù)方案
使用命名數(shù)據(jù)卷持久化 MySQL 數(shù)據(jù):
# docker-compose.yml services: mysql: image:mysql:8.0 environment: MYSQL_ROOT_PASSWORD:"password" volumes: -mysql_data:/var/lib/mysql ports: -"3306:3306" volumes: mysql_data: driver:local
使用綁定掛載持久化配置文件:
services: nginx: image:nginx:1.24 volumes: -/data/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -/data/nginx/logs:/var/log/nginx ports: -"80:80"
不要用匿名存儲:
# 錯誤:匿名 volume,重啟后數(shù)據(jù)可能丟失 volumes: -/var/lib/mysql# 匿名 volume,宿主機(jī)路徑不明確 # 正確:命名 volume volumes: -mysql_data:/var/lib/mysql
坑七:Docker 鏡像標(biāo)簽混亂(latest 陷阱)
現(xiàn)象
docker run my-app:latest拉取了新版本,但業(yè)務(wù)邏輯沒變
docker build -t my-app:1.0 .打了 tag 但docker images顯示
部署后發(fā)現(xiàn)版本不對,查不到是哪個鏡像
原理
latest只是一個普通的 tag,不是自動指向最新版本的特殊標(biāo)簽。如果你docker build時不指定 tag,默認(rèn)就是latest。很多人誤以為latest總是指向最新版本,但實(shí)際上latest的指向完全取決于最后一次docker build -t my-app:latest或docker tag操作。
另外,本地latest和遠(yuǎn)程倉庫的latest可能不是同一個版本。
排查命令
# 查看鏡像的所有 tag docker images my-app # 查看鏡像的創(chuàng)建時間 docker inspect my-app:latest | grep Created # 查看鏡像的完整 ID docker images --no-trunc my-app # 對比本地 latest 和遠(yuǎn)程 latest 是否相同 docker pull my-app:latest docker images my-app:latest
修復(fù)方案
始終使用具體版本標(biāo)簽,不要用 latest:
# Dockerfile FROMnginx:1.24.0-alpine # 不用 latest,用精確版本
# 構(gòu)建時指定精確版本 docker build -t my-app:1.2.3 . docker build -t my-app:release-20240115 . # 打 tag 說明提交 hash docker build -t my-app:v1.2.3-$(git rev-parse --short HEAD) .
GitOps 工作流:
# Jenkinsfile / GitLab CI / GitHub Actions
stages:
-build
-push
-deploy
build:
stage:build
script:
-IMAGE_TAG=${CI_COMMIT_SHORT_SHA}-${CI_BUILD_ID}
-dockerbuild-tregistry.example.com/my-app:${IMAGE_TAG}.
-dockerpushregistry.example.com/my-app:${IMAGE_TAG}
-echo${IMAGE_TAG}>image_tag.txt
deploy:
stage:deploy
script:
-IMAGE_TAG=$(catimage_tag.txt)
-kubectlsetimagedeployment/my-appapp=registry.example.com/my-app:${IMAGE_TAG}
坑八:容器進(jìn)程PID 1 和信號處理問題
現(xiàn)象
docker stop
容器收到 SIGTERM 后沒有優(yōu)雅退出
docker kill
日志顯示main process exited, code 0但子進(jìn)程變成了僵尸進(jìn)程
原理
容器內(nèi)的 PID 1 進(jìn)程對信號處理有特殊要求。默認(rèn)情況下,Docker 將信號轉(zhuǎn)發(fā)給 PID 1 進(jìn)程,但:
如果 PID 1 進(jìn)程是shell 腳本(如CMD ["/bin/sh", "-c", "java -jar app.jar"]),shell 本身不轉(zhuǎn)發(fā)信號,Java 進(jìn)程收不到 SIGTERM
如果 PID 1 進(jìn)程沒有正確處理 SIGTERM,容器會一直等直到 timeout(默認(rèn) 10 秒),然后被 SIGKILL
某些基礎(chǔ)鏡像的 PID 1 不是應(yīng)用本身,而是 tini 或 systemd
排查命令
# 查看容器內(nèi)的進(jìn)程樹 dockerexecps aux # 查看 PID 1 的進(jìn)程是什么 dockerexec cat /proc/1/cmdline | tr'?'' ' dockerexec ps -p 1 # 測試發(fā)送 SIGTERM 后的停止時間 time docker stop
修復(fù)方案
方案一:使用 exec 形式的 CMD(讓信號直接發(fā)給應(yīng)用)
# 錯誤:shell 形式,shell 作為 PID 1,不轉(zhuǎn)發(fā)信號 CMDjava -jar app.jar CMD["/bin/sh","-c","java -jar app.jar"] # 正確:exec 形式,直接運(yùn)行應(yīng)用,應(yīng)用作為 PID 1 CMD["java","-jar","app.jar"] # 如果需要運(yùn)行腳本,用 exec 把信號轉(zhuǎn)發(fā)給子進(jìn)程 ENTRYPOINT["/entrypoint.sh"] # entrypoint.sh 內(nèi)容: # #!/bin/bash # trap 'kill -TERM $PID' TERM INT # java -jar app.jar & # PID=$! # wait $PID
方案二:使用 init 進(jìn)程(Docker 20.10+ 內(nèi)置 tini)
docker run --init my-app:latest
# Dockerfile FROMalpine RUNapk add --no-cache tini ENTRYPOINT["/sbin/tini","--"] CMD["java","-jar","app.jar"]
方案三:設(shè)置 stopTimeout(適用于 Docker Swarm / Compose)
services: app: image:my-app:latest stop_grace_period:30s# 給容器 30 秒的優(yōu)雅停止時間 stop_signal:SIGTERM
坑九:生產(chǎn)環(huán)境忘記設(shè)資源限制導(dǎo)致雪崩
現(xiàn)象
單臺宿主機(jī)上跑了太多容器,內(nèi)存被打爆
一個容器內(nèi)的 Java 應(yīng)用內(nèi)存泄漏把整個宿主機(jī)的容器都拖垮
容器被 OOMKill 后重啟,但重啟后又 OOM,形成死亡循環(huán)
宿主機(jī) Load 飆到 100+,所有容器響應(yīng)極慢
原理
沒有資源限制的容器理論上可以使用宿主機(jī)全部資源。當(dāng)一個容器出問題(如內(nèi)存泄漏),它會吸干宿主機(jī)的內(nèi)存,導(dǎo)致:
其他容器因內(nèi)存不足被 OOMKill
Docker daemon 本身也可能受影響
宿主機(jī) kernel 進(jìn)入 OOM,響應(yīng)變慢
這就是"雪崩"——一個點(diǎn)的問題擴(kuò)散到整個系統(tǒng)。
排查命令
# 查看所有容器內(nèi)存使用
docker stats --no-stream
# 查看運(yùn)行中的容器及其資源限制
docker ps --format"table {{.Names}} {{.Image}} {{.Status}} {{.Ports}}"
# 查看設(shè)置了內(nèi)存限制的容器
docker ps --format"{{.Names}}"|whilereadname;do
limit=$(docker inspect$name--format'{{.HostConfig.Memory}}')
echo"$name:$limit"
done
# 查看宿主機(jī)的整體資源使用
top
free -h
df -h
修復(fù)方案
Always set resource limits in production:
services:
app:
image:my-app:latest
deploy:
resources:
limits:
memory:512M
cpus:'0.5'
reservations:
memory:256M
cpus:'0.25'
restart_policy:
condition:on-failure
max_attempts:3
# 命令行方式 docker run -d --memory=512m --memory-reservation=256m --cpus=0.5 --cpus-reservation=0.25 --restart=on-failure:3 my-app:latest
內(nèi)存限制要設(shè)置,但不要設(shè)置過大:
# 假設(shè)應(yīng)用正常需要 400M,設(shè)置 512M,留點(diǎn)余量 --memory=512m # 不要設(shè)太大(如 4G),否則調(diào)度器無法感知實(shí)際需求
坑十:Docker daemon 安全暴露(2375/2376端口)
現(xiàn)象
阿里云/騰訊云控制臺告警:服務(wù)器開放了 Docker 2375 端口
curl http://server:2375/info能獲取 Docker daemon 完整信息
docker -H tcp://server:2375 ps能在本地操作遠(yuǎn)程服務(wù)器上的容器
服務(wù)器被入侵,挖礦程序通過 Docker 逃逸到宿主機(jī)
原理
Docker daemon 默認(rèn)不開放 TCP 端口。如果管理員為了"方便管理"把 Docker 端口暴露到公網(wǎng)(-H tcp://0.0.0.0:2375),任何能訪問到這個端口的人都可以:
在宿主機(jī)上以 root 權(quán)限運(yùn)行任意容器
讀取宿主機(jī)的所有文件
通過容器逃逸獲得宿主機(jī) root 權(quán)限
2375 是未加密的 Docker API,2376 是 TLS 加密版本。但即使 2376 如果沒有正確配置證書,也是危險的。
排查命令
# 檢查 Docker daemon 監(jiān)聽端口 ps aux | grep dockerd | grep -v grep ss -tlnp | grep docker # 檢查 docker daemon 啟動參數(shù) systemctl cat docker | grep ExecStart # 測試是否對外開放 curl http://localhost:2375/info 2>/dev/null &&echo"2375 is open" curl https://localhost:2376/info 2>/dev/null &&echo"2376 is open" # 從外部測試(如果有權(quán)限) nmap -p 2375,2376
修復(fù)方案
立即關(guān)閉暴露的 Docker API:
# 如果是通過 systemd 啟動,修改 unit 文件 # /etc/systemd/system/docker.service.d/override.conf [Service] ExecStart= ExecStart=/usr/bin/dockerd # 不要加 -H tcp://0.0.0.0:2375 # 重載配置 systemctl daemon-reload systemctl restart docker # 確認(rèn)端口已關(guān)閉 ss -tlnp | grep docker
如果確實(shí)需要遠(yuǎn)程 Docker API 管理,用 TLS:
# 生成 TLS 證書(參考 Docker 官方文檔)
# 使用 docker-machine 或手動生成 CA + server cert + client cert
# 配置 Docker daemon(/etc/docker/daemon.json)
{
"tls":true,
"tlscert":"/etc/docker/tls/server-cert.pem",
"tlskey":"/etc/docker/tls/server-key.pem",
"tlscacert":"/etc/docker/tls/ca.pem",
"hosts": ["fd://","tcp://127.0.0.1:2376"]
}
# 客戶端連接時必須帶證書
docker -H tcp://server:2376 --tlsverify
--tlscert=client-cert.pem
--tlskey=client-key.pem
--tlscacert=ca.pem ps
網(wǎng)絡(luò)層限制:
# 防火墻限制 Docker API 端口只能從管理網(wǎng)段訪問 iptables -A INPUT -p tcp --dport 2375 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 2375 -j DROP
容器安全最佳實(shí)踐:
永遠(yuǎn)不要把 Docker API 端口暴露到公網(wǎng)
使用--read-only模式運(yùn)行容器,防止寫入惡意文件
使用--security-opt=no-new-privileges防止特權(quán)升級
不要用--privileged運(yùn)行容器
定期審查容器能力:docker inspect --format '{{.HostConfig.CapAdd}}'
額外補(bǔ)充:容易被忽視的 5 個坑
坑十一:容器時區(qū)問題(和坑二重申)
坑十二:忘記 --restart always 導(dǎo)致容器退出后無人管
# 正確:生產(chǎn)環(huán)境建議用 restart-policy docker run -d --restart=unless-stopped my-app:latest # restart 策略選項(xiàng): # no: 不自動重啟(默認(rèn)) # on-failure: 非零退出碼時重啟 # on-failure 非零退出碼時最多重啟 3 次 # always: 始終重啟,dockerd 重啟后也會重啟 # unless-stopped: 始終重啟,但 dockerd 重啟前手動停掉的不會自動重啟
坑十三:數(shù)據(jù)卷權(quán)限問題
# 掛載宿主機(jī)的目錄給 Nginx,Nginx 進(jìn)程用 nginx 用戶運(yùn)行 # 但 /data/www 是 root 擁有的,nginx 無法讀取 docker run -v /data/www:/usr/share/nginx/html nginx # 解決方案一:容器內(nèi)用 root 運(yùn)行(不推薦生產(chǎn)) # 解決方案二:修改宿主機(jī)目錄權(quán)限 chmod -R 755 /data/www # 解決方案三:在 Dockerfile 里創(chuàng)建用戶并設(shè)置正確權(quán)限
坑十四:跨容器網(wǎng)絡(luò)通信(bridge vs host)
# 默認(rèn) bridge 網(wǎng)絡(luò):容器間需要通過 IP 或 --link 別名通信 # 但 --link 已廢棄,推薦用 user-defined bridge network # 正確做法:創(chuàng)建自定義網(wǎng)絡(luò) docker network create my-net docker run --network=my-net --name redis redis:alpine docker run --network=my-net --name app my-app:latest # app 容器內(nèi)可以直接 ping redis,因?yàn)樗鼈冊谕痪W(wǎng)絡(luò) # host 網(wǎng)絡(luò):容器共享宿主機(jī)的網(wǎng)絡(luò)命名空間 # 端口直接暴露到宿主機(jī),但失去了網(wǎng)絡(luò)隔離 docker run --network=host my-app:latest # 如果兩個容器都綁定 80,會沖突
坑十五:多階段構(gòu)建泄露敏感信息
# 錯誤:在構(gòu)建階段把敏感信息帶進(jìn)了鏡像 FROMgolang:1.21AS builder COPY. /app RUNgo build -o app . # 運(yùn)行階段也包含了源碼和構(gòu)建工具 FROMalpine COPY--from=builder /app /app COPY--from=builder /root/.npm /root/.npm # 暴露了 npm 憑證 # 正確:多階段構(gòu)建,只復(fù)制最終產(chǎn)物 FROMgolang:1.21AS builder COPY. /app RUNgo build -ldflags="-w -s"-o app . # builder 階段使用的 .npmrc、.cargo 等不會進(jìn)入最終鏡像 FROMalpine COPY--from=builder /app /app RUNchmod +x /app CMD["/app"]
總結(jié)
這 10 + 5 個坑是 Docker 生產(chǎn)環(huán)境中最常見的故障來源,按優(yōu)先級整理如下:
| 坑 | 嚴(yán)重程度 | 出現(xiàn)頻率 |
|---|---|---|
| Disk Full(存儲空間耗盡) | 高(服務(wù)中斷) | 極高 |
| Docker API 2375 端口暴露 | 極高(安全) | 高 |
| 沒有設(shè)置資源限制 | 高(雪崩風(fēng)險) | 極高 |
| OOMKilled | 高(服務(wù)中斷) | 高 |
| 進(jìn)程信號處理不當(dāng) | 中(重啟慢/無法重啟) | 高 |
| 容器內(nèi)時間不一致 | 中(業(yè)務(wù)日志錯亂) | 極高 |
| DNS 無法解析內(nèi)網(wǎng)域名 | 中(服務(wù)不可用) | 高 |
| 數(shù)據(jù)沒有持久化 | 高(數(shù)據(jù)丟失) | 高 |
| latest 標(biāo)簽混亂 | 低到中(版本錯亂) | 高 |
| 無法訪問外網(wǎng) | 中(部分功能失效) | 中 |
建議把這些坑的排查命令整理成一張"Docker 故障排查卡",關(guān)鍵時刻能省大量時間。
-
存儲
+關(guān)注
關(guān)注
13文章
4916瀏覽量
90358 -
容器
+關(guān)注
關(guān)注
0文章
540瀏覽量
23044 -
Docker
+關(guān)注
關(guān)注
0文章
539瀏覽量
14447
原文標(biāo)題:別再踩坑!生產(chǎn)環(huán)境 Docker 最易中招的 10 個問題
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
Firefly-RK3288開發(fā)環(huán)境的搭建流程和常見問題
數(shù)碼舵機(jī)常見問題原理分析及解決
MPU6050常見問題的分析與處理
在嵌入式系統(tǒng)中使用FPGA時的常見問題及對策
伺服線束生產(chǎn)加工過程中的常見問題
驅(qū)動芯片在應(yīng)用中的常見問題分析與解決
生產(chǎn)環(huán)境中使用Docker的常見問題分析
評論