暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【Kubernetes系列】认识docker容器

帽爹的技术轮子 2021-05-05
444

日常学习记录,本文主要来自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


# 将工作目录切换为/app
WORKDIR /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 }}'  4ddf4638572d
25686

通过查看宿主机的 proc 文件,看到这个 25686 进程的所有 Namespace 对应的文件:



$ ls -l /proc/25686/ns
total 0
lrwxrwxrwx 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]


文章转载自帽爹的技术轮子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论