全栈手账 订阅 RSS

Docker 常用操作手册

Docker 是一个开源的应用容器引擎,让开发者可以打包应用及其依赖到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。本文从概念到实战,覆盖日常 90% 的操作场景。

读了 47 分钟 更新于 8 月 18 日

一、Docker 简介

1.1 核心概念

概念 说明 类比
镜像(Image) 只读模板,包含应用运行所需的所有内容(代码、依赖、环境) 面向对象中的"类"
容器(Container) 镜像的运行实例,可启动/停止/删除 面向对象中的"对象"
仓库(Registry) 存放镜像的地方,Docker Hub 是最大的公共仓库 GitHub
Dockerfile 描述如何构建镜像的文本文件 源代码
docker-compose 定义和运行多容器应用的工具 部署脚本

1.2 Docker vs 传统虚拟机

对比项 Docker 容器 传统虚拟机(VM)
启动速度 秒级 分钟级
资源占用 MB 级 GB 级
隔离性 进程级隔离 操作系统级隔离
系统依赖 共享宿主机内核 每个 VM 有完整内核
镜像大小 通常几十~几百 MB 几个 GB
并发密度 单机可跑数百容器 几十个 VM 就很吃力
适用场景 微服务、CI/CD、开发环境 强隔离、异构 OS

二、安装

2.1 CentOS

bash
# 卸载旧版本yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine# 安装依赖yum install -y yum-utils# 添加 Docker 官方源(国内用阿里云镜像)yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# 安装yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# 启动并设置开机自启systemctl start dockersystemctl enable docker# 验证docker --versiondocker run hello-world

2.2 Ubuntu

bash
# 更新包索引apt update# 安装依赖apt install -y ca-certificates curl gnupg lsb-release# 添加 Docker 官方 GPG keycurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg# 添加源echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null# 安装apt updateapt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# 启动systemctl start dockersystemctl enable docker

2.3 Windows / Mac

  1. 下载 Docker Desktop:https://www.docker.com/products/docker-desktop
  2. 安装后启动 Docker Desktop
  3. 验证:终端运行 docker --version

2.4 镜像加速配置

bash
# 编辑配置文件mkdir -p /etc/dockercat > /etc/docker/daemon.json << 'EOF'{  "registry-mirrors": [    "https://mirror.ccs.tencentyun.com",    "https://docker.mirrors.ustc.edu.cn",    "https://hub-mirror.c.163.com"  ],  "log-driver": "json-file",  "log-opts": {    "max-size": "100m",    "max-file": "3"  }}EOF# 重启 Dockersystemctl daemon-reloadsystemctl restart docker

三、镜像操作

3.1 搜索镜像

bash
# 在 Docker Hub 搜索docker search mysqldocker search nginx --limit 5  # 只显示前 5 个# 输出列:# NAME          镜像名# DESCRIPTION   描述# STARS         点赞数(越高越热门)# OFFICIAL      是否官方 [OK]# AUTOMATED     是否自动构建

3.2 拉取镜像

bash
# 默认拉 latestdocker pull mysql# 指定版本docker pull mysql:8.0docker pull nginx:1.25-alpinedocker pull node:18# 指定完整路径(从其他仓库拉)docker pull registry.cn-hangzhou.aliyuncs.com/library/mysql:8.0

3.3 查看镜像

bash
# 列出本地镜像docker images# 只显示镜像 IDdocker images -q# 过滤显示docker images --filter "dangling=true"  # 只显示悬空镜像(无标签的中间层)docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}"  # 自定义格式

3.4 删除镜像

bash
# 按 ID 删除docker rmi <image-id># 按名称:标签删除docker rmi mysql:8.0# 强制删除(即使有容器引用)docker rmi -f mysql:8.0# 批量删除所有镜像docker rmi $(docker images -q)# 清理悬空镜像(无标签的中间层)docker image prune# 清理所有未使用的镜像docker image prune -a

3.5 镜像标签

bash
# 给镜像打标签docker tag mysql:8.0 my-mysql:v1# 推送到私有仓库前打标签docker tag my-app:latest registry.example.com/my-app:v1.0

3.6 镜像保存与加载

