容器本身没有价值, 有价值的是"容器编排"
From Dcoker To Kurbernets
Linux 容器:
- 一组联合挂载在
/var/lib/docker/aufs/mnt
上的 rootfs
,这一部分我们称为“容器镜像”(Container Image),是容器的静态视图
;
- 一个由 Namespace+Cgroups 构成的隔离环境,这一部分我们称为“容器运行时”(Container Runtime),是
容器的动态视图
。
安装docker
1
2
3
4
|
# 安装docker
sudo curl -fsSL get.docker.com -o get-docker.sh
# 指定国内mirror
sudo sh get-docker.sh --mirror Aliyun
|
1
2
3
4
5
6
|
# systemd 是系统init程序,开启初始化系统
# 管理资源(.mount, .service, .target, .wants)
# systemctl 是其进程管理命令
# 如果需求开机自启,建议打开
# sudo systemctl enable docker
sudo systemctl start docker
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# centos 7.x
# 通过systemd进行操作 /etc/docker/daemon.json
sudo mkdir -p /etc/docker
# set paste
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
# docker daemon-reload
# docker restart
sudo systemctl daemon-reload
sudo systemctl restart docker
# docker info查看修改结果
|
镜像理解
镜像是一种轻量级的,可执行的独立软件包.
用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时所需的库、环境变量和配置文件。
- 基于UnionFS的文件组织方式
- bootfs+rootfs
Dockerfile
用来构建Docker镜像, 由一系列命令和参数构成的脚本文件.
保留字 |
作用 |
FROM |
当前镜像是基于哪个镜像的 第一个指令必须是FROM |
MAINTAINER |
镜像维护者的姓名和邮箱地址 |
RUN |
构建镜像时需要运行的指令 |
EXPOSE |
当前容器对外暴露出的端口号 |
WORKDIR |
指定在创建容器后,终端默认登录进来的工作目录,一个落脚点 |
ENV |
用来在构建镜像过程中设置环境变量 |
ADD |
将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar包 |
COPY |
类似于ADD,拷贝文件和目录到镜像中 将从构建上下文目录中<原路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置 |
VOLUME |
容器数据卷,用于数据保存和持久化工作 |
CMD |
指定一个容器启动时要运行的命令 Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换 |
ENTRYPOINT |
指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及其参数 |
其实, docker默认会维护一个ENTRYPOINT
(/bin/sh -c
), 所以, ENTRYPOINT
+CMD
(/bin/sh -c "python app.py"
)
从字面上快来看, CMD
就是shell
中服务运行的指令
, ENTRYPOINT
是系统启动服务运行的指令
的
Docker 网络
- Docker启动, 在宿主机初始化一个
docker0
的虚拟网桥
- Docker分配一个宿主机中未被占用的私有网段给
docker0
, 后面启动的容器也会自动分配同一网段地址
- 创建容器,Docker同步创建
veth pair
的网络通道, 一个是eth0
,在运行容器中,另一个挂载docker0
的vethXXX
.实现宿主机-容器,容器-容器间的虚拟共享网络.
常用命令
1
2
3
4
5
6
7
8
9
10
11
|
# 查看docker网络信息
docker network ls
# 创建新的网桥
docker network create -d bridge 网桥名称
# 删除一个网桥
docker network rm 网桥名称
# 指定容器使用网桥
docker run -d -p 8890:80 --name nginx001 --network info nginx
docker run -d -p 8891:80 --name nginx002 --network info nginx
#`注意:一旦指定网桥后--name指定名字就是主机名,多个容器指定在同一个网桥时,可以在任意一个容器中使用主机名与容器进行互通`
# curl http://nginx001 在nginx002中即可通过http://container-name 与同一个网桥中的容器进行网络交互
|
Dcoker 数据卷
数据卷
是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
数据卷
可以在容器之间共享和重用
- 对
数据卷
的修改会立马生效
- 对
数据卷
的更新,不会影响镜像
数据卷
默认会一直存在,即使容器被删除
1
2
3
4
5
6
7
8
|
# 创建数据卷 默认在/var/lib/docker/volumes目录下创建 自动在my-vol目录下创建_data数据通道文件
docker volume create my-vol
# 查看my-vol详细
docker volumn inspect my-vol
# 挂在数据卷
docker run -d -P --name web -v my-vol:/usr/share/nginx/html nginx
# 删除数据卷
docker volume rm my-vol
|
Docker compose
命令对象与格式
对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。
执行 docker-compose [COMMAND] --help
或者 docker-compose help [COMMAND]
可以查看具体某个命令的使用格式。
docker-compose
命令的基本的使用格式是
1
|
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
|
命令选项
-f, --file FILE
指定使用的 Compose 模板文件,默认为 docker-compose.yml
,可以多次指定。
-p, --project-name NAME
指定项目名称,默认将使用所在目录名称作为项目名。
--x-networking
使用 Docker 的可拔插网络后端特性
--x-network-driver DRIVER
指定网络后端的驱动,默认为 bridge
--verbose
输出更多调试信息。
-v, --version
打印版本并退出。
命令使用说明
up
格式为 docker-compose up [options] [SERVICE...]
。
-
该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
-
链接的服务都将会被自动启动,除非已经处于运行状态。
-
可以说,大部分时候都可以直接通过该命令来启动一个项目。
-
默认情况,docker-compose up
启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。
-
当通过 Ctrl-C
停止命令时,所有容器将会停止。
-
如果使用 docker-compose up -d
,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。
-
默认情况,如果服务容器已经存在,docker-compose up
将会尝试停止容器,然后重新创建(保持使用 volumes-from
挂载的卷),以保证新启动的服务匹配 docker-compose.yml
文件的最新内容
down
- 此命令将会停止
up
命令所启动的容器,并移除网络
exec
ps
格式为 docker-compose ps [options] [SERVICE...]
。
列出项目中目前的所有容器。
选项:
restart
格式为 docker-compose restart [options] [SERVICE...]
。
重启项目中的服务。
选项:
-t, --timeout TIMEOUT
指定重启前停止容器的超时(默认为 10 秒)。
rm
格式为 docker-compose rm [options] [SERVICE...]
。
删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop
命令来停止容器。
选项:
-f, --force
强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项。
-v
删除容器所挂载的数据卷。
start
格式为 docker-compose start [SERVICE...]
。
启动已经存在的服务容器。
stop
格式为 docker-compose stop [options] [SERVICE...]
。
停止已经处于运行状态的容器,但不删除它。通过 docker-compose start
可以再次启动这些容器。
选项:
-t, --timeout TIMEOUT
停止容器时候的超时(默认为 10 秒)。
top
查看各个服务容器内运行的进程。
unpause
格式为 docker-compose unpause [SERVICE...]
。
恢复处于暂停状态中的服务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
version: "3.2"
services:
tomcat01: #服务名称
container_name: tomcat01 # 相当于run 的 --name
image: tomcat:8.0-jre8 #使用哪个镜像 相当于run image
ports: #用来完成host与容器的端口映射关系 相当于run -p
- "8080:8080"
volumes: #完成宿主机与容器中目录数据卷共享 相当于run -v
#- /root/apps:/usr/local/tomcat/webapps #使用自定义路径映射
- tomcatwebapps01:/usr/local/tomcat/webapps
networks: #代表当前服务使用哪个网络桥 相当于run --networ
- hello
tomcat02: #服务名称
container_name: tomcat02
image: tomcat:8.0-jre8 #使用哪个镜像
ports: #用来完成host与容器的端口映射关系
- "8081:8080"
volumes: #完成宿主机与容器中目录数据卷共享
#- /root/apps:/usr/local/tomcat/webapps #使用自定义路径映射
- tomcatwebapps02:/usr/local/tomcat/webapps
networks: #代表当前服务使用哪个网络桥
- hello
mysql:
image: mysql:5.7.32
container_name: mysql
ports:
- "3307:3306"
volumes:
- mysqldata:/var/lib/mysql
- mysqlconf:/etc/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
- hello
redis:
image: redis:5.0.10
container_name: redis
ports:
- "6379:6379"
volumes:
- redisdata:/data
networks:
- hello
command: "redis-server --appendonly yes" #run 镜像之后用来覆盖容器内容默认命令
volumes: #声明上面服务所使用的自动创建的卷名
tomcatwebapps01: #声明指令的卷名 compose自动创建该卷名但是会在之前加入项目名
external: #使用自定义卷名
false #true确定使用指定卷名 注意:一旦使用外部自定义卷名启动服务之前必须手动创建
tomcatwebapps02:
mysqldata:
mysqlconf:
redisdata:
networks: #定义服务用到桥
hello: #定义上面的服务用到的网桥名称 默认创建就是 bridge
external:
true #使用外部指定网桥 注意:网桥必须存在
|
常用命令
辅助命令
1
2
3
4
|
# 1.安装完成辅助命令
docker version -------------------------- 查看docker的信息
docker info -------------------------- 查看更详细的信息
docker --help -------------------------- 帮助命令
|
镜像命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 1.查看本机中所有镜像
docker images -------------------------- 列出本地所有镜像
-a 列出所有镜像(包含中间映像层)
-q 只显示镜像id
# 2.搜索镜像
docker search [options] 镜像名 ------------------- 去dockerhub上查询当前镜像
-s 指定值 列出收藏数不少于指定值的镜像
--no-trunc 显示完整的镜像信息
# 3.从仓库下载镜像
docker pull 镜像名[:TAG|@DIGEST] ----------------- 下载镜像
# 4.删除镜像
docker rmi 镜像名 -------------------------- 删除镜像
-f 强制删除
|
容器命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# 1.运行容器
docker run 镜像名 -------------------------- 镜像名新建并启动容器
--name 别名为容器起一个名字
-d 启动守护式容器(在后台启动容器)
-p 映射端口号:原始端口号 指定端口号启动
例:docker run -it --name myTomcat -p 8888:8080 tomcat
docker run -d --name myTomcat -P tomcat
# 2.查看运行的容器
docker ps -------------------------- 列出所有正在运行的容器
-a 正在运行的和历史运行过的容器
-q 静默模式,只显示容器编号
# 3.停止|关闭|重启容器
docker start 容器名字或者容器id --------------- 开启容器
docker restart 容器名或者容器id --------------- 重启容器
docker stop 容器名或者容器id ------------------ 正常停止容器运行
docker kill 容器名或者容器id ------------------ 立即停止容器运行
# 4.删除容器
docker rm -f 容器id和容器名
docker rm -f $(docker ps -aq) -------------------------- 删除所有容器
# 5.查看容器内进程
docker top 容器id或者容器名 ------------------ 查看容器内的进程
# 6.查看查看容器内部细节
docker inspect 容器id ------------------ 查看容器内部细节
# 7.查看容器的运行日志
docker logs [OPTIONS] 容器id或容器名 ------------------ 查看容器日志
-t 加入时间戳
-f 跟随最新的日志打印
--tail 数字 显示最后多少条
# 8.进入容器内部
docker exec [options] 容器id 容器内命令 ------------------ 进入容器执行命令
-i 以交互模式运行容器,通常与-t一起使用
-t 分配一个伪终端 shell窗口 bash
# 9.容器和宿主机之间复制文件
docker cp 文件|目录 容器id:容器路径 ----------------- 将宿主机复制到容器内部
docker cp 容器id:容器内资源路径 宿主机目录路径 ----------------- 将容器内资源拷贝到主机上
# 10.数据卷(volum)实现与宿主机共享目录
docker run -v 宿主机的路径|任意别名:/容器内的路径 镜像名
注意:
1.如果是宿主机路径必须是绝对路径,宿主机目录会覆盖容器内目录内容
2.如果是别名则会在docker运行容器时自动在宿主机中创建一个目录,并将容器目录文件复制到宿主机中
# 11.打包镜像
docker save 镜像名 -o 名称.tar
# 12.载入镜像
docker load -i 名称.tar
# 13.容器打包成新的镜像
docker commit -m "描述信息" -a "作者信息" (容器id或者名称)打包的镜像名称:标签
|
docker镜像
docker的镜像实际是由一层一层的文件系统组成。
Docker的镜像的文件系统是基于unionFS(联合文件系统)技术.
UnionFS可以将不同物理位置的目录合并, 挂载到同一个目录.
该系统会将每一次修改作为一个个层进行叠加, 同时将不同目录挂载到同一个虚拟文件系统.
容器镜像设计中, 为了解决各类依赖以及实现依赖共享,
容器, 是一个特殊的进程.
进程 –> Namespace&Cgroup –> rootfs –> docker
进程 & 程序
- 程序: 用于组织和操作数据和设备的可执行指令的集合
- 进程: 程序运行起来后的动态的计算机执行要素的总和,程序的动态组织运行的逻辑集合
隔离 & 限制
1
2
3
4
5
6
7
8
|
# 启动busybox镜像
sudo docker run -it busybox /bin/sh
# 查看当前busybox的container中的所有进程
ps -a
# PID USER TIME COMMAND
# 1 root 0:00 /bin/sh
# 7 root 0:00 ps -a
|
进入一个busybox的容器内,只存在启动命令进程/bin/sh
和查看ps命令进程ps -a
。
并没有云主机的运行进程–container被宿主机隔离了。
container真的是独立自主的运行环境?–这个虚拟机还有什么区别?
虚拟机虚拟了整个宿主操作系统的硬件系统, 一个用于主机的所有的镜像系统
Docker 伪装了进程, 提供一个实现和维护进程的应用.
Namespace
通过clone
将宿主机中一个进程封装成一个局域独立
的进程, 对进程, 网络,文件以及用户等资源提供隔离机制.
Cgroups
则对这样一个进程进行运行时的资源使用限制,限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等.
Namepsace
Namespace
是kernel
一个功能,隔离一系列的系统资源空间。用于将一个进程只能使用指定的内容。
Namespace类型 |
调用类型参数 |
说明 |
Mount Namespace |
CLONE_NEWNS |
隔离进程所能看到的挂载点视图 |
UTS Namespace |
CLONE_NEWUTS |
隔离nodename和domainname UTS 用于属于自己的hostname |
IPC Namespace |
CLONE_NEWIPC |
隔离System V PIC和POSIX queues |
PID Namesapce |
CLONE_NEWPID |
隔离进程PID |
Network Namespace |
CLONE_NEWNET |
隔离网络设备、IP地址端口等网络Namespace |
User Namespace |
CLONE_NEWUSER |
隔离用户组 |
- clone()将host namespace克隆到虚拟namspace
- unshare()将进程移除namespace ??
- setns()将进程加入namespace中 ??
Union File System
把其他文件系统联合到一个联合挂载点的文件系统服务
UTS Namespace
UTS NS 用于隔离nodename和domainname
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
/* ************************************************************************
> File Name: main.go
> Author: hanzi_zhu
> Created Time: Wed 02 Nov 2022 09:46:31 AM EDT
> Description: mydocker-UTS Namespace
*********************************************************************** */
package main
import (
"os/exec"
"syscall"
"os"
"log"
)
func main(){
// 指定被fork出来的新进程内初始命令 默认sh来执行
cmd := exec.Command("sh")
// syscall 调用clone 在sh环境通过CLONE_NEWUTS创建UTS Namespace
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
// go run main.go 通过sh,进入子UTS Namepsace 新进程
// 做两实验
// pstree -pl [yum -y install psmisc]
// sshd(1067)─┬─sshd(1601)─┬─bash(1608)───go(85015)─┬─main(85075)─┬─sh(85080)───pstree(85215)
// 其中main程序PID 85075
// echo $$ [查看当前进程]
// 当前进程为85080 同新的进程sh
// readlink /proc/85075/ns/uts [查看父进程main的uts]
// uts:[4026531838]
// readlink /proc/85080/ns/uts [查看sh新进程的uts]
// uts:[4026532417]
// 父子进程的uts是不一致的
// hostname -b bird [5080 修改hostname]
// hostname [bird]
// 再到main父进程间查看hostname [MiWiFi-R4AC-srv]
// 子进程的操作不影响父进程 隔离开来
|
IPC/PID/MountUser Namespace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
/* ************************************************************************
> File Name: main.go
> Author: hanzi_zhu
> Created Time: Wed 02 Nov 2022 09:46:31 AM EDT
> Description: mydocker main
*********************************************************************** */
package main
import (
"os/exec"
"syscall"
"os"
"log"
)
func main(){
// 指定被fork出来的新进程内初始命令 默认sh来执行
cmd := exec.Command("sh")
// syscall 调用clone 在sh环境通过CLONE_NEWUTS创建UTS Namespace
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC |
syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
syscall.CLONE_NEWUSER,
}
// cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(1), Gid: uint32(1)} // 在linux 3.10中不能这样加入 否则报fork/exec /usr/bin/sh: operation not permitted
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
os.Exit(-1)
}
// 注意:
// Centos 内核版本 3.10 需要手动开启user namesapce
// 不然运行go run main.go 报fork/exec /usr/bin/sh: invalid argument
// 解决方法:echo 640 > /proc/sys/user/max_user_namespaces
|
Network namespace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
/* ************************************************************************
> File Name: main.go
> Author: hanzi_zhu
> Created Time: Wed 02 Nov 2022 09:46:31 AM EDT
> Description: mydocker main
*********************************************************************** */
package main
import (
"os/exec"
"syscall"
"os"
"log"
)
func main(){
// 指定被fork出来的新进程内初始命令 默认sh来执行
cmd := exec.Command("sh")
// syscall 调用clone 在sh环境通过CLONE_NEWUTS创建UTS Namespace
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC |
syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
syscall.CLONE_NEWUSER | syscall.CLONE_NEWNET,
}
//cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(1), Gid: uint32(1)}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
os.Exit(-1)
}
// 对比host和main进程内net信息
// 命令:ip addr
// host的net信息完整
// main进程nei信息为空--该进程网络命名空间为隔离状态
|
Cgroups
Cgroups
实现对进程以及其子进程的资源限制、控制和统计能力
。
这样就可以控制Namespace隔离空间的资源使用、监控和统计,使得进程之间合理使用用以宿主机的而基础设施。
主要功能如下:
- 资源限制:对进程组使用的资源总额进行限制。
- 优先级分配:通过分配 CPU 时间片与硬盘 I/O,控制进程运行优先级。
- 资源统计: 统计进程、系统实际资源使用量。
- 进程控制:对进程组执行挂起、恢复等操作。
- 进程分组管理
- subsystem是一组资源控制模块,其关联指定的限制的cgroup,对Cgroup中的进程做相应的限制和控制
例如blkio\cpu\cpuset\cpuacct\devices\freezer\memory\net_cls\net_prio\ns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
cd /sys/fs/cgroup
ll
# drwxr-xr-x blkio 设置对块的输入输出的访问控制
# lrwxrwxrwx cpu -> cpu,cpuacct 进程cpu的调度策略
# lrwxrwxrwx cpuacct -> cpu,cpuacct 统计cgroup中进程的CPU占用
# drwxr-xr-x cpu,cpuacct
# drwxr-xr-x cpuset 多核机器中设置cgroup中进程可以使用cpu和内存
# drwxr-xr-x devices 设备的访问
# drwxr-xr-x freezer 用于挂起和恢复cgroup中进程
# drwxr-xr-x hugetlb
# drwxr-xr-x memory 控制cgroup进程的内存
# lrwxrwxrwx net_cls -> net_cls,net_prio 进程网络分类,便于区分进程的网络流量
# drwxr-xr-x net_cls,net_prio
# lrwxrwxrwx net_prio -> net_cls,net_prio 网络优先级
# drwxr-xr-x perf_event
# drwxr-xr-x pids
# drwxr-xr-x systemd
|
- hierachy 实现Cgroup的树状结构,完成Cgroup的继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
sudo docker run -itd busybox
# b69f64965d0eef3efd533667c726e2c35997eff2673e9d563244b90300fa05b
cd /sys/fs/cgroup/memory/b69f64965d0eef3efd533667c726e2c35997eff2673e9d563244b90300fa05b
ll
# -rw-r--r-- 1 root root 0 Mar 23 22:47 cgroup.clone_children
# --w--w--w- 1 root root 0 Mar 23 22:47 cgroup.event_control
# -rw-r--r-- 1 root root 0 Mar 23 22:47 cgroup.procs
# -rw-r--r-- 1 root root 0 Mar 23 22:47 tasks
# -rw-r--r-- 1 root root 0 Mar 23 22:47 notify_on_release
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.failcnt
# --w------- 1 root root 0 Mar 23 22:47 memory.force_empty
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.failcnt
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.limit_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.max_usage_in_bytes
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.slabinfo
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.tcp.failcnt
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.tcp.limit_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.tcp.max_usage_in_bytes
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.tcp.usage_in_bytes
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.kmem.usage_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.limit_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.max_usage_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.memsw.failcnt
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.memsw.limit_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.memsw.max_usage_in_bytes
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.memsw.usage_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.move_charge_at_immigrate
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.numa_stat
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.oom_control
# ---------- 1 root root 0 Mar 23 22:47 memory.pressure_level
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.soft_limit_in_bytes
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.stat
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.swappiness
# -r--r--r-- 1 root root 0 Mar 23 22:47 memory.usage_in_bytes
# -rw-r--r-- 1 root root 0 Mar 23 22:47 memory.use_hierarchy
cat memory.limit_in_bytes # 查看cgroup的内存限制
cat memory.usage_in_bytes # 查看当前cgroup的内存使用大小
|