1. 项目概述:为什么Docker能成为效率倍增器?

如果你还在为“在我机器上能跑”的经典问题头疼,或者每次新同事入职都要花半天配环境,那Docker就是你一直在等的那个答案。这玩意儿不是什么银弹,但它确实能把开发、测试、部署里那些重复、琐碎又容易出错的脏活累活,打包成一个标准化的“集装箱”。我见过太多团队,从手动配环境到全面容器化之后,效率的提升不是百分之几十,而是几倍的增长。说“暴涨300%”听起来像营销口号,但当你真正把镜像构建、服务编排、CI/CD流水线都跑通之后,回头看看那些被省下来的时间,你会发现这个数字甚至可能保守了。

Docker的核心价值,在于它提供了一种全新的软件交付和运行范式。它把应用及其完整的运行环境(包括代码、运行时、系统工具、系统库和设置)一起打包成一个轻量级、可移植的容器。这个容器在任何安装了Docker引擎的地方,表现都完全一致。这意味着,从你本地Mac的IDE,到测试团队的Linux服务器,再到云上的生产环境,应用的行为不会有任何神秘差异。对于开发者而言,最直接的感受就是:再也不用写冗长的环境配置文档了,再也不用处理“依赖地狱”了,一键就能拉起一个包含Redis、MySQL、消息队列的完整开发环境。

2. 核心知识点深度拆解与实战脉络

要真正玩转Docker,把它从“一个能用命令的工具”变成“提升研发效能的体系化工程实践”,需要系统性地掌握十个环环相扣的核心知识点。它们不是孤立的命令集合,而是一个从入门到精通的技能树。

2.1 容器与镜像:理解基石与构建物

这是最根本的一对概念,必须掰扯清楚。 镜像(Image) 是一个只读的模板,里面包含了运行容器所需的文件系统结构和内容。你可以把它理解为一个软件的“安装包”或者“蓝图”。这个安装包是分层的,每一层代表对文件系统的一次修改(比如添加一个软件包,修改一个配置文件)。这种分层机制是Docker轻量化和高效复用的秘密。

容器(Container) 则是镜像的一个运行实例。当你基于一个镜像启动容器时,Docker会在镜像的只读层之上,添加一个可写的“容器层”。所有运行时的修改(比如应用产生的日志、上传的文件、临时数据)都发生在这个可写层。当容器被删除时,这个可写层也随之消失,这保证了容器的“无状态性”和可丢弃性。一个镜像可以同时运行出多个容器,它们相互隔离。

实战心得 :很多新手会把容器当成虚拟机,这是一个常见的误解。虚拟机虚拟化的是整个硬件和操作系统(Guest OS),而容器只是利用宿主机的操作系统内核,通过命名空间(Namespace)和控制组(Cgroup)实现进程、网络、文件系统等资源的隔离,因此它更轻量、启动更快(秒级 vs 分钟级)、资源开销更小。理解这一点,你就能明白为什么容器不适合运行所有类型的应用(比如需要特殊内核模块的应用)。

2.2 Dockerfile:从零到一构建自定义镜像

镜像是从哪来的?除了从Docker Hub拉取现成的,更多时候我们需要自己构建。Dockerfile就是一个纯文本的构建脚本,里面包含了一系列的指令,告诉Docker如何一步步组装我们的镜像。

一个典型的Dockerfile是这样的:

# 1. 指定基础镜像
FROM node:18-alpine AS builder
# 2. 设置工作目录
WORKDIR /app
# 3. 复制依赖定义文件
COPY package*.json ./
# 4. 安装依赖(利用缓存层)
RUN npm ci --only=production
# 5. 复制应用源码
COPY . .
# 6. 构建应用
RUN npm run build

# 7. 多阶段构建:使用更小的运行时镜像
FROM nginx:alpine
# 8. 从上一阶段复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 9. 暴露端口
EXPOSE 80
# 10. 定义启动命令
CMD [“nginx”, “-g”, “daemon off;”]

关键指令解析

  • FROM :一切镜像的起点,必须且只能是第一条有效指令(ARG除外)。选择合适的基础镜像(如 alpine , slim 版本)能极大减小最终镜像体积。
  • RUN :在构建过程中执行命令。每一条 RUN 都会创建一个新的镜像层。为了减少层数,通常用 && 将多个命令串联,并用 \ 换行保持可读性。
  • COPY vs ADD :优先使用 COPY ,它更透明。 ADD 有额外的功能(如解压tar包,从URL下载),但行为不够清晰。
  • CMD vs ENTRYPOINT CMD 定义容器启动时默认执行的命令及其参数,容易被 docker run 后面的命令覆盖。 ENTRYPOINT 更像是容器的“二进制文件”, CMD 的内容会作为参数传给 ENTRYPOINT 。两者组合使用非常灵活。