bash
# 保存镜像为 tar 文件(离线传输用)docker save -o mysql.tar mysql:8.0# 或docker save mysql:8.0 > mysql.tar# 加载 tar 文件docker load -i mysql.tar# 或docker load < mysql.tar# 查看镜像详情docker inspect mysql:8.0docker history mysql:8.0  # 查看镜像构建历史(每层)

3.7 查看镜像详情

bash
# 查看镜像的完整信息docker inspect mysql:8.0# 查看镜像构建层docker history mysql:8.0# 查看 MySQL 镜像的架构信息docker inspect mysql:8.0 --format '{{.Architecture}} {{.Os}}'

四、容器操作

4.1 创建并启动容器

bash
docker run [OPTIONS] IMAGE [COMMAND]# 常用 OPTIONS--name        容器名-d            后台运行-it           交互式(进入容器终端)-p            端口映射 宿主端口:容器端口-P            随机端口映射-v            挂载数据卷 宿主路径:容器路径-e            设置环境变量--env-file    从文件读取环境变量--network     指定网络--restart     重启策略(no/always/on-failure/unless-stopped)--rm          容器退出后自动删除--entrypoint  覆盖入口点-w            设置工作目录

示例:

bash
# 启动 Nginxdocker run -d --name my-nginx -p 80:80 nginx# 启动 MySQLdocker run -d --name my-mysql \  -p 3306:3306 \  -e MYSQL_ROOT_PASSWORD=123456 \  -e MYSQL_DATABASE=travel_db \  -v /data/mysql:/var/lib/mysql \  --restart unless-stopped \  mysql:8.0# 启动 Redisdocker run -d --name my-redis \  -p 6379:6379 \  -e REDIS_PASSWORD=YourRedisPass \  -v /data/redis:/data \  redis:7-alpine redis-server --requirepass YourRedisPass# 进入容器docker run -it --name my-ubuntu ubuntu /bin/bash# 一次性容器(退出即删)docker run --rm -it alpine sh

4.2 查看容器

bash
# 查看运行中的容器docker ps# 查看所有容器(包括已停止的)docker ps -a# 只显示容器 IDdocker ps -q# 自定义格式docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"# 查看最近创建的容器docker ps -ldocker ps -n 5  # 最近 5 个

4.3 启动 / 停止 / 重启

bash
docker start   <容器名或ID>    # 启动docker stop    <容器名或ID>    # 停止(优雅关闭,发送 SIGTERM)docker kill    <容器名或ID>    # 强制停止(SIGKILL)docker restart <容器名或ID>    # 重启# 批量停止所有容器docker stop $(docker ps -q)# 批量删除所有已停止的容器docker container prune

4.4 进入容器

bash
# 方式 1:exec(推荐,不会新建进程)docker exec -it my-nginx /bin/bashdocker exec -it my-nginx sh       # alpine 镜像用 sh# 方式 2:attach(直接连到主进程,退出会导致容器停止)docker attach my-nginx# Ctrl+P, Ctrl+Q 退出而不停止容器# 方式 3:nsenter(高级,需安装)PID=$(docker inspect --format "{{.State.Pid}}" my-nginx)nsenter --target $PID --mount --uts --ipc --net --pid

4.5 查看日志

bash
# 查看全部日志docker logs my-nginx# 实时查看docker logs -f my-nginx# 查看最近 100 行docker logs --tail 100 my-nginx# 查看指定时间后的日志docker logs --since "2024-01-01" my-nginxdocker logs --since 30m my-nginx  # 最近 30 分钟# 带时间戳docker logs -t my-nginx# 导出日志到文件docker logs my-nginx > nginx.log 2>&1

4.6 容器与宿主机文件互传

bash
# 从容器复制到宿主机docker cp my-nginx:/etc/nginx/nginx.conf /tmp/nginx.conf# 从宿主机复制到容器docker cp /tmp/nginx.conf my-nginx:/etc/nginx/nginx.conf# 复制整个目录docker cp my-nginx:/etc/nginx/ /tmp/nginx-config/

4.7 查看容器详情与资源

bash
# 查看容器完整信息docker inspect my-nginx# 查看指定字段docker inspect my-nginx --format '{{.State.Status}}'docker inspect my-nginx --format '{{.NetworkSettings.IPAddress}}'docker inspect my-nginx --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'# 查看容器资源使用(CPU、内存、网络、IO)docker statsdocker stats my-nginx  # 指定容器docker stats --no-stream  # 只输出一次# 查看容器内进程docker top my-nginx# 查看容器端口映射docker port my-nginx

