06 修改内核参数

一 引入问题

runC在创建容器时,出于安全考虑,/proc/sys目录是以只读方式挂载到容器里的(容器启动后/proc/sys/下的内容默认都取自宿主机,并没有重新初始化)

docker run -d --name test1 centos:7 tail -f /dev/null
[root@test05 ~]# docker exec -ti test1 sh # 为ro只读
sh-4.2# mount |grep -w "/proc/sys"
proc on /proc/sys type proc (ro,nosuid,nodev,noexec,relatime)

因为是只读的,
所以对于一个已经运行着的容器,我们在容器内是无法修改/proc/sys下的内容的

[root@test04 ~]# docker container run -ti --rm --name test centos:7 sh
sh-4.2# cat /proc/sys/net/ipv4/ip_forward
1
sh-4.2# echo 0 > /proc/sys/net/ipv4/ip_forward
sh: /proc/sys/net/ipv4/ip_forward: Read-only file system  # 只读文件系统

而/proc/sys/net下包含了tcp/ip协议栈的大多数内核参数,有时候我们需要为其定义自己单独的tcp/ip协议参数

二 储备知识

容器网络名称空间
容器有自己的独立的网络名称空间,容器网络名称空间隔离了哪些东西

  • 第一种,网络设备,这里指的是 lo,eth0 等网络设备。你可以可以通过 ip link命令看到它们。

  • 第二种是 IPv4 和 IPv6 协议栈。从这里我们可以知道,IP 层以及上面的 TCP 和 UPD 协议栈也是每个 Namespace 独立工作的。

    所以 IP、TCP、PUD 的很多协议,它们的相关参数也是每个 Namespace 独立的,这些参

    数大多数都在 /proc/sys/net/ 目录下面,同时也包括了 TCP 和 UPD 的 port 资源。

  • 第三种,IP 路由表,这个资源也是比较好理解的,你可以在不同的 Network Namespace运行 ip route 命令,就能看到不同的路由表了。

  • 第四种是防火墙规则,其实这里说的就是 iptables 规则了,每个 Namespace 里都可以独立配置 iptables 规则。

  • 最后一种是网络的状态信息,这些信息你可以从 /proc/net 和 /sys/class/net 里得到,这里的状态基本上包括了前面 4 种资源的的状态信息。

三 如何修改容器内网络参数

注意:
想要修改,需要在容器启动之后立即完成修改,等容器内服务都对外提供服务了,
你再去修改,很多建立好的链接都不会生效

3.1 以特权模式启动容器

如果我们用特权模式启动,在容器中,可以任意修改sysctl内核参数,但是你需要知道的是
1、开启特权模式会增加安全风险
2、当你开启特权模式之后,在容器内修改的一些内核参数,可能会影响到宿主机(进而影响到该宿主机上所有其他容器),也可能不会影响

示例1:特权模式启动容器,在容器内修改net.ipv4.ip_forward不会影响宿主机

# 1、在宿主机查看
[root@test04 ~]# cat /proc/sys/net/ipv4/ip_forward  
1

# 2、进入容器内修改net.ipv4.ip_forward为0
[root@test04 ~]# docker container run -ti --rm --privileged --name test centos:7 sh
sh-4.2# cat /proc/sys/net/ipv4/ip_forward
1
sh-4.2# echo 0 > /proc/sys/net/ipv4/ip_forward
sh-4.2# cat /proc/sys/net/ipv4/ip_forward
0

# 3、跑到宿主机查看,会看到宿主机没有变,依然为1
[root@test04 ~]# cat /proc/sys/net/ipv4/ip_forward  
1

示例2:特权模式启动容器,在容器内修改vm.swappiness会影响宿主机,即修改的就是宿主机的

# 1、在宿主机查看
[root@test04 ~]# cat /proc/sys/net/ipv4/ip_forward  
1

# 2、进入容器内修改net.ipv4.ip_forward为0
[root@test04 ~]# docker container run -ti --rm --privileged --name test centos:7 sh
sh-4.2# cat /proc/sys/net/ipv4/ip_forward
1
sh-4.2# echo 0 > /proc/sys/net/ipv4/ip_forward
sh-4.2# cat /proc/sys/net/ipv4/ip_forward
0

# 3、开启另外一个终端,在宿主机查看,会看到宿主机没有变,依然为1
[root@test04 ~]# cat /proc/sys/net/ipv4/ip_forward  
1

注意修改成功后,你去宿主机查看,仍然不变,因为容器拥有自己的独立的网络名称空间

# 1、在宿主机上
[root@test05 ~]# cat /proc/sys/vm/swappiness 
30

# 2、在容器内
[root@test05 ~]# docker container run -ti --rm --privileged --name test centos:7 sh
sh-4.2# cat /proc/sys/vm/swappiness 
30
sh-4.2# echo 10 > /proc/sys/vm/swappiness 
sh-4.2# cat /proc/sys/vm/swappiness 
10
sh-4.2# exit  # 此时你即便退出了容器,你去宿主机查看,会发现宿主机swappiness被改为了10
exit

# 3、在宿主机上
[root@test05 ~]# cat /proc/sys/vm/swappiness 
10

为什么呢???
内核方面做了大量的工作,把一部分sysctl内核参数进行了namespace化(namespaced)。 也就是多个容器和主机可以各自独立设置某些内核参数。例如, 可以通过net.ipv4.ip_local_port_range,在不同容器中设置不同的端口范围。

如何判断一个参数是不是namespaced?
运行一个具有privileged权限的容器, 然后在容器中修改该参数,看一下在host上能否看到容器在中所做的修改。如果看不到, 那就是namespaced, 否则就部署namespaced。
目前已经namespace化的sysctl内核参数:

  • kernel.shm*,
  • kernel.msg*,
  • kernel.sem,
  • fs.mqueue.*,
  • net..
    注意, vm.
    并没有namespace化。 比如vm.max_map_count, 在主机或者一个容器中设置它, 其他所有容器都会受影响,都会看到最新的值。

3.2 在宿主机使用nsenter

如果你可以用root账号登录到宿主机,那么可以借助nsenter命令进入容器名称空间修改,这种不需要开启特权模式,但效果与其是类似的
即如果修改的是namespaced的参数, 则不会影响host和其他容器。反之,则会影响它们。

使用nsenter来修改

# 1、root 用户
nsenter -t <容器的pid> -n bash -c 'echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time'

# 2、非root用户
sudo nsenter -t <pid> -n sudo bash -c 'echo 600 > /proc/sys/net/ipv4/tcp_keep
alive_time' 

nsenter使用详解

联系管理员微信tutu19192010,注册账号

上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术