Understanding Docker Technology
Docker 是一个旨在帮助开发者构建、共享和运行容器化应用的平台。它处理了繁琐的环境配置工作,让你可以专注于代码。Docker 是一个开源的应用容器引擎,基于 Go 编程语言构建,并在 Apache 2.0 许可证下发布。Docker 允许开发者将应用及其依赖包打包到一个轻量级、可移植的容器中,然后可以部署到任何主流的 Linux 机器上,同时也实现了虚拟化。
容器完全使用沙箱机制,彼此之间没有任何接口(类似于 iPhone 上的应用程序)。更重要的是,容器的性能开销极低。
Application Scenarios of Docker
| 场景 | 描述 |
|---|---|
| 微服务架构 | 每个服务独立容器化,便于管理和扩展 |
| CI/CD 流水线 | 与 Jenkins/GitLab CI 集成,实现自动化构建和测试 |
| 开发环境统一 | 新成员可以一键启动全套依赖服务(如数据库、消息队列) |
| 云原生基础 | Kubernetes 等编排工具基于 Docker 管理容器集群 |
Core Advantages
| 优势 | 描述 |
|---|---|
| 跨平台一致性 | 解决”在我机器上能跑”的问题,确保开发、测试、生产环境的一致性 |
| 资源高效 | 容器直接共享宿主机内核,无需虚拟化整个操作系统,从而节省内存和 CPU 资源 |
| 快速部署 | 秒级启动容器,支持自动化弹性伸缩 |
| 隔离性 | 每个容器拥有独立的文件系统、网络和进程空间 |
Core Concepts
| 概念 | 描述 |
|---|---|
| 容器(Container) | 轻量级的运行实例,包含应用代码、运行时环境和依赖库。基于镜像创建,与其他容器隔离,共享宿主机操作系统内核(比虚拟机更高效) |
| 镜像(Image) | 只读模板,定义了容器的运行时环境(如操作系统、软件配置等)。通过分层存储优化空间和构建速度 |
| Dockerfile | 文本文件,描述如何自动构建镜像(如指定基础镜像、安装软件、复制文件等) |
| 仓库(Registry) | 存储和分发镜像的平台,如 Docker Hub(官方公共仓库)或私有仓库(如 Harbor) |
Docker vs Virtual Machines
| 特性 | 虚拟机 | Docker 容器 |
|---|---|---|
| 隔离级别 | 硬件级虚拟化 | 操作系统级虚拟化 |
| 操作系统 | 每个虚拟机需要完整的操作系统 | 共享宿主机操作系统内核 |
| 资源消耗 | 重量级,消耗更多资源 | 轻量级,消耗较少资源 |
| 启动时间 | 分钟级 | 秒级 |
| 性能开销 | 较高 | 接近原生性能 |
| 镜像大小 | GB 级别 | MB 级别 |
架构对比:
1 | Traditional VMs: Docker Containers: |
Basic Commands
镜像命令
1 | # Pull an image (such as the official Nginx image) |
容器命令
1 | # Run a container (-d for detached, -p for port mapping) |
系统命令
1 | # View Docker system usage |
Docker Data Volumes
What is a Data Volume
数据卷(Data Volume) 是一个虚拟目录,充当容器目录与宿主机目录之间的桥梁。它解决了以下问题:
| 问题 | 解决方案 |
|---|---|
| 数据持久化 | 容器删除后数据仍然保留 |
| 配置管理 | 方便修改配置文件 |
| 静态资源 | 提供外部静态文件服务 |
Volume Commands
1 | # Create a volume |
Mounting Local Directories
1 | # Mount local directory (use absolute path or ./) |
重要提示: 本地目录必须以 / 或 ./ 开头。没有这些前缀的名称会被视为数据卷名称。
Docker Networking
Default Networks
| 网络 | 描述 |
|---|---|
bridge |
容器的默认网络;提供隔离 |
host |
共享宿主机网络栈;无隔离 |
none |
无网络连接 |
Custom Networks
1 | # Create a custom network |
关键优势: 在自定义网络中,容器可以使用容器名作为主机名进行通信:
1 | # In 'my-network', 'mysql' container can be accessed via 'mysql' hostname |
Building Custom Images
Image Structure
Docker 镜像分层构建:
1 | Layer 4: Application Layer (your jar/code) |
Dockerfile Syntax
常用 Dockerfile 指令:
| 指令 | 描述 | 示例 |
|---|---|---|
FROM |
基础镜像 | FROM openjdk:11-jre |
ENV |
环境变量 | ENV TZ=Asia/Shanghai |
COPY |
从宿主机复制文件 | COPY app.jar /app.jar |
ADD |
复制并解压归档文件 | ADD config.tar.gz /config |
RUN |
执行命令 | RUN apt-get update |
EXPOSE |
暴露端口 | EXPOSE 8080 |
ENTRYPOINT |
容器启动命令 | ENTRYPOINT ["java", "-jar", "/app.jar"] |
CMD |
默认命令参数 | CMD ["--server.port=8080"] |
Building Images
1 | # Build from Dockerfile in current directory |
Docker Compose
Docker Compose 允许你使用 YAML 文件来定义和运行多容器应用。
Basic Syntax
1 | version: "3.8" |
Common Commands
1 | # Start all services |
Practical Examples
Deploying MySQL
1 | docker run -d \ |
Deploying a Java Application
Dockerfile:
1 | FROM openjdk:11-jre-slim |
构建和运行:
1 | # Build image |
Best Practices
安全
- 使用特定版本的镜像:生产环境中避免使用
latest标签;使用明确的版本号 - 以非 root 用户运行:在 Dockerfile 中添加
USER指令1
2RUN adduser -D appuser
USER appuser - 扫描镜像漏洞:使用
docker scan或集成到 CI/CD 流程中 - 不要嵌入密钥:使用环境变量、Docker secrets 或外部密钥管理服务
性能
利用构建缓存:按从最少变化到最频繁变化的顺序排列 Dockerfile 指令
减少镜像层数:在合理的情况下合并多个
RUN命令使用多阶段构建:
1
2
3
4
5
6
7
8
9# Build stage
FROM maven:3.8-openjdk-11 AS build
COPY . .
RUN mvn clean package
# Runtime stage
FROM openjdk:11-jre-slim
COPY --from=build /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
维护
- 为镜像添加标签:
1
2
3LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="My Application" - **使用
.dockerignore**:排除构建上下文中不必要的文件 - 设置资源限制:防止容器消耗所有资源
- 实施健康检查:
1
2HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
生产就绪
| 实践 | 命令/配置 |
|---|---|
| 重启策略 | docker run --restart unless-stopped |
| 资源限制 | docker run --memory=512m --cpus=1.0 |
| 日志轮转 | 配置 Docker daemon 日志选项 |
| 网络隔离 | 使用自定义网络,而非默认 bridge |
FAQ
问:Dockerfile 中 COPY 和 ADD 有什么区别?
答: COPY 只是将文件从宿主机复制到容器中。ADD 有额外的功能:
- 可以自动解压本地的 tar 归档文件
- 可以从 URL 下载文件
建议: 大多数情况下使用 COPY;仅在需要特殊功能时才使用 ADD。
问:如何从同一网络的另一台机器访问容器?
答: 使用宿主机的 IP 地址和映射的端口。例如,宿主机 IP 为 192.168.1.100 且映射了 8080 端口:
1 | http://192.168.1.100:8080 |
问:为什么我的容器启动后立即退出?
答: 常见原因:
- 前台进程退出(主进程停止时容器也会停止)
- 命令或入口点配置错误
- 应用启动时出错
调试方法: 使用 docker logs <container> 查看日志,或不带 -d 参数以交互方式运行。
问:容器删除后如何持久化数据?
答: 使用命名数据卷(named volumes)或绑定挂载(bind mounts):
1 | # Named volume |
问:docker-compose 和 docker compose 有什么区别?
答: docker-compose(V1)是基于 Python 的旧版工具。docker compose(V2)是基于 Go 的插件,集成在 Docker CLI 中。现在推荐使用 V2。
问:如何减小 Docker 镜像大小?
答: 策略:
- 使用更小的基础镜像(Alpine、Distroless)
- 使用多阶段构建
- 删除不必要的依赖和缓存文件
- 在合理范围内减少镜像层数
问:能在 Docker 中运行 GUI 应用吗?
答: 可以,但比较复杂。你需要:
- 与宿主机共享 X11 socket
- 设置适当的 DISPLAY 环境变量
- 处理权限问题
通常不建议在生产环境中使用,但开发环境中可行。
问:如何排查容器之间的网络连通性问题?
答: 步骤:
- 确保容器在同一网络中
- 验证使用容器名进行 DNS 解析
- 使用
docker network inspect检查配置 - 使用
docker exec从容器内部执行 ping 测试
Summary
Docker 通过容器化技术革新了应用部署方式。关键要点:
| 概念 | 要点 |
|---|---|
| 容器 vs 虚拟机 | 容器共享宿主机内核;虚拟机虚拟化硬件 |
| 镜像 vs 容器 | 镜像是蓝图;容器是运行中的实例 |
| 数据持久化 | 使用数据卷保存需要在容器重启后保留的数据 |
| 网络 | 自定义网络支持通过容器名进行服务发现 |
| Docker Compose | 适合多容器应用编排 |
Docker 让开发者能够一次构建、到处运行,解决了”在我机器上能跑”的问题,简化了从开发到生产的路径。