在Docker环境中如何运行自己的代码
作者:铉铉这波能秀
一、什么是 Docker?
1.1 Docker 的定义与核心定位
Docker 是由 Docker Inc.(后被 Mirantis 收购)开发的一款开源的容器化平台,基于 Go 语言开发,遵循 Apache 2.0 开源协议。其核心定位是:将应用程序及其依赖环境打包成轻量级、可移植、自包含的容器,使得应用可以在任何支持 Docker 的环境中以相同的方式运行。
通俗来讲,Docker 就像一个 “标准化的集装箱”:无论你的应用是 Python 写的 Web 服务、Node.js 开发的前端项目,还是 Java 构建的微服务,都可以被装进这个 “集装箱” 里。这个 “集装箱” 包含了应用运行所需的所有东西 —— 代码、运行时、系统工具、系统库,只要有 Docker 运行环境,这个 “集装箱” 就能无缝运行,无需担心环境差异。
1.2 Docker 的核心架构
Docker 采用客户端 - 服务器(C/S)架构,核心组件包括:
- Docker Client(客户端):用户交互的入口,通过命令行(
docker命令)或 API 向 Docker Daemon 发送指令(如构建镜像、启动容器); - Docker Daemon(守护进程):运行在宿主机的后台进程,负责处理客户端的请求,管理镜像、容器、网络、数据卷等核心资源;
- Docker Registry(镜像仓库):存储 Docker 镜像的仓库,分为公有仓库(如 Docker Hub)和私有仓库(如企业内部仓库);
- Containerd:底层容器运行时,负责容器的创建、启动、停止等生命周期管理,Docker Daemon 不再直接操作容器,而是通过 Containerd 调用 RunC;
- RunC:轻量级的容器运行时,遵循 OCI(开放容器倡议)标准,是容器运行的核心执行器。
核心交互流程:用户通过 Docker Client 输入 docker run 命令 → Docker Daemon 接收指令后,从 Registry 拉取镜像(若本地无)→ 调用 Containerd 创建容器 → RunC 启动容器进程,完成应用运行。
二、为什么要使用 Docker?—— 解决开发部署的核心痛点
2.1 彻底终结 “环境不一致” 的噩梦
“在我本地能跑,到测试环境就报错” 是开发人员的经典吐槽,根源在于开发、测试、生产环境的差异:
- 开发用 macOS + Python 3.8,测试服务器是 CentOS 7 + Python 3.6,依赖包版本冲突导致代码运行异常;
- 前端项目依赖 Node.js 16,运维部署时用了 Node.js 18,打包后的代码出现兼容性问题;
- 数据库版本不一致:开发用 MySQL 8.0,生产用 MySQL 5.7,SQL 语法不兼容导致功能失效。
Docker 的解决方案是:将应用 + 运行环境打包成镜像,镜像在任何支持 Docker 的环境中运行结果一致。无论你是在 macOS、Windows、Linux 还是云服务器上运行,只要镜像相同,应用行为就完全一致,真正实现 “一次构建,到处运行”。
三、核心概念辨析:虚拟机、Docker 容器与镜像
要掌握 Docker,必须先理清三个核心概念:虚拟机、Docker 容器、Docker 镜像,以及它们之间的关系。
3.1 传统虚拟机:重量级的环境隔离方案
虚拟机(VM)是通过虚拟化技术在物理服务器上模拟出的独立操作系统实例,核心依赖 Hypervisor(虚拟化管理程序,如 VMware、KVM、VirtualBox)。
3.1.1 虚拟机的架构
- 物理机(Host Machine):底层的硬件服务器,提供 CPU、内存、存储、网络等物理资源;
- Hypervisor:运行在物理机上的虚拟化层,负责将物理资源分配给不同的虚拟机;
- 客户机(Guest Machine):虚拟机实例,包含完整的操作系统(如 Windows、Linux)和应用程序;
- Guest OS:虚拟机内的操作系统,每个虚拟机都有独立的内核和系统库。
3.1.2 虚拟机的特点
- 完全隔离:每个虚拟机拥有独立的内核、文件系统、网络,与其他虚拟机和宿主机完全隔离;
- 重量级:需要模拟完整的硬件和操作系统,启动时间长(分钟级),资源占用高(每个虚拟机需分配固定的 CPU、内存);
- 兼容性好:可运行任何操作系统和应用,不受宿主机系统限制。
3.2 Docker 容器:轻量级的进程隔离
Docker 容器是基于 Linux 内核技术实现的轻量级隔离环境,本质上是宿主机上的一组受限制的进程。
3.2.1 容器的核心隔离技术
Docker 容器的隔离性依赖 Linux 内核的两大核心特性:
- Namespace:实现资源隔离,包括 PID(进程 ID)、NET(网络)、MNT(文件系统)、UTS(主机名)、IPC(进程间通信)、USER(用户)等 Namespace。每个容器拥有独立的 Namespace,只能看到自己的进程、网络、文件系统,无法感知宿主机或其他容器的资源;
- Cgroup(Control Group):实现资源限制,可限制容器的 CPU、内存、磁盘 I/O、网络带宽等资源,避免容器抢占宿主机资源。
3.2.2 容器的特点
- 轻量级:无需模拟硬件和操作系统内核,共享宿主机内核,启动时间短(毫秒级),资源占用低(按需分配资源,无需固定分配);
- 高效隔离:进程级隔离,隔离性略弱于虚拟机,但足以满足绝大多数应用场景;
- 可移植性:基于镜像运行,可在任何支持 Docker 的环境中迁移;
- 快速扩缩容:容器创建 / 销毁速度快,可快速响应业务扩缩容需求。
3.3 Docker 镜像:容器的 “只读模板”
Docker 镜像(Image)是创建 Docker 容器的只读模板,包含了容器运行所需的所有文件系统、代码、运行时、依赖、配置等。
3.3.1 镜像的核心特性
- 只读性:镜像一旦构建完成,就无法修改,只能以只读方式存在;
- 分层结构:镜像基于 UnionFS(联合文件系统)实现分层存储,每个层都是一个只读的文件系统片段,多个镜像可共享相同的层,节省存储空间。例如:Python 3.9-alpine 镜像包含基础层(alpine 系统)、Python 运行时层、依赖层,多个基于该镜像的容器可共享这些层;
- 可复用性:镜像可作为基础模板,构建新的镜像(如基于 Python 3.9-alpine 镜像,添加自己的代码和依赖,构建新的应用镜像)。
3.4 虚拟机 vs Docker 容器:核心差异对比
| 特性 | 虚拟机 | Docker 容器 |
|---|---|---|
| 内核 | 每个虚拟机有独立内核 | 共享宿主机内核(仅 Linux 容器) |
| 启动时间 | 分钟级 | 毫秒级 |
| 资源占用 | 高(固定分配 CPU / 内存) | 低(按需分配,共享资源) |
| 隔离级别 | 硬件级(完全隔离) | 进程级(内核级隔离) |
| 镜像 / 镜像体积 | 大(包含完整操作系统,GB 级) | 小(仅包含应用和依赖,MB 级) |
| 可移植性 | 差(依赖 Hypervisor) | 好(跨平台运行) |
| 扩缩容效率 | 低(启动慢,资源固定) | 高(启动快,资源弹性分配) |
| 适用场景 | 需完全隔离的场景(如多操作系统运行) | 微服务、CI/CD、快速部署、环境标准化 |
3.5 Docker 容器与镜像的关系:模板与实例
Docker 容器和镜像的关系,类似于类与对象的关系(镜像可以理解为一个生产容器的模具):
- 镜像:相当于 “类”,是只读的模板,定义了容器的结构和行为;
- 容器:相当于 “对象”,是镜像的运行实例,基于镜像创建,拥有可写层(镜像为只读,容器在镜像的基础上添加一层可写层,所有修改都在可写层中进行)。
核心关系总结:
- 一个镜像可以创建多个容器(一个类可以实例化多个对象);
- 容器启动时,Docker 会加载镜像的所有只读层,并在顶部创建一个可写层;
- 容器停止后,可写层的数据不会丢失,重启容器后仍可访问;
- 删除容器时,可写层会被删除,镜像的只读层不会受影响;
- 可通过
docker commit将容器的可写层转换为新的镜像层,实现镜像的更新。
示例:基于 python:3.9-alpine 镜像创建两个容器 A 和 B,A 和 B 共享镜像的只读层,各自拥有独立的可写层。修改 A 容器内的文件,只会影响 A 的可写层,不会影响 B 容器和原始镜像。
四、如何选择并拉取合适的 Docker 镜像?
镜像是 Docker 运行的基础,选择合适的镜像直接影响容器的稳定性、体积和安全性。本节将详细讲解镜像的选择原则、拉取方法和本地管理。
4.1 镜像的核心来源
4.1.1 公有镜像仓库:Docker Hub
Docker Hub(https://hub.docker.com/)是官方的公有镜像仓库,包含数百万个官方和社区镜像,是最主要的镜像来源:
- 官方镜像:由 Docker 官方或软件厂商维护(如
python、node、nginx、mysql),安全性高、更新及时、兼容性好; - 社区镜像:由开发者或社区维护,可能包含定制化配置,但需注意安全性(避免恶意镜像)。
4.1.2 私有镜像仓库
企业内部通常会搭建私有镜像仓库(如 Docker Registry、Harbor),用于存储内部定制的镜像:
- 避免敏感代码 / 配置泄露;
- 提高镜像拉取速度(无需访问公网);
- 统一管理企业内部的镜像版本。
4.2 选择镜像的核心原则
4.2.1 优先选择官方镜像
官方镜像经过严格测试,安全性和稳定性有保障,且有清晰的版本更新记录。
例如:选择 python:3.9-alpine 而非社区维护的 xxx/python:3.9。
4.2.2 选择轻量化的镜像版本
镜像体积越小,拉取速度越快,占用存储空间越少。常见的轻量化版本:
- alpine 版本:基于 Alpine Linux(轻量级 Linux 发行版,体积约 5MB),是最常用的轻量化版本,如
python:3.9-alpine、nginx:alpine; - slim 版本:精简版,去掉了不必要的组件,体积介于 full 版本和 alpine 版本之间,如
python:3.9-slim; - full 版本:完整版本,包含所有组件,体积大,适合需要完整工具链的场景。
注意:alpine 版本可能缺少部分系统库,若应用依赖特定库(如 glibc),需手动安装。
4.2.3 明确指定镜像标签,避免使用 latest
latest 是镜像的默认标签,指向最新版本,但无法保证版本的稳定性(可能随时更新)。生产环境中必须指定具体版本标签,如 python:3.9.18-alpine 而非 python:latest。
标签命名规则:通常包含 “主版本。次版本。补丁版本 - 系统版本”,如 node:18.18.2-alpine3.18。
4.2.4 关注镜像的安全性
- 查看镜像的漏洞扫描报告(Docker Hub 提供镜像的安全扫描功能);
- 避免使用未知来源的社区镜像,防止包含恶意代码;
- 定期更新镜像,修复已知漏洞。
4.2.5 考虑镜像的维护性
选择维护活跃的镜像,避免使用已停止更新的版本(如 Python 2.7 已停止维护,应避免使用)。可通过 Docker Hub 查看镜像的 “Last Updated” 时间,判断维护状态。
4.3 不同场景的镜像选择示例
| 应用场景 | 推荐镜像 | 选择理由 |
|---|---|---|
| Python 微服务(生产) | python:3.9-alpine | 体积小、资源占用低,适合生产环境 |
| Python 开发环境 | python:3.9-slim | 包含基础工具链,便于调试 |
| Node.js 前端项目部署 | node:18-alpine | 轻量化,适合打包和运行前端代码 |
| Java Spring Boot 应用 | openjdk:17-jdk-alpine | 体积小,支持 Spring Boot 3.x |
| Nginx 静态资源托管 | nginx:alpine | 轻量级,性能高,适合静态资源部署 |
| MySQL 数据库(测试) | mysql:5.7-alpine | 轻量化,适合测试环境 |
| MySQL 数据库(生产) | mysql:8.0.36 | 完整版本,稳定性高,支持生产环境特性 |
4.4 镜像拉取的核心命令与实操
4.4.1 搜索镜像
使用 docker search 命令搜索 Docker Hub 上的镜像:
bash运行:
# 搜索 Python 镜像 docker search python # 筛选官方镜像(--filter=is-official=true) docker search --filter=is-official=true python # 筛选星数≥1000的镜像(--filter=stars=1000) docker search --filter=stars=1000 python
4.4.2 拉取镜像
使用 docker pull 命令拉取镜像,格式:docker pull 镜像名:标签。
bash运行:
# 拉取官方 Python 3.9-alpine 镜像 docker pull python:3.9-alpine # 拉取指定版本的 Nginx 镜像 docker pull nginx:1.25.3-alpine # 拉取私有仓库的镜像(需先登录) docker pull registry.example.com/my-app:v1.0
若不指定标签,默认拉取 latest 标签:
bash运行:
docker pull python # 等价于 docker pull python:latest
4.4.3 登录私有镜像仓库
拉取 / 推送私有镜像前,需先登录仓库:
bash运行:
# 登录 Docker Hub docker login # 登录私有仓库 docker login registry.example.com
输入用户名和密码后,登录信息会保存在 ~/.docker/config.json 文件中。
4.5 镜像的本地管理
4.5.1 查看本地镜像
bash运行:
# 查看所有本地镜像
docker images
# 精简输出格式(只显示镜像ID、名称、标签、大小)
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
# 查看镜像的详细信息
docker inspect python:3.9-alpine
4.5.2 重命名镜像
使用 docker tag 命令为镜像添加新标签(常用于推送镜像到私有仓库):
bash运行:
# 格式:docker tag 原镜像名:标签 新镜像名:标签 docker tag python:3.9-alpine registry.example.com/my-python:3.9-alpine
4.5.3 删除镜像
使用 docker rmi 命令删除本地镜像:
bash运行:
# 删除指定镜像(通过镜像名:标签) docker rmi python:3.9-alpine # 删除指定镜像(通过镜像ID) docker rmi 1234567890ab # 强制删除(镜像被容器使用时,需加 -f) docker rmi -f python:3.9-alpine # 删除所有未使用的镜像(清理空间) docker image prune -a
注意:删除镜像前,需先删除基于该镜像创建的容器(或强制删除)。
4.5.4 查看镜像构建历史
使用 docker history 命令查看镜像的分层构建历史,可排查镜像体积过大的原因:
bash运行:
docker history python:3.9-alpine
4.5.5 运行容器 / 退出容器 / 管理镜像 / 启动已停止容器
(一)运行容器
(docker run:基于镜像创建 + 启动新容器,核心是「run 镜像」)
1. 基础语法
bash 运行:
docker run [可选参数] <镜像名/镜像ID> [容器内要执行的命令]
- 镜像名 / ID:必须指定(比如
ubuntu:20.04、python:3.9-slim,或镜像 ID 如f8c79dc85f05); - 可选参数:控制容器的运行方式(交互式、后台、命名、端口映射等);
- 容器内命令:可选,比如
bash(进入终端)、python app.py(运行脚本)。
2. 常用示例(从简单到复杂)
| 场景 | 命令示例 | 说明 |
|---|---|---|
| 最简运行(前台) | docker run ubuntu:20.04 | 基于 ubuntu:20.04 镜像创建容器,执行镜像默认命令(通常是 bash),但无终端交互,运行后立即退出 |
| 交互式运行(常用) | docker run -it ubuntu:20.04 bash | -it:-i(交互式输入)+-t(分配终端),进入容器的 bash 终端,可执行命令 |
| 后台运行(守护态) | docker run -d --name my-ubuntu ubuntu:20.04 sleep 3600 | -d:后台运行;--name:给容器命名(避免随机名称);sleep 3600:容器后台运行 1 小时 |
| 端口映射 + 后台运行 | docker run -d -p 8080:80 --name my-nginx nginx | -p 8080:80:主机 8080 端口映射到容器 80 端口,访问主机 8080 = 访问容器 80 |
3. 关键参数解释
-it:必选(交互式操作),缺一则无法进入容器终端;-d:后台运行(守护进程),容器在后台执行,不占用当前终端;--name:自定义容器名(如my-app),否则 Docker 会随机生成名称;-p:端口映射(主机端口:容器端口),对外暴露容器服务;-v:目录挂载(主机目录:容器目录),实现主机和容器文件共享(如-v /host/data:/container/data)。
(二)退出容器
退出容器的核心是区分「是否停止容器」,取决于你运行容器的方式(前台 / 后台)。
1. 场景 1:交互式容器(-it 前台运行,比如 docker run -it ubuntu bash)
| 退出方式 | 命令 / 操作 | 效果 |
|---|---|---|
| 停止容器并退出 | 在容器终端输入 exit | 容器停止运行,回到 Linux 主机终端,容器状态变为 exited |
| 不停止容器并退出 | 按快捷键 Ctrl + P → Q | 容器继续后台运行(状态 up),仅退出容器终端,回到 Linux 主机终端 |
2. 场景 2:后台容器(-d 运行,比如 docker run -d my-nginx)
后台容器本身不占用终端,无需 “退出”,若要操作 / 停止:
bash 运行:
# 先进入后台容器的终端(可选) docker exec -it my-nginx bash # 进入后可执行命令,退出用 exit(仅退出终端,容器仍运行) # 停止后台容器(彻底“退出”容器运行) docker stop my-nginx # 按容器名停止;也可用容器ID:docker stop <容器ID>
(三)“启动已停止的容器”
docker run 是创建新容器(每次 run 都会生成新容器),而已停止的容器(比如 exit 后的容器)需要用 docker start 启动,这才是 “运行已有容器” 的正确方式。
1. 先查看所有容器(找到已停止的容器)
bash 运行:
docker ps -a # -a:显示所有容器(运行中+已停止) # 输出示例: # CONTAINER ID IMAGE COMMAND STATUS NAMES # abc123 ubuntu:20.04 "bash" Exited (0) 5min ago my-ubuntu
2. 启动已停止的容器(「运行容器」的正确方式)
bash 运行:
# 语法:docker start [可选参数] <容器名/容器ID> docker start my-ubuntu # 启动名为my-ubuntu的容器(后台运行) docker start -i my-ubuntu # -i:交互式启动(前台运行,可输入命令)
3. 重启容器(停止 + 启动)
bash 运行:
docker restart my-ubuntu # 重启容器(无论当前是否运行)
(四)删除容器 / 镜像
1. 删除容器(需先停止,或强制删除)
bash 运行:
# 先停止容器 docker stop my-ubuntu # 删除容器 docker rm my-ubuntu # 强制删除运行中的容器(不推荐,除非紧急) docker rm -f my-ubuntu # 批量删除所有已停止容器(常用) docker rm $(docker ps -aq --filter status=exited)
2. 删除镜像(需先删除基于该镜像的所有容器)
bash 运行:
# 先查看镜像 docker images # 输出镜像名、标签、ID # 示例:REPOSITORY TAG IMAGE ID CREATED SIZE # ubuntu 20.04 f8c79dc85f05 2 hours ago 72.8MB # 删除镜像(语法:docker rmi <镜像名:标签/镜像ID>) docker rmi ubuntu:20.04 # 按名称+标签删除 docker rmi f8c79dc85f05 # 按镜像ID删除 # 强制删除被容器引用的镜像(不推荐,先删容器) docker rmi -f ubuntu:20.04
五、实战:将自己的代码运行在 Docker 容器中
掌握了镜像的选择和拉取后,接下来进入核心实战环节:将自己的代码打包成镜像,并在容器中运行。本节将讲解通用流程,并提供多语言示例,确保你能直接落地。
5.1 前提准备:Docker 环境安装与验证
5.1.1 安装 Docker
Linux(Ubuntu/Debian):
bash运行:
# 更新软件源 sudo apt update # 安装依赖 sudo apt install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 添加 Docker 软件源 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io # 启动 Docker 服务 sudo systemctl start docker # 设置开机自启 sudo systemctl enable docker # 将当前用户加入 docker 组(避免每次使用 sudo) sudo usermod -aG docker $USER # 重新登录生效 logout
Windows/macOS:下载 Docker Desktop(https://www.docker.com/products/docker-desktop/),安装后打开即可,内置 Docker Engine、Docker Compose 等工具。
5.1.2 验证 Docker 安装
bash运行:
# 查看 Docker 版本 docker --version # 运行 hello-world 容器(验证环境是否正常) docker run hello-world
若输出 “Hello from Docker!”,说明 Docker 安装成功。
5.2 通用流程:代码容器化的核心步骤
无论使用哪种编程语言,代码容器化的核心流程都包含以下 5 步:
- 整理代码与依赖;
- 编写 Dockerfile;
- 构建 Docker 镜像;
- 启动容器运行代码;
- 验证与调试。
5.2.1 步骤 1:整理代码与依赖
将代码和依赖清单放在同一个目录(称为 “Docker 上下文目录”),避免冗余文件(如日志、缓存、编译产物),减少镜像体积。
依赖清单的常见形式:
- Python:
requirements.txt; - Node.js:
package.json/package-lock.json; - Java:
pom.xml(Maven)/build.gradle(Gradle); - Go:
go.mod/go.sum。
5.2.2 步骤 2:编写 Dockerfile(核心)
Dockerfile 是镜像构建脚本,定义了镜像的构建步骤。Dockerfile 是无后缀的纯文本文件(无 .txt/.sh 等后缀),默认文件名是 Dockerfile(首字母大写,行业通用规范,小写 dockerfile 也可,但不推荐);若需区分环境(如开发 / 生产),也可自定义命名(如 Dockerfile.dev/Dockerfile.prod),构建时需手动指定文件名。
不同系统创建 Dockerfile 的方法
1. Linux/macOS(终端操作)
直接通过终端命令创建空的 Dockerfile,或用编辑器编辑:
bash 运行:
# 1. 创建空的 Dockerfile(最快捷) touch Dockerfile # 2. 编辑 Dockerfile(选其一) vim Dockerfile # 用 vim 编辑(需会 vim 基本操作) nano Dockerfile # 用 nano 编辑(更简单,新手推荐) code Dockerfile # 用 VS Code 编辑(需安装 VS Code)
其他操作(自定义Dockerfile文件生成位置):
1. 确定当前所在文件夹
执行以下命令,终端会输出绝对路径(比如 /home/yourname/project),这是你当前的位置:
bash 运行:
pwd # 打印当前工作目录(Print Working Directory)
2. 方式 1:指定目录创建 Dockerfile(推荐,先切换目录再创建)
步骤:先 cd 到目标文件夹,再创建 Dockerfile,确保文件落在预期位置。
bash 运行:
# 示例:想把Dockerfile创建在 /opt/my-docker-project 目录下 # 1. 切换到目标目录(如果目录不存在,先创建:mkdir -p /opt/my-docker-project) cd /opt/my-docker-project # 2. 确认已切换成功(可选) pwd # 输出应是 /opt/my-docker-project # 3. 创建空的Dockerfile touch Dockerfile # 4. 验证文件是否存在(可选) ls # 会看到 Dockerfile 列在输出中
3. 方式 2:直接指定路径创建(无需切换目录)
如果不想 cd 到目标目录,可直接通过「绝对 / 相对路径」创建 Dockerfile,比如:
bash 运行:
# 绝对路径创建:直接指定 Dockerfile 的完整保存路径 touch /opt/my-docker-project/Dockerfile # 相对路径创建:基于当前目录的子目录(比如当前在 /home/yourname,想创建到 ./docker 子目录) mkdir -p ./docker # 先创建子目录(如果不存在) touch ./docker/Dockerfile
4. 验证 Dockerfile 的位置(避免建错路径)
bash 运行:
# 查看文件的绝对路径(最直观) realpath Dockerfile # 若在目标目录,输出如 /opt/my-docker-project/Dockerfile # 或查看指定路径下的文件 ls /opt/my-docker-project/ # 看是否有 Dockerfile
2. Windows 系统
Windows 需注意避免自动添加 .txt 后缀,推荐 3 种方式:
方式 1:记事本手动创建
- 右键桌面 / 项目目录 → 新建 → 文本文档;
- 打开记事本,输入内容后点击「文件 → 另存为」;
- 「文件名」填
Dockerfile(无引号),「保存类型」选「所有文件」,「编码」选UTF-8,点击保存; - 删除自动生成的 .txt 文件(若有)。
方式 2:PowerShell/CMD 命令打开终端,进入目标目录,执行:
powershell
# Windows PowerShell New-Item Dockerfile -ItemType File # 或 CMD 命令 type nul > Dockerfile
方式 3:编辑器(VS Code/Notepad++)
- 打开 VS Code → 新建文件(Ctrl+N);
- 直接命名为
Dockerfile(无后缀); - 保存到目标目录(Ctrl+S)。
Dockerfile内容的核心指令:
| 指令 | 作用 |
|---|---|
| FROM | 指定基础镜像(必须是第一行),如 python:3.9-alpine |
| WORKDIR | 设置容器内的工作目录(避免文件散落) |
| COPY | 把本地文件复制到容器内(格式:COPY 本地路径 容器路径) |
| ADD | 类似 COPY,支持解压压缩包、下载远程文件 |
| RUN | 构建镜像时执行的命令(如安装依赖、编译代码) |
| ENV | 设置环境变量 |
| EXPOSE | 声明容器暴露的端口(仅提示,不实际映射) |
| CMD | 容器启动时执行的命令(只能有一个,多写会覆盖) |
| ENTRYPOINT | 容器启动的入口命令(与 CMD 配合使用,优先级更高) |
| VOLUME | 声明数据卷(用于持久化数据) |
| USER | 指定后续命令的执行用户 |
Dockerfile 编写原则:
- 尽量减少分层:将多个
RUN命令合并为一个(用&&连接),减少镜像层数; - 清理缓存:安装依赖后清理缓存文件(如
apt clean、pip cache purge),减小镜像体积; - 使用
.dockerignore文件:排除不需要复制到容器的文件(如.git、node_modules、__pycache__)。
5.2.3 步骤 3:构建 Docker 镜像
使用 docker build 命令构建镜像,格式:docker build -t 镜像名:标签 上下文路径。
参数说明:
-t:给镜像打标签(方便识别);.:上下文路径(当前目录,Docker 会读取该目录下的所有文件用于构建);--no-cache:不使用缓存(强制重新构建所有层,用于调试)。
5.2.4 步骤 4:启动容器运行代码
使用 docker run 命令启动容器,核心参数:
-p:端口映射(宿主机端口:容器端口),如-p 8080:5000;-d:后台运行容器;--name:给容器命名;-v:挂载数据卷(本地目录:容器目录);--env:设置容器环境变量;--restart:容器重启策略(如always,容器崩溃后自动重启)。
5.2.5 步骤 5:验证与调试
- 查看容器运行状态:
docker ps; - 访问应用:
curl http://localhost:8080; - 查看容器日志:
docker logs 容器名; - 进入容器内部调试:
docker exec -it 容器名 /bin/sh; - 查看容器详细信息:
docker inspect 容器名。
5.3 多语言实战示例
5.3.1 示例 1:Python Flask 应用容器化
项目结构(在Linux主机中创建)
my-python-app/ ├── app.py # 业务代码 ├── requirements.txt # 依赖清单 ├── Dockerfile # 镜像构建脚本 └── .dockerignore # 忽略文件
代码文件
app.py

python文件内容:
from flask import Flask
import os
app = Flask(__name__)
# 读取环境变量
APP_NAME = os.getenv("APP_NAME", "Docker Python App")
@app.route('/')
def hello():
return f"Hello from {APP_NAME}! My code is running in Docker container."
if __name__ == '__main__':
# 绑定 0.0.0.0,容器外可访问
app.run(host='0.0.0.0', port=5000)
requirements.txt
flask==2.3.3

.dockerignore
# Git 相关 .git .gitignore # Python 编译/虚拟环境 __pycache__/ *.pyc *.pyo *.pyd venv/ .venv/ # 敏感/本地配置 .env .env.* # 编辑器/系统文件 .idea/ .vscode/ .DS_Store # 日志/临时文件 *.log tmp/
使用
touch .dockerignore
创建,因为.开头的文件是隐藏文件,所以创建后是看不到的,可以用:
ls -a

查看文件夹中的所有文件,看到输出有.dockerignore即可。如果需要向ignore中写入内容,可以通过文本编辑器vim或nano实现:(打开nano,将要写入的内容粘贴进去,粘贴完成后,按 Ctrl+O 保存,这时底部会出现保存的文件名,再按enter键完成保存。接下来按 Ctrl+X 退出 nano。)
nano .dockerignore

Dockerfile
FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && pip cache purge COPY . . ENV APP_NAME="My Python Docker App" EXPOSE 5000 CMD ["python", "app.py"]
使用:touch Dockerfile构建
【注:虽然后面没有手动执行 docker pull 命令,但镜像拉取的动作在 docker build 阶段被自动触发了—— 核心是 Dockerfile 里的 FROM 指令,Docker 会在构建时自动完成 “检查本地镜像→缺失则拉取” 的流程。「等价于 docker pull python:3.9-slim」的操作】
构建与运行
bash运行:
# 构建镜像 docker build -t my-python-app:v1 . # 启动容器(端口映射 8080:5000,后台运行) docker run -p 8080:5000 -d --name my-python-container my-python-app:v1 # 验证 curl http://localhost:8080 # 输出:Hello from My Python Docker App! My code is running in Docker container. # 查看日志 docker logs my-python-container
如果构建过程中卡住了,可以通过Ctrl+C结束进程,通过:
docker builder prune -f
清理 Docker 构建缓存。如果之前构建过 my-python-app:v1 镜像,想删除后重新构建,执行:
# 删除指定镜像 docker rmi my-python-app:v1 # 若镜像被容器引用,先删除容器再删镜像: docker rm -f flask-app && docker rmi my-python-app:v1
之后再运行构建代码,构建完成:

运行容器:
docker run -d -p 5000:5000 --name flask-app my-python-app:v1
在浏览器顶部访问:http://localhost:5000,即可查看到运行结果

如果使用后想停止运行容器,可以使用docker ps查看容器列表
# 仅显示运行中的容器 docker ps # 或查看所有容器(包括已停止的) docker ps -a
输出示例(关键看 NAMES 列是 flask-app,PORTS 列是 0.0.0.0:5000->5000/tcp):

临时停止容器(保留容器,可重启)
如果只是想停止运行,但后续还想重启(比如修改代码后重新启动),bash 运行:
# 方式1:用容器名称停止(推荐,直观) docker stop flask-app # 方式2:用容器ID停止(替换为你的容器ID,比如 abc123456789) docker stop abc123456789

停止后,再次执行 docker ps 会看不到该容器,docker ps -a 能看到状态变为 Exited (0)。
重启已停止的容器(临时停止后想恢复运行)
bash 运行:
# 用名称重启 docker start flask-app # 用ID重启 docker start abc123456789
4. 彻底停止并删除容器(无需保留)
如果确认后续不需要该容器,可直接停止并删除,bash 运行:
# 方式1:先停止再删除(稳妥) docker stop flask-app && docker rm flask-app # 方式2:强制删除运行中的容器(无需先停止,快捷) docker rm -f flask-app
清理关联资源(可选)
删除镜像(如果后续不需要该镜像)连构建的 my-python-app:v1 镜像也删除。bash 运行:
# 先确保容器已删除,再删镜像 docker rmi my-python-app:v1 # 若镜像被其他容器引用,强制删除 docker rmi -f my-python-app:v1
5.4 进阶优化:让容器运行更实用
5.4.1 数据卷(Volume):持久化数据
容器内的数据默认存储在可写层中,容器删除后数据会丢失。数据卷用于将容器内的目录挂载到宿主机或命名卷,实现数据持久化。
绑定挂载(本地目录 → 容器目录)
bash运行:
# 将本地 ./data 目录挂载到容器 /app/data 目录 docker run -p 8080:5000 -v $(pwd)/data:/app/data my-python-app:v1
命名卷(Docker 管理的卷)
bash运行:
# 创建命名卷 docker volume create my-data # 挂载命名卷到容器 docker run -p 8080:5000 -v my-data:/app/data my-python-app:v1 # 查看卷信息 docker volume inspect my-data
5.4.2 Docker Compose:多容器管理
当应用依赖多个服务(如 MySQL、Redis)时,使用 Docker Compose 可一键启动所有服务。
示例 docker-compose.yml
yaml
version: '3.8'
services:
# 应用服务
app:
build: .
ports:
- "8080:5000"
environment:
- APP_NAME=My Python Docker App
- REDIS_HOST=redis
- MYSQL_HOST=mysql
- MYSQL_USER=root
- MYSQL_PASSWORD=123456
- MYSQL_DB=test
volumes:
- ./data:/app/data
depends_on:
- redis
- mysql
restart: always
# Redis 服务
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: always
# MySQL 服务
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=test
volumes:
- mysql-data:/var/lib/mysql
restart: always
# 命名卷
volumes:
redis-data:
mysql-data:
启动 / 停止服务
bash运行:
# 启动所有服务(后台运行) docker-compose up -d # 查看服务状态 docker-compose ps # 查看日志 docker-compose logs app # 停止服务 docker-compose down # 停止服务并删除数据卷 docker-compose down -v
5.4.3 热重载(开发环境)
开发环境中,修改代码后希望容器自动重启,无需重新构建镜像。
Python 示例(使用 flask-reload)
修改 Dockerfile 的启动命令:
CMD ["python", "-m", "flask", "run", "--host=0.0.0.0", "--port=5000", "--reload"]
启动容器时挂载代码目录:
bash运行:
docker run -p 8080:5000 -v $(pwd):/app my-python-app:v1
修改本地 app.py 后,Flask 会自动重启,无需重启容器。
5.5 调试与排错:容器运行常见问题解决
5.5.1 容器启动后访问不通
- 检查端口映射:确认
docker run命令使用了-p参数,且宿主机端口未被占用; - 检查代码绑定地址:确保服务绑定
0.0.0.0,而非127.0.0.1(容器内 127.0.0.1 仅容器自身可访问); - 检查防火墙:宿主机防火墙是否放行映射的端口;
- 查看容器日志:
docker logs 容器名,排查代码报错。
5.5.2 依赖安装失败
- 检查网络:容器是否能访问外网(可进入容器
ping baidu.com测试); - 使用国内源:在 Dockerfile 中配置国内源(如 pip、npm、maven 国内源);
- 检查依赖版本:依赖版本与基础镜像不兼容(如 Python 3.9 安装不支持的包版本)。
5.5.3 镜像体积过大
- 使用多阶段构建:仅保留运行所需文件;
- 清理缓存:安装依赖后清理缓存(如
apt clean、pip cache purge); - 合并
RUN命令:减少镜像层数; - 使用轻量化基础镜像(如 alpine 版本)。
5.5.4 容器崩溃自动重启
- 设置重启策略:
docker run --restart=always; - 查看崩溃原因:
docker logs 容器名,排查代码或依赖问题; - 限制容器资源:
docker run --memory=512m --cpus=1,避免资源耗尽。
六、总结
Docker 作为容器化技术的标杆,已成为现代软件开发和运维的必备工具。其核心价值在于解决了环境一致性、资源隔离、快速部署等核心痛点,为微服务架构、CI/CD 流水线、云原生应用提供了坚实的基础。本文从 Docker 的定义、使用价值、核心概念、镜像选择、代码容器化实战等维度,全面讲解了 Docker 的核心知识。
总结核心要点:
- Docker 是轻量级的容器化平台,核心是 “一次构建,到处运行”;
- Docker 容器是宿主机上的受限制进程,基于镜像运行,镜像为只读模板;
- 选择镜像时应优先官方、轻量化、指定版本的镜像;
- 代码容器化的核心是编写 Dockerfile,通过
docker build构建镜像,docker run启动容器; - 结合 Docker Compose 可轻松管理多服务依赖,提升部署效率。
未来,Docker 将继续与 Kubernetes(k8s) 深度融合,成为云原生技术的核心组件。掌握 Docker 不仅能提升开发 / 部署效率,更是进入云原生领域的必备技能。
附录:Docker 常用命令速查表
镜像管理
| 命令 | 作用 |
|---|---|
| docker search <name> | 搜索镜像 |
| docker pull <name>:<tag> | 拉取镜像 |
| docker images | 查看本地镜像 |
| docker rmi <name>:<tag> | 删除镜像 |
| docker tag <old> <new> | 重命名镜像 |
| docker history <name> | 查看镜像构建历史 |
| docker image prune -a | 删除未使用的镜像 |
容器管理
| 命令 | 作用 |
|---|---|
| docker run <options> <image> | 启动容器 |
| docker ps | 查看运行中的容器 |
| docker ps -a | 查看所有容器 |
| docker stop <name/id> | 停止容器 |
| docker start <name/id> | 启动已停止的容器 |
| docker restart <name/id> | 重启容器 |
| docker rm <name/id> | 删除容器 |
| docker exec -it <name/id> sh | 进入容器内部 |
| docker logs <name/id> | 查看容器日志 |
| docker inspect <name/id> | 查看容器 / 镜像详细信息 |
| docker container prune | 删除已停止的容器 |
Docker Compose
| 命令 | 作用 |
|---|---|
| docker-compose up | 启动服务 |
| docker-compose up -d | 后台启动服务 |
| docker-compose down | 停止并删除服务 |
| docker-compose ps | 查看服务状态 |
| docker-compose logs <service> | 查看服务日志 |
| docker-compose build | 构建服务镜像 |
| docker-compose restart <service> | 重启服务 |
最后
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
