Docker 学习笔记
目录
一、Docker 基础概念
1.1 什么是 Docker
Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖打包到一个轻量级、可移植的容器中,然后在任何环境中运行。
1.2 核心概念
| 概念 | 说明 |
|---|---|
| 镜像 (Image) | 只读模板,包含运行应用所需的代码、库、环境变量和配置文件 |
| 容器 (Container) | 镜像的运行实例,是独立、隔离的运行环境 |
| 仓库 (Repository) | 存储和分发镜像的地方,如 Docker Hub |
| Dockerfile | 用于构建镜像的脚本文件 |
1.3 镜像与容器的关系
镜像 (Image) ──> 运行 ──> 容器 (Container)
↑ │
└──────── 提交修改 ────────────┘
二、镜像操作
2.1 镜像搜索与下载
# 搜索镜像
docker search nginx
# 拉取镜像(默认最新版本)
docker pull nginx
# 拉取指定版本
docker pull nginx:1.21
# 拉取指定架构
docker pull --platform linux/amd64 nginx
2.2 查看本地镜像
# 列出所有镜像
docker images
# 列出镜像(简洁格式)
docker image ls
# 查看镜像详细信息
docker inspect nginx
# 查看镜像历史
docker history nginx
# 查看镜像大小
docker images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"
2.3 删除镜像
# 删除单个镜像
docker rmi nginx
# 强制删除镜像
docker rmi -f nginx
# 删除多个镜像
docker rmi nginx redis mysql
# 删除所有无标签镜像(悬空镜像)
docker image prune
# 删除所有未使用的镜像
docker image prune -a
2.4 镜像标签管理
# 给镜像打标签
docker tag nginx mynginx:v1.0
# 给镜像打多个标签
docker tag nginx myregistry.com/mynginx:v1.0
docker tag nginx mynginx:latest
三、容器操作
3.1 创建与启动容器
# 创建并启动容器
docker run -d --name mynginx -p 80:80 nginx
# 常用参数说明
# -d: 后台运行(守护模式)
# --name: 指定容器名称
# -p: 端口映射(主机端口:容器端口)
# -v: 挂载卷(主机目录:容器目录)
# -e: 设置环境变量
# --rm: 停止后自动删除容器
# -it: 交互式终端模式
# 交互式运行容器
docker run -it --name myubuntu ubuntu:20.04 /bin/bash
# 带环境变量运行
docker run -d -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=mydb --name mysql mysql:8.0
# 挂载卷运行
docker run -d -v /host/data:/container/data -v /host/config:/container/config nginx
3.2 查看容器状态
# 查看运行中的容器
docker ps
# 查看所有容器(包括停止的)
docker ps -a
# 查看容器详细信息
docker inspect 容器ID或名称
# 查看容器日志
docker logs 容器ID或名称
# 实时查看日志
docker logs -f 容器ID或名称
# 查看最近100行日志
docker logs --tail 100 容器ID或名称
# 查看容器资源使用情况
docker stats
# 查看容器进程
docker top 容器ID或名称
3.3 容器生命周期管理
# 启动容器
docker start 容器ID或名称
# 停止容器
docker stop 容器ID或名称
# 强制停止容器
docker kill 容器ID或名称
# 重启容器
docker restart 容器ID或名称
# 暂停容器
docker pause 容器ID或名称
# 恢复容器
docker unpause 容器ID或名称
# 删除容器
docker rm 容器ID或名称
# 强制删除运行中的容器
docker rm -f 容器ID或名称
# 删除所有停止的容器
docker container prune
3.4 进入容器
# 使用 exec 进入运行中的容器(推荐)
docker exec -it 容器ID或名称 /bin/bash
# 使用 sh(如果容器没有 bash)
docker exec -it 容器ID或名称 /bin/sh
# 使用 attach(共享主进程,退出会停止容器)
docker attach 容器ID或名称
3.5 容器与主机文件传输
# 从容器复制文件到主机
docker cp 容器ID:/container/path/file.txt /host/path/
# 从主机复制文件到容器
docker cp /host/path/file.txt 容器ID:/container/path/
# 复制整个目录
docker cp 容器ID:/container/dir /host/path/
四、镜像构建
4.1 Dockerfile 基础
Dockerfile 是构建 Docker 镜像的脚本文件,包含一系列指令。
常用指令
| 指令 | 说明 | 示例 |
|---|---|---|
FROM | 指定基础镜像 | FROM ubuntu:20.04 |
RUN | 执行命令 | RUN apt-get update && apt-get install -y nginx |
COPY | 复制文件到镜像 | COPY . /app |
ADD | 复制文件(支持URL和压缩包) | ADD https://example.com/file.tar.gz /app/ |
WORKDIR | 设置工作目录 | WORKDIR /app |
ENV | 设置环境变量 | ENV NODE_ENV=production |
EXPOSE | 暴露端口 | EXPOSE 8080 |
CMD | 容器启动时执行的命令 | CMD ["nginx", "-g", "daemon off;"] |
ENTRYPOINT | 容器启动入口 | ENTRYPOINT ["python", "app.py"] |
VOLUME | 创建挂载点 | VOLUME ["/data"] |
LABEL | 添加元数据 | LABEL version="1.0" |
4.2 Dockerfile 示例
示例 1:构建 Nginx 应用
# 使用官方 Nginx 基础镜像
FROM nginx:alpine
# 添加标签信息
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="Custom Nginx Image"
# 复制自定义配置文件
COPY nginx.conf /etc/nginx/nginx.conf
# 复制网站文件
COPY html/ /usr/share/nginx/html/
# 暴露端口
EXPOSE 80
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
# 启动命令
CMD ["nginx", "-g", "daemon off;"]
示例 2:构建 Node.js 应用
# 多阶段构建示例
# 第一阶段:构建
FROM node:18-alpine AS builder
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 第二阶段:运行
FROM node:18-alpine
WORKDIR /app
# 从构建阶段复制文件
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
# 暴露端口
EXPOSE 3000
# 非 root 用户运行
USER node
# 启动命令
CMD ["node", "server.js"]
示例 3:构建 Python 应用
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 5000
# 运行命令
CMD ["python", "app.py"]
4.3 构建镜像
# 基本构建
docker build -t myapp:v1.0 .
# 指定 Dockerfile 路径
docker build -t myapp:v1.0 -f /path/to/Dockerfile .
# 不使用缓存构建
docker build --no-cache -t myapp:v1.0 .
# 构建时传递参数
docker build --build-arg NODE_ENV=production -t myapp:v1.0 .
# 构建多个标签
docker build -t myapp:v1.0 -t myapp:latest .
# 查看构建过程详细输出
docker build --progress=plain -t myapp:v1.0 .
4.4 构建参数 (ARG) 使用
# Dockerfile
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine
ARG APP_ENV=development
ENV NODE_ENV=${APP_ENV}
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]
# 构建时指定参数
docker build --build-arg NODE_VERSION=20 --build-arg APP_ENV=production -t myapp:v1.0 .
五、镜像导出与导入
5.1 使用 save 和 load(保存完整镜像)
docker save 命令用于将镜像保存为 tar 归档文件,包含所有层和元数据。
# 导出单个镜像
docker save -o nginx.tar nginx:latest
# 导出多个镜像
docker save -o images.tar nginx:latest redis:latest mysql:8.0
# 使用 gzip 压缩导出
docker save nginx:latest | gzip > nginx.tar.gz
# 导入镜像
docker load -i nginx.tar
# 从 gzip 压缩文件导入
gunzip -c nginx.tar.gz | docker load
特点:
- 保存完整的镜像历史、标签和元数据
- 文件体积较大
- 适合备份和完整迁移
5.2 使用 export 和 import(导出容器文件系统)
docker export 命令将容器的文件系统导出为 tar 归档。
# 导出容器的文件系统
docker export -o container-backup.tar 容器ID或名称
# 导入为镜像
docker import container-backup.tar myimage:latest
# 导入时指定标签和命令
docker import container-backup.tar myimage:v1.0 --change 'CMD ["/bin/bash"]'
特点:
- 只导出文件系统,不包含历史记录
- 文件体积较小
- 导入后是一个扁平化的镜像(单一层)
5.3 对比:save/load vs export/import
| 特性 | save/load | export/import |
|---|---|---|
| 操作对象 | 镜像 | 容器 |
| 导出内容 | 完整镜像(多层) | 文件系统(单层) |
| 历史记录 | 保留 | 丢失 |
| 文件大小 | 较大 | 较小 |
| 适用场景 | 完整备份、迁移 | 快速备份、减小体积 |
六、容器导出与导入
6.1 容器提交为新镜像
# 将运行中的容器保存为新镜像
docker commit 容器ID或名称 myimage:v1.0
# 提交时添加作者和说明
docker commit -a "Author Name" -m "Added some config" 容器ID myimage:v1.0
# 提交时暂停容器(确保数据一致性)
docker commit --pause=true 容器ID myimage:v1.0
6.2 容器完整迁移流程
# 1. 停止容器
docker stop mycontainer
# 2. 提交容器为新镜像
docker commit mycontainer myimage:backup
# 3. 保存镜像为 tar 文件
docker save -o myimage-backup.tar myimage:backup
# 4. 传输到目标服务器(使用 scp 或其他方式)
scp myimage-backup.tar user@target-server:/path/
# 5. 在目标服务器加载镜像
docker load -i myimage-backup.tar
# 6. 运行新容器
docker run -d --name newcontainer myimage:backup
6.3 使用数据卷持久化数据
# 创建数据卷
docker volume create mydata
# 运行容器时挂载数据卷
docker run -d -v mydata:/data nginx
# 备份数据卷
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/mydata.tar.gz -C /data .
# 恢复数据卷
docker run --rm -v mydata:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/mydata.tar.gz"
# 导出数据卷到另一台机器
docker run --rm -v mydata:/data alpine tar czf - -C /data . | ssh user@target-server 'docker run --rm -i -v mydata:/data alpine tar xzf - -C /data'
七、Docker Compose
Docker Compose 是 Docker 官方提供的工具,用于定义和运行多容器应用。通过 YAML 文件配置应用服务,可以一键启动、停止和管理多个容器。
7.1 安装 Docker Compose
# Docker Desktop 已内置 Compose,无需单独安装
# 验证安装
docker compose version
# 或旧版本
docker-compose --version
7.2 docker-compose.yml 基础结构
version: '3.8' # Compose 文件版本
services: # 定义服务(容器)
service1:
image: nginx:latest
ports:
- "80:80"
service2:
image: redis:latest
volumes: # 定义数据卷
myvolume:
networks: # 定义网络
mynetwork:
7.3 常用配置指令
| 指令 | 说明 | 示例 |
|---|---|---|
image | 指定镜像 | image: nginx:latest |
build | 构建镜像 | build: ./app 或 build: context: ./app dockerfile: Dockerfile.prod |
ports | 端口映射 | ports: - "8080:80" |
volumes | 挂载卷 | volumes: - ./data:/data |
environment | 环境变量 | environment: - NODE_ENV=production 或 env_file: .env |
depends_on | 服务依赖 | depends_on: - db |
networks | 网络配置 | networks: - mynet |
restart | 重启策略 | restart: unless-stopped |
command | 覆盖默认命令 | command: ["nginx", "-g", "daemon off;"] |
7.4 实战示例
示例 1:Web 应用 + 数据库
version: '3.8'
services:
web:
image: nginx:alpine
container_name: my-web
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- api
networks:
- frontend
- backend
api:
build: ./api
container_name: my-api
environment:
- NODE_ENV=production
- DB_HOST=db
- DB_PORT=3306
env_file:
- ./api/.env
volumes:
- ./api:/app
- /app/node_modules
depends_on:
- db
networks:
- backend
restart: unless-stopped
db:
image: mysql:8.0
container_name: my-db
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
volumes:
- db_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
restart: unless-stopped
volumes:
db_data:
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不暴露到外部
示例 2:Redis 缓存集群
version: '3.8'
services:
redis-master:
image: redis:7-alpine
container_name: redis-master
ports:
- "6379:6379"
volumes:
- redis_master_data:/data
command: redis-server --appendonly yes
networks:
- redis-net
redis-slave:
image: redis:7-alpine
container_name: redis-slave
ports:
- "6380:6379"
volumes:
- redis_slave_data:/data
command: redis-server --slaveof redis-master 6379
depends_on:
- redis-master
networks:
- redis-net
redis-sentinel:
image: redis:7-alpine
container_name: redis-sentinel
ports:
- "26379:26379"
volumes:
- ./sentinel.conf:/usr/local/etc/redis/sentinel.conf
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
- redis-slave
networks:
- redis-net
volumes:
redis_master_data:
redis_slave_data:
networks:
redis-net:
driver: bridge
示例 3:开发环境配置
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
container_name: dev-app
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
- /app/.next
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true # 文件监听(Windows/Mac 需要)
command: npm run dev
stdin_open: true
tty: true
db:
image: postgres:15-alpine
container_name: dev-db
ports:
- "5432:5432"
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
POSTGRES_DB: devdb
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
container_name: dev-redis
ports:
- "6379:6379"
volumes:
postgres_data:
示例 4:生产环境配置
version: '3.8'
services:
web:
build:
context: ./web
dockerfile: Dockerfile
image: myapp/web:${VERSION:-latest}
container_name: web
ports:
- "80:80"
- "443:443"
volumes:
- ./ssl:/etc/nginx/ssl:ro
- ./logs/nginx:/var/log/nginx
depends_on:
- api
networks:
- web-tier
restart: always
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
api:
build:
context: ./api
dockerfile: Dockerfile
image: myapp/api:${VERSION:-latest}
container_name: api
environment:
- NODE_ENV=production
env_file:
- ./api/.env.production
depends_on:
- db
- redis
networks:
- web-tier
- app-tier
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:15-alpine
container_name: db
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- db_data:/var/lib/postgresql/data
- ./backups:/backups
networks:
- app-tier
restart: always
deploy:
resources:
limits:
memory: 1G
redis:
image: redis:7-alpine
container_name: redis
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- app-tier
restart: always
# 定时备份服务
backup:
image: postgres:15-alpine
container_name: backup
command: >
sh -c "
echo '0 2 * * * pg_dump -h db -U $$POSTGRES_USER $$POSTGRES_DB > /backups/backup_$$(date +%Y%m%d).sql' | crontab - &&
crond -f
"
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- ./backups:/backups
depends_on:
- db
networks:
- app-tier
volumes:
db_data:
redis_data:
networks:
web-tier:
driver: bridge
app-tier:
driver: bridge
internal: true
7.5 常用命令
# 启动所有服务(后台运行)
docker compose up -d
# 启动特定服务
docker compose up -d web
# 构建并启动
docker compose up -d --build
# 查看服务状态
docker compose ps
# 查看日志
docker compose logs
# 查看特定服务日志
docker compose logs -f api
# 停止服务
docker compose stop
# 停止并删除容器
docker compose down
# 停止并删除容器和数据卷(慎用)
docker compose down -v
# 重启服务
docker compose restart
# 重启特定服务
docker compose restart api
# 进入容器
docker compose exec api /bin/bash
# 运行一次性命令
docker compose run --rm api npm test
# 拉取最新镜像
docker compose pull
# 构建镜像
docker compose build
# 验证配置文件
docker compose config
# 查看资源使用
docker compose top
7.6 多环境配置管理
# docker-compose.yml (基础配置)
version: '3.8'
services:
web:
build: ./web
ports:
- "80:80"
api:
build: ./api
environment:
- NODE_ENV=${NODE_ENV:-development}
# docker-compose.override.yml (开发环境自动加载)
version: '3.8'
services:
web:
volumes:
- ./web:/app
command: npm run dev
api:
volumes:
- ./api:/app
command: npm run dev
# docker-compose.prod.yml (生产环境)
version: '3.8'
services:
web:
restart: always
deploy:
replicas: 2
api:
restart: always
deploy:
replicas: 3
# 开发环境(自动加载 override 文件)
docker compose up -d
# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 使用环境变量文件
docker compose --env-file .env.production up -d
7.7 Compose 与容器导出导入
# 导出 Compose 所有服务的镜像
# 1. 构建镜像
docker compose build
# 2. 导出所有镜像
for service in $(docker compose config --services); do
image=$(docker compose config | grep -A 1 "^ $service:" | grep image | awk '{print $2}')
docker save -o "${service}.tar" $image
done
# 3. 在目标机器导入
for tar in *.tar; do
docker load -i "$tar"
done
# 4. 启动服务
docker compose up -d
# 导出数据卷
docker run --rm -v project_db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_backup.tar.gz -C /data .
# 导入数据卷
docker run --rm -v project_db_data:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/db_backup.tar.gz"
八、最佳实践
7.1 镜像构建最佳实践
-
使用多阶段构建
# 构建阶段 FROM golang:1.21 AS builder WORKDIR /app COPY . . RUN go build -o myapp # 运行阶段 FROM alpine:latest COPY --from=builder /app/myapp /usr/local/bin/ CMD ["myapp"] -
最小化镜像层数
- 合并 RUN 命令
- 清理缓存和临时文件
-
使用 .dockerignore
node_modules .git *.log .env Dockerfile .dockerignore -
选择合适的基础镜像
- 优先使用官方镜像
- 使用 Alpine 版本减小体积
- 使用 Distroless 提高安全性
-
固定镜像版本
# 不推荐 FROM node:latest # 推荐 FROM node:18.17.1-alpine
7.2 容器运行最佳实践
-
使用非 root 用户
RUN useradd -m myuser USER myuser -
只暴露必要的端口
docker run -d -p 127.0.0.1:8080:80 nginx -
设置资源限制
docker run -d \ --memory=512m \ --memory-swap=1g \ --cpus=1.5 \ nginx -
使用健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/ || exit 1
7.3 常用命令速查表
镜像命令
docker images # 列出镜像
docker pull 镜像名 # 拉取镜像
docker push 镜像名 # 推送镜像
docker rmi 镜像名 # 删除镜像
docker build -t 标签 . # 构建镜像
docker tag 原镜像 新镜像 # 打标签
docker save -o 文件 镜像 # 导出镜像
docker load -i 文件 # 导入镜像
容器命令
docker ps # 列出运行中容器
docker ps -a # 列出所有容器
docker run 镜像 # 创建并启动容器
docker start 容器 # 启动容器
docker stop 容器 # 停止容器
docker restart 容器 # 重启容器
docker rm 容器 # 删除容器
docker exec -it 容器 /bin/bash # 进入容器
docker logs 容器 # 查看日志
docker inspect 容器 # 查看详情
docker cp 容器:路径 主机路径 # 复制文件
清理命令
docker system prune # 清理未使用数据
docker volume prune # 清理未使用卷
docker image prune # 清理未使用镜像
docker container prune # 清理停止的容器
docker network prune # 清理未使用网络
附录:常见问题
Q1: save 和 export 有什么区别?
docker save:操作对象是镜像,保存完整的镜像历史和元数据docker export:操作对象是容器,只导出文件系统快照
Q2: 如何减小镜像体积?
- 使用多阶段构建
- 选择轻量级基础镜像(Alpine、Distroless)
- 清理构建缓存和临时文件
- 合并 RUN 命令减少层数
- 使用 .dockerignore 排除不需要的文件
Q3: 容器数据如何持久化?
- 使用数据卷(Volumes)
- 使用绑定挂载(Bind Mounts)
- 使用 tmpfs 挂载(临时存储)
Q4: 如何将本地镜像推送到远程仓库?
# 登录仓库
docker login registry.example.com
# 给镜像打标签
docker tag myimage:latest registry.example.com/myimage:latest
# 推送镜像
docker push registry.example.com/myimage:latest
文档版本:1.1 最后更新:2026-04-02