4.8 容器提交为新镜像

bash
# 把容器当前状态保存为新镜像docker commit -m "添加了 vim" -a "作者名" my-ubuntu my-ubuntu:vim# 用新镜像启动docker run -it my-ubuntu:vim /bin/bash

不推荐用 commit 构建生产镜像——无法追溯变更,建议用 Dockerfile。

4.9 导出与导入容器

bash
# 导出容器文件系统为 tar(不是镜像,是快照)docker export my-nginx > nginx.tar# 导入为镜像docker import nginx.tar my-nginx:custom

save/load 操作的是镜像,export/import 操作的是容器快照,后者体积更小但丢失层信息和元数据。


五、Dockerfile

5.1 常用指令

指令 说明 示例
FROM 基础镜像 FROM node:18-alpine
LABEL 元数据 LABEL version="1.0"
RUN 构建时执行命令 RUN apk add --no-cache vim
COPY 复制文件到镜像 COPY . /app
ADD 复制并自动解压 tar ADD app.tar.gz /opt/
WORKDIR 设置工作目录 WORKDIR /app
ENV 环境变量 ENV NODE_ENV=production
ARG 构建参数 ARG VERSION=1.0
EXPOSE 声明端口 EXPOSE 3000
VOLUME 声明数据卷 VOLUME /data
USER 切换用户 USER node
CMD 容器启动命令(可被覆盖) CMD ["node", "app.js"]
ENTRYPOINT 入口点(不易被覆盖) ENTRYPOINT ["node"]
HEALTHCHECK 健康检查 HEALTHCHECK CMD curl -f http://localhost/ || exit 1

5.2 CMD vs ENTRYPOINT

dockerfile
# CMD:可以被 docker run 后面的命令覆盖CMD ["node", "app.js"]# docker run my-app              # 执行 node app.js# docker run my-app ls           # 执行 ls,覆盖了 CMD# ENTRYPOINT:不会被覆盖,CMD 作为参数追加ENTRYPOINT ["node"]CMD ["app.js"]# docker run my-app              # 执行 node app.js# docker run my-app server.js    # 执行 node server.js# 推荐组合:ENTRYPOINT 定命令,CMD 定默认参数

5.3 构建 Spring Boot 镜像

dockerfile
# DockerfileFROM openjdk:17-jdk-slimLABEL maintainer="your-email@example.com"WORKDIR /appCOPY target/my-project.jar app.jarENV TZ=Asia/ShanghaiENV JAVA_OPTS="-Xms512m -Xmx512m"EXPOSE 8080ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
bash
# 构建docker build -t my-project:1.0 .# 带构建参数docker build --build-arg VERSION=1.0 -t my-project:1.0 .# 运行docker run -d --name my-api \  -p 8080:8080 \  -v /data/logs:/app/logs \  --restart unless-stopped \  my-project:1.0

5.4 构建 Vue 前端镜像(Nginx 托管)

dockerfile
# 阶段 1:构建FROM node:18-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm installCOPY . .RUN npm run build# 阶段 2:运行(多阶段构建减小体积)FROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlCOPY nginx.conf /etc/nginx/conf.d/default.confEXPOSE 80CMD ["nginx", "-g", "daemon off;"]
nginx
# nginx.confserver {    listen 80;    location / {        root /usr/share/nginx/html;        try_files $uri $uri/ /index.html;    }}

5.5 多阶段构建优化

dockerfile
# 多阶段构建:最终镜像只包含最后阶段的产物,体积更小FROM node:18 AS buildWORKDIR /appCOPY . .RUN npm ci && npm run buildFROM nginx:alpineCOPY --from=build /app/dist /usr/share/nginx/html# 最终镜像只有 nginx + 静态文件,不带 node_modules

六、数据卷

6.1 三种挂载方式

bash
# 1. 具名卷(推荐生产用)—— Docker 管理docker run -d -v my-data:/var/lib/mysql mysql:8.0# 2. 匿名卷 —— 自动生成随机名docker run -d -v /var/lib/mysql mysql:8.0# 3. 绑定挂载 —— 直接挂宿主路径(开发用)docker run -d -v /data/mysql:/var/lib/mysql mysql:8.0
方式 命令 存储位置 适合场景
具名卷 -v my-data:/path Docker 管理区 生产、数据持久化
匿名卷 -v /path Docker 管理区 临时数据
绑定挂载 -v /host/path:/path 宿主机指定路径 开发、配置文件

