Part3 深入Docker:解密容器的核心要素

31 阅读8分钟

本篇文章旨在刨析 Docker 的核心要素: 容器 镜像 Dockerfile,而不是简单地背诵一堆命令。通过理解docker核心原理,我们将能够更有效地运用 Docker,避免在操作中迷失方向,并真正掌握这项强大的技术

本文涉及的技术名词: ContainerImageDockerfileDocker命令

在开始探讨 Docker 的细节之前,让我们先确认四个非常重要的要点,以便正确且快速地理解 Docker。(这些分类是我个人的总结)

  1. 三个基本元素
  2. 三个基本命令
  3. 注意命令格式
  4. 区分 Docker 与周边工具

如果学习Docker只是一味的背诵一堆命令和选项 最终可能无法真正掌握 Docker 的基础知识。

我认为与其只是机械地复制一堆命令,最后迷惑地想着“这是什么...?”,不如花点时间扎实地掌握基本概念,才是快速上手 Docker 的捷径。

三个基本元素

当使用 Docker 构建开发环境时,实际上涉及的元素并不多。在本文中,我们将以下三个元素视为基本要素:

  1. 容器(Container)
  2. 镜像(Image)
  3. Dockerfile

掌握这三个基本元素将帮助我们更简单地理解和使用 Docker,构建出高效且稳定的开发环境。

Container

容器是在主机上创建的一个用于运行特定命令的隔离区域。

在刚开始接触 Docker 时,我们可能会把容器想象成运行在主机上的虚拟操作系统,但实际上,容器只是通过 Linux 中的 Namespace 功能与其他进程隔离开的一个单独进程。Linux Namespace 本身是一项已经存在近 20 年的技术,而 Docker 则是一种通过容器和镜像让这项技术更易于使用的工具。

如下图, 在主机和每个容器中,可能会有类似 Process ID 1/etc/hosts 这样重复的同名文件,但通过 Namespace 技术映射隔离区域,避免了这些文件的冲突。

Docker 允许我们从镜像创建这个 Namespace,使其对不同的操作系统可见,并提供了方便的命令来创建和删除这些 Namespaces。

小提示: 容器仅仅是主机上的一个进程,而不是一个虚拟服务器, 利用Linux命名空间的强大的隔离机制,允许系统资源在不同进程之间独立存在和管理。

容器具有以下几个特点:

  • 容器是基于镜像创建的:每个容器都是从一个镜像开始,通过镜像定义了容器内的环境和应用程序。
  • 可以使用 Docker CLI 或 API 来创建、启动和停止容器:Docker 提供了简便的命令行工具和 API 来管理容器的生命周期。
  • 多个容器彼此独立,互不干扰:每个容器都是独立运行的,它们之间无法相互影响,因此能够独立操作。
  • Docker Engine 可以运行在本地机器、虚拟机或云环境中:这使得容器化应用能够在各种环境中部署和运行,无论是在开发、测试,还是生产环境中。

Image

镜像是一个包含了运行容器所需的所有文件和元信息的包。它并不是一个单独的文件,而是由多层信息构成的集合。这些层次的信息包括:

  • 基础镜像:定义了容器运行的基本环境,比如操作系统版本。
  • 已安装的软件:镜像中包含了应用程序及其所有依赖项。
  • 环境变量:配置了容器在运行时所需的环境变量。
  • 配置文件:包含了运行应用程序所需的各种配置文件。
  • 默认启动命令:指定了容器启动时要执行的命令。

这些层次的信息共同构成了一个完整的镜像,使得容器能够在启动时拥有预期的运行环境。

Dockerfile

Dockerfile 是一个文本文件,它可以在现有的镜像上添加新的层。

假设我们从 Docker Hub 获取了一个基于 Debian 的 Node.js 镜像(node:16),但发现该镜像缺少 git 命令,并且我们需要部署一个 Vue 单页应用(SPA)。此时,我们可以通过以下 Dockerfile 添加 git,安装项目依赖并构建应用,同时配置必要的环境变量,生成一个符合需求的自定义镜像。

# 使用官方的 Node.js 镜像作为基础镜像
FROM node:16-buster

# 安装必要的工具和依赖
RUN apt-get update && apt-get install -y git

# 设置工作目录
WORKDIR /usr/src/app

# 复制 package.json 和 package-lock.json 到工作目录
COPY package*.json ./

# 安装项目依赖
RUN npm install

# 复制应用程序代码到工作目录
COPY . .

# 构建 Vue 应用
RUN npm run build

# 安装一个轻量级的 HTTP 服务器来提供应用
RUN npm install -g serve

