Docker 容器

1. 定义

Docker 是一个容器化平台:把应用和它运行所需的一切(代码、运行时、依赖库、系统工具、配置)打包成一个标准化的镜像 (image),再以容器 (container) 的形式在任何装了 Docker 的机器上一致地运行。

一句话概括:“在我机器上能跑”这个问题,Docker 用打包整个运行环境的方式彻底解决。

类比:镜像像一个”应用光盘/安装包”,容器就是用这张光盘启动起来的一个”正在运行的实例”。同一个镜像可以跑出无数个容器。

2. Docker 解决了什么问题

传统部署的痛点:

问题传统方式Docker
环境不一致开发/测试/生产环境依赖版本各异,“在我机器上能跑”镜像固化整个环境,到哪都一样
依赖冲突一台机器跑多个应用,Python/Node 版本互相打架每个容器环境隔离,互不干扰
部署繁琐手动装依赖、配环境,几十步文档docker run 一条命令起服务
资源占用虚拟机每个都带一整套操作系统,重容器共享宿主机内核,轻量、秒级启动

2.5 什么时候该用 Docker(典型场景)

不确定”我到底啥时候需要 Docker”时,对照下面这些场景:

场景具体例子为什么用 Docker
快速跑一个服务,不想装到本机本地起 MySQL、Redis、PostgreSQL、nginx 来开发/测试一条 docker run 就有,用完删掉,不污染系统、不留一堆残留
用一个工具但不想装它的一堆依赖跑证书生成、代码生成器、格式转换等 CLI 工具作者把工具打包成镜像,挂载目录就能用,省去装环境
保证团队/上线环境一致开发、测试、生产用同一个镜像消灭”我机器上能跑”,环境完全一致
一次跑多个配套服务web + 数据库 + 缓存 一起起docker compose up 一键拉起整套,见第 7 节
隔离/做实验,随时清空试装可疑软件、练 Linux 命令、搭网络拓扑容器隔离,玩坏了 docker rm 重来一遍即可
同一软件跑多个版本同时测试 Node 18 和 Node 20、多个 Python 版本每个版本一个容器,互不干扰
部署到服务器 / 云 / K8s把应用打成镜像推上去跑标准化交付,方便扩缩容和编排

你在学网络时遇到的那种情况(生成文件)

学网络时”生成文件要用容器”通常是这几类:

  • 某个工具被打包成镜像:比如生成 TLS 证书、生成配置文件、抓包分析等工具,直接以镜像分发。你运行容器并挂载本地目录,容器把生成的文件写进这个目录,就留在你电脑上了。
  • 搭网络实验环境containerlab、GNS3 等用容器模拟多台主机/路由器,在一台电脑上组出虚拟网络拓扑来练习。
  • 临时起个网络服务测试:本地起 DNS(dnsmasq/bind)、HTTP 服务等来做实验。

关键技巧是 -v 挂载目录,让容器生成的文件落到宿主机:

# --rm 用完即删容器;-v 把当前目录挂到容器的 /output
# 容器往 /output 写的文件 = 你本地当前目录下的文件
docker run --rm -v $(pwd):/output some-tool-image
 
# 例:用某镜像生成配置到本地 ./config 目录
docker run --rm -v $(pwd)/config:/output cert-generator

没有 -v 的话,容器里生成的文件在容器删除时就一起没了——这也是新手常踩的坑。

3. 容器 vs 虚拟机(核心区别)

虚拟机 (VM)                          容器 (Container)
┌─────────────────┐                 ┌─────────────────┐
│  App A │  App B  │                 │  App A │  App B  │
├────────┼────────┤                 ├────────┼────────┤
│ Guest  │ Guest  │  ← 各自完整OS    │  依赖   │  依赖   │
│  OS    │  OS    │                 ├────────┴────────┤
├────────┴────────┤                 │  Docker Engine  │
│   Hypervisor    │                 ├─────────────────┤
├─────────────────┤                 │   宿主机内核     │ ← 共享
│    宿主机 OS     │                 ├─────────────────┤
└─────────────────┘                 │    宿主机 OS     │
                                     └─────────────────┘
  • 虚拟机:每个 VM 带一整套 Guest OS,通过 Hypervisor 虚拟硬件。隔离彻底但重(GB 级、启动几十秒)
  • 容器:共享宿主机内核,只打包应用 + 依赖。轻量(MB 级、启动毫秒~秒级),密度高
  • 代价:容器隔离性弱于 VM,且默认只能跑与宿主机同内核的系统(Linux 容器需 Linux 内核;macOS/Windows 上 Docker 其实跑在一个隐藏的 Linux 虚拟机里)

3.5 和 venv / conda 等”隔离方案”的关系

Docker 常被拿来和 Python 的 venvconda 比较,因为思路都是”环境隔离、可随时丢弃重建”。但它们隔离的层级差一大截

venv 隔离的:   只有 Python 包 (site-packages)
                └ 共用:操作系统、系统库、Python 解释器本身、其他语言/工具

conda 隔离的:  Python 包 + 部分非 Python 的 C 库
                └ 共用:操作系统内核、大部分系统环境

Docker 隔离的: 整个用户态环境——OS 发行版、系统库、任意语言运行时、
                环境变量、文件系统、网络、进程
                └ 共用:只有宿主机内核

用”厨房”的比喻(延续 venv 笔记):

  • venv = 同一间厨房里给你一个专属调料架,锅灶水电(OS、解释器)都公用,只有调料(Python 包)各管各的
  • Docker = 直接给你一整间独立厨房,灶台、水电、锅具全套隔开
维度venvcondaDocker
隔离范围只有 Python 包Python 包 + 部分 C 库整个 OS 用户态
能隔离非 Python 依赖吗不能部分能
语言限制仅 Python主要 Python(也支持 R 等)语言无关
轻重极轻(就是个目录)较重(镜像 MB~GB)
隔离强度弱(本质是改 PATH 遮蔽)强(独立文件系统/进程/网络)

一句话:venv 是”包级隔离”,conda 是”包 + 部分系统库隔离”,Docker 是”系统级隔离”。

  • 只是 Python 包/版本打架 → 用 venv / uv 就够
  • 需要隔离系统库、装非 Python 的东西、或保证换台机器一模一样 → 才上 Docker

⚠️ 别混淆:Homebrew / apt / pnpm / uv 这些是”包管理器”,目标是”方便安装软件/依赖”,装的东西通常是全局共享的,方向和”隔离”相反。 隔离是 venv / conda / Docker 干的事。实际中常配合用:先用 Homebrew 装好 Docker 或 uv,再用它们去做隔离。

4. 核心概念

概念是什么
Image(镜像)只读模板,包含应用 + 运行环境。分层存储,可复用
Container(容器)镜像的运行实例,可启停删。容器内改动默认不持久(删了就没)
Dockerfile构建镜像的”配方”脚本,逐行指令描述怎么装环境
Registry(仓库)存放镜像的地方,Docker Hub 是官方公共仓库
Layer(层)镜像由多层叠加而成,每条 Dockerfile 指令生成一层,层可缓存复用
Volume(数据卷)把数据存到容器外,实现持久化(数据库数据必用)
Network(网络)容器间通信的虚拟网络
Docker Compose用一个 YAML 文件编排多个容器(如 app + db + redis)

5. 常用命令

镜像

docker pull nginx             # 从仓库拉取镜像
docker images                 # 列出本地镜像(alias: docker image ls)
docker build -t myapp:1.0 .   # 用当前目录 Dockerfile 构建镜像并打标签
docker rmi nginx              # 删除镜像
docker tag myapp:1.0 user/myapp:1.0   # 打标签(推送前用)
docker push user/myapp:1.0    # 推送到仓库

容器

