Docker圣经:大白话说Docker底层原理,6W字实现Docker自由

Posted 疯狂创客圈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker圣经:大白话说Docker底层原理,6W字实现Docker自由相关的知识,希望对你有一定的参考价值。

说在前面:

现在拿到offer超级难,甚至连面试电话,一个都搞不到。

尼恩的技术社群(50+)中,很多小伙伴凭借 “左手云原生+右手大数据”的绝活,拿到了offer,并且是非常优质的offer,据说年终奖都足足18个月。

而云原生的核心组件是 Docker + K8S,但是 Docker 又很难。在这里,尼恩从架构师视角出发,Docker + K8S 核心原理做一个宏观的介绍。

由于内容确实太多, 所以写两个pdf 电子书,并且后续会持续升级:

(1) 《 Docker 学习圣经 》PDF

(2) 《 K8S 学习圣经 》PDF

带大家穿透Docker + K8S ,实现Docker + K8S 自由,让大家不迷路。

本书 《 Docker 学习圣经 》PDF的 V1版本,后面会持续迭代和升级。供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

注:本文以 PDF 持续更新,最新尼恩 架构笔记、面试题 的PDF文件,请从这里获取:语雀或者码云

《 Docker 学习圣经 》PDF 封面

Docker基础

作为大神或者准架构师/架构师,一定要了解一下docker的底层原理。

首先还是简单, 说明一下Docker 巨大的价值

Docker 巨大的价值

Docker 是一个开源的应用容器引擎,基于 Go 语言开发。

Docker 遵从 Apache2.0 协议开源。

Docker 的本质:

先来说说Docker 的本质

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,实现轻量级虚拟化。

docker为什么有这么巨大的价值呢?

因为,在容器技术出来之前,大家都是使用虚拟机技术,比如在 window中装一个VMware,通过这个软件我们可以虚拟出来一台或者多台电脑,实现硬件资源的细粒度分割和使用隔离。

但是 ,虚拟机技术太笨重啦!模式太重。

Docker容器技术,也是一种虚拟化技术,也是实现硬件资源的细粒度分割和使用隔离。但是,Docker是一种轻量级的虚拟机技术。

Docker容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),

对于开发人员来说,用 CE(Community Edition) 社区版就可以了

Docker的广泛应用场景:

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。

一般来说,测试环境、生产环境,基本都已经全面docker化了。

可见,docker技术,是那么那么的重要。

Docker的在DevOps(开发、运维)场景的应用

一般来说,怎么的微服务应用,有多套环境:

(1)开发
(2)测试
(3)预生产
(4)生产

四套环境,导致环境配置是十分的麻烦,每一个环境都要部署各种组件(如Redis、ES、zk) ,非常的费时费力。

更要命的是,在生产环境上, 吞吐量一上来,需要动态扩容。

使用docker,咱们可以将DevOps(开发、运维)的工作,高速完成:

(1)快速完成 发布工作

开发环境一般是 Windows/mac,最后发布到Linux。

没有docker之前,使用jar包发布,配上大量的shell脚本,然后各种配置,及其复杂。

有了docker之后,做好镜像,开发打包部署上线,一套流程做完!

(2)快速完成 交付工作

传统的交付工作,要给用户提供各种安装的帮助文档,安装程序,基础环境安装,依赖的中间件安装,等等等等。

有了docker之后,能更快速的交付和部署。 给他一套镜像,通过Docker命令,一键运行,啥都是好的。

那你看,docker 是不是,真香。

(3)更便捷的升级和扩缩容

使用了 Docker之后,我们项目打包为一个镜像,部署应用就和搭积木一样

扩展服务器A,启动一个容器就ok。

扩展服务器B,启动一个容器就ok。

如果要动态扩展,使用K8S这类分布式容器管理基础设施,配上一个HPA 控制器组件,就能自动的完成动态扩容,动态缩容。

那你看,docker 是不是,真香。

(4)服务器的性能可以被压榨到极致

Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例。

服务器的性能可以被压榨到极致

那你看,docker 是不是,真香。

接下来,随着40岁老架构师一起,来穿透docker的原理和实操吧。

只有先穿透docker,才能穿透K8S,最终穿透云原生+大数据,实现你的技术自由。

Docker的历史

2010年,几个的年轻人在美国的旧金山成立了一家公司 dotcloud。dotcloud 是一个Paas平台的创业公司,从事LXC(Linux Container容器)有关的容器技术。

Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。他们将自己的技术(容器化技术)命名就是 Docker。

Docker刚刚延生的时候,没有引起行业的注意!

虽然获得了创业孵化器(Y Combinator)的支持、也获得过一些融资,但随着IT巨头们(微软、谷歌、亚马逊等厂商)也进入PaaS凭他,dotCloud举步维艰,眼看就活不下去!

2013年,dotCloud的创始人,28岁的Solomon Hykes做了一个艰难的决定,将dotCloud的核心引擎开源,这项核心引擎技术能够将Linux容器中的应用程序、代码打包,轻松的在服务器之间进行迁移。

2013发布了 Docker-compose 组件提供容器的编排工具。

2014年 Docker 发布1.0版本,2015年Docker 提供 Docker-machine,支持 windows 平台。

docker火了。

这个基于LXC技术的核心管理引擎开源后,让全世界的技术人员感到惊艳。

大家感叹这一切太方便了!!于是,越来越多的人发现docker的优点,使用他!

虽然,Docker 项目在开源社区大受追捧,同时也被业界诟病的是: Docker 公司对于 Docker 发展具有绝对的话语权,比如 Docker 公司推行了 libcontainer 难以被社区接受。

为了防止 Docker 这项开源技术被Docker 公司控制,几个核心贡献代码的厂商诸如 Redhat,谷歌的倡导下,成立了 OCI 开源社区,制定了 OCI 开放容器标准,Open Container Initiative(OCI,开放容器标准)。

OCI 开源社区旨在于将 Docker 的发展权利回归社区,当然反过来讲,Docker 公司也希望更多的厂商安心贡献代码到Docker 项目,促进 Docker 项目的发展。

Docker 将自己容器格式和运行时 runC 捐给了 OCI,OCI 在此基础上制定了 2 个标准:

运行时标准 Runtime Specification (runtime-spec)

镜像标准 Image Specification (image-spec) :

于是通过OCI建立了 runc 项目,替代 libcontainer,这为开发者提供了除 Docker 之外的容器化实现的选择。

OCI 社区提供了 runc 的维护,而 runc 是基于 OCI 规范的运行容器的工具。

换句话说,你可以通过 runc,提供自己的容器实现,而不需要依赖 Docker。

当然,Docker 的发行版底层也是用的 runc。在 Docker 宿主机上执行 runc,你会发现它的大多数命令和 Docker 命令类似,感兴趣的读者可以自己实践如何用 runc 启动容器。

至2017年,Docker 项目转移到 Moby 项目,基于 Moby 项目,Docker 提供了两种发行版,Docker CE 和 Docker EE, Docker CE 就是目前大家普遍使用的版本,Docker EE 成为付费版本,提供了容器的编排,Service 等概念。

Docker 公司承诺 Docker 的发行版会基于 Moby 项目。这样一来,通过 Moby 项目,你也可以自己打造一个定制化的容器引擎,而不会被 Docker 公司绑定。

Docker 的入门知识

从大家常用的Docker Engine开始说起。

Docker Engine

当人们说“Docker”时,他们通常是指 Docker Engine,它是一个客户端 - 服务器应用程序,

Docker 引擎由如下主要的组件构成:Docker 客户端(Docker Client)、Docker 守护进程(Docker daemon)、containerd 以及 runc。

Docker Engine 从 CLI 中接受docker 命令,完成容器的管理:

例如使用 docker run 、docker ps 来列出正在运行的容器、

例如使用docker images 来列出镜像,

等等。

Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上,

Client通过Socket连接从客户端访问Docker守护进程。Docker守护进程从客户端接受命令,并按照命令,管理运行在主机上的容器。

  • 后台进行(dockerd)
  • REST API Server
  • CLI接口(docker)

Docker Platform

  • Docker提供了一个开发,打包,运行app的平台
  • 把app和底层infrastructure隔离开来

其三层模型如图:

到底什么是docker:

到底什么是docker:

  • docker是一个软件,可以运行在window、linux、mac等各种操作系统上。
  • docker 是一个开源的应用容器引擎,基于Go 语言开发并遵从 Apache2.0 协议开源,项目代码托管在github上进行维护
  • docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。
  • 容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。

什么是容器?

什么是容器?

  • 对软件和其依赖的标准化打包
  • 应用之间相互隔离
  • 共享同一个OS Kernel
  • 可以运行在很多主流操作系统上

注:容器和虚拟机的区别在于容器是APP层面的隔离,而虚拟化是物理资源层面的隔离

容器解决了什么问题?

  • 解决了开发和运维之间的矛盾
  • 在开发和运维之间搭建了一个桥梁,是实现devops最佳解决方案

一个docker 容器,是一个运行时环境,可以简单理解为进程运行的集装箱。

docker基本组成

docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);

docker仓库(Registry):用来保存各种打包好的软件镜像;仓库分为公有仓库和私有仓库。(很类似 maven)

docker镜像(Images):软件打包好的镜像;放在docker仓库中;

docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用

Docker 包括三个基本概念:

  • 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。

Docker 容器通过 Docker 镜像来创建。

概念 说明
Docker 镜像(Images) Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
Docker 容器(Container) 容器是独立运行的一个或一组应用,是镜像运行时的实体。
Docker 客户端(Client) Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。
Docker 主机(Host) 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
Docker Registry Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Docker 与虚拟机有何区别

Docker 的误解:Docker 是轻量级的虚拟机。

很多人将docker理解为, Docker 实现了类似于虚拟化的技术,能够让应用跑在一些轻量级的容器里。这么理解其实是错误的。

docker和kvm都是虚拟化技术,它们的主要差别:

1、Docker有着比虚拟机更少的抽象层

2、docker利用的是宿主机的内核,VM需要的是Guest OS

二者的不同:

  • VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库,然后再安装应用;
  • Container(Docker容器),在宿主机器、宿主机器操作系统上创建Docker引擎,在引擎的基础上再安装应用。

所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统,避免引导。docker是利用宿主机的操作系统,省略了这个复杂的过程,秒级!

虚拟机是加载Guest OS ,这是分钟级别的

与传统VM特性对比:

作为一种轻量级的虚拟化方式,Docker在运行应用上跟传统的虚拟机方式相比具有显著优势:

  • Docker 容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式要快得多。
  • Docker 容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器。
  • Docker 通过类似Git的操作来方便用户获取、分发和更新应用镜像,指令简明,学习成本较低。
  • Docker 通过Dockerfile配置文件来支持灵活的自动化创建和部署机制,提高工作效率。
  • Docker 容器除了运行其中的应用之外,基本不消耗额外的系统资源,保证应用性能的同时,尽量减小系统开销。
  • Docker 利用Linux系统上的多种防护机制实现了严格可靠的隔离。从1.3版本开始,Docker引入了安全选项和镜像签名机制,极大地提高了使用Docker的安全性。
特性 容器 虚拟机
启动速度 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于原生
系统支持量 单机支持上千个容器 一般几十个

docker与操作系统比较

docker是一种轻量级的虚拟化方式。与传统操作系统技术的特性比较如下表:

特 性 容 器 虚 拟 机
启动速度 秒级 分钟级
性能 接近原生 较弱
内存代价 很小 较多
硬盘使用 一般为MB 一般为GB
运行密度 单机支持上千个容器 一般几十个
隔离性 安全隔离 完全隔离
迁移性 优秀 一般

传统的虚拟机方式提供的是相对封闭的隔离。

Docker利用Linux系统上的多种防护技术实现了严格的隔离可靠性,并且可以整合众多安全工具。

从 1.3.0版本开始,docker重点改善了容器的安全控制和镜像的安全机制, 极大提高了使用docker的安全性。

Docker 的安装

安装docker前置条件

当我们安装 Docker 的时候,会涉及两个主要组件:

  • Docker CLI:客户端
  • Docker daemon:有时也被称为“服务端”或者“引擎”

环境准备

硬件总体要求,可以参考尼恩的本地硬件情况:

1、硬件要求。

本文硬件总体要求如下表:

序号 硬件 要求
1 CPU 至少2核
2 内存 至少8G
3 硬盘 至少100G磁盘空间

2、本地虚拟机环境

软件 版本
Win win10以上
virtual box 6以上
vagrant 2以上

docker+K8S学习环境非常复杂,尼恩搞这个 前前后后起码折腾了一周,

其中,很多头疼的工作,包括linux内核升级、磁盘扩容等等, 苦不堪言。

现在把这个环境,以虚拟机box镜像的方式,导出来直接给大家,

大家一键导入后,直接享受docker 的实操,享受K8S的实操,可以说,爽到不要不要的。

以上软件和 尼恩个人的虚拟机box镜像,可以找尼恩获取。

docker安装的三种方式

安装docker的三种方式

(1)离线安装

(2)在线安装

(3)用现成的

方式一 :离线安装docker

这里以 19.03.9 版本进行介绍, 其他版本是一样的。

这种安装方式,可以用于没有 互联网的 场景。

比如,很多公司,并不能直接上外网。

一、基础环境

1、操作系统:CentOS 7.3

2、Docker版本:19.03.9 官方下载地址

3、官方参考文档:https://docs.docker.com/install/linux/docker-ce/binaries/#install-static-binaries

二、Docker安装

1、下载

wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz

注意:如果事先下载好了可以忽略这一步

2、解压

把压缩文件存在指定目录下(如root),并进行解压

tar -zxvf docker-19.03.9.tgz

cd root
[root@localhost ~]# tar -zxvf docker-19.03.6.tgz
docker/
docker/containerd
docker/docker
docker/ctr
docker/dockerd
docker/runc
docker/docker-proxy
docker/docker-init
docker/containerd-shim

3、将解压出来的docker文件内容移动到 /usr/bin/ 目录下

cp docker/* /usr/bin/

4、将docker注册为service

cat /etc/systemd/system/docker.service

vi /etc/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID

# Having non-zero Limit*s causes performance problems due to accounting overhead

# in the kernel. We recommend using cgroups to do container-local accounting.

LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0

# set delegate yes so that systemd does not reset the cgroups of docker containers

Delegate=yes

# kill only the docker process, not all processes in the cgroup

KillMode=process

# restart the docker process if it exits prematurely

Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

5、启动

chmod +x /etc/systemd/system/docker.service  #添加文件权限并启动docker

systemctl daemon-reload               #重载unit配置文件

systemctl start docker     #启动Docker

systemctl enable docker.service       #设置开机自启
[root@localhost ~]# vi /etc/systemd/system/docker.service
[root@localhost ~]# chmod +x /etc/systemd/system/docker.service
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl start docker
[root@localhost ~]# systemctl enable docker.service
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /etc/systemd/system/docker.service.

6、验证

systemctl status docker #查看Docker状态

docker -v #查看Docker版本

docker info
[root@localhost ~]# systemctl status docker
 docker.service - Docker Application Container Engine
   Loaded: loaded (/etc/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2021-10-09 15:25:44 CST; 29s ago
     Docs: https://docs.docker.com
 Main PID: 1916 (dockerd)
   CGroup: /system.slice/docker.service
           ├─1916 /usr/bin/dockerd
           └─1927 containerd --config /var/run/docker/containerd/containerd.toml --log-level info

Oct 09 15:25:43 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:43.671407996+08:00" level=info msg="scheme \\"unix\\" not r...e=grpc
Oct 09 15:25:43 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:43.671440368+08:00" level=info msg="ccResolverWrapper: se...e=grpc
Oct 09 15:25:43 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:43.671462935+08:00" level=info msg="ClientConn switching ...e=grpc
Oct 09 15:25:43 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:43.750687781+08:00" level=info msg="Loading containers: start."
Oct 09 15:25:44 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:44.072960862+08:00" level=info msg="Default bridge (docke...dress"
Oct 09 15:25:44 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:44.153444071+08:00" level=info msg="Loading containers: done."
Oct 09 15:25:44 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:44.175249299+08:00" level=info msg="Docker daemon" commit...9.03.6
Oct 09 15:25:44 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:44.175337834+08:00" level=info msg="Daemon has completed ...ation"
Oct 09 15:25:44 localhost.localdomain systemd[1]: Started Docker Application Container Engine.
Oct 09 15:25:44 localhost.localdomain dockerd[1916]: time="2021-10-09T15:25:44.195084106+08:00" level=info msg="API listen on /var/ru....sock"
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost ~]# docker -v
Docker version 19.03.6, build 369ce74a3c
[root@localhost ~]# docker info

方式二 :在线安装docker

如果可以连接公网,建议在线安装。

这里注意 linux和 docker的版本。

尼恩安装 docker 最新版本的时候,发现依赖了 Centos 8 以上的版本。

在线安装docker步骤

  1. 更新yum
yum update
  1. 安装工具包
yum -y install yum-utils
  1. 设置yum源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

以腾讯源为例

https://mirrors.cloud.tencent.com/docker-ce/linux/centos/docker-ce.repo
  1. 安装Docker-Ce(社区版)
yum install docker-ce
  1. 查看docker版本(用来确认是否安装成功)
# 输入 docker-v 后如果出现下面的内容则代表安装成功
[root@VM-24-9-centos ~]# docker -v
Docker version 20.10.23, build 7155243
  1. Docker镜像加速(国内使用)
# 需要确定/etc下面是否有docker这个文件夹,若没有则需要使用下面的命令进行创建
mkdir -p /etc/docker

# 创建配置文件daemon.json
vi /etc/docker/daemon.json

# 写入以下内容

"registry-mirrors": [
"https://mirror.ccs.tencentyun.com" # 可以替换为其他厂商的地址
    ]


# 重载一下配置
systemctl daemon-reload
  1. 启动Docker服务
systemctl start docker
  1. 验证docker是否可以使用
[root@VM-24-9-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

方式三 :用现成的 (大大的省事)

docker+K8S 是一整套技术体系。

但是,docker+K8S学习环境非常复杂,尼恩搞这个 前前后后起码折腾了一周。

其中,很多头疼的工作,包括linux内核升级、磁盘扩容等等, 苦不堪言。

现在把这个环境,以虚拟机box镜像的方式,导出来直接给大家,

大家一键导入后,直接享受docker 的实操享受K8S的实操

可以说,爽到不要不要的。

以上环境和 尼恩个人的虚拟机box镜像,可以找尼恩获取。

Docker Container概述

什么是Container 容器

  • 通过Image创建(copy)
  • 在Image layer之上建立一个container layer(可读写)
  • 类比面向对象:类和实例
  • Image负责app的存储和分发,Container负责运行app

容器与镜像的关系

  • 镜像:镜像是只读文件,提供运行程序完整的软硬件资源。
  • 容器:容器是镜像的实例,由docker负责创建,容器之间彼此隔离。

Docker本地容器相关的操作

Container相关命令

  • 创建容器 docker run centos
  • 创建容器 docker run -it centos
  • 查看活跃容器 docker ps
  • 查询容器状态 docker container ls -a
  • 移除容器 docker container rm + [container ID]
  • 移除镜像 docker image rm + [image ID]
  • 显示所有containerID docker container ls -aq
  • 移除所有的container docker rm $(docker container ls -aq)

创建容器

创建名为"centos6"的容器,并在容器内部和宿主机中查看容器中的进程信息

docker run -itd -p 6080:80 -p 6022:22 docker.io/lemonbar/centos6-ssh:latest

结果如下

[root@VM-4-17-centos ~]#    docker run -itd -p 80:80 -p 6022:22 docker.io/lemonbar/centos6-ssh:latest
Unable to find image \'lemonbar/centos6-ssh:latest\' locally
latest: Pulling from lemonbar/centos6-ssh
a3ed95caeb02: Pull complete
f79eb1f22352: Pull complete
67c1aaa530c8: Pull complete
80447774eee7: Pull complete
6d67b3a80e5a: Pull complete
f1819e4b2f8f: Pull complete
09712b5b9acc: Pull complete
8bc987c5494f: Pull complete
c42b021d0ff2: Pull complete
Digest: sha256:093c2165b3c6fe05d5658343456f9b59bb7ecc690a7d3a112641c86083227dd1
Status: Downloaded newer image for lemonbar/centos6-ssh:latest
a4f1c9b8abcda78c8764cc285183dfa56cd1aa4ce6d111d4d9e77f3a57f3d5fc

查看活跃容器 docker ps

docker ps

查看全部容器

查询容器状态

docker ps -a

docker container ls -a

两个命令,效果差不多

停止容器

docker stop id

删除容器

docker rm id

查看容器的进程信息

docker top:查看容器中运行的进程信息,支持 ps 命令参数。

语法

docker top [OPTIONS] CONTAINER [ps OPTIONS]

容器运行时不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top命令,

可以使用docker top来实现查看container中正在运行的进程。

docker top 容器名称

尼恩的虚拟机中,存在容器zookeeper/ mysql,如果想查看zookeeper/ mysql 容器内的运行进程信息,

可以使用下述命令:

docker top zookeeper
docker top mysql

如何查找容器名称?

很多的命令,用到容器名称

如何查找容器名称,可以使用下面的命令

[root@localhost ~]# docker ps --format ".Names"

结果如下:

docker最为常用的几个命令

docker的守护进程查看

systemctl status docker

docker 镜像查看

docker image ls

docker 容器查看

docker ps

Docker Registry配置和查看

cat /etc/docker/daemon.json

配置私有仓库

cat>/etc/docker/daemon.json<<EOF


  "registry-mirrors":["http://10.24.2.30:5000","https://tnxkcso1.mirrors.aliyuncs.com"],

  "insecure-registries":["10.24.2.30:5000"]


EOF

Docker容器进入的4种方式

在使用Docker创建了容器之后,大家比较关心的就是如何进入该容器了,

其实进入Docker容器有好几多种方式,这里我们就讲一下常用的几种进入Docker容器的方法。

进入Docker容器比较常见的几种做法如下:

  • 使用docker attach
  • 使用SSH
  • 使用nsenter
  • 使用exec

方式1:使用docker attach进入Docker容器

Docker提供了attach命令来进入Docker容器。

接下来我们创建一个守护态的Docker容器,然后使用docker attach命令进入该容器。

sudo docker run -itd ubuntu:14.04 /bin/bash  

然后我们使用docker ps查看到该容器信息,接下来就使用docker attach进入该容器

 docker attach c1437f4bd302  

可以看到我们已经进入到该容器中了。

但在,使用该命令有一个问题:

当多个窗口同时使用该命令进入该容器时,所有的窗口都会同步显示。

如果有一个窗口阻塞了,那么其他窗口也无法再进行操作。

因为这个原因,所以docker attach命令不太适合于生产环境,平时自己开发应用时可以使用该命令。

方式2:使用SSH进入Docker容器

在生产环境中排除了使用docker attach命令进入容器之后,相信大家第一个想到的就是ssh。

在镜像(或容器)中安装SSH Server,这样就能保证多人进入。

容器且相互之间不受干扰了,相信大家在当前的生产环境中(没有使用Docker的情况)也是这样做的。

但是使用了Docker容器之后不建议使用ssh进入到Docker容器内。

方式3:使用nsenter进入Docker容器

在上面两种方式都不适合的情况下,还有一种比较方便的方法,即使用nsenter进入Docker容器。

1、什么是nsenter?

nsenter命令是一个可以在指定进程的命令空间下运行指定程序的命令。它位于util-linux包中。

util-linux 是一个开放源码的软件包,是一个对任何 Linux 系统的基本工具套件。含有一些标准 Unix 工具,如 login。
util-linux 软件包包含许多工具。其中比较重要的是加载、卸载、格式化、分区和管理硬盘驱动器,打开 tty 端口和得到内核消息。

nsenter用途 ?

一个最典型的用途就是进入容器的网络命令空间。相当多的容器为了轻量级,是不包含较为基础的命令的,比如说ip address,ping,telnet,ss,tcpdump等等命令,这就给调试容器网络带来相当大的困扰:只能通过docker inspect ContainerID命令获取到容器IP,以及无法测试和其他网络的连通性。这时就可以使用nsenter命令仅进入该容器的网络命名空间使用宿主机的命令调试容器网络。

在了解了什么是nsenter之后,系统默认将我们需要的nsenter安装到主机中, nsenter --help 查看帮助

nsenter --help 查看帮助

$ nsenter --help

nsenter [options] [program [arguments]]

options:
-t, --target pid:指定被进入命名空间的目标进程的pid
-m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
-u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
-i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
-n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
-p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
-U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
-G, --setgid gid:设置运行程序的gid
-S, --setuid uid:设置运行程序的uid
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录

如果没有给出program,则默认执行$SHELL。

2、nsenter安装

如果没有安装的话,按下面步骤安装即可(注意是主机而非容器或镜像)

具体的安装命令如下:

wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz
tar -xzvf util-linux-2.24.tar.gz
cd util-linux-2.24/
./configure --without-ncurses
make nsenter
sudo cp nsenter /usr/local/bin

3、nsenter的 使用

nsenter可以访问另一个进程的名称空间。

所以为了连接到某个容器我们还需要获取该容器的第一个进程的PID。

怎么办呢 ? 可以使用docker inspect命令来拿到该 进程的 PID。

docker inspect 命令使用如下:

sudo docker inspect --help

inspect命令可以分层级显示一个镜像或容器的信息。

比如我们当前有一个正在运行的容器

可以使用docker inspect来查看该容器的详细信息。

sudo docker inspect c1437f4bd302

由其该信息非常多,此处只截取了其中一部分进行展示。如果要显示该容器第一个进行的PID可以使用如下方式

sudo docker inspect -f .State.Pid    c1437f4bd302

在拿到该进程PID之后我们就可以使用nsenter命令访问该容器了。

sudo nsenter --target 22299 --mount --uts --ipc --net --pid

其中的 22299 即刚才拿到的进程的PID

输入该命令便进入到容器中

$ nsenter --target 上面查到的进程id --mount --uts --ipc --net --pid

解释nsenter指令中进程id之后的参数的含义:

–mount参数是进去到mount namespace中 (文件系统)
–uts参数是进入到uts namespace中 (主机名与域名)
–ipc参数是进入到System V IPC namaspace中 (信号量、消息队列和共享内容)
–net参数是进入到network namespace中 (网络设备、网络栈、端口)
–pid参数是进入到pid namespace中 (进程编号)
–user参数是进入到user namespace中 (用户和用户组)

看看下面的例子,进入到容器的 network namespace中 ,看看IP地址,是不是变了。

docker隔离应用应用涉及到的六大名称空间

1、pid 命名空间(进程ID)

不同用户的进程就是通过 pid 命名空间隔离开的,且不同命名空间中可以有相同 pid。

所有的 LXC (Linux 容器)进程在 Docker 中的父进程为 Docker 进程,每个 LXC 进程具有不同的命名空间。

同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。

2、net 命名空间(网络)

有了 pid 命名空间,每个命名空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。

网络隔离是通过 net 命名空间实现的, 每个 net 命名空间有独立的 网络设备,IP 地址,路由表,/proc/net 目录。这样每个容器的网络就能隔离开来。

Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。

3、ipc 命名空间(进程间通信)

容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。

然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 命名空间中的进程间交互,因此需要在 IPC 资源申请时加入命名空间信息,每个 IPC 资源有一个唯一的 32 位 id。

4、mnt 命名空间(挂载文件系统)

类似 chroot,将一个进程放到一个特定的目录执行。

mnt 命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间 中的进程所看到的文件目录就被隔离开了。

同 chroot 不同,每个命名空间中的容器在 /proc/mounts 的信息只包含所在命名空间的 mount point。

5、UTS 命名空间(主机名/域名)

UTS("UNIX Time-sharing System") 命名空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。

6、user 命名空间(用户)

每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。

nsenter查看docker的连接

由于使用DOCKER的时候,ESTABLISHED连接不会出现在netstat中,在运行中的docker容器中列出打开的套接字的方法

查看连接:

sudo docker inspect -f .State.Pid    e9eaef999da9

sudo nsenter -t  3473  -n netstat | grep ESTABLISHED    

方式4:使用docker exec进入Docker容器

除了上面几种做法之外,docker在1.3.X版本之后还提供了一个新的命令exec用于进入容器,这种方式相对更简单一些,下面我们来看一下该命令的使用:

sudo docker exec --help

接下来我们使用该命令进入一个已经在运行的容器

sudo docker ps  
sudo docker exec -it 容器id  /bin/bash  

在容器内部和宿主机中查看容器中的进程信息

进入一个名称为 rmqbroker-ha-b 的容器,查看进程信息

docker exec -it rmqbroker-ha-b  /bin/bash   ps -ef

结果如下:

我们可以使用docker exec命令进入容器PID名空间,并执行应用。

通过ps -ef命令,可以看到每个 rmqbroker-ha-b 容器都包含一个PID为1的进程,
容器的启动进程是 "sh mqbroker -c /opt/rocketmq.....",具有特殊意义。

利用docker top命令,可以让我们从宿主机操作系统中看到容器的进程信息。

"sh mqbroker -c /opt/rocketmq....." 这个命令的进程,在 容器里边是1 ,在容器外部 3473

查看其父进程信息

ps -ef | grep 3401

root        3401       1  0 12:06 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id e9eaef999da9183b9be0b3239881bc6b9c2070f13057c322dfed3d072820e962 -address /run/containerd/containerd.sock
3000        3473    3401  0 12:06 ?        00:00:00 sh mqbroker -c /opt/rocketmq-4.6.0/conf/broker.conf autoCreateTopicEnable=true &
root       26491   24084  0 16:16 pts/1    00:00:00 grep --color=auto 3401

我们使用docker run 启用一个容器时,docker 会给每个容器都启动一个containerd-shim-runc-v2 父进程,这个进程又启动了一个ttrpc server(类似grpc/httpserver), containerd 通过 ttrpc和containerd-shim-runc-v2 通信来管理容器

从父亲进程可以看到:容器的本质是进程。

containerd-shim-runc-v2 后面的参数:namespace用来做命名空间隔离,cgroup用来做资源限制。

containerd-shim-runc-v2 进程很特殊,它们跑在一些特定的namespace和cgroup下。

站在这些进程的角度看,它们会以为自己跑在一个独立的机器上,看不到其他进程,也看不到其他文件。

这是其实是操作系统为它虚拟出来的一个独立的、隔离的环境,是假的。

查看子进程信息

[root@VM-4-17-centos ~]#  ps aux | grep 27880

总计三个命令

docker top  rmqbroker-ha-b  #查看容器进程

ps -ef | grep 3401 #查看父进程
ps aux | grep 3473  #查看子进程(容器)

Docker本地镜像载入与载出

两种办法

  • 保存镜像(保存镜像载入后获得跟原镜像id相同的镜像)
  • 保存容器(保存容器载入后获得跟原镜像id不同的镜像)

拉取镜像

通过命令可以从镜像仓库中拉取镜像,默认从Docker Hub 获取。

命令格式:

docker image pull <repository>:<tag>

docker image pull   rancher/rke-tools:v0.1.52

[rancher/rke-tools:v0.1.52

保存镜像

  • docker save 镜像id -o /home/mysql.tar
  • docker save 镜像id > /home/mysql.tar
docker save  docker.io/rancher/rancher-agent   -o /home/rancher-agent .tar

docker save  f29ece87a195  -o /home/rancher-agent.tar

docker save  docker.io/rancher/rke-tools   -o /home/rke-tools-v0.1.52.tar

载入镜像

  • docker load -i mysql.tar
docker load -i /usr/local/rancher-v2.3.5.tar

docker load -i /usr/local/rancher-agent.tar

docker  inspect  f29ece87a1954772accb8a2332ee8c3fe460697e3f102ffbdc76eb9bc4f4f1d0

docker load -i /usr/local/rke-tools-v0.1.52.tar
docker load -i mysql.tar

[root@localhost ~]# docker load -i /usr/local/rancher-v2.3.5.tar
43c67172d1d1: Loading layer [==================================================>]  65.57MB/65.57MB
21ec61b65b20: Loading layer [==================================================>]  991.2kB/991.2kB
1d0dfb259f6a: Loading layer [==================================================>]  15.87kB/15.87kB
f55aa0bd26b8: Loading layer [==================================================>]  3.072kB/3.072kB
e0af200d6950: Loading layer [==================================================>]  126.1MB/126.1MB
088ed892f9ad: Loading layer [==================================================>]  6.656kB/6.656kB
6aa3142b4130: Loading layer [==================================================>]   34.5MB/34.5MB
f4e84c05ab29: Loading layer [==================================================>]  70.41MB/70.41MB
11a6e4332b53: Loading layer [==================================================>]  224.8MB/224.8MB
46d1ac556da7: Loading layer [==================================================>]  3.072kB/3.072kB
0f8b224a5802: Loading layer [==================================================>]  57.87MB/57.87MB
519eba7d586a: Loading layer [==================================================>]  99.58MB/99.58MB
3f8bb7c0c150: Loading layer [==================================================>]  4.608kB/4.608kB
c22c9a5a8211: Loading layer [==================================================>]  3.072kB/3.072kB
Loaded image: rancher/rancher:v2.3.5

打个tag

docker tag  f29ece87a1954772accb8a2332ee8c3fe460697e3f102ffbdc76eb9bc4f4f1d0 rancher/rancher-agent:v2.3.5

docker tag  f29ece87a195   172.18.8.104/rancher/rancher-agent:v2.3.5

docker tag 6e421b8753a2  172.18.8.104/rancher/rke-tools:v0.1.52 

83fe4871cf67
docker rmi image_name

docker rmi  -f  172.18.8.104/rancher/coredns-coredns:1.6.5 

docker rmi   -f   172.18.8.104/rancher/coredns-coredns:v3.4.3-rancher1

docker rmi hub.doge.net/ubuntu:latest

保存镜像

  • docker export 镜像id -o /home/mysql-export.tar
  • docker save 镜像tag -o /home/mysql-export.tar

载入镜像

  • docker import mysql-export.tar

Harbor私有镜像仓库

Harbor (港口,港湾)是一个用于存储和分发Docker镜像的企业级Registry服务器。

除了Harbor这个私有镜像仓库之外,还有Docker官方提供的Registry。

相对Registry,Harbor具有很多优势:

  1. 提供分层传输机制,优化网络传输 Docker镜像是是分层的,而如果每次传输都使用全量文件(所以用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定传输的对象。
  2. 提供WEB界面,优化用户体验 只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界面可以支持登陆、搜索功能,包括区分公有、私有镜像。
  3. 支持水平扩展集群 当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分解。
  4. 良好的安全机制 企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限,具有更好的安全性。

Harbor安装

harbor是用过docker-compose 编排的。

所以 安装的过程中,会检查docker、docker-compose 进程,确保提前启动。

这些,在咱们的虚拟机里边,docker、docker-compose 进程已经预装好了的。

查看docker是否安装成功;

[root@centos1 ~]# docker -v
Docker version 20.10.23, build 7155243

查看docker-compose是否安装成功;

docker-compose -version

[root@centos1 ~]# docker-compose -version
docker-compose version 1.25.1, build a82fef07
[root@centos1 ~]#

接下来,开始安装harbor

1、下载 Harbor的压缩包;

https://github.com/goharbor/harbor/releases

咱们用这个包: harbor-offline-installer-v2.3.2.tgz

咱们的学习网盘当中,尼恩已经上传了哈

2、上传压缩包到虚拟机,并解压;

[root@centos1 ~]# cd /usr/local/
[root@centos1 local]# mkdir harber
[root@centos1 local]# cd harber/

tar -zxvf harbor-offline-installer-v2.3.2.tgz

3、创建harbor访问域名证书

OpenSSL是一个强大的安全套接字层密码库,Apache使用它加密HTTPS,OpenSSH使用它加密SSH,但是,你不应该只将其作为一个库来使用,它还是一个多用途的、跨平台的密码工具。

参考:

Harbor docs | Configure HTTPS Access to Harbor (goharbor.io)

mkdir -p /usr/local/harbor/ssl && cd /usr/local/harbor/ssl
openssl genrsa -out tls.key 4096
      
 openssl req -x509 -new -nodes -sha512 -days 3650 \\
 -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=cdh1" \\
 -key tls.key \\
 -out tls.cert
  • 第一步创建ssl文件夹用来存储证书,
  • 第二步生成key (私钥),
  • 最后一步使用生成的key自签证书。自签证书包含公钥

days后面是你自签证书的有效时间可以自行修改。

\'CN=\'后面就写你自己的IP地址或者你自己的域名。

生成完成之后显示如下

4、配置harbor

修改Harbor的配置(harbor.yml);
修改主机地址:hostname: 192.168.56.121;
修改端口(默认端口80):port: 85;

cd /usr/local/harbor/harbor    #进入到harbor目录
cp   harbor.yml.tmpl    harbor.yml
vim harbor.yml   #编辑harbor的配置文件

#修改以下内容
hostname = 192.168.56.121  #修改harbor的启动ip,这里需要依据系统ip设置
port: 85 #harbor的端口,有两个端口,http协议(80)和https协议(443)
harbor_admin_password = 123456   #修改harbor的admin用户的密码
data_volume: /harbor/data #修改harbor存储位置

故harbor.yml中certificate填写为如上tls.cert的文件目录地址:/usr/local/harbor/ssl/tls.cert

故harbor.yml中private_key填写为如上tls.key的文件目录地址:/usr/local/harbor/ssl/tls.key

5、./prepare 准备

启动之前需要使用./prepare命令进行一些预置工作,下载相关依赖;

此时需要开启docker服务,不然会报错;

这个过程可能有点长,需要耐心等待;

/prepare

6、./install.sh

准备工作完成后,使用./install.sh进行Harbor的安装;
这个过程会持续一段时间,耐心等待;

./install.sh

访问

http://cdh1:85/

登录
默认登录名:admin;
默认登录密码:Harbor12345; 被尼恩改成了 12345
具体可以查看harbor.yml;

7、停止或者重启 Harbor

cd /usr/local/harber/harbor/

docker-compose up -d 启动
docker-compose start 启动
docker-compose stop 停止
docker-compose restart 重新启动

修改docker配置文件,使docker支持harbor

编辑客户机/etc/docker/daemon.json文件

"insecure-registries":["192.168.56.121:85"]

重启客户机docker服务

systemctl restart docker #或者(service docker restart)

[root@centos1 harbor]# cat  /etc/docker/daemon.json

  "registry-mirrors": [
    "https://bjtzu1jb.mirror.aliyuncs.com",
    "http://f1361db2.m.daocloud.io",
    "https://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://reg-mirror.qiniu.com",
    "https://dockerhub.azk8s.cn",
    "https://registry.docker-cn.com"
  ],
  "insecure-registries":["192.168.56.121:85"]

[root@centos1 ssh]# cat /etc/docker/daemon.json

  "registry-mirrors": [
    "https://bjtzu1jb.mirror.aliyuncs.com",
    "http://f1361db2.m.daocloud.io",
    "https://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://reg-mirror.qiniu.com",
    "https://dockerhub.azk8s.cn",
    "https://registry.docker-cn.com",
   "https://cdh1"
  ]

Harbor使用

可以 尝试上传镜像到 Harbor。

如果是另一台机器,需要添加本地hosts

echo \'192.168.56.121 cdh\' >> /etc/hosts

因为我们的证书是自签的是不受到其他机器信任的,所以我们要在 harber的客户端机器上放上我们的证书,才能拉取镜像。

使用下面的代码,在要使用 harber的客户端机器 上保存证书,其中 cdh1 部分使用你自己的域名或者是IP地址。

mkdir -p /etc/docker/certs.d/cdh1
scp 192.168.56.122:/usr/local/harbor/ssl/tls.cert /etc/docker/certs.d/cdh1/

本地docker 登录的话

mkdir -p /etc/docker/certs.d/cdh1
cp /usr/local/harbor/ssl/tls.cert /etc/docker/certs.d/cdh1/ca.crt

mkdir -p /etc/docker/certs.d/192.168.56.121

然后使用如下语句登录harbor,如果没有使用80端口一定要用IP地址加上你的端口号,冒号之后填端口号,查看自己harbor.yml里http或https里的端口详情。

docker login cdh1

报错 证书问题, 证书不含SAN

什么是含有SAN的证书

docker 的新版本使用golang 1.15+版本上,老的x509 证书不行了

SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。

subjectAltName 在 RFC 5280 4.2.1.6.中提供了详细的说明,subjectAltName 是 X.509 version 3 的一个扩展项,该扩展项用于标记和界定证书持有者的身份。

在 X.509 格式的证书中,一般使用 Issuer 项标记证书的颁发者信息,该项必须是一个非空的 Distinguished Name 名称。除此之外还可以使用扩展项 issuerAltName 来标记颁发者的其他名称,这是一个非关键的扩展项。

对于证书持有者,一般使用 Subject 项标记,并使用 subjectAltName 扩展项提供更详细的持有者身份信息。 subjectAltName 全称为 Subject Alternative Name,缩写为 SAN。它可以包括一个或者多个的电子邮件地址,域名,IP地址和 URI 等,详细定义如下:

SubjectAltName ::= GeneralNames
   GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

   GeneralName ::= CHOICE 
        otherName                       [0]     OtherName,
        rfc822Name                      [1]     IA5String,
        dNSName                         [2]     IA5String,
        x400Address                     [3]     ORAddress,
        directoryName                   [4]     Name,
        ediPartyName                    [5]     EDIPartyName,
        uniformResourceIdentifier       [6]     IA5String,
        iPAddress                       [7]     OCTET STRING,
        registeredID                    [8]     OBJECT IDENTIFIER 
    

当颁发的证书不存在 Subject 项的时候,证书必须包含扩展项 subjectAltName,并且标记为关键(critical)的。当颁发的证书存在 Subject 项的时候,必须将扩展项 subjectAltName 标记为非关键(no-critical)的。注意:用于颁发证书的 CA 证书是必须包含 Subject 项的。

根据 RFC 6125 中的规定,当一个网站使用证书

以上是关于Docker圣经:大白话说Docker底层原理,6W字实现Docker自由的主要内容,如果未能解决你的问题,请参考以下文章

K8S学习圣经:大白话说K8S底层原理,14W字实现K8S自由

Docker底层原理

Docker —— Docker 的底层原理

好奇宝宝看 Docker 底层原理(中)

Docker底层原理

docker底层原理