一、前言:为什么我们需要 Docker
如果你写过 Web 应用、跑过数据库、部署过服务,大概率遇到过这些头疼事:
"在我电脑上明明能跑啊,怎么到你那就不行了?"
"这个项目要装 Python 3.11,另一个要 3.9,冲突了。"
"新同事入职花了三天配环境,最后还是少装了某个 so 库。"
"服务器一升级,原来跑得好好的服务全挂了。"
这些问题的根源,是 “运行环境不一致”。代码本身可能没变,但围绕它的操作系统、依赖库、运行时版本、环境变量、网络配置一旦变化,行为就可能天差地别。
Docker 的核心思想,就是把代码和它运行所需的一切,打包进一个标准化的"集装箱"——镜像(Image),然后在任何支持 Docker 的机器上,原样启动出一模一样的运行环境。
一旦你用过 Docker 部署过哪怕一个 Nginx,你会立刻意识到这套思路的价值:
- 环境一致:开发、测试、生产用同一个镜像,不会"我电脑能跑你电脑跑不了"。
- 秒级启动:容器是进程级别的隔离,启动速度远快于虚拟机。
- 资源占用低:共用宿主机内核,不需要为每个应用分配一套完整的操作系统。
- 易于迁移与扩展:Kubernetes、Swarm、各家云厂商都能直接调度 Docker 镜像。
这篇文章会带你从零开始,系统学完 Docker 的核心概念与日常实战。
二、核心概念:先把术语搞清楚
Docker 的世界里,最重要的概念只有五个。把它们理解清楚,后面的命令就是水到渠成。
01 镜像(Image)
镜像是一个只读模板,可以理解为"类的定义"或者"系统安装盘的镜像文件"。
它里面包含了:
- 操作系统的基础层(通常是精简版 Linux,如
alpine、ubuntu、debian) - 应用程序代码与可执行文件
- 运行时依赖(Node.js、Python、Java、Nginx 等)
- 环境变量、配置文件、启动脚本
镜像采用**分层(layer)**结构,每一行 Dockerfile 指令都生成一个只读层,所有层叠加在一起形成最终镜像。这种设计让镜像可以被多个不同镜像复用,节省存储与下载时间。
镜像本身是静态的,不能直接运行。
02 容器(Container)
容器是镜像的运行实例——相当于"根据类 new 出来的对象"。
当你用 docker run 启动一个镜像,Docker 会在镜像的最上层添加一个可写层(writable layer),容器内所有运行时的改动(新建文件、修改配置、写入日志)都发生在这层。删除容器后,可写层一并销毁,数据不会保留。
容器之间相互独立,每个容器都有自己的文件系统、进程空间、网络接口,看起来就像一台独立的"小电脑"。
03 仓库(Registry / Repository)
仓库是存放和分发镜像的地方,最知名的公共仓库是 Docker Hub。
镜像的完整名称由三部分组成:
[仓库地址/]镜像名[:标签]
例如:
nginx:默认从 Docker Hub 下载官方nginx镜像,latest标签nginx:1.27:指定 1.27 版本registry.cn-hangzhou.aliyuncs.com/myteam/myapp:v1:从阿里云私有仓库拉取myapp:v1
你可以把它类比成 Git:镜像 = 代码提交,仓库 = 代码托管平台,标签 = 某个版本号。
04 Dockerfile
Dockerfile 是一个文本文件,用几行声明式指令描述"如何镜像一个镜像"。
例如:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
配合 docker build 命令,就能把这份描述变成一个可分发的镜像。
Dockerfile 是 Docker 生态的核心自动化工具,所有可复现的镜像都应该从 Dockerfile 构建,而不是手动"容器里装好再导出"。
05 Volume(数据卷)
容器默认是无状态的——删掉容器,里面的数据也没了。
Volume 是 Docker 提供的持久化存储机制,把容器内的某个目录映射到宿主机上,使数据独立于容器生命周期。后面我们会详细讲它的用法。
一张图理解 Docker 全貌
三、安装 Docker
01 Windows
推荐安装 Docker Desktop,自带 Docker Engine 与可视化界面。
- 访问 docker.com/products/docker-desktop 下载安装包
- 双击安装,按提示一路 Next(会提示启用 WSL 2,按提示操作)
- 安装完成后重启电脑
- 打开 PowerShell,执行:
docker --version
docker run hello-world
看到 Hello from Docker! 字样即表示安装成功。
注意:Docker Desktop 对个人与小公司(少于 250 人、年收入低于 1000 万美元)是免费的,企业大规模使用需付费订阅。
02 macOS
同样推荐 Docker Desktop,下载 Apple Silicon 或 Intel 对应版本,安装即用。
也可以用 brew install --cask docker 一行命令搞定。
03 Linux
以 Ubuntu 为简示例:
# 卸载旧版本(如有)
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
# 添加 Docker 官方 GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 添加仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 验证
sudo docker run hello-world
04 配置镜像加速(国内强烈建议)
国内访问 Docker Hub 经常超时,建议配置镜像加速器。
Linux 下编辑 /etc/docker/daemon.json:
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
然后重启:
sudo systemctl daemon-reload
sudo systemctl restart docker
Windows / macOS 在 Docker Desktop 的 Settings -> Docker Engine 里直接编辑 JSON 即可。
四、镜像操作:拉取、查看、删除
01 搜索镜像
docker search nginx
02 拉取镜像
docker pull nginx # 默认 latest 标签
docker pull nginx:1.27 # 指定版本
docker pull ubuntu:22.04
03 查看本地镜像
docker images
输出示例:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4f0fcc4e60a4 2 weeks ago 188MB
nginx 1.27 4f0fcc4e60a4 2 weeks ago 188MB
ubuntu 22.04 2dc39ba59dc3 3 weeks ago 77.8MB
04 查看镜像详细信息
docker inspect nginx
会看到完整 JSON,包括镜像各层、配置、环境变量、入口点等。
05 删除镜像
docker rmi nginx:1.27 # 按名字:标签
docker rmi 4f0fcc4e60a4 # 按镜像 ID
docker image prune # 清理悬空镜像(无标签的)
docker image prune -a # 清理所有未被使用的镜像
删除镜像前必须先删除基于它运行的所有容器。
06 给镜像打标签
docker tag nginx:latest mynginx:v1
这并不会复制镜像,只是给同一个镜像 ID 加了个别名,常用于推送到私有仓库前改名。
五、容器操作:日常最常用的部分
01 启动容器
docker run -d -p 8080:80 --name mynginx nginx
参数解释:
-d:后台运行(detached),不阻塞当前终端-p 8080:80:把宿主机的 8080 端口映射到容器的 80 端口--name mynginx:给容器起个名字,不指定会随机生成nginx:使用的镜像
02 常用 run 参数一览
| 参数 | 含义 | 示例 |
|---|---|---|
-d | 后台运行 | docker run -d nginx |
-it | 交互式终端(常用于 bash) | docker run -it ubuntu bash |
-p | 端口映射 宿主机:容器 | -p 8080:80 |
-P | 随机映射所有 EXPOSE 端口 | docker run -P nginx |
--name | 容器名 | --name web |
-e | 环境变量 | -e MYSQL_ROOT_PASSWORD=123456 |
-v | 挂载卷 | -v /host/path:/container/path |
--restart | 自动重启策略 | --restart=always |
--rm | 退出后自动删除容器 | docker run --rm alpine echo hi |
-u | 指定用户 | -u root 或 -u 1000:1000 |
--network | 加入网络 | --network mynet |
--hostname | 设置容器内主机名 | --hostname node1 |
03 查看运行中的容器
docker ps
加 -a 查看所有(包括已停止的):
docker ps -a
输出字段含义:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4f0fcc4e60a4 nginx "/docker…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp mynginx
04 停止 / 启动 / 重启 / 删除容器
docker stop mynginx # 优雅停止(发送 SIGTERM,10s 后 SIGKILL)
docker start mynginx # 启动已存在的容器
docker restart mynginx # 重启
docker rm mynginx # 删除已停止的容器
docker rm -f mynginx # 强制删除运行中的容器
docker container prune # 删除所有已停止的容器
05 进入容器内部
容器已经在运行时,可以用以下命令进入交互终端:
docker exec -it mynginx bash
常见问题:很多精简镜像(如 alpine、nginx)没有 bash,需要换成 sh:
docker exec -it mynginx sh
如果只是想一次性执行命令:
docker exec mynginx ls /etc/nginx
06 查看容器日志
docker logs mynginx # 全部日志
docker logs -f mynginx # 跟踪输出(类似 tail -f)
docker logs --tail 100 mynginx # 最后 100 行
docker logs -t mynginx # 显示时间戳
07 查看容器资源占用
docker stats # 所有运行中容器的实时资源
docker stats mynginx # 指定容器
输出会显示 CPU、内存、网络、磁盘 IO 使用率。
08 在容器与宿主机之间复制文件
# 容器 -> 宿主机
docker cp mynginx:/etc/nginx/nginx.conf ./nginx.conf
# 宿主机 -> 容器
docker cp ./index.html mynginx:/usr/share/nginx/html/
09 查看容器内进程
docker top mynginx
六、数据持久化:Volume 与绑定挂载
容器天然是无状态的,但绝大多数应用都需要保存数据。Docker 提供两种主要方式。
01 Volume(推荐)
由 Docker 管理的持久化存储,位置由 Docker 决定(Linux 默认在 /var/lib/docker/volumes/)。
# 创建具名卷
docker volume create mydata
# 启动容器并挂载
docker run -d -p 8080:80 \
-v mydata:/usr/share/nginx/html \
--name web \
nginx
# 查看卷
docker volume ls
docker volume inspect mydata
# 删除卷(需先删除使用它的容器)
docker volume rm mydata
docker volume prune # 清理所有未被使用的卷
02 绑定挂载(Bind Mount)
直接把宿主机的任意目录挂到容器里。开发时常用——改宿主机代码,容器内立刻生效。
docker run -d -p 8080:80 \
-v /home/user/code:/usr/share/nginx/html:ro \
--name web \
nginx
-v 宿主路径:容器路径:ro,末尾的 ro 表示只读。
03 tmpfs 挂载
只在内存中,不写磁盘,适合存敏感临时数据(如密钥、token):
docker run --tmpfs /tmp alpine
三种方式对比
| 方式 | 位置 | 适用场景 |
|---|---|---|
| Volume(默认) | Docker 目录 | 生产数据库、长期存储 |
| Bind Mount | 任意宿主机目录 | 开发环境、调试 |
| tmpfs | 内存 | 临时敏感数据 |
七、网络:从端口映射到自定义网络
01 Docker 默认网络
docker network ls
默认会有三个:
bridge:默认网络,容器通过它互联host:容器直接使用宿主机网络(无网络隔离)none:完全无网络
02 端口映射
最常用的 -p 参数有三种写法:
docker run -p 8080:80 nginx # 映射到 0.0.0.0:8080
docker run -p 127.0.0.1:8080:80 nginx # 只本机访问
docker run -p 8080:80 nginx # 同上,最常用
03 自定义网络(容器互联推荐)
默认 bridge 网络下,容器之间只能通过 IP 互访,不直观。自定义网络支持容器名直接互访:
# 创建网络
docker network create mynet
# 启动两个容器加入同一网络
docker run -d --name db --network mynet \
-e POSTGRES_PASSWORD=123456 \
postgres:16
docker run -d --name app --network mynet \
-e DATABASE_URL=postgres://postgres:123456@db:5432/postgres \
myapp:latest
app 容器可以直接通过 db 这个名字访问数据库,Docker 内置 DNS 会自动解析。
04 网络常用命令
docker network ls # 列出所有网络
docker network inspect mynet # 查看网络详情
docker network connect mynet web # 把运行中容器加入网络
docker network disconnect mynet web
docker network rm mynet
八、Dockerfile 详解:从零编写镜像构建脚本
01 一个最小可用的 Dockerfile
# 基础镜像
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 先拷贝依赖文件(利用缓存)
COPY package*.json ./
# 安装依赖
RUN npm install --production
# 拷贝源代码
COPY . .
# 暴露端口(仅声明,不会真正发布)
EXPOSE 3000
# 容器启动命令
CMD ["node", "server.js"]
构建:
docker build -t myapp:v1 .
末尾的
.是构建上下文(build context),即Dockerfile所在的目录。
02 核心指令详解
| 指令 | 作用 | 示例 |
|---|---|---|
FROM | 指定基础镜像 | FROM ubuntu:22.04 |
WORKDIR | 设置后续命令的工作目录 | WORKDIR /app |
COPY | 从构建上下文拷贝文件 | COPY ./src /app/src |
ADD | 类似 COPY,支持 URL 和自动解压 | ADD app.tar.gz /app/ |
RUN | 在镜像构建时执行命令 | RUN apt-get update && apt-get install -y curl |
CMD | 容器启动默认命令(可被覆盖) | CMD ["python", "app.py"] |
ENTRYPOINT | 容器启动入口(不易被覆盖) | ENTRYPOINT ["python"] |
ENV | 设置环境变量 | ENV NODE_ENV=production |
ARG | 构建参数(构建时传入) | ARG VERSION=1.0 |
EXPOSE | 声明容器监听的端口 | EXPOSE 8080 |
VOLUME | 声明挂载点 | VOLUME /data |
USER | 切换运行用户 | USER node |
LABEL | 添加元数据 | LABEL version="1.0" |
HEALTHCHECK | 健康检查 | HEALTHCHECK CMD curl -f http://localhost/ || exit 1 |
ONBUILD | 触发器,被当基础镜像时执行 | ONBUILD COPY . /app/src |
03 CMD vs ENTRYPOINT
这是初学者最常困惑的:
CMD ["node", "server.js"]:docker run myapp node debug.js会改成跑node debug.jsENTRYPOINT ["node"]+CMD ["server.js"]:默认跑node server.js,但docker run myapp debug.js会跑node debug.js
如果命令以 shell 形式(不带中括号)写,Docker 会用 /bin/sh -c 包裹,行为略有不同,生产环境强烈建议使用 exec 形式(带中括号)。
04 多阶段构建(强烈推荐)
构建前端 / Go / Rust 项目时,编译环境通常很大,而运行时只需要产物。多阶段构建可以让最终镜像极小:
# 阶段 1:编译
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app
# 阶段 2:运行时
FROM alpine:3.20
COPY --from=builder /src/app /app
CMD ["/app"]
最终镜像可能只有十几 MB,而不用多阶段会带上整个 Go 工具链,接近 1 GB。
05 .dockerignore
与 .gitignore 类似,告诉 Docker 构建时排除哪些文件。必须创建,否则 node_modules、.git、*.log 会全被打进镜像:
.git
node_modules
*.log
.env
dist
.vscode
.idea
06 镜像构建实战:Node.js 项目
假设项目结构:
myapp/
├── Dockerfile
├── .dockerignore
├── package.json
└── server.js
Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
server.js:
const http = require('http');
http.createServer((req, res) => {
res.end('Hello from Docker!');
}).listen(3000);
构建并运行:
docker build -t myapp:v1 .
docker run -d -p 3000:3000 --name myapp myapp:v1
curl http://localhost:3000
07 镜像构建常用选项
docker build -t myapp:v1 . # 打标签
docker build -t myapp:v1 -f Dockerfile.dev . # 指定 Dockerfile
docker build --build-arg VERSION=1.2 . # 传入构建参数
docker build --no-cache . # 不使用缓存
docker build --progress=plain . # 显示完整构建日志
九、Docker Compose:多容器编排
现实项目通常不是一个应用——前端、后端、数据库、缓存、消息队列,每个都要单独的容器。手动一个一个 docker run 会非常痛苦。
Docker Compose 就是用一份 YAML 文件描述整个多容器应用,然后一条命令启动 / 停止 / 重建。
01 安装
- Docker Desktop:自带
- Linux:单独安装
docker-compose-plugin(新版 Compose V2 已集成进 Docker CLI)
02 一个完整示例:WordPress + MySQL
docker-compose.yml:
version: '3.8'
services:
db:
image: mysql:8.0
restart: always
volumes:
- dbdata:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: examplepass
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
networks:
- wpnet
wordpress:
image: wordpress:latest
restart: always
depends_on:
- db
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
networks:
- wpnet
volumes:
dbdata:
networks:
wpnet:
启动:
docker compose up -d
查看状态:
docker compose ps
查看日志:
docker compose logs -f
停止:
docker compose down # 停止并删除容器
docker compose down -v # 同时删除卷
03 常用 docker compose 命令
docker compose up -d # 后台启动所有服务
docker compose down # 停止并删除
docker compose ps # 查看服务状态
docker compose logs -f # 跟踪日志
docker compose exec web bash # 进入某个服务容器
docker compose restart web # 重启某个服务
docker compose pull # 拉取最新镜像
docker compose build # 重新构建
docker compose config # 验证并打印最终配置
04 与 Dockerfile 配合
Compose 也能直接基于 Dockerfile 构建:
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- redis
docker compose up --build 会先构建再启动。
05 实用模式:开发 + 生产两套配置
可以用 -f 指定多个文件叠加:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
开发环境 compose 覆盖默认配置,例如挂载源代码实现热更新。
十、镜像发布:从本地到仓库
01 推送到 Docker Hub
# 登录
docker login
# 打标签(必须包含用户名)
docker tag myapp:v1 yourusername/myapp:v1
# 推送
docker push yourusername/myapp:v1
02 推送到阿里云 / 腾讯云私有仓库
以阿里云为例:
# 登录(用户名是阿里云账号全名)
docker login registry.cn-hangzhou.aliyuncs.com
# 打标签
docker tag myapp:v1 registry.cn-hangzhou.aliyuncs.com/yourteam/myapp:v1
# 推送
docker push registry.cn-hangzhou.aliyuncs.com/yourteam/myapp:v1
03 自动构建(CI/CD 推荐)
更专业的做法是用 GitHub Actions / GitLab CI 在代码 push 时自动构建并推送镜像:
# .github/workflows/docker.yml 简化示例
name: Docker
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 登录 Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 构建并推送
uses: docker/build-push-action@v5
with:
push: true
tags: yourusername/myapp:latest
十一、清理与维护
Docker 用久了,本机会堆积大量无用对象:
docker system df # 查看占用
docker system prune # 清理所有停止容器、无用网络、悬空镜像
docker system prune -a # 包括所有未被使用的镜像(慎用)
docker volume prune # 清理多余卷
docker container prune # 清理停止的容器
docker image prune -a # 清理镜像
十二、常见坑与排错
01 容器一启动就退出
原因:前台进程退出(CMD 命令跑完了)。
排查:
docker logs container_name
docker ps -a # 看 STATUS 列,常见 Exited (1) xxx ago
解决:确保 CMD / ENTRYPOINT 是前台运行的进程(Nginx、Node、Java 之类),不要用 shell 跑后台再退出。
2 修改了容器内文件,重启后没了
原因:容器可写层是临时的。
解决:用 -v 挂载卷,或在 Dockerfile 中固化配置。
3 时区不对
解决:
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
或在运行时挂载:
docker run -v /etc/localtime:/etc/localtime:ro ...
4 端口被占用
# Windows
netstat -ano | findstr :8080
# Linux / macOS
lsof -i :8080
或者换个端口:docker run -p 9090:80 ...
5 容器内网络访问不到外网
docker network inspect bridge # 看配置
docker run --network host ... # 临时用 host 网络排查
最常见原因是 DNS 配置。可以在 daemon.json 加:
{
"dns": ["8.8.8.8", "1.1.1.1"]
}
6 镜像构建缓存失效
改了 COPY . . 之前的内容就重新跑 npm install,构建会变慢。把不常变化的依赖声明放在前面,常变的源码放在后面:
COPY package*.json ./
RUN npm install
COPY . . # 这一层每次都会变,但 npm install 不会重跑
7 docker build 太慢
- 配置镜像加速(前面讲过)
- 启用 BuildKit:
DOCKER_BUILDKIT=1 docker build . - 用
.dockerignore排除无关内容
十三、实战小项目:把一个 Node 应用完整 Docker 化
我们串一下完整流程,把前面所有知识用一遍。
项目结构
hello-app/
├── Dockerfile
├── .dockerignore
├── package.json
├── server.js
└── public/
└── index.html
01 写应用
package.json:
{
"name": "hello-app",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.19.0"
}
}
server.js:
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.static('public'));
app.get('/api/hello', (req, res) => {
res.json({
message: 'Hello from Docker!',
time: new Date().toISOString(),
hostname: require('os').hostname()
});
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
public/index.html:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Hello Docker</title></head>
<body>
<h1>Hello Docker!</h1>
<button onclick="fetch('/api/hello').then(r=>r.json()).then(d=>alert(JSON.stringify(d)))">
调用 API
</button>
</body>
</html>
02 Dockerfile
# 多阶段示例:本例单阶段即可,留作对比参考
FROM node:20-alpine
# 安装 curl 用于健康检查
RUN apk add --no-cache curl
WORKDIR /app
# 先装依赖
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 拷贝源码
COPY . .
# 用非 root 用户运行
USER node
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/hello || exit 1
CMD ["node", "server.js"]
.dockerignore:
node_modules
npm-debug.log
.git
.gitignore
.env
*.md
03 构建并运行
docker build -t hello-app:v1 .
docker run -d -p 3000:3000 --name hello hello-app:v1
curl http://localhost:3000/api/hello
04 用 docker compose 管理
docker-compose.yml:
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/hello"]
interval: 30s
timeout: 3s
retries: 3
启动:
docker compose up -d
docker compose logs -f
docker compose down
十四、速查表
镜像
docker images # 列出镜像
docker pull nginx # 拉取
docker rmi nginx # 删除
docker tag a b # 打标签
docker inspect nginx # 详情
docker history nginx # 看各层
docker save -o a.tar nginx # 导出
docker load -i a.tar # 导入
容器
docker run -d -p 8080:80 nginx # 启动
docker ps / docker ps -a # 查看
docker stop / start / restart
docker rm / docker rm -f
docker logs -f
docker exec -it name bash
docker stats
docker top
docker cp
网络
docker network ls
docker network create mynet
docker network connect mynet web
docker network inspect mynet
卷
docker volume ls
docker volume create mydata
docker volume rm mydata
docker volume inspect mydata
系统
docker system df
docker system prune
docker system info
Compose
docker compose up -d
docker compose down
docker compose ps
docker compose logs -f
docker compose exec app bash
docker compose build
docker compose pull
十五、学习路径建议
Docker 本身不难,但它的生态非常庞大。按这个路径学下来最稳:
- 本文内容——掌握镜像、容器、Volume、网络、Dockerfile、Compose
- 镜像优化——多阶段构建、镜像瘦身(distroless、scratch)
- 私有仓库——Harbor、registry 镜像
- 容器编排——Kubernetes(k8s)入门
- CI/CD——GitHub Actions / GitLab CI 自动构建推送镜像
- 安全——镜像扫描(Trivy)、运行时安全(Falco)、Rootless Docker
当你能在 30 分钟内把一个新项目从源码到 Dockerfile 到 Compose 一气呵成跑起来,Docker 才算真正"入门"了。
写在最后
Docker 不是银弹,它解决的是"环境一致性"这一类问题。它把软件打包成标准化、可分发的形态,让运维与协作的成本大幅下降。
刚开始学时,命令很多很容易忘,没关系——用多了自然会记住。先学会 docker run、docker ps、docker logs、docker exec 四个命令,你就已经能解决 80% 的日常问题。
剩下的 20%,留给 Compose、Dockerfile、网络和卷。每一块单独看都不复杂,串起来才是 Docker 的全貌。
如果你看完这篇文章能写出一个能跑起来的 Dockerfile,那入门就完成了。
风险提示:本文涉及的命令与配置以 Docker 24+ 版本为准,不同版本细节可能略有差异。生产环境部署请结合实际网络与安全策略进行评估。