Docker 详细学习笔记

整理日期:2026-08-18
适用版本:Docker Engine 20.10+ / 24.x / 25.x


目录

  1. Docker 基础概念
  2. 安装与配置
  3. 核心概念
  4. 常用命令速查
  5. Dockerfile 详解
  6. 镜像构建与优化
  7. 数据管理(Volume)
  8. Docker 网络
  9. Docker Compose
  10. 容器安全
  11. 最佳实践
  12. 常见问题与排错

1. Docker 基础概念

1.1 什么是 Docker

Docker 是一个开源的容器化平台,用于将应用及其依赖打包到一个可移植的容器中,然后发布到任何支持 Docker 的机器上运行。

  • 容器化:将应用和运行环境打包在一起
  • 轻量级:共享宿主机内核,启动快、占用资源少
  • 可移植:一次构建,到处运行
  • 标准化:统一的打包、分发、运行方式

1.2 容器 vs 虚拟机

特性容器(Container)虚拟机(VM)
启动速度秒级分钟级
资源占用MB 级GB 级
内核共享共享宿主机内核独立内核
隔离性进程级隔离系统级隔离
性能损耗极小较大

1.3 Docker 架构

┌─────────────────────────────────────────┐
│           Docker Client (CLI)           │
└───────────────────┬─────────────────────┘
                    │ REST API
┌───────────────────▼─────────────────────┐
│         Docker Daemon (dockerd)         │
│  ┌──────────┐  ┌──────────┐  ┌───────┐  │
│  │  Images  │  │ Containers│  │Volume│  │
│  └──────────┘  └──────────┘  └───────┘  │
└─────────────────────────────────────────┘
                    │
┌───────────────────▼─────────────────────┐
│           Docker Registry               │
│         (Docker Hub / 私有仓库)          │
└─────────────────────────────────────────┘
  • Docker Client:用户通过 CLI 与 Docker 交互
  • Docker Daemon:后台服务,负责管理 Docker 对象
  • Docker Registry:镜像仓库,存储和分发镜像
  • Images:只读模板,用于创建容器
  • Containers:镜像的运行实例

2. 安装与配置

2.1 Ubuntu 安装 Docker

# 1. 更新包索引
sudo apt-get update

# 2. 安装依赖
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# 3. 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 4. 设置稳定版仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5. 安装 Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 6. 验证安装
docker --version
docker run hello-world

2.2 配置免 sudo 运行

# 创建 docker 组(通常已存在)
sudo groupadd docker

# 将当前用户加入 docker 组
sudo usermod -aG docker $USER

# 重新登录或执行以下命令使生效
newgrp docker

# 验证
docker run hello-world

2.3 配置镜像加速器(国内必配)

编辑 /etc/docker/daemon.json:

{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
# 重启 Docker 服务
sudo systemctl daemon-reload
sudo systemctl restart docker

# 验证加速器是否生效
docker info | grep -A 10 "Registry Mirrors"

2.4 Docker 服务管理

# 启动 Docker
sudo systemctl start docker

# 设置开机自启
sudo systemctl enable docker

# 查看状态
sudo systemctl status docker

# 重启
sudo systemctl restart docker

3. 核心概念

3.1 镜像(Image)

  • 镜像是一个只读的模板,包含运行应用所需的一切(代码、运行时、库、环境变量、配置文件)
  • 镜像由多层(Layer)组成,每层对应 Dockerfile 中的一条指令
  • 镜像层是只读的,容器启动时会在顶部添加一层可写层
  • 镜像可以基于其他镜像构建(继承关系)
# 查看本地镜像
docker images
docker image ls

# 拉取镜像
docker pull nginx:latest
docker pull ubuntu:22.04

# 删除镜像
docker rmi nginx:latest
docker image rm nginx:latest

# 查看镜像详情
docker inspect nginx:latest

# 查看镜像历史(各层信息)
docker history nginx:latest

3.2 容器(Container)

  • 容器是镜像的运行实例
  • 容器之间相互隔离,有自己的文件系统、网络、进程空间
  • 容器是临时的,删除容器后,容器内的数据也会丢失(除非挂载了数据卷)
# 创建并启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

# 常用选项:
# -d          后台运行(detached)
# -it         交互式运行(interactive + tty)
# --name      指定容器名称
# -p          端口映射 宿主机:容器
# -v          挂载数据卷 宿主机路径:容器路径
# -e          设置环境变量
# --rm        容器停止后自动删除
# --network   指定网络

3.3 仓库(Registry)

  • 集中存储和分发镜像的地方
  • Docker Hub 是官方公共仓库
  • 可以搭建私有仓库(Harbor、Registry)

4. 常用命令速查

4.1 容器生命周期

# 启动容器
docker run -d --name mynginx -p 8080:80 nginx

# 启动已停止的容器
docker start mynginx

# 停止容器
docker stop mynginx

# 重启容器
docker restart mynginx

# 强制停止(发送 SIGKILL)
docker kill mynginx

# 删除容器(容器必须先停止)
docker rm mynginx

# 强制删除(包括运行中的容器)
docker rm -f mynginx

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 查看容器详情
docker inspect mynginx

# 查看容器日志
docker logs mynginx
docker logs -f mynginx        # 实时跟踪
docker logs --tail 100 mynginx # 最后100行
docker logs -t mynginx         # 显示时间戳

# 查看容器内进程
docker top mynginx

# 查看容器资源使用情况
docker stats
docker stats mynginx

4.2 进入容器

# 进入运行中的容器(推荐)
docker exec -it mynginx /bin/bash
docker exec -it mynginx sh

# 以 root 用户进入
docker exec -it -u root mynginx bash

# 查看容器输出(不进入)
docker exec mynginx ls -la /

# 复制文件到容器
docker cp /local/path mynginx:/container/path

# 从容器复制文件到本地
docker cp mynginx:/container/path /local/path

4.3 镜像管理

# 构建镜像
docker build -t myapp:v1 .
docker build -t myapp:v1 -f Dockerfile.prod .

# 给镜像打标签
docker tag myapp:v1 myregistry.com/myapp:v1

# 推送镜像到仓库
docker push myregistry.com/myapp:v1

# 搜索镜像
docker search nginx

# 清理无用镜像
docker image prune          # 清理悬空镜像(dangling)
docker image prune -a       # 清理所有未使用的镜像

# 导出镜像为 tar
docker save -o myapp.tar myapp:v1

# 从 tar 导入镜像
docker load -i myapp.tar

4.4 系统清理

# 查看 Docker 占用空间
docker system df

# 清理所有未使用的资源(镜像、容器、网络、构建缓存)
docker system prune

# 更彻底的清理(包括未使用的卷)
docker system prune -a --volumes

# 清理构建缓存
docker builder prune

5. Dockerfile 详解

5.1 Dockerfile 指令一览

指令说明
FROM指定基础镜像(必须是第一条指令)
MAINTAINER维护者信息(已废弃,用 LABEL 替代)
LABEL镜像元数据
RUN构建时执行命令
CMD容器启动时执行的默认命令
ENTRYPOINT容器启动时执行的入口命令
COPY复制文件到镜像
ADD复制文件(支持自动解压 tar、URL)
WORKDIR设置工作目录
ENV设置环境变量
ARG构建时变量
EXPOSE声明容器监听的端口
VOLUME声明挂载点
USER指定运行用户
HEALTHCHECK健康检查
ONBUILD触发器,子镜像构建时执行

5.2 常用指令详解

FROM
# 基础镜像,尽量使用官方镜像和具体版本
FROM ubuntu:22.04
FROM node:18-alpine
FROM python:3.11-slim
RUN
# shell 形式
RUN apt-get update && apt-get install -y nginx

# exec 形式
RUN ["apt-get", "install", "-y", "nginx"]

# 最佳实践:多条命令合并,减少镜像层数
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        nginx \
        curl \
        vim && \
    rm -rf /var/lib/apt/lists/*
CMD vs ENTRYPOINT

CMD:容器启动时的默认命令,可以被 docker run 后的参数覆盖。

# 三种形式
CMD ["executable","param1","param2"]  # exec 形式(推荐)
CMD ["param1","param2"]               # 作为 ENTRYPOINT 的参数
CMD command param1 param2             # shell 形式

ENTRYPOINT:容器启动时的入口命令,不会被 docker run 参数覆盖(参数会追加到 ENTRYPOINT 后)。

ENTRYPOINT ["nginx", "-g", "daemon off;"]

CMD + ENTRYPOINT 组合:

ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--spring.profiles.active=prod"]

此时 docker run myapp 会执行 java -jar app.jar --spring.profiles.active=prod
docker run myapp --spring.profiles.active=dev 会执行 java -jar app.jar --spring.profiles.active=dev

COPY vs ADD
# COPY:简单复制(推荐优先使用)
COPY . /app
COPY package.json /app/

# ADD:支持自动解压 tar 文件和 URL(谨慎使用)
ADD app.tar.gz /app/
ADD https://example.com/file.txt /app/
WORKDIR
# 设置工作目录,后续 RUN/CMD/ENTRYPOINT/COPY/ADD 都在此目录下执行
WORKDIR /app

# 可以多次使用,相当于 cd
WORKDIR /app
WORKDIR src
# 最终工作目录为 /app/src
ENV
# 设置环境变量
ENV NODE_ENV=production
ENV APP_HOME=/app
ENV PATH="$PATH:/app/bin"

# 多个变量可以写一行
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk \
    MAVEN_HOME=/usr/share/maven
ARG
# 构建时变量,仅在构建过程中可用
ARG VERSION=1.0.0
ARG BUILD_DATE

# 可以在 FROM 之前使用 ARG
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

构建时传入:

docker build --build-arg VERSION=2.0.0 -t myapp:v2 .
EXPOSE
# 声明容器监听的端口(仅作文档说明,不会自动映射)
EXPOSE 80
EXPOSE 443/tcp
EXPOSE 53/udp
USER
# 指定运行用户(安全最佳实践,不要用 root)
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
HEALTHCHECK
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -f http://localhost:80/health || exit 1

5.3 完整 Dockerfile 示例

Node.js 应用
# 多阶段构建
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# 运行阶段
FROM node:18-alpine

WORKDIR /app

ENV NODE_ENV=production
ENV PORT=3000

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001

# 从构建阶段复制
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json

USER nextjs

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1

CMD ["npm", "start"]
Python 应用
FROM python:3.11-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc && \
    rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN useradd -m appuser
USER appuser

EXPOSE 8000

CMD ["gunicorn", "app:app", "-b", "0.0.0.0:8000"]
Java 应用
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

6. 镜像构建与优化

6.1 镜像分层原理

Docker 镜像由多层只读文件系统组成:

┌─────────────────────┐
│  可写层(容器层)     │  ← 容器运行时写入
├─────────────────────┤
│  Layer 3: CMD       │
├─────────────────────┤
│  Layer 2: COPY app  │
├─────────────────────┤
│  Layer 1: RUN apt   │
├─────────────────────┤
│  Layer 0: 基础镜像   │
└─────────────────────┘
  • 每条指令创建一层
  • 相同的层可以被多个镜像共享
  • 构建时使用缓存,未变化的层直接复用

6.2 构建缓存优化

利用缓存的原则:将变化频率低的指令放在前面,变化频率高的放在后面。

# ❌ 不好:每次代码变化都会导致 npm install 重新执行
COPY . .
RUN npm install

# ✅ 好:只有 package.json 变化时才重新安装依赖
COPY package*.json ./
RUN npm install
COPY . .

6.3 减小镜像体积

1. 使用轻量基础镜像
镜像大小说明
ubuntu:22.04~77MB完整 Ubuntu
debian:bookworm-slim~80MB精简 Debian
alpine:3.18~7MB超轻量 Alpine
node:18~990MB完整 Node.js
node:18-slim~250MB精简 Node.js
node:18-alpine~130MBAlpine Node.js
2. 多阶段构建(Multi-stage Build)
# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .

# 运行阶段(只包含编译后的二进制)
FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

最终镜像只有几 MB,而不是几百 MB。

3. 清理包管理器缓存
# Debian/Ubuntu
RUN apt-get update && \
    apt-get install -y --no-install-recommends package && \
    rm -rf /var/lib/apt/lists/*

# Alpine
RUN apk add --no-cache package

# Python pip
RUN pip install --no-cache-dir -r requirements.txt

# npm
RUN npm ci --only=production && npm cache clean --force
4. 合并 RUN 指令
# ❌ 不好:产生 3 层
RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*

# ✅ 好:只产生 1 层
RUN apt-get update && \
    apt-get install -y --no-install-recommends nginx && \
    rm -rf /var/lib/apt/lists/*

6.4 .dockerignore

类似 .gitignore,排除不需要复制到镜像中的文件:

# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.env.local
dist
*.log
.DS_Store

7. 数据管理(Volume)

7.1 数据持久化的三种方式

方式说明适用场景
VolumesDocker 管理,存于宿主机 Docker 目录推荐使用,数据持久化
Bind Mounts挂载宿主机任意目录开发环境、配置文件
tmpfs挂载到内存,不持久化敏感数据、临时文件

7.2 Volume 常用命令

# 创建卷
docker volume create mydata

# 查看卷列表
docker volume ls

# 查看卷详情
docker volume inspect mydata

# 删除卷
docker volume rm mydata

# 清理未使用的卷
docker volume prune

7.3 使用 Volume

# 命名卷
docker run -d --name db -v mydata:/var/lib/mysql mysql:8.0

# 匿名卷(Docker 自动生成名称)
docker run -d --name db -v /var/lib/mysql mysql:8.0

# 挂载宿主机目录(Bind Mount)
docker run -d --name nginx -v /host/path:/usr/share/nginx/html nginx

# 只读挂载
docker run -d --name nginx -v /host/path:/usr/share/nginx/html:ro nginx

7.4 数据卷容器

# 创建数据卷容器
docker create -v /data --name datastore busybox true

# 其他容器挂载数据卷容器的卷
docker run -d --volumes-from datastore --name app1 myapp
docker run -d --volumes-from datastore --name app2 myapp

7.5 数据备份与恢复

# 备份:启动临时容器挂载卷,打包输出到宿主机
docker run --rm -v mydata:/data -v $(pwd):/backup busybox \
  tar czf /backup/mydata_backup.tar.gz -C /data .

# 恢复
docker run --rm -v mydata:/data -v $(pwd):/backup busybox \
  tar xzf /backup/mydata_backup.tar.gz -C /data

8. Docker 网络

8.1 网络驱动类型

驱动说明
bridge默认网络,桥接模式,容器间通过 IP 通信
host共享宿主机网络命名空间,性能最好
none无网络,完全隔离
overlay跨主机网络,用于 Swarm 模式
macvlan容器有独立 MAC 地址,像物理机一样

8.2 常用网络命令

# 查看网络列表
docker network ls

# 创建网络
docker network create mynetwork
docker network create --driver bridge mynetwork

# 查看网络详情
docker network inspect mynetwork

# 连接容器到网络
docker network connect mynetwork mycontainer

# 断开网络
docker network disconnect mynetwork mycontainer

# 删除网络
docker network rm mynetwork

# 清理未使用的网络
docker network prune

8.3 容器间通信

方式一:通过 IP 通信(不推荐,IP 会变)
# 查看容器 IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mycontainer
方式二:自定义网络 + 容器名(推荐)
# 创建自定义网络
docker network create app-net

# 启动容器并加入网络(使用 --name)
docker run -d --name db --network app-net mysql:8.0
docker run -d --name web --network app-net -p 8080:80 nginx

# 容器间可以直接用名称通信
docker exec web ping db
方式三:Link(已过时,不推荐)
docker run -d --name db mysql:8.0
docker run -d --name web --link db:db nginx

8.4 端口映射

# 映射指定端口
docker run -d -p 8080:80 nginx

# 映射到指定网卡
docker run -d -p 127.0.0.1:8080:80 nginx

# 随机映射宿主机端口
docker run -d -p 80 nginx

# 映射多个端口
docker run -d -p 80:80 -p 443:443 nginx

# 查看端口映射
docker port mycontainer

8.5 DNS 配置

# 指定 DNS
docker run -d --dns 8.8.8.8 nginx

# 添加 host 条目
docker run -d --add-host=host.docker.internal:host-gateway nginx

9. Docker Compose

9.1 简介

Docker Compose 是用于定义和运行多容器 Docker 应用的工具。通过 YAML 文件配置应用服务,然后一条命令启动所有服务。

9.2 安装

# Docker Desktop / Docker Engine 20.10+ 已内置 compose 插件
docker compose version

# 旧版独立安装(docker-compose)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

9.3 Compose 文件结构

# docker-compose.yml
version: "3.8"

services:
  web:
    build: .
    ports:
      - "8080:80"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
    volumes:
      - .:/app
    networks:
      - app-net

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: myapp
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - app-net

volumes:
  db-data:

networks:
  app-net:
    driver: bridge

9.4 常用命令

# 启动所有服务(前台)
docker compose up

# 后台启动
docker compose up -d

# 指定 compose 文件
docker compose -f docker-compose.prod.yml up -d

# 停止并删除容器、网络
docker compose down

# 停止并删除容器、网络、卷
docker compose down -v

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs
docker compose logs -f web
docker compose logs --tail=100

# 进入服务容器
docker compose exec web bash

# 重启服务
docker compose restart web

# 重新构建镜像
docker compose build
docker compose up -d --build

# 拉取最新镜像
docker compose pull

# 查看配置(验证 compose 文件)
docker compose config

# 扩展服务实例
docker compose up -d --scale web=3

9.5 完整示例:LNMP 环境

version: "3.8"

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/ssl:/etc/nginx/ssl
      - ./www:/var/www/html
    depends_on:
      - php
    networks:
      - frontend
      - backend

  php:
    image: php:8.2-fpm-alpine
    volumes:
      - ./www:/var/www/html
      - ./php/php.ini:/usr/local/etc/php/php.ini
    depends_on:
      - mysql
    networks:
      - backend

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: myapp
      MYSQL_USER: myapp
      MYSQL_PASSWORD: myapp123
    volumes:
      - mysql-data:/var/lib/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d
    ports:
      - "3306:3306"
    networks:
      - backend

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    networks:
      - backend

volumes:
  mysql-data:
  redis-data:

networks:
  frontend:
  backend:

9.6 环境变量与 .env 文件

# .env 文件
MYSQL_ROOT_PASSWORD=secret
MYSQL_DATABASE=myapp
TAG=v1.0.0
services:
  db:
    image: mysql:${TAG}
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}

9.7 多环境配置

# docker-compose.yml(基础配置)
services:
  web:
    build: .
    ports:
      - "8080:80"
# docker-compose.override.yml(开发环境,自动加载)
services:
  web:
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development
# docker-compose.prod.yml(生产环境)
services:
  web:
    image: myregistry.com/myapp:latest
    deploy:
      replicas: 3
    environment:
      - NODE_ENV=production
# 开发环境(默认加载 docker-compose.yml + docker-compose.override.yml)
docker compose up -d

# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

10. 容器安全

10.1 安全最佳实践

1. 不要以 root 用户运行
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
2. 使用官方镜像
  • 优先使用 Docker Hub 官方镜像
  • 验证镜像签名(Docker Content Trust)
  • 定期扫描镜像漏洞
3. 最小化镜像
  • 使用多阶段构建
  • 只包含运行必需的文件
  • 不安装不必要的工具
4. 限制容器资源
# 限制内存
docker run -d --memory="512m" --memory-swap="1g" nginx

# 限制 CPU
docker run -d --cpus="1.5" nginx
docker run -d --cpuset-cpus="0,1" nginx
5. 只读文件系统
docker run -d --read-only nginx
6. 禁用特权模式
# ❌ 不要用
docker run --privileged ...

# ✅ 按需添加特定能力
docker run --cap-add=NET_ADMIN ...
7. 安全扫描
# 扫描镜像漏洞
docker scan myapp:v1

# 使用 trivy
trivy image myapp:v1

10.2 敏感信息管理

# ❌ 不要在 Dockerfile 中硬编码
ENV PASSWORD=secret123

# ✅ 使用环境变量(运行时传入)
docker run -e DB_PASSWORD=secret myapp

# ✅ 使用 secrets(Swarm 模式)
docker secret create db_password ./password.txt

# ✅ 使用 .env 文件(开发环境)
# 注意:.env 不要提交到 Git

11. 最佳实践

11.1 Dockerfile 最佳实践

  1. 使用官方基础镜像:优先选择官方维护的镜像
  2. 固定版本标签:不要用 latest,用具体版本号如 nginx:1.25-alpine
  3. 最小化镜像层数:合并 RUN 指令
  4. 利用构建缓存:将变化少的指令放前面
  5. 使用 .dockerignore:排除不必要的文件
  6. 多阶段构建:编译和运行分离
  7. 非 root 用户:创建专用用户运行应用
  8. 一条容器一个进程:每个容器只跑一个主进程
  9. 健康检查:添加 HEALTHCHECK
  10. 清晰的注释:关键步骤添加注释

11.2 容器使用最佳实践

  1. 容器是临时的:随时可以销毁和重建
  2. 数据放卷里:重要数据用 Volume 持久化
  3. 日志输出到 stdout/stderr:不要写文件,用 docker logs 查看
  4. 配置通过环境变量传入:遵循 12-Factor 应用原则
  5. 使用自定义网络:不要用默认 bridge 网络
  6. 命名规范:容器、镜像、卷使用有意义的名称

11.3 生产环境最佳实践

  1. 使用编排工具:Kubernetes、Docker Swarm
  2. 资源限制:设置 CPU、内存限制
  3. 健康检查:配置就绪探针和存活探针
  4. 滚动更新:零停机部署
  5. 监控告警:Prometheus + Grafana
  6. 日志收集:ELK / Loki
  7. 自动扩缩容:根据负载自动调整实例数
  8. 安全扫描:CI/CD 中集成镜像漏洞扫描

12. 常见问题与排错

12.1 容器启动后立即退出

原因:容器没有前台进程在运行。

排查:

# 查看退出的容器日志
docker logs <container_id>

# 查看退出码
docker ps -a

解决:确保 CMD/ENTRYPOINT 启动的进程在前台运行。例如 Nginx 要用 daemon off;。

12.2 端口映射不生效

排查:

# 查看端口映射
docker port <container>

# 查看容器是否在监听
docker exec <container> netstat -tlnp

# 检查宿主机防火墙
sudo ufw status
sudo iptables -L

12.3 容器间无法通信

排查:

# 确认在同一网络
docker inspect <container> | grep NetworkMode

# 测试网络连通性
docker exec <container1> ping <container2>
docker exec <container1> curl http://<container2>:port

解决:使用自定义网络,通过容器名通信。

12.4 镜像构建慢

优化方向:

  1. 配置国内镜像加速器
  2. 优化 Dockerfile 顺序,利用缓存
  3. 使用 .dockerignore 减少上下文
  4. 多阶段构建减小最终镜像

12.5 磁盘空间不足

# 查看占用
docker system df

# 清理
docker system prune -a --volumes

# 清理日志
truncate -s 0 /var/lib/docker/containers/*/*-json.log

12.6 权限问题(Permission denied)

常见场景:挂载宿主机目录后,容器内进程无写入权限。

解决:

# 方式一:修改宿主机目录权限
chmod 777 /host/path

# 方式二:容器内使用与宿主机相同 UID/GID 的用户
docker run -u $(id -u):$(id -g) myapp

# 方式三:Dockerfile 中指定 UID
RUN usermod -u 1000 appuser

12.7 常用排错命令

# 查看容器详细信息
docker inspect <container>

# 查看容器进程
docker top <container>

# 查看资源使用
docker stats

# 实时查看事件
docker events

# 查看 Docker 守护进程日志
sudo journalctl -u docker -f

# 进入容器网络命名空间调试
docker run --rm --net container:<target> nicolaka/netshoot bash

附录:常用命令速查表

容器管理

docker run          # 创建并启动容器
docker start        # 启动已停止的容器
docker stop         # 停止容器
docker restart      # 重启容器
docker rm           # 删除容器
docker ps           # 列出容器
docker inspect      # 查看详情
docker logs         # 查看日志
docker exec         # 在容器中执行命令
docker cp           # 复制文件
docker stats        # 资源统计

镜像管理

docker build        # 构建镜像
docker pull         # 拉取镜像
docker push         # 推送镜像
docker images       # 列出镜像
docker rmi          # 删除镜像
docker tag          # 打标签
docker save         # 导出镜像
docker load         # 导入镜像
docker history      # 查看镜像历史

数据卷与网络

docker volume create    # 创建卷
docker volume ls        # 列出卷
docker volume rm        # 删除卷
docker network create   # 创建网络
docker network ls       # 列出网络
docker network connect  # 连接网络

Compose

docker compose up       # 启动服务
docker compose down     # 停止并删除
docker compose ps       # 查看状态
docker compose logs     # 查看日志
docker compose exec     # 执行命令
docker compose build    # 构建镜像

学习建议:

  1. 先理解核心概念(镜像、容器、仓库)
  2. 动手实践常用命令
  3. 学习 Dockerfile 编写和镜像优化
  4. 掌握数据卷和网络配置
  5. 学习 Docker Compose 编排多容器应用
  6. 了解容器安全和最佳实践
  7. 进阶学习 Kubernetes 等编排工具

更多推荐