news 2026/8/3 18:54:12

Docker 入门到实战:用 Docker 部署一个 Python Web 应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker 入门到实战:用 Docker 部署一个 Python Web 应用

前言

你有没有过这样的经历:在自己电脑上跑得好好的 Python Web 应用,换到服务器上就报一堆依赖错误;或者接手别人的项目,光是配环境就花了大半天。Docker 就是来解决这个问题的。

这篇文章会手把手带你从零掌握 Docker,覆盖核心概念、安装、第一个容器、实战项目部署,以及常见的坑和解决方案。跟着做,保证你能跑通。


一、Docker 核心概念:镜像、容器、仓库

先搞清楚三个最核心的概念,记住三个词:镜像、容器、仓库

1.1 镜像(Image)—— 应用的"快照"

你可以把镜像理解成一张只读的光盘。这张光盘里包含了运行一个应用所需的一切:代码、系统依赖、环境变量、配置文件,全部打包在一起。你不需要关心光盘里装了什么,只需要把它放进电脑就能跑。

在 Docker 里,一个镜像可能是一个完整的 Ubuntu 系统 + Nginx,也可能只是一个精简的 Python 运行环境。镜像是只读的,你不能直接修改它。

1.2 容器(Container)—— 光盘的"运行实例"

当你把这张光盘放进电脑、光盘开始转动,就形成了一个正在运行的"容器"。容器是镜像的运行实例。你可以同时运行多个容器,它们互相隔离、互不影响,就像同一张光盘可以在不同的电脑里各跑各的。

简单说:镜像 = 模板,容器 = 实例

1.3 仓库(Registry)—— 镜像的"网盘"

仓库就是存放镜像的地方,最常用的是 Docker Hub,相当于 Docker 界的 GitHub。你可以从上面 pull(拉取)别人做好的镜像,比如nginxpythonmysql;也可以 push(推送)自己制作的镜像到仓库供别人使用。

类比一下:

概念生活中的比喻
镜像(Image)操作系统安装盘(ISO 文件)
容器(Container)从光盘安装后正在运行的电脑
仓库(Registry)云端下载站,存放各种镜像

二、环境准备:安装 Docker Desktop

2.1 Windows 安装

最低要求:

  • Windows 10/11 专业版、企业版或教育版
  • 开启 WSL 2(Windows Subsystem for Linux 2)
  • 建议至少 8GB 内存

步骤:

  1. 打开 Docker Desktop 官网,下载 Windows 版本安装包。

  2. 双击安装包安装,安装过程中勾选“Use WSL 2 instead of Hyper-V”(推荐),一路点 Next 即可。

  3. 安装完成后,启动 Docker Desktop,等待右下角出现一个小鲸鱼图标且状态稳定。

  4. 打开 PowerShell(或 CMD),验证安装:

docker--versiondocker-compose--version

如果输出了版本号,说明安装成功。

注意:如果你的 Windows 是家庭版,不支持 WSL 2,可以安装 Docker Desktop 的旧版(使用 Hyper-V 后端),但需要手动开启 Hyper-V 功能。微软官方有详细的开启步骤,可以搜索"Windows 家庭版开启 Hyper-V"。

2.2 macOS 安装

  1. 同样从 Docker Desktop 官网 下载 macOS 版本(Apple Silicon 和 Intel 处理器分别有对应版本)。

  2. 下载完成后,将 Docker Desktop.app 拖入应用程序文件夹。

  3. 启动 Docker Desktop,等待状态栏显示绿色鲸鱼图标。

  4. 打开终端验证:

docker--version

2.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 就等于访问容器里的 Nginx
  • nginx:告诉 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-nginx

STATUS 显示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 app=FastAPI(title="Docker 实战 API",version="1.0.0")@app.get("/")defhome():return{"message":"你好,Docker 容器里的 FastAPI!"}@app.get("/health")defhealth():return{"status":"healthy"}

app/requirements.txt— 依赖清单:

fastapi==0.111.0 uvicorn[standard]==0.29.0

app/init.py— 空的初始化文件(Python 包需要):

# 空文件,仅作为包标识

4.3 编写 Dockerfile

Dockerfile 是 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 .env

4.5 构建镜像

在项目根目录(包含 Dockerfile 的目录)执行:

dockerbuild-tmy-flask-app.
  • -t my-flask-app:给镜像起个标签名(tag)
  • .:表示 Dockerfile 在当前目录

构建过程中你会看到 Docker 一步步执行 Dockerfile 中的指令,最终输出:

Successfully built [镜像ID] Successfully tagged my-flask-app:latest

4.6 运行容器

dockerrun-d--namemy-flask-app-p8000:8000 my-flask-app

4.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.py:

importredisfromfastapiimportFastAPI app=FastAPI(title="Docker 实战 API v2",version="1.1.0")# Docker Compose 会自动创建名为 redis 的网络,服务之间可以用服务名互相访问r=redis.Redis(host="redis",port=6379,decode_responses=True)@app.get("/")defhome():return{"message":"你好,FastAPI + Redis!"}@app.get("/count")defcount():c=r.incr("visits")return{"visits":c}@app.get("/health")defhealth():return{"status":"healthy"}

app/requirements.txt:

fastapi==0.111.0 uvicorn[standard]==0.29.0 redis==5.0.4

5.3 编写 docker-compose.yml

version:"3.8"services:# 我们的 Web 应用web:build:.ports:-"8000:8000"volumes:-./app:/app# 挂载本地代码目录,修改代码不用重新构建镜像depends_on:-redis# 等待 redis 服务启动后再启动 webenvironment:-REDIS_HOST=redis# Redis 缓存服务redis:image:redis:7-alpine# 使用精简版 Redis 镜像ports:-"6379:6379"volumes:-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. 查看哪个进程占用了端口(Windows)netstat-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,会做转换,但混用路径风格容易出问题。

解决方案:

  1. 统一使用正斜杠/(Dockerfile 里始终用正斜杠)
  2. 项目路径不要有中文和空格
  3. 如果在 CMD 中写 Windows 路径(比如 Python 的Path对象),记得转换成正斜杠或使用pathlib

坑四:Windows 下文件换行符导致脚本执行失败

问题:Shell 脚本在 Linux 容器里报bad interpreter或语法错误。

原因:Windows 换行符是\r\n,Linux 是\n,混在一起会导致 Shebang 行(#!/bin/bash)被解析成#!/bin/bash\r,找不到解释器。

解决方案:

在 PowerShell 中设置 git 提交时自动转换换行符:

gitconfig--globalcore.autocrlftrue

或者在项目中添加.gitattributes文件:

* text=auto

坑五:容器内存不足

问题:容器里的应用运行着运行着突然崩溃,或者报内存错误。

原因:Docker Desktop 默认给容器的内存配额可能较小。

解决方案:Docker Desktop → Settings → Resources,增大内存和 CPU 配置。Web 开发用途建议至少分配 4GB 内存。


坑六:修改代码后容器没有更新

问题:改了代码,但容器里还是旧版本。

原因:如果是docker run启动的,源代码已经被打包进镜像,修改本地文件不会影响运行中的容器。

解决方案:

  1. 重新构建镜像:docker-compose builddocker build
  2. 重新启动容器:docker-compose up --build
  3. 或者用 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 psdocker logsdocker exec这些高频命令用熟,效率会高很多。


Docker 的学习曲线其实不陡峭,核心就是镜像、容器、仓库三个概念,加上Dockerfiledocker-compose.yml两个文件。搞懂这些,你就已经超过 50% 的 Docker 使用者了。剩下的就是在实践中不断积累经验。

动手试试吧,你的第一步容器已经在等着你了。


如有问题,欢迎在评论区交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/3 18:54:00

3步掌握Hackintosh项目:如何为17个品牌打造完美macOS体验

3步掌握Hackintosh项目:如何为17个品牌打造完美macOS体验 【免费下载链接】Hackintosh Hackintosh long-term maintenance model EFI and installation tutorial 项目地址: https://gitcode.com/gh_mirrors/ha/Hackintosh 黑苹果技术让普通PC用户也能体验到m…

作者头像 李华
网站建设 2026/8/3 18:52:56

Webpack 3 中的新特性

本文简短地分享下最新发布的 Webpack 3 中的新特性,供大家参考。 1. Webpack 3 的新特性 6 月 20 日,Webpack 发布了最新的 3.0 版本,并在 Medium 发布了公告。 Webpack 目前几乎作为前端开发的标配,一些变化都可能影响到实际的…

作者头像 李华
网站建设 2026/8/3 18:51:40

快速解锁GitHub访问的终极解决方案:Fast-GitHub浏览器扩展

快速解锁GitHub访问的终极解决方案:Fast-GitHub浏览器扩展 【免费下载链接】Fast-GitHub 国内Github下载很慢,用上了这个插件后,下载速度嗖嗖嗖的~! 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 你是否曾经在…

作者头像 李华
网站建设 2026/8/3 18:51:16

React.js 开发参见问题 QA

文章中我整理了 React.js 开发过程中一些参见问题的解答汇总,供大家参考。 1. 一些课程资源 课程源码 GitHub 地址:https://github.com/ParryQiu/IMOOC-React 1.1 2018-03-26 更新 针对源码文件夹 react-router-4_webpack-2-update 更新了免费的讲解…

作者头像 李华
网站建设 2026/8/3 18:47:33

微信小程序开发平台新功能「云开发」快速上手体验

微信小程序开发平台刚刚开放了一个全新的功能:云开发。 简单地说就是将开发人员搭建微信小程序后端的成本再次降低,此文刚好在此产品公测时,来快速上手看看都有哪些方便开发者的功能更新。 微信小程序一直保持一个比较稳定的节奏进行功能的开…

作者头像 李华