前言你有没有过这样的经历在自己电脑上跑得好好的 Python Web 应用换到服务器上就报一堆依赖错误或者接手别人的项目光是配环境就花了大半天。Docker 就是来解决这个问题的。这篇文章会手把手带你从零掌握 Docker覆盖核心概念、安装、第一个容器、实战项目部署以及常见的坑和解决方案。跟着做保证你能跑通。一、Docker 核心概念镜像、容器、仓库先搞清楚三个最核心的概念记住三个词镜像、容器、仓库。1.1 镜像Image—— 应用的快照你可以把镜像理解成一张只读的光盘。这张光盘里包含了运行一个应用所需的一切代码、系统依赖、环境变量、配置文件全部打包在一起。你不需要关心光盘里装了什么只需要把它放进电脑就能跑。在 Docker 里一个镜像可能是一个完整的 Ubuntu 系统 Nginx也可能只是一个精简的 Python 运行环境。镜像是只读的你不能直接修改它。1.2 容器Container—— 光盘的运行实例当你把这张光盘放进电脑、光盘开始转动就形成了一个正在运行的容器。容器是镜像的运行实例。你可以同时运行多个容器它们互相隔离、互不影响就像同一张光盘可以在不同的电脑里各跑各的。简单说镜像 模板容器 实例。1.3 仓库Registry—— 镜像的网盘仓库就是存放镜像的地方最常用的是 Docker Hub相当于 Docker 界的 GitHub。你可以从上面 pull拉取别人做好的镜像比如nginx、python、mysql也可以 push推送自己制作的镜像到仓库供别人使用。类比一下概念生活中的比喻镜像Image操作系统安装盘ISO 文件容器Container从光盘安装后正在运行的电脑仓库Registry云端下载站存放各种镜像二、环境准备安装 Docker Desktop2.1 Windows 安装最低要求Windows 10/11 专业版、企业版或教育版开启 WSL 2Windows Subsystem for Linux 2建议至少 8GB 内存步骤打开 Docker Desktop 官网下载 Windows 版本安装包。双击安装包安装安装过程中勾选“Use WSL 2 instead of Hyper-V”推荐一路点 Next 即可。安装完成后启动 Docker Desktop等待右下角出现一个小鲸鱼图标且状态稳定。打开 PowerShell或 CMD验证安装docker--versiondocker-compose--version如果输出了版本号说明安装成功。注意如果你的 Windows 是家庭版不支持 WSL 2可以安装 Docker Desktop 的旧版使用 Hyper-V 后端但需要手动开启 Hyper-V 功能。微软官方有详细的开启步骤可以搜索Windows 家庭版开启 Hyper-V。2.2 macOS 安装同样从 Docker Desktop 官网 下载 macOS 版本Apple Silicon 和 Intel 处理器分别有对应版本。下载完成后将 Docker Desktop.app 拖入应用程序文件夹。启动 Docker Desktop等待状态栏显示绿色鲸鱼图标。打开终端验证docker--version2.3 加速配置国内用户必看国内拉取 Docker Hub 镜像速度很慢建议配置镜像加速。Docker Desktop 界面 → Settings → Docker Engine在右侧 JSON 配置中加入镜像源{registry-mirrors:[https://docker.mirrors.ustc.edu.cn,https://hub-mirror.c.163.com]}点击 Apply Restart等 Docker 重启后生效。三、第一个容器跑一个 Nginx安装好了先来小试牛刀跑一个 Nginx一个开源的 Web 服务器。3.1 拉取镜像dockerpull nginx这条命令的意思是从 Docker Hub 拉取最新的 Nginx 镜像。终端会显示下载进度条第一次下载需要等一会儿镜像有 100 MB。3.2 运行容器dockerrun-d--namemy-nginx-p8080:80 nginx逐个解释这行命令docker run运行一个容器-d后台运行detached 模式不占用当前终端--name my-nginx给容器起个名字叫 my-nginx方便后续管理-p 8080:80把宿主机的 8080 端口映射到容器的 80 端口访问本机 8080 就等于访问容器里的 Nginxnginx告诉 Docker 用哪个镜像来创建容器3.3 验证容器运行状态dockerps你应该能看到类似这样的输出CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a1b2c3d4e5f6 nginx /docker-entrypoint.… 10 seconds ago Up 9 seconds 0.0.0.0:8080-80/tcp my-nginxSTATUS 显示Up表示容器正在运行。3.4 打开浏览器验证在浏览器访问http://localhost:8080如果看到 “Welcome to nginx!” 页面说明你的第一个容器已经成功运行了3.5 停止和删除容器# 停止容器dockerstop my-nginx# 删除容器dockerrmmy-nginx# 如果想同时删除容器和镜像dockerrmmy-nginxdockerrmi nginx恭喜你完成了第一个容器操作接下来我们进入实战项目。四、实战项目用 Docker 部署一个 Flask Web 应用这一节我们来做一个真正有用的东西用 Docker 部署一个基于 FastAPI 的 Python Web 应用。FastAPI 和 Flask 二选一这里选 FastAPI性能更好类型提示支持更好但原理和 Flask 完全一样。4.1 项目结构先建立项目目录和文件flask-docker-project/ ├── app/ │ ├── __init__.py │ ├── main.py │ └── requirements.txt ├── Dockerfile ├── .dockerignore └── docker-compose.yml后面用到4.2 编写应用代码app/main.py— 主应用文件fromfastapiimportFastAPI appFastAPI(titleDocker 实战 API,version1.0.0)app.get(/)defhome():return{message:你好Docker 容器里的 FastAPI}app.get(/health)defhealth():return{status:healthy}app/requirements.txt— 依赖清单fastapi0.111.0 uvicorn[standard]0.29.0app/init.py— 空的初始化文件Python 包需要# 空文件仅作为包标识4.3 编写 DockerfileDockerfile 是 Docker 构建镜像的配方告诉 Docker这个镜像要装什么系统、放什么文件、运行什么命令。Dockerfile# 第一步指定基础镜像 # python:3.11-slim 是一个精简的 Python 3.11 镜像体积小不到 150MB FROM python:3.11-slim # 第二步设置工作目录 WORKDIR /app # 第三步先复制依赖文件再安装依赖利用 Docker 缓存层 # 注意必须先 COPY requirements.txt再 RUN pip install最后才 COPY 源代码 # 这样修改源代码时Docker 不需要重新安装依赖速度快很多 COPY app/requirements.txt . # 安装依赖使用清华镜像源加速国内环境 RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 第四步复制源代码 COPY app/ . # 第五步暴露端口和 -p 映射对应 EXPOSE 8000 # 第六步容器启动时运行的命令 # uvicorn 是 FastAPI 自带的 ASGI 服务器 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]为什么要先装依赖再复制代码这涉及到 Docker 的分层缓存机制。如果先复制代码每次改代码都会触发重新安装依赖浪费大量时间。把依赖安装和代码分开Docker 就能智能复用缓存层。4.4 .dockerignore 文件类似于 .gitignore告诉 Docker 忽略哪些文件不打包进镜像__pycache__ *.pyc *.pyo .git .venv venv *.egg-info .env4.5 构建镜像在项目根目录包含 Dockerfile 的目录执行dockerbuild-tmy-flask-app.-t my-flask-app给镜像起个标签名tag.表示 Dockerfile 在当前目录构建过程中你会看到 Docker 一步步执行 Dockerfile 中的指令最终输出Successfully built [镜像ID] Successfully tagged my-flask-app:latest4.6 运行容器dockerrun-d--namemy-flask-app-p8000:8000 my-flask-app4.7 验证打开浏览器访问http://localhost:8000→ 应返回{message:你好Docker 容器里的 FastAPI}http://localhost:8000/docs→ 自动打开 FastAPI 自带的 API 文档页面这是 FastAPI 的亮点功能五、Docker Compose 编排多个服务前面的例子只跑了一个容器。但在真实项目中一个 Web 应用通常还需要数据库MySQL/PostgreSQL、缓存Redis、反向代理Nginx等多个服务。Docker Compose 就是用来一键编排多个容器的工具。5.1 场景描述我们给 FastAPI 应用加上 Redis 缓存让它变成一个计数器每次访问/count接口数字 1存到 Redis 里。5.2 修改应用代码app/main.pyimportredisfromfastapiimportFastAPI appFastAPI(titleDocker 实战 API v2,version1.1.0)# Docker Compose 会自动创建名为 redis 的网络服务之间可以用服务名互相访问rredis.Redis(hostredis,port6379,decode_responsesTrue)app.get(/)defhome():return{message:你好FastAPI Redis}app.get(/count)defcount():cr.incr(visits)return{visits:c}app.get(/health)defhealth():return{status:healthy}app/requirements.txtfastapi0.111.0 uvicorn[standard]0.29.0 redis5.0.45.3 编写 docker-compose.ymlversion:3.8services:# 我们的 Web 应用web:build:.ports:-8000:8000volumes:-./app:/app# 挂载本地代码目录修改代码不用重新构建镜像depends_on:-redis# 等待 redis 服务启动后再启动 webenvironment:-REDIS_HOSTredis# Redis 缓存服务redis:image:redis:7-alpine# 使用精简版 Redis 镜像ports:-6379:6379volumes:-redis-data:/data# 持久化 Redis 数据# 定义命名卷Redis 数据不会因为容器删除而丢失volumes:redis-data:5.4 启动所有服务# 在 docker-compose.yml 所在目录执行docker-composeup-d-d表示后台运行。Docker Compose 会自动为你创建内部网络让 web 和 redis 能够互相通信。5.5 验证# 查看运行状态docker-composeps# 测试 APIcurlhttp://localhost:8000/count# 返回 {visits:1}curlhttp://localhost:8000/count# 返回 {visits:2}每次访问/count数字都会增加存储在 Redis 里。5.6 常用 Docker Compose 命令docker-composeup-d# 启动所有服务后台docker-composeup--build# 重新构建并启动docker-composedown# 停止并删除所有容器docker-composedown-v# 停止并删除容器和卷数据会丢失docker-composelogs-f# 查看日志-f 实时跟踪docker-composerestart# 重启所有服务docker-composeexecwebsh# 进入 web 容器内部调试用六、常用命令速查表镜像操作命令说明docker pull nginx:latest拉取镜像docker images列出本地所有镜像docker build -t my-app .从 Dockerfile 构建镜像docker rmi nginx删除镜像docker tag my-app:latest my-user/my-app:v1给镜像打标签docker push my-user/my-app:v1推送镜像到仓库容器操作命令说明docker run -d --name my-nginx -p 8080:80 nginx运行容器docker ps查看运行中的容器docker ps -a查看所有容器包括已停止的docker stop my-nginx停止容器docker start my-nginx启动已停止的容器docker restart my-nginx重启容器docker rm my-nginx删除容器docker logs -f my-nginx查看容器日志docker exec -it my-nginx bash进入容器内部交互式批量清理# 删除所有已停止的容器dockercontainer prune# 删除所有未使用的镜像dockerimage prune-a# 一键清理容器 镜像 网络dockersystem prune-a七、踩坑点常见问题及解决方案坑一端口冲突问题运行容器时报错Bind for 0.0.0.0:8000 failed: port is already allocated。原因宿主机上已经有程序占用了这个端口或者之前运行的同名容器没有完全退出。解决方案# 1. 查看哪个进程占用了端口Windowsnetstat-ano|findstr :8000# 2. 关闭对应进程或改用其他端口dockerrun-d-p8001:8000 my-flask-app# 3. 如果是旧容器没删干净强制删除dockerrm-fmy-flask-app预防给生产环境的容器起有意义的名称用-p映射时留意端口分配。坑二文件权限问题问题容器内写的文件宿主机无法修改或者反过来。原因Linux 容器的用户默认是 root但挂载的宿主机目录可能是当前用户的权限。解决方案在 Dockerfile 中创建非 root 用户推荐做法# 在用户创建组和用户 RUN groupadd -r appgroup useradd -r -g appgroup appuser # 切换到普通用户运行 USER appuser CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]或者在运行容器时设置用户dockerrun-d-u$(id-u):$(id-g)my-flask-app坑三Windows 路径问题问题在 Dockerfile 中用COPY ./app /app时提示找不到文件或者路径在容器内不识别。原因Windows 的路径分隔符是反斜杠\。虽然 Docker Desktop for Windows 内部用的是 WSL 2会做转换但混用路径风格容易出问题。解决方案统一使用正斜杠/Dockerfile 里始终用正斜杠项目路径不要有中文和空格如果在 CMD 中写 Windows 路径比如 Python 的Path对象记得转换成正斜杠或使用pathlib坑四Windows 下文件换行符导致脚本执行失败问题Shell 脚本在 Linux 容器里报bad interpreter或语法错误。原因Windows 换行符是\r\nLinux 是\n混在一起会导致 Shebang 行#!/bin/bash被解析成#!/bin/bash\r找不到解释器。解决方案在 PowerShell 中设置 git 提交时自动转换换行符gitconfig--globalcore.autocrlftrue或者在项目中添加.gitattributes文件* textauto坑五容器内存不足问题容器里的应用运行着运行着突然崩溃或者报内存错误。原因Docker Desktop 默认给容器的内存配额可能较小。解决方案Docker Desktop → Settings → Resources增大内存和 CPU 配置。Web 开发用途建议至少分配 4GB 内存。坑六修改代码后容器没有更新问题改了代码但容器里还是旧版本。原因如果是docker run启动的源代码已经被打包进镜像修改本地文件不会影响运行中的容器。解决方案重新构建镜像docker-compose build或docker build重新启动容器docker-compose up --build或者用 volume 挂载docker-compose.yml 中已配置./app:/app这样改代码不用重建容器但注意需要开启 uvicorn 的热重载--reload参数。八、经验总结写完这篇教程我想分享几点真实的经验1. 善用-d和日志刚开始用 Docker 时很多人喜欢前台运行不加-d看日志这没问题。但一旦确认能跑立刻切后台。长时间占用终端不说关掉终端容器也跟着关了。2. 先跑通再优化不要一上来就追求完美 Dockerfile。先让应用跑起来再逐步优化减少镜像体积、加多阶段构建、分离开发/生产配置。能跑是最重要的。3. 多看官方文档Docker 的官方文档写得非常清晰尤其是 Dockerfile 最佳实践和 Docker Compose 文件参考比大多数博客都权威。遇到问题先查官方文档。4. Docker 不是万能药Docker 解决的是环境一致性问题但不解决架构设计问题。如果你的应用本身有性能瓶颈Docker 只是换了个环境跑不会让它变快。5. 定时清理无用资源Docker 的镜像、容器、网络会占用不少磁盘空间养成定期docker system prune的习惯或者用docker image prune -a清理未使用的镜像。6. 记常用命令别每次都查把docker ps、docker logs、docker exec这些高频命令用熟效率会高很多。Docker 的学习曲线其实不陡峭核心就是镜像、容器、仓库三个概念加上Dockerfile和docker-compose.yml两个文件。搞懂这些你就已经超过 50% 的 Docker 使用者了。剩下的就是在实践中不断积累经验。动手试试吧你的第一步容器已经在等着你了。如有问题欢迎在评论区交流。