日常学习记录,本文主要来自Kubernetes In Action书籍和张磊大神的深入剖析Kubernetes专栏的总结,帮助自己后续复习使用
一、容器概念
1.什么是容器
容器其实是一种沙箱技术,一种特殊的单进程而已;容器之间是相互隔离的,即应用与应用之间因为有了边界而不互相干扰,实际就是典型的Paas平台;一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制
2.容器vs虚拟机优势在哪
硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS;每个虚拟机需要运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用
而容器仅仅只是运行在宿主机上被隔离的单个进程,仅消耗应用容器消耗的资源,不会有其他进程的开销;容器的强一致性,无论开发、测试、生产环境是一致的
3.Linux底层隔离与限制
1)Namespace
Namespace的使用方式,其实就是Linux 创建新进程的一个可选参数,用 clone() 系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID 参数,比如:
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
Linux还提供了以下类型的命名空间:
Mount(mnt)
Process ID(pid)
Network(net)
Inter-process communicaion(ipd)
UTS
User ID(user)
需要注意的在Linux内核中,很多资源和对象不能被Namespace化,如时间
2)Cgroups(Control group)
Cgroups最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等;可以在/sys/fs/cgroup创建目录指定对应pid的cpu、内存等资源限制
ls /sys/fs/cgroup
需要注意的Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源;而在容器里面执行top命令时,会发现显示的信息是宿主机的CPU、内存等信息,而不是当前容器的信息,问题原因在于/proc文件系统不了解cgroup的存在(可以通过lxcfs处理)
4、容器镜像
Mount Namespace是基于对 chroot 的不断改良才被发明出来的,它也是 Linux 操作系统里的第一个 Namespace,可以通过ls /查看,而挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)
对于docker而已,它最核心的原理实际上就是为待创建的用户进程:
1.启用 Linux Namespace 配置(视图隔离)
2.设置指定的 Cgroups 参数(资源隔离)
3.切换进程的根目录(Change Root)(容器镜像生效,以实现环境一致性。所谓容器镜像,本质就是容器的根文件系统(rootfs))
需要注意的是rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像
5、Union file system(UnionFs)
Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。UnionFS最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下;Docker 镜像使用的 rootfs,一般由多个“层”组成:
$ docker image inspect ubuntu:latest..."RootFS": {"Type": "layers","Layers": ["sha256:f49017d4d5ce9c0f544c...","sha256:8f2b771487e9d6354080...","sha256:ccd4d61916aaa2159429...","sha256:c01d74f99de40e097c73...","sha256:268a067217b5fe78e000..."]# docker联合挂载点目录$ /var/lib/docker/aufs/mnt/

上面的读写层通常也称为容器层,下面的只读层称为镜像层,所有的增删查改操作都只会作用在容器层,相同的文件上层会覆盖掉下层。知道这一点,就不难理解镜像文件的修改,比如修改一个文件的时候,首先会从上到下查找有没有这个文件,找到,就复制到容器层中,修改,修改的结果就会作用到下层的文件,这种方式也被称为copy-on-write
二、Dockerfile的使用
# 使用官方提供的Python开发镜像作为基础镜像FROM python:2.7-slim# 将工作目录切换为/appWORKDIR /app# 将当前目录下的所有内容复制到/app下ADD . /app# 使用pip命令安装这个应用所需要的依赖#RUN 原语就是在容器里执行 shell 命令RUN pip install --trusted-host pypi.python.org -r requirements.txt# 允许外界访问容器的80端口EXPOSE 80# 设置环境变量ENV NAME World# 设置容器进程为:python app.py,即:这个Python应用的启动命令#CMD ["python", "app.py"]等价于"docker run python app.py"CMD ["python", "app.py"]
ENTRYPOINT原语,它和 CMD 都是 Docker 容器进程启动所必需的参数,完整执行格式是:“ENTRYPOINT CMD”,但是,默认情况下,Docker 会提供一个隐含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 时,比如在我们这个例子里,实际上运行在容器里的完整进程是:/bin/sh -c "python app.py",即 CMD 的内容就是 ENTRYPOINT 的参数(Docker 容器的启动进程统称为 ENTRYPOINT)
需要注意的是,Dockerfile 中的每个原语(指Dockerfile中的FROM、RUN、ADD等)执行后,都会生成一个对应的镜像层
$ docker inspect --format '{{ .State.Pid }}' 4ddf4638572d25686
通过查看宿主机的 proc 文件,看到这个 25686 进程的所有 Namespace 对应的文件:
$ ls -l /proc/25686/nstotal 0lrwxrwxrwx 1 root root 0 Aug 13 14:05 cgroup -> cgroup:[4026531835]lrwxrwxrwx 1 root root 0 Aug 13 14:05 ipc -> ipc:[4026532278]lrwxrwxrwx 1 root root 0 Aug 13 14:05 mnt -> mnt:[4026532276]lrwxrwxrwx 1 root root 0 Aug 13 14:05 net -> net:[4026532281]lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid -> pid:[4026532279]lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid_for_children -> pid:[4026532279]lrwxrwxrwx 1 root root 0 Aug 13 14:05 user -> user:[4026531837]lrwxrwxrwx 1 root root 0 Aug 13 14:05 uts -> uts:[4026532277]