6.2 数据卷管理

bash
# 列出所有数据卷docker volume ls# 查看数据卷详情docker volume inspect my-data# 创建数据卷docker volume create my-data# 删除数据卷docker volume rm my-data# 清理未使用的数据卷docker volume prune

6.3 数据备份与恢复

bash
# 备份:把数据卷内容打包到宿主机docker run --rm \  -v my-data:/data:ro \  -v /backup:/backup \  alpine tar czf /backup/my-data.tar.gz -C /data .# 恢复:把备份解压到新数据卷docker run --rm \  -v my-data:/data \  -v /backup:/backup \  alpine sh -c "cd /data && tar xzf /backup/my-data.tar.gz"

6.4 常用挂载场景

bash
# MySQL 数据持久化docker run -d -v /data/mysql:/var/lib/mysql mysql:8.0# Redis 数据持久化docker run -d -v /data/redis:/data redis:7-alpine# Nginx 配置和日志docker run -d \  -v /data/nginx/conf:/etc/nginx/conf.d \  -v /data/nginx/html:/usr/share/nginx/html \  -v /data/nginx/logs:/var/log/nginx \  nginx# 开发热更新(源码挂载进容器)docker run -d \  -v /my-project/src:/app/src \  -p 3000:3000 \  my-node-app

七、网络

7.1 网络模式

模式 说明 使用场景
bridge(默认) 桥接网络,容器通过虚拟网桥通信 通用、单机多容器
host 共享宿主机网络栈,无网络隔离 对网络性能要求高
none 无网络 安全隔离、离线计算
container:xxx 共享另一个容器的网络 容器间紧密耦合

7.2 网络操作

bash
# 列出网络docker network ls# 创建自定义网络(推荐)docker network create my-network# 创建时指定子网和网关docker network create --subnet=172.20.0.0/16 my-network# 查看网络详情docker network inspect my-network# 容器加入网络docker run -d --network my-network --name my-app my-image# 已运行的容器加入网络docker network connect my-network my-container# 断开网络docker network disconnect my-network my-container# 删除网络docker network rm my-networkdocker network prune  # 清理未使用网络

7.3 容器间通信

bash
# 创建网络docker network create app-net# 启动 MySQL(在同一网络)docker run -d --network app-net --name mysql mysql:8.0# 启动后端应用(用容器名作为主机名访问 MySQL)docker run -d --network app-net --name api my-app# 在 api 容器内可以用 mysql:3306 连接数据库# Docker 内置 DNS 会把容器名解析为容器 IP

关键:同一自定义网络中的容器可以用容器名作为主机名互相访问,无需知道 IP。


八、Docker Compose

8.1 安装

Docker Compose V2 已作为 Docker 插件集成,安装 Docker 时自动安装。验证:

bash
docker compose version

8.2 docker-compose.yml 示例

yaml
# docker-compose.ymlversion: '3.8'services:  # MySQL 数据库  mysql:    image: mysql:8.0    container_name: app-mysql    restart: unless-stopped    environment:      MYSQL_ROOT_PASSWORD: rootpassword      MYSQL_DATABASE: travel_db      MYSQL_USER: travel_user      MYSQL_PASSWORD: TravelUserPassword      TZ: Asia/Shanghai    ports:      - "3306:3306"    volumes:      - mysql-data:/var/lib/mysql      - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql  # 启动时执行    networks:      - app-net    healthcheck:      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]      interval: 10s      timeout: 5s      retries: 5  # Redis 缓存  redis:    image: redis:7-alpine    container_name: app-redis    restart: unless-stopped    command: redis-server --requirepass YourRedisPass    ports:      - "6379:6379"    volumes:      - redis-data:/data    networks:      - app-net  # 后端 API  api:    build:      context: ./api      dockerfile: Dockerfile    container_name: app-api    restart: unless-stopped    depends_on:      mysql:        condition: service_healthy      redis:        condition: service_started    environment:      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/travel_db      SPRING_DATASOURCE_USERNAME: travel_user      SPRING_DATASOURCE_PASSWORD: TravelUserPassword      SPRING_REDIS_HOST: redis      SPRING_REDIS_PORT: 6379      SPRING_REDIS_PASSWORD: YourRedisPass    ports:      - "8080:8080"    volumes:      - ./logs:/app/logs      - ./uploads:/app/uploads    networks:      - app-net  # 前端 Nginx  web:    build:      context: ./web      dockerfile: Dockerfile    container_name: app-web    restart: unless-stopped    ports:      - "80:80"      - "443:443"    volumes:      - ./nginx/conf.d:/etc/nginx/conf.d      - ./nginx/cert:/etc/nginx/cert      - ./uploads:/usr/share/nginx/html/uploads    depends_on:      - api    networks:      - app-netvolumes:  mysql-data:  redis-data:networks:  app-net:    driver: bridge

