Docker 入门指南

Docker是一种轻量级容器技术,利用Linux命名空间和控制组实现资源隔离,解决了环境依赖和部署效率问题。它将应用及其依赖打包为可移植的镜像,支持"一次构建,到处运行"。核心组件包括镜像、容器、Dockerfile和仓库,通过标准化流程简化开发部署。相比虚拟机更轻量高效,适用于微服务、CI/CD等场景。最佳实践包括多阶段构建、避免root运行等。Docker已成为现代云原生开发的重要基石。

作品集: Docker学习
作者头像
LumiBee
2 天前 · 11 0
分享

Docker 入门指南

1. 虚拟化的演进

在容器化技术出现之前,软件部署主要面临两大挑战:环境依赖的复杂性传统虚拟化的资源开销

  • 依赖地狱: 一个应用程序的运行往往依赖于特定的操作系统、系统库、运行时环境以及各种第三方库。当多个应用部署在同一台服务器上时,它们之间可能存在依赖冲突(例如,应用 A 需要 Lib v1.0,而应用 B 需要 Lib v2.0)。手动管理这些依赖关系非常复杂、易错,并且严重影响了应用的可移植性,导致了经典的“在我机器上能跑”问题。
  • 传统虚拟化: 虚拟机技术通过 Hypervisor 在物理硬件之上模拟出一整套虚拟硬件,并在其上运行一个完整的客户机操作系统(Guest OS)。这种方式虽然提供了优秀的隔离性,但每个虚拟机都包含一个完整的操作系统内核,导致了显著的资源开销和较慢的启动速度。这限制了在单台物理服务器上能够承载的应用密度。

Docker 的诞生正是为了解决上述问题。它并非凭空创造,而是巧妙地利用并整合了 Linux 内核已有的关键特性——命名空间控制组

  • 命名空间实现了资源视图的隔离。它为每个容器创建了独立的运行环境视图,包括进程树、网络栈、挂载点 等。这使得容器内的进程感觉自己独占了整个操作系统,而实际上它们只是被隔离在宿主机内核的一个特定“房间”里。
  • 控制组则实现了物理资源的限制与审计。它能够精确地分配和限制每个容器可以使用的 CPU 时间、内存大小、磁盘 I/O 等,确保了多租户环境下的公平性和稳定性。

通过这种方式,Docker 提供了一种操作系统级的虚拟化方案。它省去了 Guest OS 的开销,实现了应用的秒级启动和更高的部署密度,同时通过标准化的镜像格式,从根本上解决了环境依赖和一致性的难题,为现代软件架构的快速交付和部署奠定了基础。

2. 核心定义与价值

  • 核心定义: Docker 是一个开源的应用容器引擎,它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中,然后可以发布到任何流行的 Linux 或 Windows 机器上,也可以实现虚拟化。
  • 解决的关键问题:
    1. 环境一致性问题: 根治了“在我机器上能跑”的顽疾,保证了开发、测试、生产环境的高度一致。
    2. 部署效率低下问题: 传统部署需要复杂的环境配置,耗时且易出错。Docker 实现了“一次构建,到处运行”(Build once, run anywhere)。
    3. 资源隔离与利用率问题: 提供了比虚拟机更轻量级的资源隔离方案,可以在一台物理机上运行更多的应用,提升了服务器的资源利用率。
  • 核心价值主张: 加速应用交付、标准化部署流程、提升资源效率。

3. 核心工作原理

要理解 Docker,我们需要知道这几个核心概念:

  • 镜像 (Image): 可以把它看作一个只读的模板,一个面向对象编程中的“类”。镜像包含了运行应用所需的一切:代码、运行时(如 JDK)、库、环境变量和配置文件。
  • 容器 (Container): 是镜像的一个可运行实例,一个面向对象编程中的“对象”。容器是真正运行应用的地方。我们可以创建、启动、停止、删除容器。每个容器都是相互隔离的,保证了应用的独立性和安全性。
  • Dockerfile: 这是一个文本文件,里面包含了一条条的指令,用来描述如何构建一个镜像。它就像一份制作“集装箱”的“施工图纸”。
  • 仓库 (Repository): 用来集中存放和分发镜像的地方。最著名的就是官方的 Docker Hub。

它们的关系是:我们编写 Dockerfile -> 通过 docker build 命令构建出 Image -> 通过 docker run 命令运行 Image,生成 Container