# 暴露应用运行的端口
EXPOSE 5000

# 使用 serve 提供构建后的应用
CMD ["serve", "-s", "dist", "-l", "5000"]

小提示: 在 Dockerfile 中,应用程序代码通常是从构建 Docker 镜像的上下文目录复制到容器内的工作目录。Dockerfile 中的 COPY . . 指令将当前目录(即运行 docker build 命令时所在的目录)下的所有文件复制到容器内的工作目录

这个 Dockerfile 基于 Debian 的 Node.js 镜像,安装了 git,复制并安装了项目依赖,构建了 Vue 单页应用,然后使用 serve 提供构建后的应用,最终在 5000 端口运行。

三个基本命令

当我们理解了 Docker 的三个基本元素(容器、镜像、Dockerfile)后,可以发现,Docker 的基本命令形式其实也可以归纳为三种类型:

  1. 启动容器:通过已有的镜像启动并运行一个容器。
  2. 创建镜像:使用 Dockerfile 或其他方法生成一个新的镜像,满足特定需求。
  3. 管理容器:对已经运行的容器进行操作,比如停止、重启或者查看状态。

启动一个容器

docker container run 命令用于从镜像运行一个容器, 这个命令会基于指定的镜像启动一个新的容器,并在其中执行指定的命令或应用程序。

其拥有大量参数选项,根据容器的用途,我们可以配置相应的参数来定制容器的行为。归根结底,这个命令的核心功能还是从镜像创建一个容器,这是最基础的操作。

创建镜像

docker image build 命令用于从 Dockerfile 创建一个镜像; 如下图:

上图中我们看到Docker Desktop 还包括 Docker Compose、Kubernetes 等组件。

这意味着,除了 Docker Engine 和 Linux 内核之外,还可以使用 Docker Desktop 轻松管理多容器应用(通过 Docker Compose)以及容器编排(通过 Kubernetes)。这些功能使得 Docker Desktop 成为一个功能强大的工具,适合在 Windows 和 Mac 上进行复杂的开发和部署任务。

管理容器

docker container exec 命令用于向已经运行的容器发送指令。

由于它的目标是一个正在运行的容器,因此必须在执行 docker container run 之后使用。这个命令不能用于操作镜像或 Dockerfile,只能在容器已经启动后进行交互。如下图:

新旧命令对比

使用过Docker命令的同学可能已经注意到, 上面使用的都是docker container run而非 docker run命令; 这是因为Docker 命令在 2017 年 1 月发布的 v1.13 版本中经历了一次重大变化,旧的 docker run 命令被替换为新的 docker container run 命令。这是因为之前的命令过于直接,如 docker rundocker build 等,使得用户很难区分各个命令的用途。因此,从 v1.13 版本开始,Docker 推荐使用子命令格式,这样可以更清楚地指定每个命令的目标,例如容器、镜像等。

小提示: 这种命令变化旨在提高命令的可读性和可理解性,让用户在使用 Docker 时能够更轻松地掌握各个命令的具体作用和使用场景。

老命令新命令
docker builddocker image build
docker rundocker container run
docker pulldocker image pull
docker createdocker container create
docker startdocker container start
docker imagesdocker image ls
docker psdocker container ls

Docker Compose

Docker Compose 是一个强大的容器编排工具,通过编写 Yaml 文件可以定义并一次性启动和管理多个容器。使用 Compose,我们可以轻松设置容器之间的网络、共享存储以及依赖关系,从而简化了复杂应用的部署和管理。

Kubernetes

Kubernetes 是一款编排软件,它通过编写 JSON 或 Yaml 文件,方便轻松地运行多个相同的容器来构建集群、监控容器,并在容器出现故障时自动重启容器。Kubernetes 的强大之处在于它能够高效管理和扩展大规模的容器化应用程序,确保系统的稳定性和可用性。无论是在开发环境还是生产环境,Kubernetes 都为容器管理提供了高度自动化和灵活的解决方案。

总结

本篇文章涉及的新名词较多,所以在结尾我来简要总结一下:

基本元素

  • 容器:容器是主机上一个隔离的进程。
  • 镜像:镜像是由称为层的元信息集合构成的,可以发布在 Docker Hub 等平台上。
  • Dockerfile:Dockerfile 是一个用于向镜像添加层的文本文件,可以在 GitHub 等平台上共享。

基本命令

  • 启动容器
  • 创建镜像
  • 操作容器

命令形式

  • 最重要的是清楚自己想要实现什么。
  • 新命令更加易懂,而旧命令则书写简短。