KylinSP3 | 一篇搞定金砖信息技术应用创新赛Docker容器集群管理
- 一、知识准备
-
- 1. Docker介绍
- 2. 四大对象
-
- 2.1 镜像
- 2.2 容器
- 2.3 网络
- 2.4 数据卷
- 3. Namespace介绍
-
- 3.1 PID 名字空间
- 3.2 net名字空间
- 3.3 ipc名字空间
- 3.4 mnt 名字空间
- 3.5 uts名字空间
- 3.6 user名字空间
- 4.Docker底层原理-cgroups
- 5.UnionFS
- 6. AUFS的概念
- 7. Overlay2
- 8. Docker工作流程
- 9. Docker Engine
-
- 9.1 Docker daemon
- 9.2 docker client
- 9.3 Client和Daemon分离
- 9.4 Docker镜像加速器
- 二、Docker镜像和容器应用
-
- 1. Docker镜像应用
- 2. Docker容器应用
- 三、案例实施
-
- 1. docker的基本安装与使用
- 2. Docker镜像应用综合案例
- 3. 解决容器启动时执行命令No command specified
- 4.Docker容器应用综合案例
- 5. Docker容器集群管理
-
- 2.1 安装docker服务和配置镜像加速器
- 2.2 制作容器进行压缩文件
- 2.3 将镜像压缩包导入镜像库
- 2.4 创建容器
- 2.5 mariadb-01数据库root配置
- 2.6 mariadb-02数据库root配置
- 2.7 主备模式配置
- 2.8 mariabd-01数据库与表配置
使用环境:Kylin-Server-V10-SP3
一、知识准备
1. Docker介绍
Docker是一个开源项目,诞生于2013年初,最初是dotCloud 公司内部的项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会,遵从了Apache2.0协议,项目代码在 GitHub 上进行维护。
Docker项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker的基础是Linux(LXC)容器技术。作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。首先,Docker容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。其次,Docker对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。Docker容器可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
具体说来,Docker在如下几个方面具有较大的优势:
- 更快速的交付和部署
- 更高效的虚拟化
- 更轻松的迁移和扩展
- 更简单的管理
2. 四大对象
命名空间(Namespaces)、控制组(Control Groups)和联合文件系统(Union File System为底层提供的实现,Docker将其封装,开发者并不直接操作。在Docker中,提出了一些软件层面的概念,是操作Docker所针对的对象。
- 镜像(Image)
- 容器(Container)
- 网络(Network)
- 数据卷(Volume)
2.1 镜像
镜像(Image)是其他虚拟化技术(特别是虚拟机)中常常被使用的一个概念,所谓镜像,可以理解为一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容。Docker的镜像与虚拟机中的镜像还是有一定区别的。Docker是利用了AUFS作为底层文件系统实现,通过这种方式,Docker实现了一种增量式的镜像结构。
每次对镜像内容的修改,Docker都会将这些修改铸造成一个镜像层,而一个镜像其实就是由其下层所有的镜像层所组成的。每一个镜像层单独拿出来,与它之下的镜像层都可以组成一个镜像。另外,由于这种结构,Docker的镜像实质上是无法被修改的,因为所有对镜像的修改只会产生新的镜像,而不是更新原有的镜像。
镜像的基本指令
- FROM:定义基础镜像
- MAINTAINER:作者或维护者
- RUN:运行Linux命令
- ADD:增加文件或目录
- EVN:定义环境变量
- CMD:运行进程
2.2 容器
容器(Container),用来隔离虚拟环境的基础设施,而在Docker里,被引申为隔离出来的虚拟环境。如果把镜像理解为编程中的类,那么容器就可以理解为类的实例。
镜像内存放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成为了一个「活」的空间。用更官方的定义,Docker的容器应该有三项内容组成:
- 一个Docker镜像
- 一个程序运行环境
- 一个指令集合
2.3 网络
对于大部分程序来说,它们的运行都不是孤立的,而是与其他程序进行交互,绝大多数情况下指的就是数据信息的交换,网络通讯是目前最常用的一种程序间的数据交换方式。
在Docker中,实现了强大的网络功能,不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离。
2.4 数据卷
除了网络之外,文件也是重要的进行数据交互的资源。为了保证数据的独立性,通常会单独挂载一个文件系统来存放数据。这种操作在虚拟机中是繁琐的,因为不但要搞定挂载在不同宿主机中实现的方法,还要考虑挂载文件系统兼容性,虚拟操作系统配置等问题。值得庆幸的是,这些在Docker里都已经轻松的实现了,只需要简单的一两个命令或参数,就能完成文件系统目录的挂载。
简单的实现挂载,主要还是得益于Docker底层的UnionFileSystem技术。在UnionFS的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。在Docker中,通过这几种方式进行数据共享或持久化的文件或目录,称为数据卷(Volume)。
3. Namespace介绍
Linux内核实现Namespace的主要目的之一是实现轻量级虚拟化(容器)服务。再此之前,Linux中很多资源是全局管理。
命名空间建立系统的不同视图,对于每一个命名空间,从用户看起来,应该像一台单独的Linux计算机一样,有自己的init进程(PID为O),其他进程的PID依次递增,A和B空间都有PID为0的init进程,子容器的进程映射到父容器的进程上,父容器可以知道每一个子容器的运行状态,而子容器与子容器之间是隔离的。
想要实现一个资源隔离的容器,需要6项隔离,Linux内核提供了这6种Namespace隔离的系统调用,在同一个Namespace下的进程可以感知彼此的变化,但不了解外界的变化,因此,可以让容器中的进程以为自己在一个独立的系统环境中,达到独立和隔离的目的。
Linux提供了多个API用来操作 Namespace,它们是 clone(),setns() 和 unshare()函数
- clone():创建新进程,flags参数可以用来创建新的namespace
- setns():让进程加入存在的 namespace
- unshare():将调用进程移动到新的 namespace中
查看进程所属的 Namespace
从版本号为3.8的内核开始,/proc/[pid]/ns
目录下会包含进程所属的 namesapce 信息,使用下面的命令可以查看当前进程所属的 namespace 信息
ls -l /proc/1675/ns
3.1 PID 名字空间
不同用户的进程就是通过PID名字空间隔离开的,且不同名字空间可以有相同的pid。所有的LXC进程在Docker中的父进程为 Docker 进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的Docker嵌套。
3.2 net名字空间
有了pid名字空间,每个名字空间中的pid能够相互隔离,但是网络端口还是共享 host的端口。网络隔离是通过net名字空间实现的,每个net名字空间有独立的网络设备,IP地址,路由表,/proc/net目录。这样每个容器的网络就能隔离开来。
Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一个Docker 网桥 dockero 连接在一起。
3.3 ipc名字空间
容器中进程交互还是采用了Linux常见的进程间交瓦方法(interprocess communication-IPC),包括信号量、消息队列和共享内存等。
然而同VM不同的是,容器的进程间交互实际上还是host上具有相同 pid名字空间中的进程间交互,因此需要在IPC资源申请时加入名字空间信息,每个IPC资源有一个唯一的32位id。
3.4 mnt 名字空间
类似chroot,将一个进程放到一个特定的目录执行。mnt名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间中的进程所看到的文件目录就被隔离开。
同chroot不同,每个名字空间中的容器在/proc/mounts的信息只包含所在名字空间的 mount point。
3.5 uts名字空间
UTS(“UNIX Time-sharing System”)名字空间允许每个容器拥有独立的hostname和domain name,使其在网络上可以被视作一个独立的节点而非主机上的一个进程。
3.6 user名字空间
每个容器可以有不同的用户和组id,也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。
4.Docker底层原理-cgroups
cgroups是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对cpu,内存等资源实现精细化的控制,目前越来越火的轻量级容器Docker就使用了cgroups 提供的资源限制能力来完成cpu,内存等部分的资源控制。
另外,开发者也可以使用cgroups提供的精细化控制能力,限制某一个或者某一组进程的资源使用。
cgroups 的全称是 control groups,cgroups 为每种可以控制的资源定义了一个子系统。
- cpu子系统:主要限制进程的中CPU使用率
- cpuacct子系统:可以统计 cgroups 中进程的 CPU 使用报告
- cpuset子系统:可以为cgroups 中的进程分配单独的 CPU 节点或内存节点
- memory子系统:可以限制进程的 memory 使用量
- blkio子系统:可以限制进程的块设备IO
- devices子系统:可以控制进程能够访问的某些设备
- net_cls子系统:可以标记 cgroups 中进程的网络数据包,然后可以使用tc模块对数据包进行控制
- freezer子系统:可以挂起或恢复 cgroups 中的进程
- ns子系统:可以使不同 cgroups 下面的进程只用不同的 namespace
cgroups 层级结构(Hierarchy)
内核使用cgroup结构体来表示一个controlgroup对某一个或者某几个cgroups 子系统的资源限制cgroup结构体可以组织成一颗树的形式,每一棵cgroup结构体组成的树称之为一个cgroups层级结构。cgroups层级结构可以包含一个或者几个cgroups子系统,当前层级结构可以对其attach的cgroups子系统进行资源的限制。
在创建了cgroups层级结构中的节点(cgroup结构体)之后,可以把进程加入到某一个节点的控制任务列表中,一个节点的控制列表中的所有进程都会受到当前节点的资源限制。同时某一个进程也可以被加入到不同的cgroups层级结构的节点中,因为不同的cgroups层级结构可以负责不同的系统资源。进程和cgroup 结是一个多对多的关系。
cgroups 文件系统
Linux使用了多种数据结构在内核中实现了 cgrpups 的配置,关联了进程和 cgrpups节点。Linux内核有一个很强大的模块叫 VFS(Virtual File System)。VFS 能够把具体文件系统的细节隐藏起来,给用户态进程提供一个统一的文件系统API接口。cgroups 也是通过 VFS把功能暴露给用户态,cgroups与VFS之间的衔接部分称之为 cgroups 文件系统。
VFS是一个内核抽象层,能够隐藏具体文件系统的实现细节,从而给用户态进程提供一套统一的API接口。VFS使用了一种通用文件系统的设计,具体的文件系统只要实现了VFS的设计接口,就能够注册到VFS中,从而是使内核可以读写这种文件系统。
5.UnionFS
Union File System,简称 UnionFS,是一种为Linux、FreeBSD和NetBSD 操作系统设计的文件系统,它能够多个其他文件系统联合到一个地方来挂载。换句话说,就是多个目录合并mount 到同一个目录中。
分支管理:它使用 branch 把不同文件系统的文件或目录透明的覆盖,形成单一一致的文件系统。这些 branch 或者是 read-oly 的,或者是 read-write 的,所以当对这个虚拟后的联合文件系统进写操作时,系统是真正写到了一个新的文件中。
写时复制:copy-on-write,简写为 Cow,也叫隐式共享,是一种提高资源使用效率的资源管理技术。如果一个资源是重复的,在没有对资源做出修改前,并不需要立即复制出一个新的资源实例。这个资源被不同的所有者共享使用。
当任何一个所有者要对改资源做出修改时,复制出一个新的资源实例给该所有者进行修改,修改后的资源成为其所有者的私有资源。通过这种资源共享的方式,可以显著的减少复制相同资源带来的小号,但是这样做也会在资源的修改时增加一部分开销。
6. AUFS的概念
AUFS 又叫 Another UnionFS,后来叫 Alternative UnionFS,再后来更改为 Advance UnionFS。开发人员叫 Juniiro Okajima在 2006 年开发的。
AUFS 完全重写了早期的 UnionFs1.x,其主要目的是为了可靠性和性能,并且引入了一些新的功能,比如可写分支的负载均衡。AUFS在使用上全兼容 UnionFs,而且比之前的UnionFS 在稳定性和性能上都要好很多,后来的UnionFS2.x开始抄AUFS中的功能。
在麒麟操作系统中,可以通过 mount 命令手动创建AUFS
[Step1]:
创建实验目录
mkdir /aufs
[Step2]:
在实验目录aufs下创建mnt目标作为文件系统的挂载点
mkdir /aufs/mnt
[Step3]:
在实验目录下创建container-layer文件夹,模拟容器读写层,初始化内容
mkdir /aufs/container-layer
echo "container-layer" > /aufs/container-layer/container-layer.txt
[Step4]:
在实验目录下创建三个文件,模拟容器的镜像层,并初始化内容
mkdir /aufs/{
image-layer01,image-layer02,image-layer03}
echo "image layer 01" > /aufs/image-layer01/image-layer01.txt
echo "image layer 02" > /aufs/image-layer02/image-layer02.txt
echo "image layer 03" > /aufs/image-layer03/image-layer03.txt
[Step5]:
通过mount将container-layer01、container-layer02、container-layer03以AUFS的方式挂载到刚才创建的mnt目录下
mount -t aufs -o dirs=/aufs/container-layer:/aufs/image-layer01:/aufs/image-layer02:/aufs/image-layer03 none /aufs/mnt
- 在没有明确指定权限的情况下,默认第一个目录具有读写权限(/aufs/container-layer)
- 其余目录具有只读权限(/aufs/image-layer01、/aufs/image-layer02、/aufs/image-layer03)
[Step6]:
验证:先mnt下的image-layer03.txt文件写入数据,查看底层文件/aufs/…/image-layer03.txt,发现内容并没有发生改变
echo "image-layer03.txt" >> /aufs/mnt/image-layer03.txt
[Step7]:
当尝试向mnt/image-layer03.txt文件中写入内容,系统首先在 mnt 目录下查找名为 image-layer03.txt 文件,然后将其拷贝到读写层的 container-layer目录中,然后才对 container-layer 目录下的 image-layer03.txt 文件进行写操作,这个过程也就是 AUFS 的实际工作原理
7. Overlay2
docker支持多种 graphDriver,包括vsf、devicemapper、overlay、aufs等,其中最常用的是aufs,随着Linux你和3.18将overlay纳入其中,overlay的地位也变得更加重要。麒麟操作系统docker环境默认使用Overlay2存储驱动
docker info
docker默认的存储目录/var/lib/docker
,我们只需要关心/var/lib/docker/image
和/var/lib/docker/overlay2
目录
在/var/lib/docker/image
目录下查看,只能看到overlay2这个目录,docker会在/var/lib/docker/iamge
目录下按每个存储驱动的名字创建一个目录。
imagedb和layerdb目录是专门用来存储元数据的地方,在docker中,image是由多个layer组合而成的,layer是一个共享的层,可能有多个image会指向某个layer。
[Step1]:
查看本地容器镜像的IMAGE ID值
docker images
2.png&pos_id=img-kjuhF5Ye-1722431025652)
[Step2]:
可以在/var/lib/docker/image/overlay2/imagedb/content/sha256目录下找到容器镜像对应的元数据文件
ll /var/lib/docker/image/overlay2/imagedb/content/sha256/
[Step3]:
查看文件内容,可以看到json格式的字符串,查看关键信息(rootfs)
cat /var/lib/docker/image/overlay2/imagedb/content/sha256/605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85 | json_pp
[Step4]:
可以看到rootfs的diff_ids是一个包含了6个元素的数组,其实这个6个元素正是组成nginx镜像的6个layerID,查看layerdb目录内容
ll /var/lib/docker/image/overlay2/layerdb/
[Step5]:
查看sha256目录中内容,可以看到恰好存在6个目录,分别对应6个层,同时可以发现存在23dcec…目录刚好对应rootfs中的最底层layer,在sha256只能看到最底层目录,剩余目录因为docker使用了chainID的方式保存layer,可以通过该目录下的diff内容中找到对应的layer
ll /var/lib/docker/image/overlay2/layerdb/sha256/
ll /var/lib/docker/image/overlay2/layerdb/sha256/2edcec3590a4ec7f40cf0743c15d78fb39d832