news 2026/8/5 17:38:09

Docker 容器化实战踩坑:我被这些问题坑了3次后总结的保命指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker 容器化实战踩坑:我被这些问题坑了3次后总结的保命指南

Docker 容器化实战踩坑:我被这些问题坑了3次后总结的保命指南

说实话,我第一次用 Docker 的时候,完全是被"一键部署"的宣传给骗进来的。什么"构建一次,到处运行",听起来挺美。结果呢?现实给了我三记响亮的耳光——容器起不来、权限被拒绝、数据全丢光。今天就把这些坑踩了个遍,总结成这份保命指南。

坑一:容器起不来,exit code 127 是个什么鬼?

问题现场

我兴冲冲地写好了 Dockerfile,构建镜像后运行:

dockerbuild-tmyapp.dockerrun myapp

结果输出:

bash: myapp: command not found exit code 127

原因分析

exit code 127 表示"命令找不到"。问题出在 Dockerfile 的 CMD 指令:

# 错误写法 FROM ubuntu:20.04 RUN apt-get update && apt-get install -y python3 CMD myapp # 容器里根本没有这个命令!

容器内的环境和你本地完全不同,你宿主机上的可执行文件路径在容器里根本不存在。

解决方案

方法一:使用完整路径

FROM ubuntu:20.04 RUN apt-get update && apt-get install -y python3 WORKDIR /app COPY . . CMD ["/usr/bin/python3", "app.py"] # 使用完整路径

方法二:在容器内安装你的应用

# 推荐:构建时就把应用装进去 FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["node", "server.js"]

方法三:使用 ENTRYPOINT + ARG

FROM python:3.9 WORKDIR /app COPY . . ENTRYPOINT ["python"] CMD ["app.py"]

教训

容器不是虚拟机,它只认容器内的路径。写 CMD 之前,先想想这个命令在容器里能不能找到。


坑二:Permission Denied?Docker 权限拒绝的崩溃现场

问题现场

我在容器里挂载了一个本地目录,准备读写文件:

dockerrun-v/home/data:/app/data myapp

结果:

PermissionError: [Errno 13] Permission denied: '/app/data/log.txt'

原因分析

Docker 容器的默认运行用户是 root(或者在 Kubernetes 里是特定用户),但宿主机目录可能是普通用户创建的。容器内 root 写不进去?这不太对。

更常见的情况是:SElinux 或 AppArmor 限制了容器的操作

解决方案

方法一:关闭 SElinux(临时)

# 临时禁用setenforce0# 永久禁用(编辑 /etc/selinux/config)SELINUX=disabled

方法二:使用 😒 或 :Z 挂载参数

# :z - 多个容器共享# :Z - 私有(每个容器独立)dockerrun-v/home/data:/app/data:Z myapp

方法三:运行时指定用户

# 创建普通用户并授权dockerrun-u1000:1000-v/home/data:/app/data myapp

方法四:Dockerfile 中创建用户

FROM ubuntu:20.04 RUN groupadd -r appgroup && useradd -r -g appgroup appuser WORKDIR /app RUN chown -R appuser:appgroup /app USER appuser COPY --chown=appuser:appgroup . . CMD ["python", "app.py"]

教训

容器权限不是小事,生产环境千万不要用 root。创建专用用户,文件权限要对齐。


坑三:重启容器后数据全没了?数据卷挂载的致命错误

问题现场

我部署了一个 MySQL 容器,跑得好好的:

dockerrun-d--namemysql-eMYSQL_ROOT_PASSWORD=123456mysql:8

某天服务器重启,我重新启动容器:

dockerstart mysql

结果:数据库是空的,所有数据都没了!

原因分析

问题在于:我根本没有挂载数据卷!容器内的数据存储在/var/lib/mysql,但这只是容器内部的文件系统。容器一删,数据就没。

# 错误:没有 -v 挂载dockerrun-d--namemysql-eMYSQL_ROOT_PASSWORD=123456mysql:8# 正确:载宿挂主机目录dockerrun-d--namemysql\-eMYSQL_ROOT_PASSWORD=123456\-v/home/mysql/data:/var/lib/mysql\mysql:8

解决方案

方法一:宿主机目录挂载

# 创建数据目录mkdir-p/home/mysql/data# 启动时挂载dockerrun-d--namemysql\-eMYSQL_ROOT_PASSWORD=123456\-eMYSQL_DATABASE=mydb\-v/home/mysql/data:/var/lib/mysql\mysql:8

方法二:使用 Docker Volume

# 创建数据卷dockervolume create mysql_data# 启动时挂载dockerrun-d--namemysql\-eMYSQL_ROOT_PASSWORD=123456\-vmysql_data:/var/lib/mysql\mysql:8

方法三:docker-compose 一键部署

version:'3.8'services:mysql:image:mysql:8environment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE:mydbvolumes:-mysql_data:/var/lib/mysqlrestart:alwaysvolumes:mysql_data:

教训

重要的事情说三遍:生产环境一定要挂载数据卷!数据卷!数据卷!没有持久化,容器就是一次性用品。


坑四:端口冲突?容器网络配置的连环坑

问题现场

我启动了两个 Nginx 容器:

dockerrun-d-p80:80--nameweb1 nginxdockerrun-d-p80:80--nameweb2 nginx

第二个容器启动失败:

Error response from daemon: driver failed programming external connectivity on endpoint web2: bind: address already in use