避坑指南

  • 层缓存与构建优化 :Docker会缓存每一步的结果。把变化最频繁的步骤(如 COPY . . )放在Dockerfile后面,把变化最少的步骤(如 RUN apt-get update )放在前面,能最大化利用缓存,加速构建。
  • 多阶段构建(Multi-stage) :如上例所示,它允许你在一个Dockerfile中使用多个 FROM 指令。你可以在一个阶段( builder )使用包含完整编译工具的大镜像进行构建,然后在另一个阶段只复制构建产物到一个小巧的运行时镜像中。这是减小生产镜像体积(从GB级到MB级)的黄金法则。
  • 不要以root用户运行 :在Dockerfile中,最后应使用 USER 指令切换到一个非root用户,以增强安全性。例如: USER node

2.3 镜像仓库:分发与协作的中枢

构建好的镜像需要有个地方存放和分享,这就是镜像仓库(Registry)。Docker Hub是默认的公共仓库,你可以拉取无数开源软件的官方镜像。但对于公司内部项目,你需要搭建私有仓库。

自建私有仓库 :使用官方 registry 镜像可以快速搭建。

# 拉取镜像
docker pull registry:2
# 运行仓库容器
docker run -d -p 5000:5000 --name my-registry -v /path/to/data:/var/lib/registry registry:2

现在,你就可以向 localhost:5000/your-image:tag 推送镜像了。

企业级实践 :在生产环境,你可能会用到Harbor。它提供了图形化界面、镜像漏洞扫描、复制策略、基于角色的访问控制等企业级功能,是私有仓库的绝佳选择。

镜像命名与推送

# 给本地镜像打上私有仓库的标签
docker tag my-app:latest localhost:5000/my-app:v1.0
# 推送镜像到私有仓库
docker push localhost:5000/my-app:v1.0
# 从私有仓库拉取
docker pull localhost:5000/my-app:v1.0

注意事项 :对于非 localhost 的私有仓库地址(如 registry.mycompany.com ),如果使用HTTP而非HTTPS,需要在Docker守护进程配置( /etc/docker/daemon.json )中添加 insecure-registries 配置,并重启Docker服务。生产环境强烈建议配置TLS证书。

2.4 容器网络:打通隔离世界的桥梁

默认情况下,容器拥有独立的网络命名空间。Docker提供了几种网络模式,理解它们对部署多容器应用至关重要。

  • bridge(桥接) :默认模式。Docker会创建一个名为 docker0 的虚拟网桥,容器会连接到这个网桥,并分配一个私有IP。容器间可以通过IP通信,但外部网络需要通过端口映射( -p )才能访问容器。
  • host(主机) :容器直接使用宿主机的网络命名空间,没有隔离。容器性能最好,但端口冲突风险高。
  • none(无) :容器没有网络接口,只有lo回环地址。用于需要极致安全或自定义网络的场景。
  • container(容器) :新容器共享另一个容器的网络命名空间,两者网络视图完全一致。

创建自定义网络 :使用默认的bridge网络时,容器间只能通过IP访问,无法通过容器名解析。创建自定义的bridge网络可以解决这个问题。

# 创建自定义网络
docker network create my-app-net
# 运行容器时指定网络
docker run -d --name mysql --network my-app-net -e MYSQL_ROOT_PASSWORD=secret mysql:8
docker run -d --name app --network my-app-net -p 8080:80 my-app-image

现在,在 app 容器中,你可以直接使用 mysql 这个主机名来连接到MySQL容器,Docker内置的DNS会完成解析。

网络诊断命令

  • docker network ls :列出所有网络。
  • docker network inspect my-app-net :查看网络详情,包括连接的容器和IP分配。
  • docker exec -it app ping mysql :在容器内测试网络连通性。

2.5 数据持久化:超越容器生命周期的存储