8.3 常用命令

bash
# 在 docker-compose.yml 所在目录执行# 构建镜像docker compose build# 构建且不使用缓存docker compose build --no-cache# 启动所有服务(后台)docker compose up -d# 启动并重新构建镜像docker compose up -d --build# 查看运行状态docker compose ps# 查看日志docker compose logsdocker compose logs -f api          # 实时查看 api 的日志docker compose logs --tail 100 api  # 最近 100 行# 停止并删除容器、网络(保留数据卷)docker compose down# 停止并删除容器、网络、数据卷(⚠️ 数据会丢)docker compose down -v# 重启某个服务docker compose restart api# 重新构建并重启某个服务docker compose up -d --build api# 进入容器docker compose exec api sh# 查看服务配置docker compose config

8.4 环境变量

bash
# .env 文件(与 docker-compose.yml 同目录)MYSQL_ROOT_PASSWORD=rootpasswordAPI_PORT=8080# docker-compose.yml 中引用services:  mysql:    environment:      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}  api:    ports:      - "${API_PORT}:8080"
bash
# 使用不同 env 文件docker compose --env-file .env.production up -d

九、实战部署

9.1 一键部署 MySQL + Redis + Spring Boot + Vue

项目结构:

code
my-project/├── docker-compose.yml├── .env├── mysql/│   └── init.sql├── api/│   ├── Dockerfile│   ├── target/my-project.jar│   └── application.yml├── web/│   ├── Dockerfile│   ├── dist/│   └── nginx.conf└── nginx/    ├── conf.d/    │   └── default.conf    └── cert/
bash
# 一键启动整个项目cd my-projectdocker compose up -d --build# 查看状态docker compose ps# 查看日志docker compose logs -f# 停止docker compose down# 更新某个服务(重新构建)docker compose up -d --build api

9.2 部署 MySQL(含初始化脚本)

bash
docker run -d --name mysql \  -p 3306:3306 \  -e MYSQL_ROOT_PASSWORD=123456 \  -e MYSQL_DATABASE=travel_db \  -e MYSQL_USER=travel_user \  -e MYSQL_PASSWORD=TravelUserPassword \  -v /data/mysql:/var/lib/mysql \  -v /path/to/init.sql:/docker-entrypoint-initdb.d/init.sql \  --restart unless-stopped \  mysql:8.0 \  --character-set-server=utf8mb4 \  --collation-server=utf8mb4_unicode_ci

9.3 部署 Redis

bash
docker run -d --name redis \  -p 6379:6379 \  -v /data/redis:/data \  --restart unless-stopped \  redis:7-alpine \  redis-server --requirepass YourRedisPass \  --maxmemory 256mb \  --maxmemory-policy allkeys-lru \  --appendonly yes

9.4 部署 Nginx

bash
docker run -d --name nginx \  -p 80:80 -p 443:443 \  -v /data/nginx/conf.d:/etc/nginx/conf.d \  -v /data/nginx/html:/usr/share/nginx/html \  -v /data/nginx/logs:/var/log/nginx \  -v /data/nginx/cert:/etc/nginx/cert \  --restart unless-stopped \  nginx:1.25-alpine

9.5 部署 Spring Boot

bash
docker run -d --name api \  -p 8080:8080 \  -v /data/logs:/app/logs \  -v /data/uploads:/app/uploads \  --env-file /path/to/.env \  --restart unless-stopped \  my-project:1.0

9.6 部署 Node.js 应用

