文章目录
namespace(隔离性)
linux namespace 是一种 linux kernel 提供的资源隔离方案:
- 系统可以为进程分配不同的 namespace。
- 保证不同的 namespace 资源独立分配、进程彼此隔离,即不同 namespace 下的进程互不干扰。
linux 内核代码中 namespace 的实现
- 进程数据结构
struct task_struct {
...
/* namespaces */
struct nsproxy *nsproxy;
...
}
这里 nsproxy 属性就表示这个进程所在的 namespace 的信息。
- namespace 数据结构
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 类型:
// CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS,
// CLONE_NEWPID, CLONE_NEWUSER, CLONE_NEWUTSint clone(int (*fn)(void *), void *child_stack, int flags, void *arg)
-
setns
该系统调用可以让调用进程加入某个已经存在的 namespace 中:
int setns(int fd, int nstype)
-
unshare
该系统调用可以将调用进程移动到新的 namespace 下:
int unshare(int flags)
关于 namespace 的常用操作
- 查看当前系统的 namespace:
lsns -t <type>
- 查看某进程的 namespace:
ls -la /proc/<pid>/ns/
- 进入某 namespace 运行命令:
nsenter -t <pid> -n ip addr
namespace 练习
-
在新的 network namespace 执行 sleep 指令
unshar -fn sleep 120
-
查看进程信息
ps -ef | grep sleep
root 476484 476437 0 00:37 pts/3 00:00:00 unshare -fn sleep 120
root 476485 476484 0 00:37 pts/3 00:00:00 sleep 120
-
查看网络 namespace
lsns -t net
4026532266 net 2 476484 root unassigned unshare -fn sleep 120
-
进入该进程所在 namespace 查看网络配置,与主机不一样
nsenter -t pid -n ip a
1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
cgroups(可配额)
Cgroups (control groups) 是 linux 下用于对一个或一组进程进行资源控制和监控的机制。
可以对诸如 CPU 使用时间、内存、磁盘I/O 等进程所需资源进行限制。
不同资源的具体管理工作由相应的 cgroup 子系统来实现。
针对不同类型的资源限制,只要将限制策略在不同的子系统上进行关联即可。
cgroups 在不同的系统资源管理子系统中已层级树(Hierarchy)的方式来组织管理:
每个 cgroup 都可包含其他的子 cgroup,因此子 cgroup 能够使用的资源除了
受本 cgroup 配置的资源参数的限制,还受到父 cgroup 设置的资源限制。
linux 内核代码中 cgroups 的实现
- 进程数据结构
struct task_struct {
...
#ifdef CONFIG_CGROUPS
struct css_set __rcu *cgroups;
struct list_head cg_list;
#endif
...
}
这里 nsproxy 属性就表示这个进程所在的 namespace 的信息。
- css_set 是 cgroup_subsys_state 对象的集合
struct css_set {
/*
* Set of subsystem states, one for each subsystem. This array is
* immutable after creation apart from the init_css_set during
* subsystem registration (at boot time).
*/
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
}
CPU 子系统
- cpu.shares:可让出的能获得 CPU 使用时间的相对值。
- cpu.cfs_period_us:用来配置时间周期长度,单位为 us(微秒)。
- cpu.cfs_quota_us:用来配置当前 cgroup 在 cfs_period_us 时间内最多能使用的 CPU 时间数,单位为 us(微秒)。
- cpu.stat:cgroup 内的进程使用的 CPU 时间统计。
- nr_periods:经过 cfs_period_us 的时间周期数量。
- nr_throttled:在经过的周期内,由多少次因为进程在指定的时间周期内用光了配额时间而受到限制。
- throttled_time:cgroup 中的进程被限制使用 CPU 的总用时,单位为 ns(纳秒)。
CPU 子系统练习
-
在 cgroup cpu 子系统目录中创建目录结构
cd /sys/fs/cgroup/cpu mkdir cpudemo cd cpudemo
-
运行 busyloop(代码如下)
package main func main() { go func() { for {} }() for {} }
-
执行 top 查看 CPU 使用情况,CPU 占 100%(我的ecs只有一核)
-
通过 cgroup 限制 CPU 使用
- 把进程添加到 cgroup 进程配置组
echo ps -ef | grep busyloop | grep -v grep | awk '{print $2}' > cgroup.procs
- 设置 cpuquota
echo 10000 > cpu.cfs_quota_us
// 每 10 万个 CPU 时间片只能拿到 1 万个
- 把进程添加到 cgroup 进程配置组
-
执行 top 查看 CPU 使用情况,CPU 占用变为 10%
memory 子系统
- memory.usage_in_bytes:cgroup 下进程使用的内存,包含 cgroup 及其子 cgroup 下的进程使用的内存。
- memory.max_usage_in_bytes:cgroup 下进程使用内存的最大值,包含子 cgroup 的内存使用量。
- memory.limit_in_bytes:设置 cgroup 下进程最多能使用的内存。如果设置为 -1,表示对该 cgroup 的内存使用不作限制。
- memory.oom_control:设置是否在 cgroup 中使用 OOM (Out Of Memory) Killer,默认为使用。
当属于该 cgroup 的进程使用的内存超过最大的限定值时,会立刻被 OOM Killer 处理。
Union FS
// TODO