Docker与容器:彻底告别“在我电脑上明明是好的!”
这篇文章将带你了解 Docker 和容器的全部基础知识,为你后续的动手实践奠定坚实的基础。
想象一下你精心烹饪了一道菜,用的是你家特有的厨具、独家秘方香料和精确的火候。这道菜在你家尝起来完美无瑕。但当你把食谱(你的代码)给朋友,让他用他家的厨房(他的电脑)来做时,味道却完全变了。可能他家的炉子火力不一样,或者他少了一种关键香料。
软件开发也是如此。一个应用程序(比如我们的航空订单系统)的运行,不仅仅依赖于代码本身,还依赖于它所处的环境,包括:
操作系统:Windows, macOS, 还是某个特定版本的 Linux (Ubuntu/CentOS)?
运行时:特定版本的 Java (JDK 17), Node.js (v18) 等。
依赖库:项目所依赖的各种第三方库和工具。
配置文件:数据库地址、端口号等。
当开发环境、测试环境和生产环境(最终部署的服务器)之间存在细微差异时,就会出现那个经典的、令人头疼的问题:“在我电脑上明明是好的啊!”
为了解决环境一致性问题,技术经历了两个主要阶段。
阶段一:虚拟机 (Virtual Machine, VM)
理念:在物理服务器上,通过一个名为 Hypervisor 的软件,虚拟出多台完整的“虚拟电脑”。每台虚拟电脑都有自己独立的操作系统、CPU、内存和硬盘。
比喻:为了隔离环境,你直接租了一整栋独立的房子(VM)。房子里厨房、卧室、卫生间一应俱全(完整的OS)。
优点:隔离性极强,环境绝对一致。
缺点:笨重且低效。每个VM都包含一个完整的操作系统,占用大量磁盘空间(动辄数GB),启动缓慢(分钟级),资源开销大。
阶段二:容器 (Container)
理念:一种轻量级的虚拟化技术。所有容器共享宿主机的操作系统内核,但它们各自拥有独立的用户空间(文件系统、进程、网络)。
比喻:你不再租一整栋房子,而是在一栋公寓楼(宿主机)里租了一个个标准化的单间(Container)。所有单间共享大楼的基础设施(宿主机OS内核),但每个单间内部的家具和布局(应用和依赖)是独立且互不干扰的。
优点:轻量、快速、高效。容器镜像非常小(MB级),启动极快(秒级),资源占用少,可以在一台物理机上运行远超VM数量的容器。
特性虚拟机 (VM)容器 (Container)启动速度分钟级秒级镜像大小GB级MB级资源占用高(内存、CPU)低隔离性操作系统级别(强)进程级别(较强)核心虚拟化硬件,包含完整OS共享宿主机OS内核
Docker 正是目前最流行、最易用的容器化技术平台。它提供了一整套工具,让我们能够轻松地创建、管理和分发容器。
要掌握 Docker,必须理解以下三个核心概念。它们的关系可以类比为面向对象编程中的“类”与“对象”。
a. 镜像 (Image):只读的蓝图
定义:镜像是创建容器的模板,它是一个只读的文件。它打包了应用程序运行所需的一切:代码、运行时、库、环境变量和配置文件。
比喻:
它是一份详尽的菜谱,规定了制作某道菜需要的所有食材和步骤。
它是面向对象编程中的类 (Class)。
它是一张系统安装光盘。
特性:
分层结构:Docker镜像由一系列的层(layers)构成。每一层代表了Dockerfile中的一条指令。这种设计使得镜像的构建和分发非常高效,因为可以复用相同的层。
只读:镜像本身是不可修改的。
b. 容器 (Container):运行中的实例
定义:容器是镜像的一个可运行的实例。当镜像被启动后,就在其顶层创建了一个可写层,这就构成了容器。
比喻:
它是根据菜谱(Image)做出来的一道可以品尝的菜(Container)。
它是类(Image)的一个实例/对象 (Object)。
它是从安装光盘安装好后,正在运行的操作系统。
特性:
可运行、可写:容器是一个活动的进程,你可以在其中进行读写操作。
隔离性:每个容器都运行在自己独立的环境中,互不影响。
轻量:可以轻松地创建、启动、停止、删除。
c. 仓库 (Repository):存放镜像的仓库
定义:仓库是集中存放和分发镜像的地方。
比喻:它是一个巨大的菜谱库或应用商店。
分类:
公共仓库:如 Docker Hub,是官方的、全球最大的公共镜像仓库,你可以在上面找到几乎所有常用软件的官方镜像(如mysql, nginx, openjdk)。
私有仓库:企业或个人可以搭建自己的私有仓库,用于存放内部的、非公开的应用程序镜像。
在我们的课程项目中,你将遵循以下标准流程来使用Docker:
编写 Dockerfile
Dockerfile 是一个文本文件,它定义了如何构建一个镜像。你将在其中书写一系列指令,告诉Docker该如何一步步地“打包”你的应用。
后端Spring Boot应用 Dockerfile 示例:
Generated dockerfile
# 1. 选择一个包含Java 17的基础镜像
FROM openjdk:17-slim
# 2. 将本地构建好的jar包复制到镜像中
COPY target/order-system-backend.jar /app.jar
# 3. 声明容器将监听8080端口
EXPOSE 8080
# 4. 定义容器启动时要执行的命令
ENTRYPOINT ["java", "-jar", "/app.jar"]
构建镜像 (docker build)
在包含Dockerfile的目录下,运行命令 docker build -t my-backend-app .。
Docker会读取Dockerfile中的指令,逐层构建,最终在你的本地机器上生成一个名为 my-backend-app 的镜像。
运行容器 (docker run)
运行命令 docker run -p 8080:8080 -d my-backend-app。
这条命令会使用 my-backend-app 镜像创建一个新的容器。
-p 8080:8080: 将宿主机的8080端口映射到容器的8080端口,这样我们就可以通过访问宿主机的8080端口来访问容器内的应用。
-d: 后台运行容器(detached mode)。
推送镜像 (docker push) (用于分享和部署)
首先给镜像打上带有仓库地址的标签:docker tag my-backend-app your-dockerhub-username/my-backend-app
然后推送到Docker Hub:docker push your-dockerhub-username/my-backend-app
这样,你的同事或CI/CD服务器就能从Docker Hub上拉取这个镜像来运行了。
我们的航空订单系统包含多个服务:前端、后端、数据库。如果手动管理这三个容器的启动顺序和网络连接,会非常繁琐。
Docker Compose 是一个用于定义和运行多容器Docker应用程序的工具。你使用一个 YAML 文件 (docker-compose.yml) 来配置你的应用服务,然后使用一个简单的命令,就可以创建并启动所有服务。
docker-compose.yml 示例:
Generated yaml
version: '3.8'
services:
# 后端服务
backend:
build: ./backend # 指定后端项目的Dockerfile位置
ports:
- "8080:8080"
depends_on: # 声明依赖关系,先启动数据库
- database
# 前端服务
frontend:
build: ./frontend # 指定前端项目的Dockerfile位置
ports:
- "80:80"
# 数据库服务
database:
image: mysql:8.0 # 直接使用Docker Hub上的官方MySQL镜像
environment:
MYSQL_ROOT_PASSWORD: your_secret_password
核心命令:
docker-compose up -d: 一键启动yml文件中定义的所有服务,并在后台运行。
docker-compose down: 停止并移除所有相关的容器、网络。
总结
通过本文,你应该理解了:
Docker解决了环境一致性的痛点。
核心概念:镜像 (Image) 是模板,容器 (Container) 是运行实例,仓库 (Repository) 是存储。
标准流程:通过 Dockerfile 构建镜像,运行为容器,并可推送到仓库分享。
Docker Compose 用于轻松编排和管理由多个容器组成的复杂应用。
Comments (0)