kubernetes 笔记 1

参考--极客时间 深入剖析kubernetes

容器隔离使用namespace技术,将容器进程和宿主机进程隔离。

普通进程:pid = clone(main_function, stack_size, SIGCHLD, NULL);

容器进程:int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

使用CLONE_NEWPID参数,使容器进程无法查看宿主机其他进程,并且将自己的pid设置为1。

Linux 操作系统还提供了 Mount、UTS、IPC、Network 和 User 这些 Namespace。

linux内核无法被namespace化的资源和对象:

时间:使用settimeofday(2)系统调用修改时间,整个宿主机的时间也被修改

=====

Cgroups: Linux内核用来为进程设置资源限制的功能。

Cgroups以文件和目录的方式组织在操作系统 /sys/fs/cgroup路径下,Ubuntu可以使用mount命令将其展示出来:

# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)

/sys/fs/cgroup/目录下有很多子目录(子系统),显示本主机可以限制的资源种类。以cpu为例:

# ls /sys/fs/cgroup/cpu
cgroup.clone_children  cpuacct.stat       cpuacct.usage_percpu       cpuacct.usage_sys   cpu.cfs_quota_us  docker             system.slice
cgroup.procs           cpuacct.usage      cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.shares        notify_on_release  tasks
cgroup.sane_behavior   cpuacct.usage_all  cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.stat          release_agent      user.slice

cfs_period 和 cfs_quota组合使用,表示在cfs_period时间内,只能分配到cfs_quota总量的CPU使用时间。

blkio,为块设备设定I/O 限制,一般用于磁盘等设备;
cpuset,为进程分配单独的 CPU 核和对应的内存节点;
memory,为进程设定内存使用的限制

使用:

只需要在每个子系统下面,为每一个容器创建一个控制组(即新创建一个目录),然后启动容器后,将进程pid写入到对应控制组的tasks文件中即可。

$ echo <PID> > /sys/fs/cgroup/cpu/container/tasks
$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
# 100ms(100000us)的时间内,只能使用20ms(20000us)的CPU时间,即20%的CPU带宽

一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

=====

mount namespace:

mount namespace和其他namespace略有不同,它对容器视图的改变,一定伴随着挂载操作(mount)才能生效。

Linux操作系统有chroot命令可以帮助在shell中完成根目录的挂载(change root file system),即rootfs

chroot /path /bin/bash

容器大概流程:

1. 启用Linux namespace配置,

2. 设置指定的cgroups参数,

3. 切换进程根目录rootfs(change root)(优先pivot_root,没有使用chroot)

???

docker create 没有创建系统挂载点?启动之后才会创建??

为什么podman create 后就可以使用podman mount container返回系统挂载点??

???

镜像层 ro+wh(read only + whitout)

要删除只读镜像层的内容只需在rw层添加.wh.filename

init 层用来存放/etc/hosts, /etc/resolv.conf 等信息,这些信息只对当前容器有效,commit时不会携带此层

使用下面命令来查看容器pid:

docker inspect --format '{{ .State.Pid }}' <containerId>

查看宿主机proc文件来查看进程对应的namespace

ls -l /proc/PID/ns
# ls -l /proc/11520/ns
total 0
lrwxrwxrwx 1 root root 0 May 27 21:30 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 May 27 21:30 ipc -> 'ipc:[4026532432]'
lrwxrwxrwx 1 root root 0 May 27 21:30 mnt -> 'mnt:[4026532430]'
lrwxrwxrwx 1 root root 0 May 27 21:30 net -> 'net:[4026532435]'
lrwxrwxrwx 1 root root 0 May 27 21:30 pid -> 'pid:[4026532433]'
lrwxrwxrwx 1 root root 0 May 27 21:30 pid_for_children -> 'pid:[4026532433]'
lrwxrwxrwx 1 root root 0 May 27 21:30 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 May 27 21:30 uts -> 'uts:[4026532431]'

使用setns()系统调用来讲一个进程加入到已有的namespace中,达到docker exec的效果。

docker提供了--net 参数允许一个容器加入到另外一个容器network namespace中,

docker run -it --net container:<containerId> <image> <command>

如果使用--net=host,则不会为此容器建立network namespace,直接共享主机网络栈

Copy-on-Write:

在容器中对rootfs做的任何修改,都会被操作系统先拷贝到可读写层,然后再修改。

Volume:

docker run -v /test...
#此方式会创建一个临时目录/var/lib/docker/[volumeId]/_data,然后挂载到/test上
docker run -v /path:/path

挂载数据卷,在容器执行chroot/pivot_root之前,容器是可以查看到宿主机的全部文件系统,只需要在rootfs准备好后,执行chroot或pivot_root之前,将指定宿主机的目录,挂载到容器目录/test(overlay2 对应/var/lib/docker/overlay2/[可读写层ID]/merged/test上、aufs在/var/lib/docker/aufs/mnt/[可读写层ID]/test上),因为执行这个操作时,mount namespace已经创建,所以挂载事件只能在容器内可见,而宿主机不可见。

以上操作都是docker创建的初始化进程dockerinit进行的,dockerinit负责根目录的准备,挂载设备和目录,配置hostname等一系列在容器内进行的初始化操作,随后通过调用execv()系统调用,让应用进程取代自己,成为pid 1的进程。

使用的挂载技术就是Linux绑定挂载(mount --bind)

mount --bind /home /test 会将/home挂载到/test上,所做的修改都是对被挂载目录的修改,一旦执行unmount命令,/test 目录原来的内容就会恢复。

并且宿主机并不知道这个挂载的存在,所以在宿主机眼中,容器在宿主机上对应/test目录始终是空的。因为docker commit是在宿主机视角去执行的,因此不会携带/test目录里的内容,但是/test目录还是会被提交并出现在新的镜像中。

猜你喜欢

转载自www.cnblogs.com/tiandz/p/12963413.html
今日推荐