为什么 docker 容器中的 shell 显示来自主机的 dmesg 内容?
Why is a shell within a docker container showing dmesg content from the host?
我在 Ubuntu yakkety 上有一个 docker 容器 运行ning Debian jessie。
当在 docker 内(例如通过 ssh
连接)时,我与主机隔离(这是预期的)。然而,我意识到 dmesg
向我显示了主机而不是容器的消息。 它如何访问其主机的信息?
docker容器的配置并不特殊(除了它使用特定的网桥,不同于docker0
),特别是它在任何特权模式下都不运行 (下图"Privileged": false
):
root@srv ~# docker inspect minecraft-1-8
[
{
"Id": "748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e",
"Created": "2016-12-01T15:35:05.287672787Z",
"Path": "/usr/bin/supervisord",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 28650,
"ExitCode": 0,
"Error": "",
"StartedAt": "2016-12-15T18:37:08.409564695Z",
"FinishedAt": "2016-12-15T18:37:07.457274028Z"
},
"Image": "sha256:78a2f88d47e29523503c2196ed2faaa3d1039d948d73987edc03b2abd338595d",
"ResolvConfPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hostname",
"HostsPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hosts",
"LogPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e-json.log",
"Name": "/minecraft-1-8",
"RestartCount": 0,
"Driver": "overlay",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "docker",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": -1,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0
},
"GraphDriver": {
"Name": "overlay",
"Data": {
"LowerDir": "/var/lib/docker/overlay/e78ce9dbcedd6974429a4aada8f38913b7d35da41f586f203dd99a568f38b6c3/root",
"MergedDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/merged",
"UpperDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/upper",
"WorkDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/work"
}
},
"Mounts": [],
"Config": {
"Hostname": "minecraft-1-8",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/usr/bin/supervisord"
],
"Image": "minecraft",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "cf411634babad31138ab4572b9cd7306f74a54dd1baf4cd8d7706d7e7020c594",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/cf411634baba",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"docker": {
"IPAMConfig": {
"IPv4Address": "10.200.0.100"
},
"Links": null,
"Aliases": [
"748cfdfbf3fb"
],
"NetworkID": "7b20560b36032d36ffe6c0ebece6b4408355d207f4e203a2957b0434ee0afdc1",
"EndpointID": "9fa4fc914dfe76022ce0db02e48a7e7c85c57bc2a15b0b3e5d81b1f24d95f376",
"Gateway": "10.200.0.1",
"IPAddress": "10.200.0.100",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:0a:c8:00:64"
}
}
}
}
]
在大多数发行版的 dmesg
is not a privileged command. Any user can use the klogctl 接口中读取内核环形缓冲区。
$ id
uid=1001(matt) gid=1001(matt) groups=1001(matt)
$ dmesg | head -1
[ 0.000000] Initializing cgroup subsys cpuset
但除了读取之外什么也做不了
$ dmesg -C
dmesg: klogctl failed: Operation not permitted
延伸至 Docker
$ sudo docker run debian dmesg | head -1
[ 0.000000] Initializing cgroup subsys cpuset
$ sudo docker run debian dmesg -C
dmesg: klogctl failed: Operation not permitted
限制访问
您可以通过 /proc/sys/kernel/dmesg_restrict
将读取权限限制为 root 用户和具有 CAP_SYSLOG 或 CAP_SYS_ADMIN capabilities 的用户。
$ echo 1 > /proc/sys/kernel/dmesg_restrict
那么您应该会收到一条权限被拒绝的消息:
$ docker run ubuntu:yakkety dmesg
dmesg: read kernel buffer failed: Operation not permitted
运行 特权模式下的容器将重新获得对主机内核环缓冲区的访问权限
$ docker run --privileged ubuntu:yakkety dmesg
[146902.131915] br-fa26f1dc96a1: port 3(veth80d3d5d) entered disabled state
...
如果您永久需要它,请使用 sysctl 配置 kernel.dmesg_restrict=1
。
命名空间
至于为什么内核日志不像其他内核区域那样有名称间距,我认为答案是"it's difficult"。在这个 2012 Stepping closer to practical containers: "syslog" namespaces LWN post. I can't see any reference's to it getting any further than proposed patches: https://lwn.net/Articles/562389/ https://lwn.net/Articles/561271/. As you can see in this recent netfilter patch 中,有比你想知道的更多的细节,他们有一个变通方法允许容器名称 space 中的规则使用全局日志。
我在 Ubuntu yakkety 上有一个 docker 容器 运行ning Debian jessie。
当在 docker 内(例如通过 ssh
连接)时,我与主机隔离(这是预期的)。然而,我意识到 dmesg
向我显示了主机而不是容器的消息。 它如何访问其主机的信息?
docker容器的配置并不特殊(除了它使用特定的网桥,不同于docker0
),特别是它在任何特权模式下都不运行 (下图"Privileged": false
):
root@srv ~# docker inspect minecraft-1-8
[
{
"Id": "748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e",
"Created": "2016-12-01T15:35:05.287672787Z",
"Path": "/usr/bin/supervisord",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 28650,
"ExitCode": 0,
"Error": "",
"StartedAt": "2016-12-15T18:37:08.409564695Z",
"FinishedAt": "2016-12-15T18:37:07.457274028Z"
},
"Image": "sha256:78a2f88d47e29523503c2196ed2faaa3d1039d948d73987edc03b2abd338595d",
"ResolvConfPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hostname",
"HostsPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/hosts",
"LogPath": "/var/lib/docker/containers/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e/748cfdfbf3fb5526cb7151cbc0857117af3c7bd8ab9e086c4f2efb897290d66e-json.log",
"Name": "/minecraft-1-8",
"RestartCount": 0,
"Driver": "overlay",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "docker",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": -1,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0
},
"GraphDriver": {
"Name": "overlay",
"Data": {
"LowerDir": "/var/lib/docker/overlay/e78ce9dbcedd6974429a4aada8f38913b7d35da41f586f203dd99a568f38b6c3/root",
"MergedDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/merged",
"UpperDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/upper",
"WorkDir": "/var/lib/docker/overlay/e8422e4707d95db8ea747af2367626cc8bf16e95f8eb05dfad9a63461c9ade86/work"
}
},
"Mounts": [],
"Config": {
"Hostname": "minecraft-1-8",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/usr/bin/supervisord"
],
"Image": "minecraft",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "cf411634babad31138ab4572b9cd7306f74a54dd1baf4cd8d7706d7e7020c594",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/cf411634baba",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"docker": {
"IPAMConfig": {
"IPv4Address": "10.200.0.100"
},
"Links": null,
"Aliases": [
"748cfdfbf3fb"
],
"NetworkID": "7b20560b36032d36ffe6c0ebece6b4408355d207f4e203a2957b0434ee0afdc1",
"EndpointID": "9fa4fc914dfe76022ce0db02e48a7e7c85c57bc2a15b0b3e5d81b1f24d95f376",
"Gateway": "10.200.0.1",
"IPAddress": "10.200.0.100",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:0a:c8:00:64"
}
}
}
}
]
在大多数发行版的 dmesg
is not a privileged command. Any user can use the klogctl 接口中读取内核环形缓冲区。
$ id
uid=1001(matt) gid=1001(matt) groups=1001(matt)
$ dmesg | head -1
[ 0.000000] Initializing cgroup subsys cpuset
但除了读取之外什么也做不了
$ dmesg -C
dmesg: klogctl failed: Operation not permitted
延伸至 Docker
$ sudo docker run debian dmesg | head -1
[ 0.000000] Initializing cgroup subsys cpuset
$ sudo docker run debian dmesg -C
dmesg: klogctl failed: Operation not permitted
限制访问
您可以通过 /proc/sys/kernel/dmesg_restrict
将读取权限限制为 root 用户和具有 CAP_SYSLOG 或 CAP_SYS_ADMIN capabilities 的用户。
$ echo 1 > /proc/sys/kernel/dmesg_restrict
那么您应该会收到一条权限被拒绝的消息:
$ docker run ubuntu:yakkety dmesg
dmesg: read kernel buffer failed: Operation not permitted
运行 特权模式下的容器将重新获得对主机内核环缓冲区的访问权限
$ docker run --privileged ubuntu:yakkety dmesg
[146902.131915] br-fa26f1dc96a1: port 3(veth80d3d5d) entered disabled state
...
如果您永久需要它,请使用 sysctl 配置 kernel.dmesg_restrict=1
。
命名空间
至于为什么内核日志不像其他内核区域那样有名称间距,我认为答案是"it's difficult"。在这个 2012 Stepping closer to practical containers: "syslog" namespaces LWN post. I can't see any reference's to it getting any further than proposed patches: https://lwn.net/Articles/562389/ https://lwn.net/Articles/561271/. As you can see in this recent netfilter patch 中,有比你想知道的更多的细节,他们有一个变通方法允许容器名称 space 中的规则使用全局日志。