目录
一、cgroup简介
二、 容器资源控制
1、内存限制
2、cpu限额
3、Block IO限制
三、docker 安全加固
在使用 docker 运行容器时,默认的情况下,docker没有对容器进行硬件资源的限制,当一台主机上运行几百个容器,这些容器虽然互相隔离,但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制,那么容器之间会互相影响,小的来说会导致容器资源使用不公平;大的来说,可能会导致主机和集群资源耗尽,服务完全不可用。
docker 作为容器的管理者,自然提供了控制容器资源的功能。正如使用内核的 namespace 来做容器之间的隔离,docker 也是通过内核的 cgroups 来做容器的资源限制;包括CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制
Linux Cgroups 的全称是 Linux Control Group。 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。 Linux Cgroups 给用户暴露出来的操作接口是文件系统。 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。 执行此命令查看:mount -t cgroup
在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
docker ps
docker run -d --name demo nginx ##运行一个容器
docker ps
docker inspect demo ##查看demo信息
docker inspect demo | grep Pid ##可以看到pid为3904,是一个进程
cd /proc/3904/
ls
cd ns
ls ##可以看到有6种ns
ll -d /var/lib/docker/ #docker所有信息都在这个目录中,继承超级用户权限
rpm -qa | grep docker ##有无根模式
docker run --help | grep memory
docker ps
docker rm -f demo
docker run --rm -it --memory 200M busybox ##运行容器限制使用内存200M
free -m ##容器内和宿主机 的内存信息共享
ll -d /proc/meminfo ##内存信息存储目录
docker ps
docker inspect 8eaf11fb38be ##可以看到设置的内存200M
docker ps
docker rm -f brave_driscolldocker run -d --name demo -m 200M nginx
docker ps
mount -t cgroup ##可以看到以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下
cd /sys/fs/cgroup/
ls
cd memory/
ls
cd docker/
ls ##可以看到运行的容器
cd ee9e314442a1946014927017f4f34bfd956d8e780bb531c494607b8df49dddb3
ls
cat memory.limit_in_bytes##查看内存控制的资源限制,200M说明已经受限
docker run -d --name demo2 nginx ##再开一个容器不做内存限制
cd - #切换到之前的目录
cd ..
ls ##可以看到demo2容器id
cd 3955d8631839ffc805157981b147aab75fd4008e68974d438c1483be9b769743
ls
cat memory.limit_in_bytes ##查看内存限制,没有限制
cd ..
pwd 所有的docker 容器都在这个docker 目录中,这个目录里面的信息都是继承父级memory子系统的
ls
cd ..
ls
cat memory.limit_in_bytes
mkdir x1##创建x1控制器
cd x1/
ls 里面内容继承父级子系统的
cat memory.limit_in_bytes
echo 209715200 > memory.limit_in_bytes 给予200M内存使用量
cat memory.limit_in_bytes
cd
df #可以看到tmpfs挂接的是物理机的1/2的内存
cd /dev/shm/
ls
free -m ##查看内存
dd if=/dev/zero of=bigfile bs=1M count=100 ##在此目录下写数据耗费的是内存
free -m ##空闲少了100M内存
ls
rm -f bigfile
free -m #删除刚建立的文件,物理内存还原
vmstat ##此命令也可以查看内存使用量
free -m
dd if=/dev/zero of=bigfile bs=1M count=300
free -m ##可以看到少了300M
cd /sys/fs/cgroup/memory/x1/
ls
cat memory.limit_in_bytes #可以看到设置的内存限制为200M
id ##因为使用的是超级用户,不受限制
cd -
ls
rm -f bigfile
free -m
cd -
ls
cat tasks ##要使之生效,必须将其加入到进程任务中
yum search cgroup
yum install -y libcgroup-tools.x86_64
cd -
ls
cgexec -g memory:x1 dd if=/dev/zero of=bigfile bs=1M count=300 ###内存子系统x1控制器
控制物理内存不能超过200free -m #可以看到物理内存少了200M,但是swap分区也使用了100M
rm -f bigfile
free -m
cgexec -g memory:x1 dd if=/dev/zero of=bigfile bs=1M count=300
free -m ##swap交换分区是物理内存不够用时备用的
rm -f bigfile
cd -
ls
docker run --help | grep memory
cat memory.memsw.limit_in_bytes#内存和swap总共限制资源
cat memory.limit_in_bytes
echo 209715200 > memory.memsw.limit_in_bytes ##给予200M
cat memory.memsw.limit_in_bytes
cd -
cgexec -g memory:x1 dd if=/dev/zero of=bigfile bs=1M count=300 ##命令被kill,swap不可用
free -m
du -h bigfile ##文件大小为200M
docker ps
docker inspect demo | grep Pid ##过滤出demo的pid
cd /sys/fs/cgroup/memory/ 进入memory控制器
ls
cd docker/
ls 可以看到运行容器ID
cd ee9e314442a1946014927017f4f34bfd956d8e780bb531c494607b8df49dddb3 进入demo
ls
cat tasks ##容器内所有的进程都可以看到
cd ..
ls
cd 3955d8631839ffc805157981b147aab75fd4008e68974d438c1483be9b769743 进入demo2
ls
cat tasks #容器的进程还有容器内nginx其他进程,都是自动添加
docker inspect demo2 | grep Pid
cd
docker run --help | grep cpu ##针对cpu 的限制
docker run --help | grep devi ##还有设备io的
Linux 通过 CFS(Completely Fair Scheduler,完全公平调度器)来调度各个进程对 CPU 的使用。CFS 默认的调度周期是 100ms。
我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少 CPU 时间。使用--cpu-period即可设置调度周期,使用--cpu-quota即可设置在每个周期内容器能使用的 CPU 时间。两者一般配合使用。
cd /sys/fs/cgroup/
ls
cd cpu
ls
mkdir x2
cd x2/ ##继承父级子系统的文件
ls
cat cpu.cfs_quota_us #-1 表示没有任何限制
cat cpu.cfs_period_us
echo 20000 > cpu.cfs_quota_us ##表示20%的cpu运行时间每100ms
cat cpu.cfs_quota_us
dd if=/dev/zero of=/dev/null & ##此动作会直接占据cpu
top ##top命令查看cpu占用
cd /sys/devices/system/
ls
cd cpu/
ls ##cpu0不可以被关闭
cd cpu1/
ls
cat online
echo 0 > online 设置关闭cpu1
cat online
top ##按“1”可以看到只有cpu0运行,cpu1被关闭
echo 1 > online ##重启开启cpu1
top
cd /sys/fs/cgroup/
ls
cd cpu/ ##进入cpu进程
cd x2/
ls
echo 6205 > tasks #把dd进程id直接放入task 中
cat tasks
top #查看到%cpu为20%
kill 6205 #不需要时可以kill
top
cd
docker ps
docker rm -f demo
docker rm -f demo2
docker run -d --cpu-period=100000 --cpu-quota=20000 --name demo nginx##运行容器将 CFS 调度的周期设为 100000,将容器在每个周期内的 CPU 配额设置为 20000,表示该容器每 100ms 可以得到 20% 的 CPU 运行时间
docker ps
cd /sys/fs/cgroup/
ls
cd cpu
cd docker/
ls
cd def37a843dfc59e92d781f7e7e7ec0ee6831202d6cb3154175d93e15159f83d8
ls
cat cpu.cfs_quota_us 自动设置CPU 配额为 20000
docker run -it --device-write-bps /dev/vda:30MB centos:7 ##--device-write-bps限制写设备的bps速率为30MB/s
--/# dd if=/dev/zero of=/bigfile bs=1M count=200 oflag=direct #目前的block IO限制只对direct IO有效。(不使用文件缓存)
可以看到速率为31.6MB/s
docker run -it centos:7 ##不加速率限制运行,可以看到速率达到863MB/s
docker container prune
docker ps -a
docker rm -f demo
在容器内查看内存时显示的是宿主机的内存信息,为了安全起见有时候需要做限制
docker run --rm -it --memory 200M busybox
/ # free -m #给了200M但是swap出现的还是2G *proc是没有做隔离的,所以容器和宿主机看到的是一样的【直接访问的是根下的proc】
cd /proc/
ls
cd
ls
yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm
lxcfs /var/lib/lxcfs & ##运行软件打入后台
ps ax
cd /var/lib/lxcfs/ 默认的数据目录:/var/lib/lxcfs/
ls #会生成相应的cgroup和proccd cgroup/
ls
cd ..
cd proc/
ls #可以看到每一个文件都分别代表宿主机的6样信息
把lxcfs-2.0.5-3.el7.centos.x86_64.rpm从真机中传到docker1
利用LXCFS增强docker容器隔离性和资源可见性
docker run -it -m 256m -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw -v /var/lib/lxcfs/proc/stat:/proc/stat:rw -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw centos:7 ##此时运行容器,运行时将lxcfs数据目录下的内容挂载到容器内
--/# free -m #可以看到swap分区有200M
docker container prune
docker run --rm -it busybox--/ # ip addr --/ # ip link set down dev eth0 #执行命令没有操作权限,不允许 --/ # id #可以看到是超级用户默认在运行容器时容器内的用户并不是真正的root用户
设置特权级运行的容器:--privileged=true 有的时候我们需要容器具备更多的权限,比如操作内核模块,控制swap交换分区,挂载USB磁盘,修改MAC地址等
docker run --rm -it --privileged=true busybox##可以执行ip link set
这个权限比较大,接近于宿主机的root用户,为了防止用户权限的滥用,需要增加权限,只提供给容器必须的权限。此时Docker提供了权限白名单的机制,使用–cap-add添加必要的权限。
docker run --rm -it --cap-add=NET_ADMIN busybox ##容器具有网络管理的权限-/ # fdisk -l #看不到磁盘分区
docker run --rm -it --privileged=true busybox ##可以查看磁盘