dockerfile
FROM node:18-alpineWORKDIR /appCOPY package*.json ./RUN npm ci --productionCOPY . .EXPOSE 3000CMD ["node", "dist/main.js"]
bash
docker run -d --name node-app \  -p 3000:3000 \  -v /data/logs:/app/logs \  --restart unless-stopped \  my-node-app:1.0

十、镜像加速

10.1 配置国内镜像源

bash
# 编辑 /etc/docker/daemon.json{  "registry-mirrors": [    "https://mirror.ccs.tencentyun.com",    "https://docker.mirrors.ustc.edu.cn",    "https://hub-mirror.c.163.com"  ]}# 重启systemctl daemon-reloadsystemctl restart docker# 验证docker info | grep -A 5 "Registry Mirrors"

10.2 使用私有仓库

bash
# 登录docker login registry.example.com# 打标签docker tag my-app:1.0 registry.example.com/my-app:1.0# 推送docker push registry.example.com/my-app:1.0# 拉取docker pull registry.example.com/my-app:1.0

10.3 搭建私有仓库

bash
# 启动私有仓库docker run -d -p 5000:5000 --name registry \  -v /data/registry:/var/lib/registry \  --restart always \  registry:2# 使用(HTTP 不安全,需配置 insecure-registries)# /etc/docker/daemon.json 添加:# { "insecure-registries": ["your-server-ip:5000"] }

十一、常用命令速查

镜像操作

命令 说明
docker images 列出本地镜像
docker search xxx 搜索镜像
docker pull xxx 拉取镜像
docker rmi xxx 删除镜像
docker tag old new 打标签
docker save -o file.tar xxx 保存为 tar
docker load -i file.tar 从 tar 加载
docker build -t name:tag . 构建镜像
docker history xxx 查看镜像层
docker inspect xxx 查看详情
docker image prune 清理悬空镜像
docker image prune -a 清理所有未使用镜像

容器操作

命令 说明
docker run -d --name xxx IMAGE 后台启动
docker run -it IMAGE sh 交互式启动
docker ps 查看运行中容器
docker ps -a 查看所有容器
docker start/stop/restart xxx 启动/停止/重启
docker kill xxx 强制停止
docker exec -it xxx sh 进入容器
docker logs -f xxx 查看日志
docker cp xxx:/path /host 容器→宿主机
docker cp /host xxx:/path 宿主机→容器
docker stats 资源使用
docker top xxx 容器内进程
docker inspect xxx 容器详情
docker rm xxx 删除容器
docker rm -f xxx 强制删除
docker container prune 清理已停止容器

数据卷

命令 说明
docker volume ls 列出数据卷
docker volume create xxx 创建
docker volume inspect xxx 详情
docker volume rm xxx 删除
docker volume prune 清理未使用

网络

命令 说明
docker network ls 列出网络
docker network create xxx 创建
docker network inspect xxx 详情
docker network connect net container 连接
docker network disconnect net container 断开
docker network prune 清理未使用

Compose

命令 说明
docker compose up -d 启动所有
docker compose up -d --build 重新构建并启动
docker compose down 停止并删除
docker compose down -v 连数据卷一起删
docker compose ps 查看状态
docker compose logs -f 实时日志
docker compose restart xxx 重启某服务
docker compose exec xxx sh 进入容器
docker compose build 构建镜像

系统清理

命令 说明
docker system df 查看 Docker 磁盘占用
docker system prune 一键清理(容器+镜像+网络+数据卷)
docker system prune -a 清理所有未使用资源
docker system prune -a --volumes 连数据卷一起清理

十二、常见问题

12.1 磁盘占用过大

bash
# 查看 Docker 占用docker system df# 清理悬空镜像docker image prune# 清理所有未使用镜像docker image prune -a# 清理停止的容器docker container prune# 清理未使用的数据卷docker volume prune# 一键清理docker system prune -a# 查看 /var/lib/docker 大文件du -sh /var/lib/docker/*

12.2 端口冲突

bash
# 查看端口被谁占用lsof -i:8080# 或netstat -tlnp | grep 8080# 停止占用端口的容器或进程docker stop <container># 或kill <PID># 修改容器端口映射docker stop my-containerdocker rm my-containerdocker run -d -p 9090:8080 ...  # 换个端口

12.3 容器内中文乱码

