“容器本身的价值非常有限真正有价值的是容器编排。”
容器与进程
docker利用Namespace机制,使被隔离的应用的进程空间做了修改。在Linux中创建线程的系统调用是clone()
int pid = clone(main_function, stack_size, SINCHLD, NULL);
这个系统调用就会为我们创建一个新的进程,并返回它的PID。
而当我们用clone
系统调用一个创建一个新进程时,就可以在参数中指定CLONE_NEWPID
(PID namespaces)。
int pid = clone(main_function, stack_size, CLONE_NEWPID, NULL)
开辟一个新的进程空间,pid是1。但真实的PID还是没变。
实际上,创建容器进程时,指定了该进程所需要启用的一组Namespace参数。
所以,容器其实是一种特殊的进程而已。
隔离与限制
docker的隔离技术是应用的Linux内核自带的技术手段,Namespace。
虚拟机与docker相比,hypervisor那样对应用进程的隔离环境负责,也不会创建任何实体的“容器”,真正对隔离环境负责的是宿主机的操作系统本身。docker更多的是旁路式的辅助和管理工作。
但容器的隔离问题还是存在得。多个容器共用一个操作系统内核。低版本Linux主机运行高版本Linux容器也是行不通的。
在Linux内核中有很多资源和对象是不能被Namespace化的,比如系统时间。当我们修改容器内的时间,系统时间也随之改变。所以当我们使用容器时,必须考虑“什么能做什么不能做”。
所以在生产环境中,没人把容器暴露在公网下。
docker的限制技术是Linux Cgroups,是用来为进程设置资源限制的一个重要功能。Cgroups限制的资源包括CPU、内存、磁盘、带宽等。
Cgroup还能够对进程进行优先级设置、审计,以及讲进程挂起和恢复等操作。
在Linux中,Cgroup向用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的/sys/fs/cgroup
的路径下。
CPU 子系统,主要限制进程的 CPU 使用率。
- cpuacct 子系统,可以统计 cgroup 中的进程的 CPU 使用报告。
- cpuset 子系统,可以为 cgroup中的进程分配单独的 CPU 节点或者内存节点。
- memory 子系统,可以限制进程的 Memory 使用量。
- blkio子系统,可以限制进程的块设备 IO。
- devices 子系统,可以控制进程能够访问某些设备。net_cls 子系统,可以标记 cgroups中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
- freezer 子系统,可以挂起或者恢复cgroup 中的进程。
下面是cgroup的目录:
[root@jenkins test2]# ls /sys/fs/cgroup/
blkio/ cpu,cpuacct/ freezer/ net_cls/ perf_event/
cpu/ cpuset/ hugetlb/ net_cls,net_prio/ pids/
cpuacct/ devices/ memory/ net_prio/ systemd/
文件系统目录:
[root@jenkins test2]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuacct,cpu)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_prio,net_cls)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids)
CPU子系统的配置文件:
[qtec@localhost ~]$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpuacct.usage_percpu cpu.stat
cgroup.event_control cpu.cfs_period_us notify_on_release
cgroup.procs cpu.cfs_quota_us release_agent
cgroup.sane_behavior cpu.rt_period_us tasks
cpuacct.stat cpu.rt_runtime_us
cpuacct.usage cpu.shares
这里面cpu.cfs_quota_us
和cpu.rt_period_us
。两者需要组合使用,可以限制进程在长度为cfs_period
的一段时间内,只能被分配到总量为cfs_quota的CPU时间。CPU的使用比率:cfs_quota/cfs_period
。
简单来讲:cpu.cfs_period_us
是运行周期,cpu.cfs_quota_us
是在周期内这些进程占用多少时间。
对CPU的相关控制在cpuacct
目录下:
[qtec@localhost ~]$ ls /sys/fs/cgroup/cpuacct/
cgroup.clone_children cpuacct.usage_percpu cpu.stat
cgroup.event_control cpu.cfs_period_us notify_on_release
cgroup.procs cpu.cfs_quota_us release_agent
cgroup.sane_behavior cpu.rt_period_us tasks
cpuacct.stat cpu.rt_runtime_us
cpuacct.usage cpu.shares
cgroup对Docker的限制,用户态的表现: