Docker容器化应用与结构

目录
  • 容器化应用
    • 什么是容器化应用
    • 应用怎么打包
    • Docker 镜像组成
    • 联合文件系统
    • Linux 内核
  • Docker 结构
    • Docker 服务与客户端
    • Docker 客户端
    • 容器运行时
    • Docker 引擎
    • Docker 引擎变化
    • Docker 引擎的架构
      • containerd
      • shim
      • runc

容器化应用

什么是容器化应用

containerized applications 指容器化的应用,我们常常说使用镜像打包应用程序,使用 Docker 发布、部署应用程序,那么当你的应用成功在 Docker 上运行时,称这个应用是 containerized applications。

应用怎么打包

容器化应用的最主要特征是使用镜像打包应用的运行环境以及应用程序,可以通过 Docker 启动这个镜像,进而将 应用程序启动起来。

将一个应用程序打包为镜像,大约分为以下过程:

  • 编写 Dockerfile 文件 -- 定义构建镜像的流程
  • 选择一个基础镜像(操作系统) -- 操作系统
  • 安装应用的需要的环境 -- 运行环境
  • 复制程序文件 -- 应用程序
  • 启动 Dockerfile -- 生成镜像

操作系统运行环境Web程序(C#)Ubuntu 18.04.NET Core Runtime3.1安装运行环境操作系统运行环境Web程序(C#)

Docker 镜像组成

以 .NET Core(C#) 程序为例,一个 Docker 镜像的层次如下图所示:

在 Docker 镜像中,操作系统是高度精简的,可能只有一个精简的 Shell,甚至没有 Shell。而且镜像中的操作系统还不包含内核,容器都是共享所在的宿主机的内核。所以有时会说容器仅包含必要的操作系统(通常只有操作系统文件和文件系统对象),容器中查看到的 Linux 内核版本与宿主机一致。

Docker 镜像的是由一系统文件组成的。

联合文件系统

Linux 有名为 Unionfs 的文件系统服务,可以将不同文件夹中的文件联合到一个文件夹中。Unionfs 有称为分支的概念,一个分支包含了多个目录和文件,多个分支可以挂载在一起,在挂载时,可以指定一个分支优先级大于另一个分支,这样当两个分支都包含相同的文件名时,一个分支会优先于另一个分支,在合并的目录中,会看到高优先级分支的文件。

Docker 中,层层组成镜像的技术也是联合文件系统,Union File System。Docker 镜像中的操作系统是根文件系统,在上一小节的图片中,可以看到有 bin、boot 等目录。我们都知道,Docker 镜像是由多层文件组成的,在上面的示例图片中有三层组成:根文件系统、环境依赖包、应用程序文件。当镜像层生成后,便不能被修改,如果再进行操作,则会在原来的基础上生成新的镜像层,层层联合,最终生成镜像。当然生成的镜像可能会因为层数太多或者操作过多,导致出现大量冗余,镜像臃肿。

Docker 的镜像分层是受 Linux Unionfs 启发而开发的,Docker 支持多种文件联合系统,如 AUFS、OverlayFS、VFS 等。

Docker 在不同系统中可以选择的联合文件系统:

Linux发行版 推荐的存储驱动程序 替代驱动程序
Ubuntu overlay2 overlay, devicemapper, aufs, zfs,vfs
Debian overlay2 overlay, devicemapper, aufs,vfs
CentOS overlay2 overlay, devicemapper, zfs,vfs

 提示

Docker Desktop for Mac 和 Docker Desktop for Windows 不支持修改存储驱动程序,只能使用默认存储驱动程序。

Linux 内核

既然 Docker 容器需要与 Linux 内核结合才能使用,那么我们看一下 Linux 内核的功能,稍微了解一下 Linux 内核在支撑 Docker 容器运作中起到什么作用。

Linux 内核主要包含以下功能:

  • 内存管理:追踪记录有多少内存存储了什么以及存储在哪里;
  • 进程管理:确定哪些进程可以使用中央处理器(CPU)、何时使用以及持续多长时间;
  • 设备驱动程序:充当硬件与进程之间的调解程序/解释程序;
  • 系统调用和安全防护:接受程序请求调用系统服务;
  • 文件系统:操作系统中负责管理持久数据的子系统,在 Linux 中,一切皆文件。

Linux 层次结构如下:

Docker 容器中包含了一个操作系统,包含简单的 shell 或者不包含,其层次结构如图所示:

Docker 结构

本节将了解 Docker 的组成部件和结构。

Docker 服务与客户端

Docker 由 Service 和 Client 两部分组成,在服务器上可以不安装 Docker Client,可以通过 Http Api 等方式与 Docker Servie 通讯。

在安装了 Docker 的主机上执行命令 docker version 查看版本号。

Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:58:10 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:56:35 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.6
  GitCommit:        d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Docker 客户端

要想跟 Docker Server 通讯,可以使用 Restful API、UNIX 套接字或网络接口(Socket)。Docker 官方的客户端是一个二进制命令行程序,使用 Go 语言编写,我们也可以使用 C#、Java 等语言写一个类似的程序,Docker 客户端不需要安装到 Docker Server 所在的主机,Client 跟 Server 可以远程通讯。

Docker 的客户端是许多 Docker 用户与 Docker 交互的主要方式,当我们使用 docker run 之类的命令时,客户端会将这些命令发送到 Docker Server,由 Docker Server 解析并执行命令。

Docker for Linux 中最为常见的同主机通讯方式是 Unix 域套接字。很多软件都支持使用域套接字与 Docker 通讯,例如 CI/CD 软件 Jenkins,使用域套接字连接 Docker,能够利用 Docker 启动容器构建应用程序以及使用 Docker 来做一些不可描述的事情。

容器运行时

容器运行时是提供运行环境并启动容器的软件,我们最常听说的是 Docker,此外还有 containerdCRI-O 等。可以毫不夸张的说,整个 Kubernetes 建立在容器之上。

默认情况下,Kubernetes 使用 容器运行时接口(Container Runtime Interface,CRI) 来与服务器中容器运行时交互。所以 Kubernetes 支持多种容器软件,但只能使用一种容器运行时进行工作,在有多个容器运行时的情况下,我们需要指定使用何种运行时,如果你不指定运行时,则 kubeadm 会自动尝试检测到系统上已经安装的运行时, 方法是扫描一组众所周知的 Unix 域套接字。

Linux 是多进程操作系统,为了让多个系统中的多个进程能够进行高效的通讯,出现和很多方法,其中一种是域套接字(Unix domain socket),只能用于在同一计算机中的进程间通讯,但是其效率高于网络套接字(socket),域套接字不需要经过网络协议处理,通过系统调用将数据从一个进程复制到另一个进程中。

域套接字使用一个 .sock 文件进行通讯,常见的容器软件其对应域套接字如下:

运行时 域套接字
Docker /var/run/dockershim.sock
containerd /run/containerd/containerd.sock
CRI-O /var/run/crio/crio.sock

同一主机下常见进程通讯方式有 共享内存、消息队列、管道通讯(共享文件)。

Unux 域套接字是套接字和管道之间的混合物。 在 Linux 中,有很多进程,为了让多个进程能够进行通讯,出现和很多方法,其中一种是套接字(socket)。一般的 socket 都是基于 TCP/IP 的,称为网络套接字,可以实现跨主机进程通讯。在 Linux 中有一种套接字,名为域套接字,只能用于在同一计算机中的进程间通讯,但是其效率高于网络套接字。域套接字使用一个 .sock 文件进行通讯。

当计算机中有多种容器运行时,Kubernetes 默认优先使用 Docker。

如果你想了解 CRI ,请点击:

https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md

Docker 引擎

Docker 引擎也可以说是 Docker Server,它由 Docker 守护进程(Docker daemon)、containerd 以及 runc 组成。

当使用 Docker client 输入命令时,命令会被发送到 Docker daemon ,daemon 会侦听请求并管理 Docker 对象,daemon 可以管理 镜像、容器、网络和存储卷等。

下面这个图是新 Docker 版本的结构组成。

Docker 引擎变化

Docker 首次发布时,Docker 引擎由两个核心组件构成:LXC 和 Docker daemon,这也是很多文章中称 Docker 是基于 LXC 的原因,旧版本的 Docker 利用了 LXC、cgroups、Linux 内核编写。接下来我们了解一下 LXC 。

LXC (Linux Container)是 Linux 提供的一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,它是操作系统层面上的虚拟化技术。LXC 提供了对诸如命名空间(namespace) 和控制组(cgroups) 等基础工具的操作能力,它们是基于 Linux 内核的容器虚拟化技术。我们不需要深入了解这个东西。

Docker 一开始是使用 LXC 做的,LXC 是一个很牛逼的开源项目,但是随着 Docker 的成熟,Docker 开始抛弃 LXC,自己动手手撕容器引擎。

为什么 Docker 要抛弃 LXC 呢?首先,LXC 是基于 Linux 的。这对于一个立志于跨平台的 Docker 来说是个问题,离开 LXC,怎么在 MAC、Windows 下运行?其次,如此核心的组件依赖于外部工具,这会给项目带来巨大风险,甚至影响其发展。

Docker 引擎的架构

下面是一张 Docker 的架构图。

Docker client 和 Docker daemon 在前面已经介绍过了,接下来介绍其他组件。

containerd

containerd 是一个开源容器引擎,是从 Docker 开源出去的。之前有新闻说 Kubernetes 不再支持 Docker,只支持 containerd,很多人以为 Docker 不行了。

一开始 Docker 是一个 “大单体”,随着 Docker 的成长,Docker 开始进行模块化,Docker 中的许多模块都是可替换的,如 Docker 网络。支持容器运行的核心代码自然也抽出来,单独做一个模块,便是 containerd。Kubernetes 不再支持 Docker,只不过是降低依赖程度,减少对其他模块的依赖,只集中在 containerd 上。当我们安装 Docker 时,自然会包含 containerd。如果我们不需要 Docker 太多组件,那么我们可以仅仅安装 containerd,由 Kubernetes 调度,只不过我们不能使用 Docker client 了。因此可以说,Kubernetes 不再支持 Docker,并不代表会排斥 Docker。

containerd 的主要任务是容器的生命周期管理,如启动容器、暂停容器、停止容器等。containerd 位于 daemon 和 runc 所在的 OCI 层之间。

shim

shim 它的作用非常单一,那就是实现 CRI 规定的每个接口,然后把具体的 CRI 请求“翻译”成对后端容器项目的请求或者操作。

这里要区别一下,dockershim 和 containerd-shim,dockershim 是一个临时性的方案,dockershim 会在 Kubernetes v1.24中 删除(2022年),这也是 Kubernetes 不再支持 Docker 的另一组件。

 提示

CRI 即 Container Runtime Interface,容器运行时接口,容器引擎要支持 Kubernetes ,需要实现 CRI 接口,例如 runc 、crun 两种是常见的 Container Runtime。

shim 是容器进程的父进程,shim 的生命周期跟容器一样长,shim 是一个轻量级的守护进程,它与容器进程紧密相关,但是 shim 与容器中的进程完全分离。shim 可以将容器的 stdin、stdout、srderr 流重定向到日志中,我们使用 docker logs 即可看到容器输出到控制台的流。

关于 shim,我们就先了解到这里,后面会继续讲解一个示例。

runc

runc 实质上是一个轻量级的、针对 Libcontainer 进行了包装的命令行交互工具,runc 生来只有一个作用——创建容器,即 runc 是一个由于运行容器的命令行工具。

 提示

Libcontainer 取代了早期 Docker 架构中的 LXC。

如果主机安装了 Docker,我们可以使用 runc --help 来查看使用说明。我们可以这样来理解 runc,runc 是在隔离环境生成新的进程的工具,在这个隔离环境中有一个专用的根文件系统(ubuntu、centos等)和新的进程树,这个进程树的根进程 PID=1

到此这篇关于Docker容器化应用与结构的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Docker 文件系统-AUFS 原理介绍

    目录 什么是联合文件系统 如何配置 Docker 的 AUFS 模式 AUFS 工作原理 AUFS 是如何存储文件的? AUFS 是如何工作的? 1. 读取文件 修改文件或目录 AUFS 演示 准备演示目录和文件 创建 AUFS 联合文件系统 验证 AUFS 的写时复制 结语 前言: 我们知道,Docker 主要是基于 Namespace.cgroups 和联合文件系统这三大核心技术实现的.前面的课时我详细讲解了 Namespace 和 cgroups 的相关原理,那么你知道联合文件系统是什么吗

  • 从进程中去理解 Docker隔离技术

    目录 1.起源 2.容器类比进程 3.隔离技术 4.总结 1.起源 “容器”这项技术的来龙去脉: 容器技术的兴起源于 PaaS 技术的普及: Docker 公司发布的 Docker 项目具有里程碑式的意义: Docker 项目通过“容器镜像”,解决了应用打包这个根本性难题. 容器本身没有价值,有价值的是“容器编排”. 也正因为如此,容器技术生态才爆发了一场关于“容器编排”的“战争”.而这次战争,最终以 Kubernetes 项目和 CNCF 社区的胜利而告终. 容器,到底是怎么一回事儿? 容器其

  • docker安装nginx并配置ssl的方法步骤

    最近想在吃灰了一年多的服务器上,安装一下docker,结果始终找不到合适的yum源,后来经过一番百度才知道,原来centos8要凉了,所以好多镜像站都移除了CentOS 8的源. 没办法,短暂的思考之后,决定重装一下操作系统,换成centos7.9,好在服务器上没啥重要东西,只要给blog挪个窝就行了. 重装系统之后,安装docker过程非常顺利. 开始安装nginx. 1.直接拉取最新的nginx镜像 docker pull nginx 2.新建一些目录,把nginx容器内的相关文件夹挂载到宿

  • 详解Docker Compose配置文件参数

    目录 1. image 2. build 3. command 4.container_name 5.depends_on 6.dns 7. tmpfs 8. entrypoint 9.env_file 10. environment 11. expose 12. external_links 13. extra_hosts 14. labels 15. links 16. logging 17. pid 18. ports 19. security_opt 20. stop_signal 21

  • Docker 隔离与限制原理介绍

    目录 为什么 Docker 比虚拟机受欢迎 优点 不足 资源限制 总结 为什么 Docker 比虚拟机受欢迎 在上一篇文章中,详细介绍了 Linux 容器中用来实现“隔离”的技术手段:Namespace.而通过这些讲解,你应该能够明白,Namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容.但对于宿主机来说,这些被“隔离”了的进程跟其他进程并没有太大区别.说到这一点,在之前虚拟机与容器技术的对比图里,不应该把 Docker

  • Docker部署项目完全使用指南(小结)

    目录 环境准备 Docker安装启动 Java环境安装 Docker远程访问配置 Docker重启 IDEA配置Docker 项目配置 配置Dockerfile文件 Docker配置 Maven打包生成Docker镜像 总结 Linux操作命令 Docker操作命令 环境准备 Docker安装启动 检查系统内核是否满足3.10及以上版本: uname -r 升级内核软件包: yum update 使用yum安装Docker: yum install docker 启动Docker: system

  • Docker镜像与容器的导入导出操作实践

    目录 一.前言 二.docker镜像的导入和导出 1.docker镜像的导出 2.docker镜像的导入 三.docker容器的导入和导出 1.docker容器的导出 2.docker容器的导入 四.总结 一.前言 随着容器技术的发展,现在很多的应用程序系统都会选择使用docker容器进行部署,但是有时候使用docker容器进行部署的时候会遇到问题,比如说我们的应用程序里面需要依赖其他第三方的镜像,如果这时候服务器是在内网不能连接外网的情况下,那么就无法部署了.基于这种情况,docker官方支持

  • Docker容器化应用与结构

    目录 容器化应用 什么是容器化应用 应用怎么打包 Docker 镜像组成 联合文件系统 Linux 内核 Docker 结构 Docker 服务与客户端 Docker 客户端 容器运行时 Docker 引擎 Docker 引擎变化 Docker 引擎的架构 containerd shim runc 容器化应用 什么是容器化应用 containerized applications 指容器化的应用,我们常常说使用镜像打包应用程序,使用 Docker 发布.部署应用程序,那么当你的应用成功在 Doc

  • Node.js服务Docker容器化应用实践小结

    本篇不会讲解 Docker 命令的使用.安装等,因为在之前一篇文章一文零基础教你学会 Docker 入门到实践中也已经讲解的很详细了,不清楚的可以点击链接回头在重新看下,本篇重点是介绍 Node.js 项目如何进行 Docker 容器化及一些实践优化,还有一些常见的问题,当然如果还有其它使用上的问题也欢迎大家在评论区进行留言补充. 作者简介:五月君,Nodejs Developer,热爱技术.喜欢分享的 90 后青年,公众号「Nodejs技术栈」,Github 开源项目 www.nodejs.r

  • Docker容器化spring boot应用详解

    前置条件 容器化spring boot应用所需环境: jdk 1.8 + maven 3.0 + 我们的需求是:使用maven打包,将spring boot应用制作成docker镜像并上传到docker hub.在其他机器上,可以直接docker pull并运行容器. 创建spring boot应用 spring boot 包结构为: └── src └── main └── java └── me └── ithakar 创建spring boot Application主类,src/main

  • Django Docker容器化部署之Django-Docker本地部署

    本章将在本地搭建一个容器化的 Django 项目,感受 Docker 的运作方式. 前期准备 开发环境 虽然有基于 Windows 的 Docker 版本,但各方面兼容做得都不太好(安装也麻烦些),因此建议读者在学习前,自行安装好 Linux 或 Mac 系统.当然你愿意折腾的话,在 Windows 上搞也行. 别担心,以后开发 Django 项目仍然可以在 Windows 下进行,仅仅是开发时不使用 Docker 而已. 软件安装 Docker:学习 Docker 当然要安装 Docker 软

  • Docker容器化部署Python应用过程解析

    简单应用部署 一.目录结构: └── Pythonpro #目录 └── test.py #文件 └── requirements.txt #文件 └── Dockerfile #文件 二.编写Dockerfile文件 # 基于镜像基础 FROM python:3.6.4 # 创建代码文件夹工作目录 /code RUN mkdir /code # 复制当前代码文件到容器中 /code COPY . /code # 安装所需的包 RUN pip install -r /code/requireme

  • 详解利用ELK搭建Docker容器化应用日志中心

    概述 应用一旦容器化以后,需要考虑的就是如何采集位于Docker容器中的应用程序的打印日志供运维分析.典型的比如SpringBoot应用的日志 收集.本文即将阐述如何利用ELK日志中心来收集容器化应用程序所产生的日志,并且可以用可视化的方式对日志进行查询与分析,其架构如下图所示: 架构图 镜像准备 镜像准备 ElasticSearch镜像 Logstash镜像 Kibana镜像 Nginx镜像(作为容器化应用来生产日志) 开启Linux系统Rsyslog服务 修改Rsyslog服务配置文件: v

  • Docker容器化部署尝试——多容器通信(node+mongoDB+nginx)

    原因是这样的 想要部署一个mocker平台,就在朋友的推荐下选择了 api-mocker 这个现成的项目 该项目分为服务端node.客户端vue.以及数据库mongoDB 在尝试直接部署的时候发现需要装一大堆的环境,node.mongo.nginx啊,特别的麻烦,之前简单的使用过docker,就在想能不能用docker免环境直接部署呢?于是就有了这次的尝试 多容器通信 该项目分为3个部分,于是就要建立3个容器(node.mongo.nginx) 那容器之间怎么实现通信呢? # 通过link指令建

  • .NETCore Docker实现容器化与私有镜像仓库管理

    一.Docker介绍 Docker是用Go语言编写基于Linux操作系统的一些特性开发的,其提供了操作系统级别的抽象,是一种容器管理技术,它隔离了应用程序对基础架构(操作系统等)的依赖.相较于虚拟机而言,Docker共享的是宿主机的硬件资源,使用容器来提供独立的运行环境来运行应用.虚拟机则是基于Supervisor(虚拟机管理程序)使用虚拟化技术来提供隔离的虚拟机,在虚拟机的操作系统上提供运行环境!虽然两者都提供了很好的资源隔离,但很明显Docker的虚拟化开销更低! Docker涉及了三个核心

  • Docker大型项目容器化改造

    虚拟化和容器化是项目云化不可避免的两个问题.虚拟化由于是纯平台操作,一个运行于linux操作系统的项目几乎不需要做任何改造就可以支持虚拟化.而项目如果要支持容器化则需要做许多细致的改造工作.容器化相对于虚拟化的优势也相当明显,运行于裸机性能高,秒级启停容器,更不用说开发.测试.布署一致的环境(DevOps理念),以及上篇提到的微服务的能力.大家还可以找到各种文章来介绍容器化(Docker)的知识,这里我们就不一一赘述.下面我们会根据项目的实际情况,介绍下容器化改造会面临的问题和解决方案. 一个几

  • 容器化技术架构jenkins docker k8s脚本浅析

    目录 前言碎语 浅谈docker 浅谈k8s的部署脚本 最后聊聊jenkinspipeline 前言碎语 基于kubernetes容器化技术架构能够带来诸多好处,诸如,弹性伸缩,自动修复等,在比如蓝绿部署,灰度发布等.近几年容器化技术飞速发展,了解服务网格 的人可能会发现,新兴技术 istio 等service mesh技术没有容器化的技术环境根本就没法实践. 浅谈docker docker可以类比为jvm,jvm也是虚拟机,然后docker的image可以类比为jar包,jar运行在jvm里面

随机推荐