Docker学习笔记

0 阅读9分钟

Docker 学习笔记

目录

  1. Docker 基础概念
  2. 镜像操作
  3. 容器操作
  4. 镜像构建
  5. 镜像导出与导入
  6. 容器导出与导入
  7. Docker Compose
  8. 最佳实践

一、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/loadexport/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: ./appbuild: context: ./app dockerfile: Dockerfile.prod
ports端口映射ports: - "8080:80"
volumes挂载卷volumes: - ./data:/data
environment环境变量environment: - NODE_ENV=productionenv_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 镜像构建最佳实践

  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"]
    
  2. 最小化镜像层数

    • 合并 RUN 命令
    • 清理缓存和临时文件
  3. 使用 .dockerignore

    node_modules
    .git
    *.log
    .env
    Dockerfile
    .dockerignore
    
  4. 选择合适的基础镜像

    • 优先使用官方镜像
    • 使用 Alpine 版本减小体积
    • 使用 Distroless 提高安全性
  5. 固定镜像版本

    # 不推荐
    FROM node:latest
    
    # 推荐
    FROM node:18.17.1-alpine
    

7.2 容器运行最佳实践

  1. 使用非 root 用户

    RUN useradd -m myuser
    USER myuser
    
  2. 只暴露必要的端口

    docker run -d -p 127.0.0.1:8080:80 nginx
    
  3. 设置资源限制

    docker run -d \
      --memory=512m \
      --memory-swap=1g \
      --cpus=1.5 \
      nginx
    
  4. 使用健康检查

    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: 如何减小镜像体积?

  1. 使用多阶段构建
  2. 选择轻量级基础镜像(Alpine、Distroless)
  3. 清理构建缓存和临时文件
  4. 合并 RUN 命令减少层数
  5. 使用 .dockerignore 排除不需要的文件

Q3: 容器数据如何持久化?

  1. 使用数据卷(Volumes)
  2. 使用绑定挂载(Bind Mounts)
  3. 使用 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