Docker入门系列——镜像原理

Docker 的核心概念之一是 Docker 镜像,它是一个轻量级、独立的、可执行的包,包含了运行软件所需的一切。

1. 什么是 Docker 镜像?

可以把 Docker 镜像理解成一种"容器模板"或"静态蓝图"。它包含了操作系统、依赖库、应用程序代码和配置等,是一种静态且不可更改的打包文件,采用分层结构,每一层都是在镜像构建过程中添加的某个组件或步骤。这种分层结构不仅提高了构建和运行的效率,还能优化存储空间。

镜像构建通常从一个基础操作系统镜像(例如 Ubuntu、Alpine)开始,接着按需添加依赖库、应用代码等内容,最终生成一个用于运行容器的可复用"快照"。想象一下,镜像就像是一个系统的备份,一旦构建完成,它就可以用来启动一个容器,而容器是镜像的运行实例。

镜像的构建一般是通过编写 Dockerfile 来实现。Dockerfile 是一组命令集合,用于定义镜像构建的每个步骤。例如,FROM 指令定义基础镜像,RUN 指令安装依赖,COPY 指令添加文件,最后 CMD 或 ENTRYPOINT 定义容器的启动命令。构建过程可以总结为以下步骤:

  1. 创建基础层:镜像通常从一个操作系统镜像开始,例如 ubuntu 或 alpine。
  2. 安装依赖:使用 RUN 指令安装所需的依赖。
  3. 添加文件:使用 COPY 或 ADD 指令将应用代码复制到镜像中。
  4. 设置启动命令:通过 CMD 或 ENTRYPOINT 指令定义容器启动时运行的命令。

每一条指令都会创建一层,最终生成的镜像即包含了所有指令执行后的累积结果。

Docker 镜像是容器的模板,容器是镜像的运行实例。每当你启动一个容器时,Docker 会基于镜像创建一个可写层,称为"容器层",并在该层上运行应用。容器层用于存储容器运行过程中产生的文件和数据,而镜像本身保持不变。

2. Docker 镜像的工作原理

Docker 镜像是分层构建的,每一层代表构建镜像过程中的一个步骤。每一层都被缓存,如果一个镜像的某一层已经存在,Docker 会复用它,而不是重新创建。这种机制显著提高了构建速度。

例如,如果您只更新了应用程序代码,而没有更新基础操作系统或依赖项,Docker 将只重建发生变化的层。这是 Docker 高效的关键。

不同的镜像可以共享相同的基础层,这样可以减少存储空间的使用。例如,多个应用都可能基于相同的 Ubuntu 层,Docker 只需存储一个该层的副本。

以下是层次工作的简单分解:

  • 基础层:这通常是轻量级的 Linux 发行版,如 Alpine 或 Ubuntu。
  • 依赖层:包含应用所需的依赖库。
  • 应用层:包括您的应用程序所需的库和依赖项。
  • 配置层:您的应用程序需要的任何特定配置、环境变量或额外工具。

Docker 使用分层存储驱动(如 AUFS、OverlayFS、Btrfs 等)来管理这些层。在 Docker 启动时,它会把这些层"叠加"起来形成一个完整的文件系统供容器使用。分层存储驱动的关键功能如下:

  • 叠加机制:Docker 会将不同的只读层与容器的读写层叠加起来,提供一个统一的文件系统。对于容器内部的操作来说,它看起来像一个完整的文件系统。
  • 写时复制:容器在运行时会有一个单独的可写层,所有对文件的修改都会存储在这个可写层中,而不会影响只读的基础层。这样不仅可以保护镜像文件的完整性,还能实现资源的高效利用。

例如,如果容器修改了某个文件,Docker 不会直接在只读层中更改该文件,而是将其复制到容器的写层中并在写层上修改。

3. Docker 镜像与容器

一个常见的困惑点是 Docker 镜像和容器之间的区别。为了使概念更清晰,您可以将 Docker 镜像和容器视为类似于面向对象编程概念:

  • Docker 镜像 :这就像编程中的一个 。类定义了结构和行为(方法和属性),但在您创建实例之前并不实际执行任何操作。类似地,Docker 镜像是一个静态蓝图,包含了运行应用程序的指令和依赖项,但它本身并不主动运行。

示例 :一个 Car 类可能定义了 colormodelspeed 等属性,但在您创建实例之前它并不是一辆真正的汽车。

  • Docker 容器 :这就像类的一个 实例。当您实例化(运行)一个类时,您会得到一个可以与世界互动的活对象。类似地,当您运行一个 Docker 镜像时,它就变成了一个活的 Docker 容器,在隔离环境中执行应用程序。