docker run nginx                        # 用镜像启动容器(前台)
docker run -d nginx                     # 后台运行(detached)
docker run -d -p 8080:80 nginx          # 端口映射:宿主机8080 -> 容器80
docker run -it ubuntu bash              # 交互式进入容器 shell
docker run --name web -d nginx          # 指定容器名
docker ps                               # 列出运行中的容器
docker ps -a                            # 列出所有容器(含已停止)
docker stop web                         # 停止容器
docker start web                        # 启动已停止的容器
docker rm web                           # 删除容器
docker logs web                         # 看容器日志
docker logs -f web                      # 实时跟踪日志
docker exec -it web bash                # 进入正在运行的容器执行命令

数据卷 / 挂载

docker run -v mydata:/var/lib/mysql mysql        # 具名卷持久化数据
docker run -v $(pwd):/app node                   # 把当前目录挂进容器(开发常用)
docker volume ls                                 # 列出数据卷

清理(省磁盘)

docker system prune              # 清理停止的容器、无用网络、悬空镜像
docker system prune -a           # 更狠:连没被使用的镜像也删
docker container prune           # 只清停止的容器
docker image prune               # 只清悬空镜像

6. Dockerfile 示例(构建镜像的配方)

# 基础镜像
FROM node:20-alpine
 
# 设置工作目录
WORKDIR /app
 
# 先拷依赖清单并安装(利用层缓存:代码改了但依赖没改时不重装)
COPY package*.json ./
RUN npm install
 
# 再拷源码
COPY . .
 
# 声明容器监听端口(文档作用,不自动映射)
EXPOSE 3000
 
# 容器启动时执行的命令
CMD ["node", "index.js"]

构建并运行:

docker build -t my-node-app .
docker run -d -p 3000:3000 my-node-app

关键优化点:把 COPY package*.json + RUN npm install 放在 COPY . . 之前,这样只要依赖没变,改代码重新构建时能命中缓存、跳过装包,大幅加速。

7. Docker Compose 示例(编排多容器)

# docker-compose.yml
services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - dbdata:/var/lib/postgresql/data
 
volumes:
  dbdata:
docker compose up -d          # 一键启动所有服务
docker compose down           # 停止并删除所有服务
docker compose logs -f        # 看所有服务日志

8. 常见坑

  • 容器数据丢失:容器删了里面的数据就没了。数据库等有状态服务必须-v 挂数据卷持久化
  • 端口没映射就访问不了:容器内跑在 80 端口,宿主机访问要 -p 8080:80 显式映射,EXPOSE 只是声明不生效
  • 镜像越build越大:每层都占空间,装完东西没清缓存。用多阶段构建(multi-stage build)、alpine 基础镜像、合并 RUN 指令来瘦身
  • docker run 每次都新建容器:反复 run 会堆一堆容器,想复用已有的用 start;调试完记得 docker rm 或加 --rm 自动删
  • Mac/Windows 上性能:容器实际跑在虚拟机里,挂载本地目录(bind mount)做大量文件 IO 会慢
  • latest 标签的陷阱:不指定版本默认拉 latest,某天镜像更新会导致环境突变,生产环境应锁定具体版本号
  • 修改容器内文件不持久:容器内改的东西重建就没了,配置应通过挂载或环境变量注入,而不是进容器手改

9. 延伸阅读 / 关联概念

  • Docker Compose — 多容器编排,本地开发多服务(app + db + cache)标配
  • Kubernetes (k8s) — 生产级容器编排,管理成百上千容器的调度、扩缩容、自愈;Docker 管单机,k8s 管集群
  • 多阶段构建 (multi-stage build) — 在一个 Dockerfile 里分构建阶段和运行阶段,只把产物拷进最终镜像,大幅减小体积
  • OCI (Open Container Initiative) — 容器镜像和运行时的开放标准,Docker 镜像遵循它
  • containerd / runc — Docker 底层实际干活的容器运行时组件
  • 官方文档:https://docs.docker.com/

此文件夹下有0条笔记。