其底层依赖于 Linux 内核的两个关键技术:

  • Namespaces (命名空间): 负责资源隔离,让容器拥有自己独立的进程、网络、文件系统等。
  • Control Groups (cgroups): 负责资源限制,可以限制每个容器能使用的 CPU、内存等资源。

4. 核心用法与配置示例

4.1 关键命令

  • docker build -t <镜像名>:<标签> .:根据当前目录下的 Dockerfile 构建镜像。
  • docker images:列出本地的所有镜像。
  • docker run [OPTIONS] <镜像名>:运行一个镜像来创建并启动容器。
  • docker ps:列出正在运行的容器。
  • docker ps -a:列出所有容器(包括已停止的)。
  • docker stop <容器ID或名称>:停止一个运行中的容器。
  • docker rm <容器ID或名称>:删除一个已停止的容器。

4.2 “Hello World”级示例

  1. 创建一个名为 Dockerfile 的文件,内容如下:

    # 使用一个非常小的 Alpine Linux 作为基础镜像
    FROM alpine:latest
    
    # 在容器启动时执行的命令
    CMD ["echo", "Hello, Docker!"]
    
  2. 在终端中,进入 Dockerfile 所在目录,执行构建命令:

    docker build -t hello-docker:1.0 .
    
  3. 运行这个镜像:

    docker run hello-docker:1.0
    
  4. 我们会在终端看到输出:Hello, Docker!。恭喜,我们已经成功构建并运行了我们的第一个 Docker 容器!

4.3 结合 Java 的实战示例

假设我们有一个已经用 Maven 打包好的 Spring Boot 项目,生成了 app.jar

  1. 在项目根目录下,创建 Dockerfile 文件:

    # 步骤1: 选择一个包含 Java 17 运行环境的基础镜像
    # eclipse-temurin 是一个高质量的 OpenJDK 发行版
    FROM eclipse-temurin:17-jdk-focal
    
    # 维护者信息 (可选)
    LABEL maintainer="lumi@live.com"
    
    # 在容器内部创建一个工作目录
    WORKDIR /app
    
    # 步骤2: 将打包好的 jar 文件复制到容器的工作目录中
    # 第一个参数是宿主机路径,第二个是容器内路径
    COPY target/app.jar app.jar
    
    # 步骤3: 声明容器将要暴露的端口 (这里是 Spring Boot 默认的 8080)
    # 这只是一个元数据声明,实际端口映射在 docker run 时指定
    EXPOSE 8080
    
    # 步骤4: 定义容器启动时要执行的命令
    # 使用 exec 格式,这是推荐的做法
    ENTRYPOINT ["java", "-jar", "app.jar"]
    
  2. 构建我们的 Spring Boot 应用镜像:

    docker build -t my-spring-app:1.0 .
    
  3. 运行容器,并将容器的 8080 端口映射到宿主机的 8080 端口:

    docker run -d -p 8080:8080 --name my-app my-spring-app:1.0
    
    • -d: 后台运行容器。
    • -p 8080:8080: 将宿主机的 8080 端口映射到容器的 8080 端口。
    • --name my-app: 给容器起一个友好的名字。

现在,我们就可以通过访问 http://localhost:8080 来访问我们的 Spring Boot 应用了,它正运行在一个完全隔离的 Docker 容器里!

5. 真实应用场景

  1. 微服务架构: 每个微服务(如用户服务、订单服务、商品服务)都被打包成独立的 Docker 镜像,并作为容器运行。这使得每个服务都可以被独立地开发、部署、扩展和升级,互不影响。
  2. CI/CD (持续集成/持续部署) 流水线: 在 Jenkins 或 GitLab CI 中,构建流程的第一步就是 docker build,生成一个包含最新代码的镜像。然后,自动化测试可以在这个镜像生成的容器中运行。测试通过后,这个镜像被推送到镜像仓库,最终部署到生产环境。整个过程标准化且高效。
  3. 搭建复杂的本地开发环境: 新员工入职,需要配置 Java、MySQL、Redis、RabbitMQ 等一大堆环境?有了 Docker,只需一个 docker-compose.yml 文件和一条 docker-compose up 命令,几分钟内就能拉取所有服务的镜像并在本地运行起来,完全模拟生产环境。

6. 最佳实践与常见陷阱

最佳实践

  • 使用 .dockerignore 文件: 类似 .gitignore,它可以防止不必要的文件(如 target 目录、.idea 配置)被打包进镜像,保持镜像的整洁和苗条。
  • 采用多阶段构建: 对于 Java 这类编译型语言,可以在一个阶段使用包含 JDK 和 Maven 的完整镜像来编译和打包应用,然后在下一个阶段只把最终的 jar 包复制到一个仅包含 JRE 的轻量级镜像中。这可以使最终的生产镜像体积大大减小。
  • 不要在容器中以 root 用户运行应用: 默认情况下容器内是 root 用户,存在安全风险。最好在 Dockerfile 中创建一个普通用户,并切换到该用户来运行应用。
  • 明确镜像标签: 避免使用 latest 标签,因为它是不稳定的。始终使用明确的版本号(如 my-app:1.0.1)来标记镜像,保证部署的可追溯性和稳定性。

常见陷阱

  • 把容器当成虚拟机: 容器是无状态易逝的。不要试图在容器内部保存重要数据(如数据库文件、日志),一旦容器被删除,数据就会丢失。应该使用数据卷 (Volumes) 来持久化数据。
  • 将敏感信息硬编码到镜像中: 绝对不要在 Dockerfile 中写入数据库密码、API 密钥等。应该使用环境变量Docker Secrets 在容器启动时动态传入。
  • 构建巨大的镜像: 一个镜像包含了几 GB 的内容,这会大大拖慢构建、推送和拉取的速度。要时刻注意优化 Dockerfile,清理不必要的依赖和缓存。

7. 相关技术对比

  • Docker vs. VM:
    • VM: 在宿主机操作系统之上,通过 Hypervisor 虚拟化了一整套硬件,然后安装一个完整的客户机操作系统(Guest OS)。它很重,启动慢,但隔离性极强。
    • Docker: 直接运行在宿主机操作系统之上,共享宿主机的内核。它没有自己的内核,也没有虚拟硬件。因此它非常轻量,启动速度是秒级,但隔离性理论上弱于 VM。
    • 一句话总结: VM 是“虚拟电脑”,Docker 是“虚拟进程”。
  • Docker vs. Podman:
    • Docker: 采用 C/S 架构,有一个一直在后台运行的守护进程 (Docker Daemon)。所有 docker 命令都通过这个守护进程执行。
    • Podman: 是一个无守护进程 (Daemonless) 的容器引擎。它直接与容器运行时交互,命令和 Docker 基本兼容。因为没有中心化的守护进程,被认为在某些场景下更安全。

8. 总结

总结: Docker 通过标准化的“容器”技术,解决了软件开发和运维中最大的痛点之一——环境一致性。它让应用打包、分发和部署变得前所未有的简单、高效和可靠,是现代云原生开发的基石。

阅读量: 11

评论区

登录后发表评论

正在加载评论...
相关阅读

Elastic Stack 日志监控入门指南

# Elastic Stack 日志监控入门指南 ## 0. 核心概念:理解现代 Elastic 可观测性架构 在开始部署之前,我们必须先理解几个核心概念,这能帮助我们明白每一步操作背后的“...

85
1

Elasticsearch 入门指南

# Elasticsearch 入门指南:从零到一构建搜索引擎 在成功部署了 Elasticsearch 和 Kibana 后,如果还有不会安装的可以查看这篇[文章](https://hive...

188
1

Spring Boot 多数据源配置指南:从自动配置到手动掌控

# Spring Boot 多数据源配置指南:从自动配置到手动掌控 在企业级应用开发中,单一数据源往往无法满足复杂的业务需求。无论是为了实现读写分离、业务隔离,还是对接不同类型的数据库,配置和...

8
0

Redis00_Linux 安装使用 Redis

# Linux 安装使用 Redis Redis 是一个功能强大的内存数据结构存储,通常用作数据库、缓存和消息代理。本文将详细引导在 Linux 上安装、配置、保护和基本使用 Redis 的全...

14
1

Linux 快速安装使用 Elasticsearch 与 Kibana

# Linux 快速安装使用 Elasticsearch 与 Kibana 在 Linux 上部署Elasticsearch 和 Kibana 时,使用系统的包管理器(APT/YUM)可以极大...

131
3

hexo 搭建博客

# 博客搭建过程 ## 安装前的准备 ### 注意事项 以下所有的命令没有特别说明都可以在cmd或者powershell中运行,如果无法运行请使用管理员模式进行 ### 下载并安装...

72
0