bash
# 进入容器后设置 localedocker exec -it my-container env LANG=C.UTF-8 LC_ALL=C.UTF-8# 或在 Dockerfile 中设置ENV LANG=C.UTF-8ENV LC_ALL=C.UTF-8

12.4 容器无法联网

bash
# 检查网络docker network lsdocker network inspect bridge# 重启 Docker 服务systemctl restart docker# 检查 iptablesiptables -L -n# 如果规则丢失,重启 Docker 会自动重建# 使用 host 网络测试docker run --rm --network host alpine ping 8.8.8.8

12.5 权限问题

bash
# 挂载目录权限不足chmod -R 755 /data/mysql# SELinux 导致挂载失败# 临时关闭setenforce 0# 或挂载时加 :Zdocker run -v /data/mysql:/var/lib/mysql:Z mysql:8.0# 以非 root 用户运行docker run -u 1000:1000 ...

12.6 容器自动退出

bash
# 查看退出原因docker inspect <container> --format '{{.State.ExitCode}} {{.State.Error}}'docker logs <container># 常见原因:# 1. CMD 命令执行完就退出(前台进程结束)# 2. 容器内应用崩溃# 3. 内存不足被 OOM Killer 杀掉docker inspect <container> --format '{{.State.OOMKilled}}'

12.7 时区不正确

bash
# 方式 1:环境变量docker run -e TZ=Asia/Shanghai ...# 方式 2:挂载宿主机时区文件docker run -v /etc/localtime:/etc/localtime:ro \           -v /etc/timezone:/etc/timezone:ro \           ...# Dockerfile 中ENV TZ=Asia/ShanghaiRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

十三、最佳实践

13.1 镜像优化

  1. 用 alpine 基础镜像:node:18-alpine 比 node:18 小 10 倍
  2. 多阶段构建:构建阶段用大镜像,运行阶段只复制产物
  3. 合并 RUN 指令:减少镜像层数
  4. .dockerignore:排除 node_modules、.git 等
  5. 合理利用缓存:先 COPY package.json 再 npm install,最后 COPY 源码
dockerfile
# 好的写法(利用缓存)COPY package*.json ./RUN npm ciCOPY . .              # 源码变了不会重新 npm install# 不好的写法(每次都重新 install)COPY . .RUN npm ci
code
# .dockerignorenode_modulesnpm-debug.log.git.gitignore.envdistcoverage*.md

13.2 安全

  1. 不用 root 运行:USER node 切换非 root 用户
  2. 不存敏感信息:密码用环境变量或 secret,不要写进 Dockerfile
  3. 用官方镜像:不用来路不明的镜像
  4. 定期更新基础镜像:修复已知漏洞
  5. 扫描镜像漏洞:docker scan my-image

13.3 生产注意事项

  1. 用 --restart unless-stopped:容器异常退出自动重启
  2. 数据卷用具名卷:方便备份和迁移
  3. 日志限制大小:daemon.json 配置 log-opts
  4. 资源限制:--memory、--cpus 防止单容器吃光资源
  5. 健康检查:HEALTHCHECK 让 Docker 知道容器是否真的健康
  6. 用 Compose 编排:多容器项目不要手动 run
  7. CI/CD 自动构建:代码推送 → 自动构建镜像 → 推到仓库
bash
# 资源限制示例docker run -d \  --memory=512m \  --memory-swap=1g \  --cpus=1.5 \  --restart unless-stopped \  my-app

总结

Docker 的核心就三件事:

  1. 镜像是模板——Dockerfile 描述怎么构建,build 生成镜像
  2. 容器是实例——run 从镜像启动容器,exec 进入操作
  3. Compose 是编排——多容器一键启动,up -d 搞定一切

记住几个高频命令就能应付日常 90% 的场景:

bash
docker ps                    # 看有哪些容器在跑docker logs -f <name>        # 看日志docker exec -it <name> sh    # 进容器docker compose up -d         # 一键启动docker compose down          # 一键停止docker system prune -a       # 清理磁盘

Docker 不是魔法,它只是把"应用 + 环境"打包成了一个标准单元。 学会 Dockerfile 和 Compose,就能把任何应用变成"一键部署"。

前端、后端、部署、客服都是我一个人。写这里的东西都是真踩过的坑,不是抄来的教程。