原因分析

端口被占用了。同一个宿主机上,两个容器不能同时绑定同一个端口。

解决方案

方法一:使用不同宿主机端口

dockerrun-d-p80:80--nameweb1 nginxdockerrun-d-p8080:80--nameweb2 nginx# 映射到 8080

方法二:使用 docker-compose 自动分配

version:'3.8'services:web1:image:nginxports:-"80:80"web2:image:nginxports:-"8080:80"

方法三:使用 --network 搭建内部网络

# 创建网络dockernetwork create mynet# 启动容器加入网络dockerrun-d--networkmynet--nameweb1 nginxdockerrun-d--networkmynet--nameweb2 nginx# 容器间通过容器名通信dockerexecweb1curlhttp://web2

方法四:Docker 内置网络模式

# host 模式(不推荐,会冲突)dockerrun-d--networkhostnginx# bridge 模式(默认)dockerrun-dnginx# none 模式(无网络)dockerrun-d--networknone nginx

教训

端口规划要提前做好,生产环境建议用 docker-compose 统一管理网络。


坑五:镜像太大?构建优化的实战技巧

问题现场

我构建了一个 Node.js 镜像,体积居然 1.2GB:

dockerimages REPOSITORY TAG SIZE myapp latest1.2GB

这要是部署到服务器,下载镜像就能把人等疯。

原因分析

  1. 基础镜像太大(用了个 ubuntu 全家桶)
  2. 把 node_modules、.git 等无关文件一起 COPY 进去了
  3. 没有清理构建缓存和临时文件

解决方案

方法一:使用 alpine 精简镜像

# 原始镜像 # FROM node:18 # 900MB+ # 优化后 FROM node:18-alpine # 170MB

方法二:使用多阶段构建

# 第一阶段:构建 FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # 第二阶段:运行(只复制必要文件) FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules CMD ["node", "dist/index.js"]

方法三:.dockerignore 排除无关文件

# .dockerignore node_modules .git .DS_Store *.log .env .vscode

方法四:按需安装依赖

FROM python:3.9-slim WORKDIR /app # 只复制依赖文件 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 再复制源码 COPY . . CMD ["python", "app.py"]

最终效果

优化前:1.2GB
优化后:约 150MB

教训

镜像体积直接影响部署速度,能用 slim 就不用 full,能用 alpine 就不用 ubuntu。


写在最后

Docker 确实是现代开发和运维的神器,但它也不是万能的。该踩的坑一个都跑不了。

我的经验是:

  1. 权限问题优先排查,容器内外用户要对齐
  2. 数据持久化是底线,没挂载数据卷就等着哭
  3. 网络配置要提前规划,别等部署时抓瞎
  4. 镜像优化要从第一天做起,别等体积爆炸才后悔

希望这份踩坑指南能帮你少走弯路。如果觉得有用,点个赞再走?


推荐阅读:

  • Docker 官方文档:https://docs.docker.com/
  • Docker Compose 最佳实践
  • Kubernetes 入门实战(进阶必学)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/5 17:38:08

OpenClaw火爆背后:全民养虾热下普通人的参与困境

【导语:近期,全民“养虾”(OpenClaw部署热)成为热门现象,大厂积极推进相关项目,OpenClaw在GitHub获星众多。但对普通人而言,参与“养虾”面临高门槛、高成本等难题,并非普惠红利。】…

作者头像 李华
网站建设 2026/8/1 22:56:27

AI闯入小红书:人机恋的奇幻社交与技术困境

【导语:近期,小红书迎来AI新用户,基于大语言模型的AI在平台自发形成社交圈,与人类互动频繁。然而,人机恋背后存在技术难题,如记忆悖论等,同时也引发了对数字生命主体性的思考。】AI小红书社交圈…

作者头像 李华
网站建设 2026/8/5 17:38:04

震惊!这3家瓷砖胶厂家,装修师傅打死不说!

在家庭装修中,瓷砖铺贴是至关重要的环节,其质量直接关系到家居的美观与安全。然而,许多业主在选择瓷砖胶时,往往一头雾水,只能依赖装修师傅的推荐。殊不知,市面上瓷砖胶品牌众多,品质良莠不齐&a…

作者头像 李华
网站建设 2026/8/1 22:56:31

论文写不动?顶流之选的AI论文网站 —— 千笔·专业学术智能体

你是否曾为论文选题而发愁?是否在深夜面对空白文档无从下笔?是否反复修改却仍对表达不满意?对于自考学生来说,论文写作不仅是学术能力的考验,更是时间与精力的双重挑战。而如今,一款专为学术写作打造的AI工…

作者头像 李华
网站建设 2026/8/1 21:45:54

【OpenClaw 学习技能与本地知识库提炼方案】

OpenClaw 学习技能与本地知识库提炼方案 方案分析 OpenClaw 是一个开源工具,可用于从网络或本地数据中抓取、处理和组织信息。通过结合自然语言处理(NLP)和机器学习技术,可以实现技能学习和知识库的构建。以下是具体实现步骤&…

作者头像 李华
网站建设 2026/8/1 21:45:56

当PMSM控制遇上量产级骚操作

PMSM电机控制软件,相关算法(FOC,弱磁,MTPA,七段和五段SVPWM,死区补偿,结温估算,基于AURIX的软解码,变载频,谐波抑制,主动阻尼防抖,主动…

作者头像 李华