Docker 基础
Docker 用来把应用及其运行时打 成 镜像,在本机、CI、生产用同一套文件系统与进程环境跑起来。它和具体编程语言无关:Python、Node、Go、静态站点都可以容器化。
很多仓库的 Dockerfile / Compose 不是你说了算的——先跟现有文件与 CI 构建命令;只有新项目,或团队明确要改造时,再套推荐写法。
容器解决什么
| 痛点 | 容器怎么帮 |
|---|---|
| 「我机器能跑、你机器不行」 | 同一镜像、同一层依赖 |
| 系统库 / 原生依赖难装 | 构建阶段装好,运行镜像可精简 |
| 运行时版本漂移 | FROM 钉死基础镜像标签 |
| 本地工具链与生产不一致 | 生产以镜像为准,本机可用 Compose 贴近 |
容器边界是 镜像文件系统 + 进程;语言自带的「虚拟环境 / node_modules」等仍可能出现在镜像内部,只是协作单元变成了镜像,而不是每台机器手装一遍。
核心概念(极简)
| 概念 | 一句话 |
|---|---|
| 镜像(image) | 只读模板:系统层 + 依赖 + 应用 |
| 容器(container) | 镜像跑起来的进程实例 |
| 层(layer) | Dockerfile 每步大致对应一层;依赖与源码分开拷,利于缓存 |
| Dockerfile | 描述如何构建镜像的脚本 |
| 仓库(registry) | 存放/分发镜像(Docker Hub、GHCR、私有仓等) |
| Compose | 用 YAML 定义并启动多个容器(应用 + 数据库等) |
docker build -t my-app:dev .
docker run --rm -p 8080:8080 my-app:dev
docker compose up --build
-p 主机端口:容器端口 把容器端口映射到本机。容器里的 localhost 只指向该容器自己,访问同 Compose 网络里的其他服务要用服务名(如 db:5432),不要写 localhost。
先认现场
| 标志 | 含义 | 你通常该怎么做 |
|---|---|---|
Dockerfile / Dockerfile.* | 镜像构建入口 | 读注释与 CI 里的 docker build 参数 |
docker-compose.yml / compose.yaml | 本地多服务编排 | docker compose up(以 README 为准) |
.dockerignore | 构建上下文排除项 | 保留对本地依赖目录、.git、缓存的忽 略 |
基础镜像(node: / python: / golang: / nginx: …) | 运行时选型 | 与仓库技术栈对齐,勿随意换族 |
| 仅有 K8s/Helm、无本地 Docker 文档 | 部署在集群侧 | 问清本地是否还需 Compose |
通用 Dockerfile 习惯
与语言无关的常见结构:
- 选准并钉住基础镜像(含主版本,避免无脑
latest) - 先复制依赖清单、再安装依赖、最后复制源码 → 源码变动不致整层依赖重装(缓存友好)
- 多阶段构建:构建工具留在 builder,运行镜像只留运行所需
.dockerignore排除本地依赖目录、VCS、测试缓存,减小上下文、避免脏文件进镜像- 配置走环境变量;密钥不要写进镜像层;默认非 root 运行(以团队规范为准)
通用 .dockerignore 思路(按栈增删):
.git/
**/node_modules/
**/.venv/
**/__pycache__/
**/dist/
**/build/
**/.pytest_cache/
**/.mypy_cache/
最小示例(任意「有依赖清单的应用」)
FROM <runtime>:<version>-slim
WORKDIR /app
# 1) 只拷依赖声明
COPY <lock-or-manifest> ./
RUN <install-prod-deps>
# 2) 再拷源码
COPY . .
CMD ["<start-command>"]
具体 <runtime> / <install-prod-deps> 随语言变化;下面给几种常见写法。
各语言示例(对照)
Node(npm)
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
Python(pip)
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
Python(uv,多阶段)
与可复现锁文件配合时常用:
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:0.11.32 /uv /uvx /bin/
ENV UV_PYTHON_DOWNLOADS=0
WORKDIR /app
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-dev --no-install-project
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev --no-editable
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app /app
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "main.py"]
说明:钉 uv 版本;--locked 按提交的锁文件安装;--no-dev 去掉开发依赖;本地 .venv 必须进 .dockerignore。
Python 侧的解释器与包管理约定,见知识库「编程语言 → Python」中的多版本 / 项目与包管理;容器实践以本篇为准。
Go(多阶段)
FROM golang:1.22-bookworm AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
FROM gcr.io/distroless/static-debian12
COPY --from=builder /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
构建阶段用完整 Go 工具链;运行镜像只留静态二进制。需要 CGO / 动态链接时,运行阶段改用 debian/alpine 等带 libc 的基础镜像。
静态站点 / 反向代理
FROM nginx:1.27-alpine
COPY ./dist /usr/share/nginx/html
前端构建可在 CI 或多阶段的前一阶段完成,最终镜像只保留产物。
Compose:本地多服务
services:
api:
build: .
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
习惯:
- 密钥用环境变量 /
env_file,不要写进镜像层 - 开发可挂载源码卷;生产镜像一般打进产物,不靠 bind mount
- 默认
depends_on只保证「容器已启动」,不保证数据库已可接受连接;需要等就绪时用健康检查 +depends_on.condition(以团队模板为准)
本机工具链 vs 镜像
语言版本管理器 / 本机 SDK → 开发体验
锁文件 / 依赖清单 → 装哪一棵依赖树
Dockerfile / Compose → 如何构建与本地联调
CI → 构建、扫描、推送镜像
生产运行以 镜像标签 为准;本机 SDK 版本应与基础镜像 主版本对齐,避免「本地过、镜像挂」。
常用排错
docker compose ps # 看服务是否在跑
docker compose logs -f api # 跟日志
docker compose exec api sh # 进容器(镜像无 sh 时换 bash)
docker images # 本机镜像
docker system df # 占了多少磁盘
构建失败先看 Dockerfile 哪一步;跑起来连不上库,先确认 Compose 服务名、端口,以及应用是否在等库就绪。
你不能做主时
- 不改动正在用的基础镜像族,除非有迁移任务
- 本地调试优先:
docker compose/ README 里的 build 参数 - 只想加快安装时,可在 既有 Dockerfile 结构内 换更快安装器,并确认锁文件与缓存仍正确
- 业务 hotfix 里夹带「重写 Dockerfile + 换包管理器」风险极高
要点
- Docker 是通用运行时封装;先跟仓库现有 Dockerfile / Compose / CI
- 钉基础镜像、依赖与源码分层、
.dockerignore、配置外置、锁文件与 CI 一致 - Compose 管本地依赖服务;密钥不进镜像;容器间用服务名,勿误用
localhost - 镜像标签、锁文件、CI 三者一致,比追求「最新写法」更重要