美文网首页
docker实现原理(一) ns和cgroups

docker实现原理(一) ns和cgroups

作者: mafa1993 | 来源:发表于2022-11-15 11:00 被阅读0次
  1. 基于linux内核的cgroup namespace以及unionFS等技术,对进程进行封装和隔离
  2. 进入docker 也可以使用docker attach,exit后会退出。
  3. 将dockerfile打包成镜像 docker build -t x/x{tag} . docker push x/x:{tag}

容器标准

  1. oci标准
  2. Runtime specification 文件系统包如何解压至硬盘,供运行时运行
  3. image specification 如何通过构建系统打包,生成镜像清单、文件系统序列化文件、镜像配置

容器的主要的特性

  1. 隔离性 namespace,不同的namespace有不同的进程id,网络配置
  2. 可配额 cgroup
  3. 便携性
  4. 安全性

namespace

  1. linux namespace是 linux kernel提供的资源隔离方案
    • 系统为不同的进程分配不同的namespace
    • 保证不同的namespace自愿独立分配,进程彼此隔离
// namespace 实现代码
struct task_struct {
    struct nsproxy *nsproxy;
}

struct nsproxy {
    atomic_t count;
    struct uts_namespace *uts_ns;
    struct ipc_namespace *ipc_ns;
    struct mnt_namespace *mnt_ns;
    struct pid_namespace *pid_ns_for_children;
    struct net *net_ns;
}

linux 对namespace的操作

  1. clone,在创建新锦成的系统调用时,通过flags参数指定需要新建的namespace类型
    • int clone(int fn(void *),void *child_stack,int flags,void *arg)
  2. setns 该系统调用可以让调用的进程加入某个已经存在的namespace
    • int setns(int fd,int nstype)
  3. unshare 将调用进程移动到新的namespace下 unshare - run program with some namespaces unshared from parent(使用与父程序不共享的名称空间运行程序) https://blog.csdn.net/qq_34939308/article/details/114115443

namespace简介

  1. pidnamespace ,每个namespace中的pid能够相互隔离
  2. net namespace,每个net namespace有独立的network devices,address,ip routing tables。docker采用veth的方式将container中的虚拟网卡同host上的一个docker bridge:docker0连接到一起
  3. ipc namespace。包括常见的信号量、消息队列和共享内存
  4. mnt namespace。允许不同的namespace可按到文件结构不同,每个namespace中进程看到的文件就隔离了
  5. uts namespace。允许每个container拥有独立的hostname和domain name。从而在网络上可以被看作一个独立的节点,而不是一个进程
  6. user namespace。每个container可以有不同的user和group id。可以用容器内部的user执行程序而不是host上的用户

关于namespace的常用操作

  1. lsns -t <type> 查看当前系统的namespace
  2. ls -la /proc/pid/ns/ 查看某个进程的namespace
  3. nsenter -t pid -n ip addr 进入某namespace运行命令,和进入容器执行ip addr 返回内容一样

Cgroups

  1. 对linux下一个或者一组进程进行资源控制和监控的机制
  2. 对cpu、内存、磁盘io等资源限制
  3. 针对不同类型的资源限制,只要将限制策略在不同子系统上关联
  4. cgroups在不同的系统资源管理子系统汇总以层级树来组织,croups可以包含其他cgroups
  5. 每种资源控制是一个子系统

control Croups子系统

  1. blkio,对输入输出控制,磁盘、光盘等
  2. cpu,限制cpu的访问
  3. cpuacct,产生cpu的资源报告,这个cgroup的1
  4. cpuset,分配单独的cpu和内存
  5. devices,允许或者拒绝cgroup任务对设备的访问

cpu子系统

  1. cpu.shares,cpu可使用时长的相对值,在cpu.shares配置文件中配置数值,两个cgroup分配的cpu为这两个数值的比
  2. cpu.cfs_period_us 配置时间周期,单位us
  3. cpu.cfs_quota_us 在cfs_period_us的时间内能使用cpu的时间数,单位us
  4. cpu.stat cgroup内进程使用的cpu时间统计
  5. nr_periods 经过cfs_period_us的时间周期数量
  6. nr_throttled,在时间周期内,多少进程因为时间耗尽而受到限制不能正常执行
  7. throttled_time cgroup中进程被限制使用cpu的中用时

linux 调度器

内核默认提供了5个调度器,linxu内核使用struct sched_class来对调度器进行抽象

  1. stop调度器,优先级最高的调度类,可以抢占其他所有进程
  2. Deadline调度器,dl_sched_class 使用红黑树,吧进程按照绝对截止期限进行排序,选择最小进程进行调度
  3. RT调度器,rt_sched_dlass实时调度器,为每个优先级为何一个队列
  4. CFS调度器,cfs_sched_class 完全公平调度器,采用完全公平算法,引入虚拟运行时的概念
  5. IDLE-task调度器,每个cpu都有个idle线程,没有其他进程可以调用的使用,调度运行dele线程

在 cgroup cpu 子系统目录中创建目录结构
cd /sys/fs/cgroup/cpu
mkdir cpudemo
cd cpudemo
• 运行 busyloop
• 执行 top 查看 CPU 使用情况,CPU 占用 200%
• 通过 cgroup 限制 cpu
cd /sys/fs/cgroup/cpu/cpudemo
• 把进程添加到 cgroup 进程配置组
echo ps -ef|grep busyloop|grep -v grep|awk '{print $2}' > cgroup.procs
• 设置 cpuquota
echo 10000 > cpu.cfs_quota_us
• 执行 top 查看 CPU 使用情况,CPU 占用变为10%

cpuacct子系统

用于统计cgroup机器子cgroup下进程的cpu使用情况

  1. cpuacct.usage 进程使用cpu的时间,单位ns
  2. cpuacct.stat cpu使用时间,用户态、内核态时间

memory子系统

  1. memory.usage_in_bytes 进程使用的内存
  2. memory.max_usage_in_byutes 进程使用的内存最大值
  3. memery.limit_in_bytes cgroup下进程最多能使用的内存,默认-1 不限制
  4. memory.soft_limit_in_bytes 不会阻止进程使用超过限额的内存,只是在系统内存粗狗时,有限回收超额内存
  5. memory.oom_control 设置是否使用oom killer,默认使用,如果croup内进程超过内存,就会被kill

cgroup driver

  1. systemd
  2. cgroupsfs,默认
  3. 存在问题
    • 在systemd作为init system的系统中,默认存在两套group driver
    • 这会使docker和kubelet管理的进程被cgroupfs驱动管,而systemd拉起的由systemd驱动管,
    • kubelet会默认 --cgroup-driver=systemd 若运行时cgroup不一致时,kubelet会报错
• Memory 子系统练习
• 在 cgroup memory 子系统目录中创建目录结构
cd /sys/fs/cgroup/memory
mkdir memorydemo
cd memorydemo
• 运行 malloc(在linux机器make build) • 查看内存使用情况
watch 'ps -aux|grep malloc|grep -v grep‘
• 通过 cgroup 限制 memory
• 把进程添加到cgroup进程配置组
echo ps -ef|grep malloc |grep -v grep|awk '{print $2}' > cgroup.procs
• 设置 memory.limit_in_bytes
echo 104960000 > memory.limit_in_bytes
• 等待进程被 oom kill

相关文章

网友评论

      本文标题:docker实现原理(一) ns和cgroups

      本文链接:https://www.haomeiwen.com/subject/fqldxdtx.html