(1)PasS: Cloud Foundry,PaaS提供一种应用托管的能力,基于IaaS(Infrastructure as a service)之上
Docker镜像,使得本地环境和云端环境高度一致
(2)编排(Orchestration): 主要指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义,配置,创建,删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。
CNCF: Cloud Native Computing Foundation
Borg, Omega
Istio, Operator, Rook
Linux namespace机制:为Linux创建新进程的一个可选参数,调用的为如下方法:
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL)
除了PID Namespace机制,Linux还提供了Mount,UTS,IPC,Network和User这些namespace,用于对各种不同的进程上下文进行障眼法操作。
Docker在创建容器进程时,指定了该进程所需要启动的一组namespace参数,容器只能看到当前namespace所限定的资源,文件,设备,状态,或者配置,容器只是一种特殊的进程而已,而这些进程在namespace的作用下只能看到指定的资源,因此给人一种感觉好像和操作系统隔离了,其实只是缩小了容器所能看见的资源。
# 容器进入mac虚拟机终端
screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

docker engine 更多地扮演旁路由和辅助管理工作。

虚拟化技术:采用Hypervisor来负责创建虚拟机,该虚拟机真实存在,并且里面必须运行一个完整的Guest OS才能执行用户的应用进程;且虚拟机本身就需要占用内存,对宿主机操作系统的调用不可避免地要经过虚拟化软件的拦截和处理。
容器化技术:相比于虚拟化技术,隔离的不彻底,多个容器为运行在宿主机上的一种特殊进程,那么多个容器之间使用的就还是同一个宿主机操作系统内核。且在Linux内核中,很多资源和对象是不能被namespace化的。
如时间,加入你在容器中修改时间,宿主机也会跟着改变。
针对这种缺点,可以采用Seccomp等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为读了一层对系统调用的过滤,会拖累容器性能。
Linux Control Group 是linux内核中用来为进程设置资源限制的一个重要功能,包括CPU,内存,磁盘,网络带框。
在Linux中,Cgroups给用户暴露出来的操作接口时文件系统,即它以文件和目录的方式组织在操作系统/sys/fs/cgroup 下
Cgroup 配置及使用
(1)挂载使用cgroup

(2)创建一个container目录组,其下会自动生成相关限制文件

(3)创建一个进程用于测试

(4)将上述进程号写入tasks文件中
修改cpu.cfs_quota_us文件设置cpu使用额度为20ms,意味着限制cpu使用为20%

除了对cpu资源的限制

docker run -it --cpu-period=100000 --cpu-quota=20000 busybox /bin/bash
可以看出docker run的容器在对应的目录下都做了cgroup的限制;


一个正在运行的Docker容器,其实就是启用了多个Linux Namespace的应用进程,而该进程可以使用的资源量,受到Cgroups配置的限制,容器是一个单进程模型。
## ns.c
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];
char* const container_args[] = {
"/bin/bash",
NULL
};
int container_main(void* arg)
{
printf("Container - inside the container!\n");
// 如果你的机器的根目录的挂载类型是shared,那必须先重新挂载根目录 // mount("", "/", NULL, MS_PRIVATE, "");
mount("none", "/tmp", "tmpfs", 0, "");
execv(container_args[0], container_args);
printf("Something's wrong!\n");
return 1;
}
int main()
{
printf("Parent - start a container!\n");
int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL);
waitpid(container_pid, NULL, 0);
printf("Parent - container stopped!\n");
return 0;
}
# 执行上述代码后进入新的容器
gcc -o ns ns.c
./ns
# 但发现该容器和宿主机的内容一样
ls -al

经过实践,我们发现通过mount(“none”, “/tmp”, “tmpfs”, 0, “”);可以将指定文件挂载至容器中,从而可以控制容器中的文件;
mkdir -p ~/test
mkdir -p ~/test/{bin,lib64,lib}
cd ~/test
# 详细显示命令执行的操作
cp -v /bin/{bash,ls,sh} ~/test/bin
list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"
for i in $list; do mkdir ~/test`dirname $i`; cp -v $i ~/test$i; done
# 改变 /bin/sh 进程的根目录到~/test
chroot ~/test /bin/sh
通常会将挂载在容器根目录上,用来为容器提供隔离后执行环境的文件系统,成为容器镜像,rootfs
rootfs是一个操作系统所包含的文件,配置和目录,并不包括操作系统内核,相当于躯体,而linux操作系统内核是操作系统的灵魂,所有容器共享同一个linux内核,意味着该内核的修改会影响所有容器;
Docker在镜像的设计中,引入了层的概念,即用户制作镜像的每一步操作都会生成一个层,为增量的rootfs
# 将./B, ./A, ./C 联合挂载到./D 中,文件覆盖规则如下图
mkdir A
echo aa > ./A/a
echo xx > ./A/x
mkdir B
echo bbb > ./B/b
echo xxx > ./B/x
mkdir BB
echo bbbbbb > ./BB/b
echo xxxxxx > ./BB/x
mkdir C
mkdir D
# 其中./A为最上层,./BB为第二层,./B为第三层
# 原理:挂载时,会将低级目录文件全部拷贝到上级目录中,因此对低级目录中的文件修改并不会修改原本的文件
mount -t overlay overlay -o lowerdir=./BB:./B,upperdir=./A,workdir=./C ./D

可以看出docker使用的是overlay2的方式进行文件的联合挂载

docker pull nginx
docker inspect nginx
root@raspberrypi:~# docker inspect nginx
[
{
"Id": "sha256:b7dd3d7d83385d0bad882b2a2e1298d2c2003dd58eeae7d959e183b8d8392b9b",
"RepoTags": [
"nginx:latest"
],
"RepoDigests": [
"nginx@sha256:790711e34858c9b0741edffef6ed3d8199d8faa33f2870dea5db70f16384df79"
],
"Parent": "",
"Comment": "",
"Created": "2022-08-03T20:11:32.842853023Z",
"Container": "a562c0d94e0989705c34428ecc49bc8cf0339b71469f2574ce156593e1e05368",
"ContainerConfig": {
"Hostname": "a562c0d94e09",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.23.1",
"NJS_VERSION=0.7.6",
"PKG_RELEASE=1~bullseye"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"nginx\" \"-g\" \"daemon off;\"]"
],
"Image": "sha256:8a3bbfa267ceda280efc568b8faa75fde2761c14607d20256d73b1a390188daa",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers "
},
"StopSignal": "SIGQUIT"
},
"DockerVersion": "20.10.12",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.23.1",
"NJS_VERSION=0.7.6",
"PKG_RELEASE=1~bullseye"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Image": "sha256:8a3bbfa267ceda280efc568b8faa75fde2761c14607d20256d73b1a390188daa",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers "
},
"StopSignal": "SIGQUIT"
},
"Architecture": "arm",
"Variant": "v7",
"Os": "linux",
"Size": 109131098,
"VirtualSize": 109131098,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/3e8262849af4cbc4cde895685870114127ffd57eead9416c928784291f4ba53f/diff:/var/lib/docker/overlay2/e277a2e14d5ba7c3c7edfb746bb8e074f6bdd96fb0427a8d520e2efd4b9e43c9/diff:/var/lib/docker/overlay2/a05ffd4fecc6c4e32ed65ab5a88c4214969b88b152dab7612dd28ef1b4ebc704/diff:/var/lib/docker/overlay2/dd7005f61f9f06554ab770992ac1463727a7cd79398cde359ba5795fb381eb48/diff:/var/lib/docker/overlay2/a471495d68abb4636ca1414d1cf5e5fcd8241df8d82c4c24a8931f25d0f70ac9/diff",
"MergedDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/merged",
"UpperDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/diff",
"WorkDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:ddffee9f8d11b7acf1e1f7b78d0ec21b79d51a283a3fdaf10fd4d13d14693648",
"sha256:29110869bb9fdb3ebf6da2f4297c36cb3bd8733fdbe5bb33bfe6d77745640d3d",
"sha256:b3c88d2b26a3f1920c90dea050fa4478d71b9ccf7a6b1eea601e4f369ec52132",
"sha256:51d4212bec0900e2747c5c7ca68777922ec775dcd3b462c0e279b1c519195bec",
"sha256:54c0a6219829bca9912b9ac604b110af109a0a876c57b4716a9a68ed662dca5d",
"sha256:e44bd7094faabcc9f4e6c77e635a98a586affa70b7c36f0709848c60fc858d58"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
如上RootFS显示,ngnix由6层组成。
可以看出该文件为一个完整linux目录结构

如果自己对容器中文件进行修改后,会产生新的层,此时我们docker commit; docker push 即可生成自己的容器。
docker 支持的UnionFS: aufs, device, mapper, btrfs, overlayfs, vfs, zfs。


控制节点:包含kube-apiserver, kube-schedule, kube-controller-manager,集群中持久化数据由kube-apiserver处理后保存在etcd中。
Device Plugin: k8s用于管理GPU等宿主机物理设备的主要组件;
OCI(Open Container Interface),为CRI的一个标准,使用linux内核系统调用。
CRI(Container Runtime Interface):按标准容器运行镜像,docker为其中一个实现。
CNI(Container Network Interface):网络插件
CSI(Container Storage Interface):存储插件
Service服务的主要作用,是作为Pod的代理入口(Portal),从而代替Pod对外暴露一个固定的网络地址。

ipvs模式下,可为Service指定负载均衡策略
IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:
| 名称 | 解释 |
|---|---|
| rr | 轮替(Round-Robin) |
| lc | 最少链接(Least Connection),即打开链接数量最少者优先 |
| dh | 目标地址哈希(Destination Hashing) |
| sh | 源地址哈希(Source Hashing) |
| sed | 最短预期延迟(Shortest Expected Delay) |
| nq | 从不排队(Never Queue) |
声明式API
容器:容器运行时 + 容器镜像
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80