简单说来,我们可以将 Docker 镜像看成是 Docker 容器的静态时,也可将 Docker 容器看成是 Docker 镜像的运行时。

从 Docker 的官方文档来看,Docker 容器的定义和 Docker 镜像的定义几乎是相同,Docker 容器和 Docker 镜像的区别主要在于 docker 容器多出了一个可写层。

容器中的进程就运行在这个可写层,这个可写层有两个状态,即运行态和退出态。当我们 docker run 运行容器后,docker 容器就进入了运行态,当我们停止正在运行中的容器时,docker 容器就进入了退出态。

4. 从 Docker Hub 拉取和运行镜像

Docker Hub 是一个公共注册表,开发者可以在这里共享镜像。您可以轻松地从 Docker Hub 拉取现有镜像并在您的环境运行。

例如,要运行一个 Nginx Web 服务器,您可以使用几个命令拉取并运行官方的 Nginx 镜像:

# 从 Docker Hub 拉取 Nginx 镜像
docker pull nginx

# 将 Nginx 镜像作为容器运行
docker run -d -p 8080:80 nginx

在这个例子中:

  • docker pull nginx:从 Docker Hub 下载最新的 Nginx 镜像。
  • docker run -d -p 8080:80 nginx:以分离模式( -d)运行容器,将容器的 80 端口映射到主机的 8080 端口。

现在,如果您访问 http://localhost:8080,您应该可以看到 Nginx 的欢迎页面。

Docker Hub于2024年9月7日晚间恢复了中国大陆地区的正常访问和镜像拉取功能,可以正常访问和使用Docker Hub,速度也表现良好‌。

在此之前,由于某些原因,Docker Hub在国内无法正常访问和拉取镜像,导致许多用户无法使用Docker Hub服务。为了应对这一问题,国内用户可以采取以下替代方案:

‌- 使用镜像加速‌:配置国内Docker镜像加速地址,通过加速节点下载Docker Hub的内容。推荐使用阿里云的镜像加速服务,用户需要注册并登录阿里云,找到容器镜像服务的加速器地址,并在Docker配置文件中添加该地址‌。

‌- 使用国内镜像网站‌:例如AtomHub可信镜像中心(https://hub.atomgit.com/),这是一个国内的Docker镜像网站,用户可以在这里拉取镜像‌。

5. 创建您自己的 Docker 镜像

虽然从 Docker Hub 拉取镜像很有用,但开发者经常需要创建自定义镜像。这就是 Dockerfile 的用武之地。Dockerfile 是一个脚本,包含了一系列构建 Docker 镜像的指令。

以下是一个基本 Go 应用程序的示例 Dockerfile:

# 从基础镜像开始
FROM golang:1.18

# 设置容器内的工作目录
WORKDIR /app

# 复制 Go 模块文件
COPY go.mod ./
COPY go.sum ./

# 下载依赖项
RUN go mod download

# 复制源代码
COPY . .

# 构建应用程序
RUN go build -o myapp

# 运行应用程序的命令
CMD ["./myapp"]

构建 Docker 镜像

一旦您的 Dockerfile 准备好,您可以使用以下命令构建您的 Docker 镜像:

docker build -t my-go-app .

这个命令告诉 Docker 从当前目录(.)的 Dockerfile 构建镜像,并将其标记为 my-go-app

运行 Docker 镜像

要将您刚刚构建的镜像作为容器运行:

docker run -d -p 8080:8080 my-go-app

这个命令从 my-go-app 镜像启动一个容器,并将容器的 8080 端口映射到主机的 8080 端口。

6. 管理 Docker 镜像

Docker 提供了几个命令来帮助管理您的镜像。

  • 列出镜像:要查看系统上的所有 Docker 镜像列表,请运行:

    docker images

  • 删除镜像:如果您不再需要一个镜像,您可以使用以下命令删除它:

    docker rmi <image-id>

  • 清理未使用的镜像:Docker 还提供了一种清理未使用镜像的方法:

    docker image prune

这个命令将删除悬挂镜像(没有标记或与任何容器关联的镜像)。

7. 结论

Docker 镜像是 Docker 生态中的核心要素,作为容器的蓝图,它确保了应用程序在不同环境中的一致性和可移植性。无论是从 Docker Hub 拉取镜像,还是使用 Dockerfile 构建自定义镜像,Docker 镜像都让应用交付变得更加高效。掌握 Docker 镜像的创建和管理,您将更好地控制容器化应用程序的运行环境,让应用能够高效、可靠地部署到任何环境中。

本文由mdnice多平台发布

相关推荐
前端小小王4 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发13 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀35 分钟前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻3 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云3 小时前
npm淘宝镜像
前端·npm·node.js
dz88i83 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook