Docker 常用操作手册
Docker 是一个开源的应用容器引擎,让开发者可以打包应用及其依赖到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。本文从概念到实战,覆盖日常 90% 的操作场景。
一、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
# 卸载旧版本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-world2.2 Ubuntu
# 更新包索引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 docker2.3 Windows / Mac
- 下载 Docker Desktop:https://www.docker.com/products/docker-desktop
- 安装后启动 Docker Desktop
- 验证:终端运行
docker --version
2.4 镜像加速配置
# 编辑配置文件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 搜索镜像
# 在 Docker Hub 搜索docker search mysqldocker search nginx --limit 5 # 只显示前 5 个# 输出列:# NAME 镜像名# DESCRIPTION 描述# STARS 点赞数(越高越热门)# OFFICIAL 是否官方 [OK]# AUTOMATED 是否自动构建3.2 拉取镜像
# 默认拉 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.03.3 查看镜像
# 列出本地镜像docker images# 只显示镜像 IDdocker images -q# 过滤显示docker images --filter "dangling=true" # 只显示悬空镜像(无标签的中间层)docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" # 自定义格式3.4 删除镜像
# 按 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 -a3.5 镜像标签
# 给镜像打标签docker tag mysql:8.0 my-mysql:v1# 推送到私有仓库前打标签docker tag my-app:latest registry.example.com/my-app:v1.03.6 镜像保存与加载
# 保存镜像为 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 查看镜像详情
# 查看镜像的完整信息docker inspect mysql:8.0# 查看镜像构建层docker history mysql:8.0# 查看 MySQL 镜像的架构信息docker inspect mysql:8.0 --format '{{.Architecture}} {{.Os}}'四、容器操作
4.1 创建并启动容器
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 设置工作目录示例:
# 启动 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 sh4.2 查看容器
# 查看运行中的容器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 启动 / 停止 / 重启
docker start <容器名或ID> # 启动docker stop <容器名或ID> # 停止(优雅关闭,发送 SIGTERM)docker kill <容器名或ID> # 强制停止(SIGKILL)docker restart <容器名或ID> # 重启# 批量停止所有容器docker stop $(docker ps -q)# 批量删除所有已停止的容器docker container prune4.4 进入容器
# 方式 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 --pid4.5 查看日志
# 查看全部日志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>&14.6 容器与宿主机文件互传
# 从容器复制到宿主机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 查看容器详情与资源
# 查看容器完整信息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-nginx4.8 容器提交为新镜像
# 把容器当前状态保存为新镜像docker commit -m "添加了 vim" -a "作者名" my-ubuntu my-ubuntu:vim# 用新镜像启动docker run -it my-ubuntu:vim /bin/bash不推荐用 commit 构建生产镜像——无法追溯变更,建议用 Dockerfile。
4.9 导出与导入容器
# 导出容器文件系统为 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
# 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 镜像
# 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"]# 构建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.05.4 构建 Vue 前端镜像(Nginx 托管)
# 阶段 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.confserver { listen 80; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; }}5.5 多阶段构建优化
# 多阶段构建:最终镜像只包含最后阶段的产物,体积更小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 三种挂载方式
# 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 数据卷管理
# 列出所有数据卷docker volume ls# 查看数据卷详情docker volume inspect my-data# 创建数据卷docker volume create my-data# 删除数据卷docker volume rm my-data# 清理未使用的数据卷docker volume prune6.3 数据备份与恢复
# 备份:把数据卷内容打包到宿主机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 常用挂载场景
# 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 网络操作
# 列出网络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 容器间通信
# 创建网络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 时自动安装。验证:
docker compose version8.2 docker-compose.yml 示例
# 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: bridge8.3 常用命令
# 在 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 config8.4 环境变量
# .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"# 使用不同 env 文件docker compose --env-file .env.production up -d九、实战部署
9.1 一键部署 MySQL + Redis + Spring Boot + Vue
项目结构:
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/# 一键启动整个项目cd my-projectdocker compose up -d --build# 查看状态docker compose ps# 查看日志docker compose logs -f# 停止docker compose down# 更新某个服务(重新构建)docker compose up -d --build api9.2 部署 MySQL(含初始化脚本)
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_ci9.3 部署 Redis
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 yes9.4 部署 Nginx
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-alpine9.5 部署 Spring Boot
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.09.6 部署 Node.js 应用
FROM node:18-alpineWORKDIR /appCOPY package*.json ./RUN npm ci --productionCOPY . .EXPOSE 3000CMD ["node", "dist/main.js"]docker run -d --name node-app \ -p 3000:3000 \ -v /data/logs:/app/logs \ --restart unless-stopped \ my-node-app:1.0十、镜像加速
10.1 配置国内镜像源
# 编辑 /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 使用私有仓库
# 登录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.010.3 搭建私有仓库
# 启动私有仓库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 磁盘占用过大
# 查看 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 端口冲突
# 查看端口被谁占用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 容器内中文乱码
# 进入容器后设置 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-812.4 容器无法联网
# 检查网络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.812.5 权限问题
# 挂载目录权限不足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 容器自动退出
# 查看退出原因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 时区不正确
# 方式 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 镜像优化
- 用 alpine 基础镜像:
node:18-alpine比node:18小 10 倍 - 多阶段构建:构建阶段用大镜像,运行阶段只复制产物
- 合并 RUN 指令:减少镜像层数
- .dockerignore:排除 node_modules、.git 等
- 合理利用缓存:先 COPY package.json 再 npm install,最后 COPY 源码
# 好的写法(利用缓存)COPY package*.json ./RUN npm ciCOPY . . # 源码变了不会重新 npm install# 不好的写法(每次都重新 install)COPY . .RUN npm ci# .dockerignorenode_modulesnpm-debug.log.git.gitignore.envdistcoverage*.md13.2 安全
- 不用 root 运行:
USER node切换非 root 用户 - 不存敏感信息:密码用环境变量或 secret,不要写进 Dockerfile
- 用官方镜像:不用来路不明的镜像
- 定期更新基础镜像:修复已知漏洞
- 扫描镜像漏洞:
docker scan my-image
13.3 生产注意事项
- 用
--restart unless-stopped:容器异常退出自动重启 - 数据卷用具名卷:方便备份和迁移
- 日志限制大小:daemon.json 配置
log-opts - 资源限制:
--memory、--cpus防止单容器吃光资源 - 健康检查:
HEALTHCHECK让 Docker 知道容器是否真的健康 - 用 Compose 编排:多容器项目不要手动 run
- CI/CD 自动构建:代码推送 → 自动构建镜像 → 推到仓库
# 资源限制示例docker run -d \ --memory=512m \ --memory-swap=1g \ --cpus=1.5 \ --restart unless-stopped \ my-app总结
Docker 的核心就三件事:
- 镜像是模板——Dockerfile 描述怎么构建,
build生成镜像 - 容器是实例——
run从镜像启动容器,exec进入操作 - Compose 是编排——多容器一键启动,
up -d搞定一切
记住几个高频命令就能应付日常 90% 的场景:
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,就能把任何应用变成"一键部署"。