
1. 为什么你需要Dockerfile如果你曾经遇到过在我电脑上能跑怎么到你那就报错的情况Dockerfile就是你的救星。想象一下你开发了一个简单的天气预报网页想在朋友的电脑上展示结果发现他的Python版本不对、缺少依赖库、端口被占用... 这时候Dockerfile就像个魔法盒子把应用和它的运行环境一起打包在任何支持Docker的机器上都能一键运行。我去年帮学弟调试课程项目时就深有体会。他们用Flask写了个学生管理系统在实验室电脑运行正常但提交作业时老师的服务器环境不同导致报错。后来我们用Dockerfile重新打包再也没出现过环境问题。2. 准备你的第一个Web应用2.1 选择适合入门的项目我们从最简单的Python Flask应用开始它只需要两个文件app.py主程序文件requirements.txt依赖清单创建一个项目文件夹比如叫my_web_app然后新建app.pyfrom flask import Flask app Flask(__name__) app.route(/) def hello(): return 恭喜你的第一个Dockerized Web应用运行成功 if __name__ __main__: app.run(host0.0.0.0, port5000)再创建requirements.txtflask2.0.1这个微型应用会在访问首页时返回一句欢迎语。虽然简单但包含了Web服务的基本要素路由、响应和端口监听。2.2 验证应用能否本地运行在继续之前我们先确保应用能在本地正常工作pip install -r requirements.txt python app.py打开浏览器访问http://localhost:5000应该能看到欢迎消息。记住这个端口号5000稍后写Dockerfile时会用到。3. 编写你的第一个Dockerfile3.1 理解基础指令现在来到重头戏——在项目根目录创建Dockerfile文件注意没有扩展名。这个文件就像烹饪食谱告诉Docker如何烹制你的应用镜像。# 使用官方Python镜像作为基础 FROM python:3.9-slim # 设置工作目录容器内的路径 WORKDIR /app # 先复制依赖文件利用Docker缓存层优化构建速度 COPY requirements.txt . # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制所有项目文件 COPY . . # 暴露应用运行的端口与app.py中的端口一致 EXPOSE 5000 # 定义启动命令 CMD [python, app.py]这个Dockerfile做了以下几件事选择了一个轻量级的Python 3.9镜像作为基础在容器内创建了/app工作目录分两步复制文件先requirements.txt再其他文件这是Docker构建优化的小技巧安装了Flask依赖声明容器运行时暴露的端口定义了启动命令3.2 那些我踩过的坑刚开始写Dockerfile时我经常犯这两个错误忘记EXPOSE指令虽然不影响运行但会让其他人不知道应该映射哪个端口使用太庞大的基础镜像比如直接用python:3.9而不是python:3.9-slim导致镜像体积大了好几倍另一个实用技巧是.dockerignore文件。像.gitignore一样它可以避免把不必要的文件如__pycache__、.env等复制到镜像中减小镜像体积。在项目根目录创建它__pycache__ *.pyc .env .DS_Store4. 构建和运行你的Docker镜像4.1 构建镜像在Dockerfile所在目录运行docker build -t my-web-app .这个命令会读取当前目录的Dockerfile按照指令一步步构建镜像最后给镜像打上标签my-web-app第一次构建可能会慢一些因为要下载基础镜像。后续构建会利用缓存速度飞快。4.2 运行容器镜像构建完成后用这个命令运行它docker run -d -p 5000:5000 --name my-app my-web-app参数说明-d后台运行detached模式-p 5000:5000把主机的5000端口映射到容器的5000端口--name给容器起个名字方便后续管理现在再次访问http://localhost:5000应该能看到同样的欢迎消息但这次是从Docker容器提供的服务4.3 管理你的容器几个常用命令# 查看运行中的容器 docker ps # 查看所有容器包括已停止的 docker ps -a # 停止容器 docker stop my-app # 启动已停止的容器 docker start my-app # 删除容器 docker rm my-app # 删除镜像 docker rmi my-web-app5. 进阶技巧与最佳实践5.1 多阶段构建当你的应用需要编译时比如前端项目可以使用多阶段构建来减小最终镜像大小。这里以Node.js项目为例# 第一阶段构建阶段 FROM node:14 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 第二阶段运行阶段 FROM nginx:alpine COPY --frombuilder /app/dist /usr/share/nginx/html EXPOSE 80这种构建方式最终只包含nginx和编译好的静态文件去掉了庞大的node_modules。5.2 环境变量管理不要在Dockerfile中硬编码敏感信息使用ARG和ENV# 构建时传入的变量 ARG APP_VERSION1.0 # 运行时环境变量 ENV FLASK_ENVproduction构建时可以通过--build-arg传递变量docker build --build-arg APP_VERSION2.0 -t my-web-app .5.3 健康检查添加健康检查指令可以让Docker监控你的应用状态HEALTHCHECK --interval30s --timeout3s \ CMD curl -f http://localhost:5000/ || exit 1这样运行docker ps时可以看到容器健康状态编排工具也能据此做出反应。6. 实际项目中的经验分享去年我用Docker部署了一个机器学习API服务总结了几条实用经验日志管理默认情况下容器日志会堆积建议docker run --log-opt max-size10m --log-opt max-file3 ...时区问题容器内默认是UTC时间可以这样设置ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone数据持久化对需要保存的数据使用volumedocker run -v /path/on/host:/path/in/container ...资源限制防止容器占用过多资源docker run --memory512m --cpus1 ...7. 调试技巧当容器行为不符合预期时可以查看日志docker logs my-app进入运行中的容器检查docker exec -it my-app /bin/bash如果容器启动失败去掉-d参数直接在前台运行查看实时输出使用docker inspect my-app查看容器详细配置记得有一次我的Flask应用在容器内启动失败就是因为没把host设为0.0.0.0容器内默认的localhost与主机不互通这个小细节折腾了我半小时。