容器技术:了解Docker(一)
1. Docker是什么
首先 Docker 是一个在 2013 年开源的应用程序并且是一个基于 go 语言编写是一个开源的 pass 服务。Docker 是基于 linux 内核实现,Docker 最早采用 LXC 技术(LXC 是 Linux 原生支持的容器技术)。Docker 后改为自己研发并开源的 runc 技术运行容器。
runtime是容器真正运行的地方,runtime需要跟操作系统kernel紧密协作,为容器提供运行环境。Java程序就好比是容器,而JVM为容器提供了运行环境,容器只能在runtime中运行。(runtime就像JVM)
容器是隔离的环境中运行的一个进程,如果进程结束,容器就会停止。
2. Docker的组成
- Docker 主机(Host):一个物理机或虚拟机,用于运行 Docker 服务进程和容器。
- Docker 服务端(Server):Docker 守护进程,运行 docker 容器。
- Docker 客户端(Client):客户端使用 docker 命令或其他工具调用 docker API。
- Docker 仓库(Registry): 保存镜像的仓库,类似于 git 或 svn 这样的版本控制系统。
- Docker 镜像(Images):镜像可以理解为创建实例使用的模板。
- Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务。
Client向Docker daemon(Server)发出docker build命令就可以进行创建镜像。
Client向Docker daemon(Server)发出docker pull命令就可以让Docker daemon去远程仓库进行拉取镜像,当然如果本地有相关镜像了,也会直接提示。
Client向Docker daemon(Server)发出docker run命令,Docker daemon自检有没有此镜像,如果有,直接启动镜像。如果没有,则从远程仓库下载相关镜像,然后启动这个镜像。
docker 19.03.12 以后版本的 dockerd 和containerd 组件已经不是父子关系!以前是!
3. Docker与虚拟机对比
虚拟机
优点 | 缺点 |
---|---|
使用简单 | 需要硬件支持虚拟化技术 |
成熟的管理工具,vmware、kvm、openstack等 | 资源利用率不高 |
可以随意进行定制 | 占用资源较多 |
升级、快速扩容、快速部署和回滚百不方便 |
容器
优点 | 缺点 |
---|---|
快速部署 | 使用较为复杂 |
现成镜像 | 共享Linux系统内核 |
不依赖硬件 | |
秒级启动,相当于一个进程 |
4. Docker出现的问题
4.1 如何解决
上图一个宿主机运行了 N 个容器,多个容器带来的以下问题怎么解决:
- 怎么样保证每个容器都有不同的文件系统并且能互不影响?
- 一个 docker 主进程内的各个容器都是其子进程,那么实现同一个主进程下不同类型的子进程?各个进程间通信能相互访问(内存数据)吗?
- 每个容器怎么解决 IP 及端口分配的问题?
- 多个容器的主机名能一样吗?
- 每个容器都要不要有 root 用户?怎么解决账户重名问题?
4.2 Linux Namespace
namespace 是 Linux 系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在核内,各个 docker 容器运行在同一个 docker 主进程并且共用同一个宿主机系统内核。
各 docker 容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离。
关键技术
- MNT Namespace(mount):提供磁盘挂载点和文件系统的隔离能力
- IPC Namespace(Inter-Process Communication) :提供进程间通信的隔离能力
- UTS Namespace(UNIX Timesharing System) :提供主机名隔离能力
- PID Namespace(Process Identification) :提供进程隔离能力
- Net Namespace(network) :提供网络隔离能力
- User Namespace(user):提供用户隔离能力
Tips:关键技术可进一步查阅资料,掌握更细节的原理。
4.3 Chroot
什么是 chroot 呢?chroot 是在 Unix 和 Linux 系统的一个操作,针对正在运作的软件行程和它的子进程,改变它外显的根目录。一个运行在这个环境下,经由 chroot 设置根目录的程序,它不能够对这个指定根目录之外的文件进行访问动作,不能读取,也不能更改它的内容。
也就是给容器进程经由chroot设置根目录,使容器无法访问其他目录!
通过chroot技术实现在容器启动过程中,Docker会将容器内根目录挂载到主机上,并使用chroot命令将根目录切换为容器内的根目录。这样,容器内的进程只能访问到容器内的文件和数据,而不能访问到主机上的文件和数据,从而实现了隔离保护。
4.4 Cgroups
Cgroups 是一种 Linux 内核功能,可以限制和隔离进程的资源使用情况(CPU、内存、磁盘 I/O、网络等)。在容器的实现中,Cgroups 通常用来限制容器的 CPU 和内存等资源的使用。
4.5 UnionFS
联合文件系统,又叫 UnionFS,是一种通过创建文件层进程操作的文件系统,因此,联合文件系统非常轻快。Docker 使用联合文件系统为容器提供构建层,使得容器可以实现写时复制以及镜像的分层构建和存储。常用的联合文件系统有 AUFS、Overlay 和 Devicemapper 等。
5. Docker的核心和依赖技术
5.1 核心技术
5.1.1 容器规范
Open container (OCI)的组织,其目的就是制定开放的标准的容器规范,目前 OCI 一共发布了两个规范,分别是 runtime spec 和 和 image format spec,有了这两个规范,不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。
5.1.2 容器 runtime
runtime 是真正运行容器的地方,因此为了运行不同的容器 runtime 需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。
目前三种主流runtime:Lxc(linux上早期的runtime)、runc(Docker默认runtime)、rkt(CoreOS)
5.1.3 容器管理工具
管理工具连接 runtime 与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给 runtime 执行。runc的管理工具就是docker engine,包含后台 deamon 和 cli 两部分。
5.1.4 容器定义工具
容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建。
- Docker image:是 docker 容器的模板,runtime 依据 docker image 创建容器。
- Dockerfile:包含 N 个命令的文本文件,通过 dockerfile 创建出 docker image。
5.1.5 Registry
统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库。
-
Image registry:docker 官方提供的私有仓库部署工具。
-
Docker hub:docker 官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用。
-
Harbor:vmware 提供的自带 web 界面自带认证功能的镜像仓库,目前有很多公司使用。
5.1.6 编排工具
当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能。
因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎。容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
- Docker swarm:docker 开发的容器编排引擎。
- Kubernetes:google 领导开发的容器编排引擎,内部项目为 Borg,且其同时支持docker 和 CoreOS。
5.2 依赖技术
5.2.1 服务发现
容器的动态扩容特性决定了容器 IP 也会随之变化,因此需要有一种机制开源自动识别并将用户请求动态转发到新创建的容器上,kubernetes 自带服务发现功能,需要结合 kube-dns 服务解析内部域名。
5.2.2 容器监控
可以通过原生命令 docker ps/top/stats 查看容器运行状态,另外也可以使heapster/ Prometheus 等第三方监控工具监控容器的运行状态。
5.2.3 数据管理
容器的动态迁移会导致其在不同的 Host 之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决。
5.2.4 日志收集
docker 原生的日志查看工具 docker logs,但是容器内部的日志需要通过 ELK 等专门的日志收集分析和展示工具进行处理。