- 基于linux内核的cgroup namespace以及unionFS等技术,对进程进行封装和隔离
- 进入docker 也可以使用docker attach,exit后会退出。
- 将dockerfile打包成镜像 docker build -t x/x{tag}
容器标准
- oci标准
- Runtime specification 文件系统包如何解压至硬盘,供运行时运行
- image specification 如何通过构建系统打包,生成镜像清单、文件系统序列化文件、镜像配置
容器的主要的特性
- 隔离性 namespace,不同的namespace有不同的进程id,网络配置
- 可配额 cgroup
- 便携性
- 安全性
namespace
- 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的操作
- clone,在创建新锦成的系统调用时,通过flags参数指定需要新建的namespace类型
- int clone(int fn(void *),void *child_stack,int flags,void *arg)
- setns 该系统调用可以让调用的进程加入某个已经存在的namespace
- int setns(int fd,int nstype)
- unshare 将调用进程移动到新的namespace下 unshare - run program with some namespaces unshared from parent(使用与父程序不共享的名称空间运行程序) https://blog.csdn.net/qq_34939308/article/details/114115443
namespace简介
- pidnamespace ,每个namespace中的pid能够相互隔离
- net namespace,每个net namespace有独立的network devices,address,ip routing tables。docker采用veth的方式将container中的虚拟网卡同host上的一个docker bridge:docker0连接到一起
- ipc namespace。包括常见的信号量、消息队列和共享内存
- mnt namespace。允许不同的namespace可按到文件结构不同,每个namespace中进程看到的文件就隔离了
- uts namespace。允许每个container拥有独立的hostname和domain name。从而在网络上可以被看作一个独立的节点,而不是一个进程
- user namespace。每个container可以有不同的user和group id。可以用容器内部的user执行程序而不是host上的用户
关于namespace的常用操作
- lsns -t <type> 查看当前系统的namespace
- ls -la /proc/pid/ns/ 查看某个进程的namespace
- nsenter -t pid -n ip addr 进入某namespace运行命令,和进入容器执行ip addr 返回内容一样
Cgroups
- 对linux下一个或者一组进程进行资源控制和监控的机制
- 对cpu、内存、磁盘io等资源限制
- 针对不同类型的资源限制,只要将限制策略在不同子系统上关联
- cgroups在不同的系统资源管理子系统汇总以层级树来组织,croups可以包含其他cgroups
- 每种资源控制是一个子系统
control Croups子系统
- blkio,对输入输出控制,磁盘、光盘等
- cpu,限制cpu的访问
- cpuacct,产生cpu的资源报告,这个cgroup的1
- cpuset,分配单独的cpu和内存
- devices,允许或者拒绝cgroup任务对设备的访问
cpu子系统
- cpu.shares,cpu可使用时长的相对值,在cpu.shares配置文件中配置数值,两个cgroup分配的cpu为这两个数值的比
- cpu.cfs_period_us 配置时间周期,单位us
- cpu.cfs_quota_us 在cfs_period_us的时间内能使用cpu的时间数,单位us
- cpu.stat cgroup内进程使用的cpu时间统计
- nr_periods 经过cfs_period_us的时间周期数量
- nr_throttled,在时间周期内,多少进程因为时间耗尽而受到限制不能正常执行
- throttled_time cgroup中进程被限制使用cpu的中用时
linux 调度器
内核默认提供了5个调度器,linxu内核使用struct sched_class来对调度器进行抽象
- stop调度器,优先级最高的调度类,可以抢占其他所有进程
- Deadline调度器,dl_sched_class 使用红黑树,吧进程按照绝对截止期限进行排序,选择最小进程进行调度
- RT调度器,rt_sched_dlass实时调度器,为每个优先级为何一个队列
- CFS调度器,cfs_sched_class 完全公平调度器,采用完全公平算法,引入虚拟运行时的概念
- 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使用情况
- cpuacct.usage 进程使用cpu的时间,单位ns
- cpuacct.stat cpu使用时间,用户态、内核态时间
memory子系统
- memory.usage_in_bytes 进程使用的内存
- memory.max_usage_in_byutes 进程使用的内存最大值
- memery.limit_in_bytes cgroup下进程最多能使用的内存,默认-1 不限制
- memory.soft_limit_in_bytes 不会阻止进程使用超过限额的内存,只是在系统内存粗狗时,有限回收超额内存
- memory.oom_control 设置是否使用oom killer,默认使用,如果croup内进程超过内存,就会被kill
cgroup driver
- systemd
- cgroupsfs,默认
- 存在问题
- 在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
网友评论