容器的文件系统是临时的,容器删除,其可写层的数据也就没了。但很多应用(如数据库、文件上传)的数据需要持久化。Docker提供了三种主要方式:

  1. 绑定挂载(Bind Mount) :将宿主机上的一个目录或文件直接挂载到容器中。两者完全同步。

    docker run -v /宿主机/绝对路径:/容器内路径 nginx
    

    优点 :性能最好,修改即时可见。 缺点 :依赖宿主机特定路径,移植性差。

  2. 卷(Volume) :由Docker管理的数据存储区域,位于宿主机文件系统中(通常是 /var/lib/docker/volumes/ ),但路径对用户透明。

    # 创建卷
    docker volume create my-data
    # 使用卷
    docker run -v my-data:/容器内路径 mysql
    

    优点 :是Docker推荐的方式,易于备份、迁移和管理,与宿主机文件系统解耦。 缺点 :性能略低于绑定挂载(但通常可忽略)。

  3. 临时文件系统(tmpfs) :将数据存储在宿主机的内存中,容器停止,数据消失。适用于存储敏感信息或不需要持久化的临时文件。

    docker run --tmpfs /容器内路径 nginx
    

实战选择

  • 配置文件、代码 :在开发时,使用 绑定挂载 ,这样你可以在宿主机用IDE修改代码,容器内实时生效,实现热重载。
  • 数据库数据、上传的文件 :在生产环境,永远使用 来持久化重要数据。定期备份卷( docker run --volumes-from 配合备份工具)是你的生命线。
  • 敏感信息(密码、密钥) :不要放在镜像或环境变量里(环境变量在容器内仍可见)。使用Docker Secrets(Swarm模式)或第三方密钥管理服务(如HashiCorp Vault),或者通过只读的绑定挂载传入。

2.6 Docker Compose:定义和运行多容器应用的利器

当你的应用由多个服务组成(比如一个Web应用+一个数据库+一个缓存),用一堆 docker run 命令来管理简直是噩梦。Docker Compose通过一个 docker-compose.yml 文件,让你能用声明式的方式定义和运行整个应用栈。

一个典型的 docker-compose.yml

version: ‘3.8’
services:
  web:
    build: . # 基于当前目录的Dockerfile构建
    ports:
      - “8080:80”
    depends_on:
      - db
      - redis
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./app:/code # 开发时挂载代码
      - log-volume:/var/log/app
    networks:
      - app-net

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: mydb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-net

  redis:
    image: redis:7-alpine
    networks:
      - app-net

volumes:
  postgres-data:
  log-volume:

networks:
  app-net:
    driver: bridge

核心优势

  • 一键启停 docker-compose up -d 启动所有服务, docker-compose down 停止并清理。
  • 服务依赖 depends_on 确保服务启动顺序(注意:它只控制启动顺序,不保证服务已“就绪”,对于数据库,应用层需要有重连逻辑)。
  • 环境隔离 :每个Compose项目默认创建独立的网络,项目间服务默认不互通。
  • 变量与扩展 :支持使用 .env 文件定义环境变量,以及使用 extends 复用配置。

进阶技巧

  • 使用 docker-compose up --build 在启动前重新构建镜像。
  • 使用 docker-compose config 验证和查看最终的组合配置。
  • 为生产环境编写一个 docker-compose.prod.yml ,覆盖开发配置(如移除代码卷挂载,设置不同的环境变量)。

2.7 容器编排初探:当Compose不够用时

Docker Compose解决了单机多容器的问题。但当你的服务需要部署到多台机器、需要自动伸缩、滚动更新、服务发现和负载均衡时,就需要容器编排工具了。Kubernetes (K8s) 是当前的事实标准,但学习曲线陡峭。Docker自带的Swarm模式是一个更轻量、更简单的入门选择。

Docker Swarm核心概念

  • 节点 :分为管理节点(Manager)和工作节点(Worker)。Manager负责集群状态调度,Worker运行任务。
  • 服务 :定义了在集群中要运行的任务模板(使用哪个镜像、多少副本、端口、网络等)。
  • 任务 :服务的一个运行实例,对应一个容器。
  • :一组相互关联的服务的集合,类似于Compose项目,通过 docker stack deploy 部署。

快速创建一个Swarm集群

# 在想要作为管理节点的机器上初始化Swarm
docker swarm init --advertise-addr <MANAGER-IP>
# 命令会输出一个用于加入工作节点的token,在其他机器上运行即可加入集群
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

使用Stack部署服务 : 将你的 docker-compose.yml 文件稍作修改(主要是移除 build ,改用 image 指定已推送到仓库的镜像),然后就可以部署了。

