Dockerfile 实战:手把手教你定制属于自己的业务镜像
如果你还在手动配置服务器环境,每次部署重复装包、调配置,那说明还没真正用好 Docker。今天这篇 Linux 教程来自主机选,直接上实战:怎么写一个 Dockerfile,把业务打包成镜像,一拉就跑、换机器不翻车。

为什么业务必须走 Dockerfile 定制
直接用 `docker pull` 拉官方镜像确实省事,但跑业务总得往里塞代码、改配置、装依赖。每次启动都手动 `exec` 进去改,不仅慢,还容易漏步骤。Dockerfile 就是把这些操作固化成脚本,交给 Docker 自动构建,结果是一个干净的、可复用的镜像。这才是服务器运维该有的效率。
手写 Dockerfile:从零开始定制业务镜像
选基础镜像:别用太大的,也别用太小的
基础镜像选错了,后面全是坑。Ubuntu 镜像接近 200MB,Alpine 才 5MB,但 Alpine 的包管理器是 apk,有些软件装起来得额外配源。稳妥方案是按业务语言选:
• Python 业务:`python:3.11-slim`
• Node 业务:`node:18-alpine`
• Java 业务:`openjdk:17-jdk-slim`
dockerfile
选一个足够小、依赖齐全的 Python 基础镜像
FROM python:3.11-slim
设置工作目录和环境变量
Dockerfile 里的 `WORKDIR` 相当于 `cd` 到那个目录,后面所有命令都基于它执行。环境变量提前设好,避免运行时再传。
dockerfile
WORKDIR /app
ENV PYTHONUNBUFFERED=1
防止 Python 日志缓冲,方便实时看日志
复制依赖文件并安装,利用缓存提速
这个顺序很关键。先复制 `requirements.txt`,再执行 `pip install`,这样只要依赖文件没变,Docker 会直接复用缓存的层,不用每次重装。
dockerfile
COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt
–no-cache-dir 防止 pip 缓存撑大镜像
复制业务代码,别漏了 .dockerignore
代码放最后复制,因为代码改得最频繁。前面层缓存住,改代码只重建最后一层,构建速度快很多。
dockerfile
COPY . .
同时写一个 `.dockerignore`,把 `__pycache__`、`.git`、`node_modules` 这些垃圾文件挡在外面:
__pycache__
.git
*.pyc
.venv
暴露端口和启动命令
`EXPOSE` 只是文档作用,真正放行端口是在 `docker run -p` 里。`CMD` 是启动时执行的命令,尽量用 `exec` 形式,别用 shell 形式。
dockerfile
EXPOSE 8000
CMD ["python", "app.py"]
构建镜像并验证:别跑完就忘
构建命令加标签,方便排查版本
docker build -t myapp:v1.0 .
-t 指定镜像名和标签,后面那个点表示当前目录
构建过程中如果报错,比如 `pip install` 卡住,大概率是源太慢。换国内源:
dockerfile
RUN pip install –no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
启动容器验证业务是否正常
docker run -d -p 8000:8000 –name myapp myapp:v1.0
-d 后台运行,-p 把宿主机 8000 映射到容器 8000
然后 `curl http://localhost:8000` 看能不能返回业务页面。如果访问不了,先检查容器日志:
docker logs myapp
常见报错是端口没暴露、CMD 写错路径、依赖没装全。
老鸟叮嘱:构建镜像时最容易翻车的三个坑
1.别把密码写死在 Dockerfile 里。构建镜像会 push 到仓库,密码跟着泄漏。用环境变量或 Docker Secrets。
2.层数不是越少越好。强行合并 `RUN` 命令虽然减少层数,但一旦出错排查起来很痛苦。合理分层,每层只干一件事。
3.镜像体积不是越小越好。Alpine 虽然小,但 glibc 兼容问题能让你排查一整天。业务是生产环境,优先选 `-slim` 系列。
FAQ
Q:Dockerfile 构建报错“COPY failed: no such file or directory”怎么办?
检查你 `COPY` 的路径是不是在当前目录下,或者 `.dockerignore` 里是不是把该文件过滤掉了。可以在构建目录下先 `ls` 确认文件存在。
Q:Dockerfile 里 CMD 和 ENTRYPOINT 有什么区别?
CMD 是默认命令,可以被 `docker run` 后面的参数覆盖。ENTRYPOINT 更像固定入口,适合写死启动脚本。一般组合用:`ENTRYPOINT ["python"]` + `CMD ["app.py"]`。
Q:docker build 时卡在“Sending build context to Docker daemon”很久?
说明你的目录里文件太多。用 `.dockerignore` 把 `node_modules`、`__pycache__`、`.git` 过滤掉,重构时上下文大小会从几百MB降到几MB。
Q:构建出来的镜像很大,怎么瘦身?
多用多阶段构建(multi-stage build),比如编译阶段用 `golang:1.20`,运行阶段只复制编译产物到 `alpine`。另外不要装调试工具,生产环境镜像只留业务依赖。
Q:Dockerfile 里 `RUN apt-get update` 和 `apt-get install` 必须写在一行吗?
建议写在一行,用 `&&` 连接,避免生成中间层缓存过期的 `apt` 索引。否则后续构建镜像时索引可能过时,导致安装失败。
Q:为什么容器启动后立即退出,日志也没报错?
大概率是业务进程没有前台运行。比如 `CMD ["python", "app.py"]` 里 `app.py` 启动后 fork 出子进程就退出了,Docker 容器在 PID 1 退出后也会停。确保主进程保持前台运行,或使用 `tail -f /dev/null` 等技巧。
转载请注明出处:https://www.zhujixuan.com/jishujiaocheng/9503.html 商家投稿邮箱:zhujixuanblog@qq.com