# 部署栈
docker stack deploy -c docker-compose.yml my-app
# 查看服务状态
docker service ls
docker service ps my-app_web
# 查看栈内服务日志
docker service logs -f my-app_web

Swarm vs Kubernetes :对于中小型项目或刚接触编排的团队,Swarm足够简单易用,能解决基本的服务部署、伸缩和网络问题。它的配置与Docker Compose高度兼容,学习成本低。但当你的应用架构变得极其复杂,需要更精细的部署策略(如蓝绿部署、金丝雀发布)、自定义资源调度、复杂的网络策略时,Kubernetes是更强大的选择。你可以把Swarm看作编排的“训练轮”。

2.8 Docker与CI/CD:自动化流水线的核心引擎

持续集成和持续部署是现代软件开发的标配,而Docker在其中扮演了环境标准化和构建物标准化的关键角色。

在CI中的典型流程

  1. 代码提交 :触发CI流水线(如Jenkins、GitLab CI、GitHub Actions)。
  2. 构建镜像 :流水线在一个干净的代理(Agent)中拉取代码,执行 docker build ,根据Dockerfile构建应用镜像。
  3. 运行测试 :使用构建好的镜像启动容器,在容器内运行单元测试、集成测试。
  4. 推送镜像 :测试通过后,给镜像打上标签(如 $CI_COMMIT_SHA $CI_PIPELINE_ID ),推送到私有镜像仓库。

一个GitLab CI的 .gitlab-ci.yml 示例

stages:
  - build
  - test
  - push

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build:
  stage: build
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
  only:
    - main # 仅对main分支执行构建推送

test:
  stage: test
  script:
    - docker run --rm $IMAGE_TAG npm test # 假设是Node项目

在CD中的实践

  1. 部署到环境 :CD流水线从仓库拉取指定版本的镜像,在目标环境(开发、测试、生产)中,通过 docker run docker stack deploy kubectl apply 来部署。
  2. 回滚 :回滚变得极其简单,只需要重新部署上一个版本的镜像即可。

关键收益

  • 环境一致性 :测试环境用的镜像和生产环境一模一样,彻底杜绝“环境差异”导致的bug。
  • 构建一次,到处运行 :镜像成为唯一的交付物,简化了部署流程。
  • 快速回滚 :版本化的镜像让回滚操作秒级完成。

2.9 镜像安全与最佳实践

容器安全是一个大话题,从镜像构建开始就需要注意。

  1. 使用可信的基础镜像 :优先选择官方镜像,并指定具体的版本标签(如 node:18.18.0-alpine ),避免使用 latest ,因为它会变。定期更新基础镜像以获取安全补丁。
  2. 最小化镜像体积
    • 使用Alpine Linux等超小型基础镜像。
    • 使用多阶段构建,只将运行时必要的文件复制到最终镜像。
    • RUN 指令中,记得清理apt或apk的缓存( rm -rf /var/lib/apt/lists/* )。
  3. 以非root用户运行 :在Dockerfile末尾使用 USER 指令。
    RUN groupadd -r appuser && useradd -r -g appuser appuser
    USER appuser
    
  4. 扫描镜像漏洞 :使用 docker scan 命令(集成Snyk)或Trivy、Clair等工具,在CI流水线中加入镜像安全扫描步骤。
    docker scan my-image:tag
    
  5. 限制容器资源 :使用 -m --cpus 等参数限制容器的内存和CPU使用,防止单个容器耗尽主机资源。
    docker run -m 512m --cpus=“1.5” my-app
    

2.10 性能监控与日志管理

容器化应用跑起来之后,你需要知道它是否健康,性能如何。

日志管理

  • Docker默认的日志驱动是 json-file ,日志会存储在宿主机的 /var/lib/docker/containers/<container-id>/ 目录下。
  • 使用 docker logs <container> 查看容器日志。
  • 对于生产环境,建议配置日志驱动为 journald (如果宿主机使用systemd)或 syslog ,或者更好的是,使用 fluentd logstash 等日志收集器,将容器日志统一收集到Elasticsearch、Loki等中心化日志平台。

资源监控

  • docker stats :实时查看容器的CPU、内存、网络IO、磁盘IO使用情况。
  • docker top <container> :查看容器内运行的进程。
  • 更全面的监控方案:使用cAdvisor(容器资源监控)+ Prometheus(指标收集与告警)+ Grafana(可视化仪表盘)的组合。cAdvisor本身也是一个容器,部署非常方便。

健康检查 : 在Dockerfile或Compose文件中定义健康检查,Docker引擎会定期执行,并根据结果判断容器状态。

# 在Dockerfile中
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/health || exit 1
# 在docker-compose.yml中
services:
  web:
    image: nginx
    healthcheck:
      test: [“CMD”, “curl”, “-f”, “http://localhost”]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 5s

健康状态会显示在 docker ps 中,并且可以被编排工具(如Swarm、K8s)用来决定是否进行服务发现和流量路由。

3. 从理论到实践:一个全栈项目的容器化实战

让我们用一个具体的例子串联起上述知识点:容器化一个简单的“待办事项”全栈应用(React前端 + Node.js API + PostgreSQL数据库)。

3.1 项目结构与Dockerfile编写

假设项目结构如下:

todo-app/
├── frontend/          # React前端
│   ├── Dockerfile
│   └── ...
├── backend/           # Node.js后端
│   ├── Dockerfile
│   └── ...
└── docker-compose.yml

后端Dockerfile ( backend/Dockerfile ) :

# 多阶段构建:构建阶段
FROM node:18-alpine AS builder
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# 假设需要编译TypeScript等
# RUN npm run build

# 多阶段构建:运行阶段
FROM node:18-alpine
WORKDIR /usr/src/app
ENV NODE_ENV=production
USER node
COPY --from=builder --chown=node:node /usr/src/app/node_modules ./node_modules
COPY --from=builder --chown=node:node /usr/src/app ./
EXPOSE 3000
CMD [“node”, “server.js”]

前端Dockerfile ( frontend/Dockerfile ) :

# 构建阶段
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 使用Nginx提供静态文件
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
# 可以复制自定义的nginx配置
# COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

3.2 使用Docker Compose编排

docker-compose.yml :

version: ‘3.8’
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: todo
      POSTGRES_PASSWORD: secretpassword
      POSTGRES_DB: todos
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - app-network
    healthcheck: # 添加健康检查
      test: [“CMD-SHELL”, “pg_isready -U todo”]
      interval: 10s
      timeout: 5s
      retries: 5

  backend:
    build: ./backend
    environment:
      DATABASE_URL: postgres://todo:secretpassword@postgres:5432/todos
      NODE_ENV: production
    ports:
      - “3000:3000”
    depends_on:
      postgres:
        condition: service_healthy # 等待数据库健康
    networks:
      - app-network
    restart: unless-stopped

  frontend:
    build: ./frontend
    ports:
      - “80:80”
    depends_on:
      - backend
    networks:
      - app-network
    restart: unless-stopped

volumes:
  postgres_data:

networks:
  app-network:
    driver: bridge

3.3 开发、测试与生产配置管理

开发环境 :你可能希望前端和后端代码变更能热重载。可以创建一个 docker-compose.override.yml 文件(Compose会自动合并),用于开发。

# docker-compose.override.yml
version: ‘3.8’
services:
  backend:
    volumes:
      - ./backend:/usr/src/app # 挂载代码,实现热更新
      - /usr/src/app/node_modules # 匿名卷,防止覆盖容器内的node_modules
    environment:
      NODE_ENV: development
    command: npm run dev # 覆盖原CMD,使用开发命令

  frontend:
    build:
      context: ./frontend
      target: build # 只构建到build阶段,不复制到nginx
    volumes:
      - ./frontend:/app
      - /app/node_modules
    ports:
      - “3001:3000” # React开发服务器端口
    command: npm start # 启动开发服务器
    # 移除depends_on,因为开发服务器需要独立运行

开发时,运行 docker-compose up ,它会自动合并基础配置和override配置,给你一个带热重载的开发环境。

生产部署

  1. 为每个服务构建生产镜像并推送到私有仓库。
    docker-compose -f docker-compose.yml build
    docker-compose -f docker-compose.yml push
    
  2. 在生产服务器上,拉取镜像并使用生产Compose文件(或转换为Stack)部署。
    # 使用Stack部署(Swarm模式)
    docker stack deploy -c docker-compose.yml todo-app
    # 或者直接使用Compose(单机)
    docker-compose -f docker-compose.yml up -d
    

4. 进阶:容器化常见问题与排查心法

即使掌握了所有命令,在实际操作中还是会踩坑。这里记录一些高频问题和我的排查思路。

4.1 容器启动失败:“Exited (1)”

这是最常见的问题。容器启动后立即退出。

  • 第一步:查看日志 docker logs <container-name> 是首要命令。90%的问题原因都在日志里。
  • 第二步:检查启动命令 docker run 或Dockerfile中的 CMD / ENTRYPOINT 是否正确?命令是否存在?可以通过 docker run -it <image> sh 进入镜像内部手动执行命令调试。
  • 第三步:检查端口冲突 docker run -p 80:80 ,如果宿主机80端口已被占用,容器会启动失败。用 netstat -tulpn | grep :80 检查。
  • 第四步:检查依赖服务 。如果你的应用依赖其他容器(如数据库),确保它们先启动并且健康。在Compose中使用 depends_on + condition: service_healthy 是更好的实践。

4.2 容器内应用无法连接数据库或其他服务

“Connection refused”或“Host not found”。

  • 确认网络 :确保所有相关容器在同一个自定义Docker网络中。使用 docker network inspect <network-name> 查看。
  • 使用容器名 :在容器内连接其他服务时,应使用Docker Compose中定义的服务名(如 postgres )作为主机名,而不是 localhost 或宿主机IP。
  • 检查服务监听地址 :确保你容器内的应用服务监听的是 0.0.0.0 (所有接口),而不是 127.0.0.1 (仅本地回环)。这是新手常犯的错误。
  • 防火墙/SELinux :在某些Linux发行版上,宿主机防火墙或SELinux可能会阻止容器网络。可以暂时禁用测试。

4.3 镜像体积过大

一个简单的Node.js应用镜像可能超过1GB。

  • 使用 .dockerignore 文件 :像 .gitignore 一样,排除不需要的文件(如 node_modules , .git , logs , *.md )被复制到构建上下文,能显著加速构建和减小上下文大小。
  • 多阶段构建是王道 :如前所述,这是减小镜像体积最有效的方法。
  • 选择小巧的基础镜像 -alpine 版本通常是好选择。但要注意,某些库在Alpine上可能需要额外安装兼容包。
  • 合并RUN指令,清理缓存
    # 不好
    RUN apt-get update
    RUN apt-get install -y package
    # 好
    RUN apt-get update && apt-get install -y package \
        && rm -rf /var/lib/apt/lists/*
    

4.4 磁盘空间被占满

Docker会占用大量磁盘空间,主要是镜像、容器和卷。

  • 查看磁盘使用 docker system df 命令非常直观。
  • 清理无用资源
    • docker image prune :删除悬空镜像(未被任何标签引用的中间层镜像)。
    • docker container prune :删除所有已停止的容器。
    • docker system prune -a 谨慎使用 。这会删除所有未使用的镜像、容器、网络和卷(未被任何容器引用的卷)。建议先不加 -a 查看会删除什么。
  • 限制日志大小 :默认的 json-file 日志驱动不限制大小。可以在 /etc/docker/daemon.json 中配置全局日志轮转,或为单个容器配置。
    {
      “log-driver”: “json-file”,
      “log-opts”: {
        “max-size”: “10m”,
        “max-file”: “3”
      }
    }
    

4.5 性能问题排查

容器内应用感觉慢。

  • docker stats :首先查看容器的实时资源使用情况(CPU、内存)。是不是达到限制了?
  • docker top <container> :查看容器内哪个进程占用了资源。
  • 进入容器分析 docker exec -it <container> sh ,然后使用容器内可用的命令(如 top , htop , free -m )进行深入分析。注意,Alpine镜像可能没有 bash 和完整的诊断工具,可以事先在镜像中安装,或者使用 docker run --pid=host --network=host 特权模式在宿主机上分析(生产环境慎用)。
  • I/O瓶颈 :如果使用卷,检查宿主机磁盘IO。对于数据库等IO密集型应用,考虑使用SSD或高性能云盘。

掌握这十个核心知识点,并理解它们之间的关联,你就能从“会使用Docker命令”进阶到“能用Docker思维设计和优化开发运维流程”。效率的提升不是来自某个炫酷的命令,而是来自这一整套标准化、自动化、可重复的实践体系。当你和团队不再为环境问题争吵,当新功能可以一键部署和回滚,当资源利用率和系统稳定性显著提高时,你就会真切感受到那“300%”的效率红利从何而来。

更多推荐