我嘗試從 /bin 運行 ls 的副本(并嘗試在容器中不在 /bin 中的任何可執行檔案上)并得到錯誤。
docker run -v ~/Desktop/test:/test alpine:latest /test/ls
exec /test/ls: no such file or directory
當我運行另一個命令時,我可以看到該檔案。
docker run -v ~/Desktop/test:/test alpine:latest ls /test
ls
我嘗試chmode在此檔案上設定 x,但沒有得到任何更改。改變形象也沒有任何影響。我已經更新了 docker 并且全部由apt-get update && apt-get upgrade.
我使用 Ubuntu 20.04.3 LTS。
Docker 版本 20.10.17,構建 100c701
檢查
{
"Id": "abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33",
"Created": "2022-06-13T19:59:49.630474765Z",
"Path": "/test/ls",
"Args": [],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 1,
"Error": "",
"StartedAt": "2022-06-13T19:59:50.017551978Z",
"FinishedAt": "2022-06-13T19:59:50.016401363Z"
},
"Image": "sha256:0ac33e5f5afa79e084075e8698a22d574816eea8d7b7d480586835657c3e1c8b",
"ResolvConfPath": "/var/lib/docker/containers/abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33/hostname",
"HostsPath": "/var/lib/docker/containers/abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33/hosts",
"LogPath": "/var/lib/docker/containers/abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33/abd66c400e6f58313d71c63c92688472874cdd4393d42e22df23a90264083b33-json.log",
"Name": "/cranky_pare",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/home/egor/Desktop/test:/test"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"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,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/115140c86b11eb773f30d2329ec05388224e75dfbcef9977c87bb3f0e32e8769-init/diff:/var/lib/docker/overlay2/22348355d634b9183f798e9622f71809a9a62a7c6accdf723aa72d979e3ba7f4/diff",
"MergedDir": "/var/lib/docker/overlay2/115140c86b11eb773f30d2329ec05388224e75dfbcef9977c87bb3f0e32e8769/merged",
"UpperDir": "/var/lib/docker/overlay2/115140c86b11eb773f30d2329ec05388224e75dfbcef9977c87bb3f0e32e8769/diff",
"WorkDir": "/var/lib/docker/overlay2/115140c86b11eb773f30d2329ec05388224e75dfbcef9977c87bb3f0e32e8769/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/home/egor/Desktop/test",
"Destination": "/test",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
"Hostname": "abd66c400e6f",
"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": [
"/test/ls"
],
"Image": "alpine:latest",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "fb64f195f203033f02b9c5555e0b1d2cdd2819f3ac12f3046416f8e13378bc3d",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/fb64f195f203",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "cb261cd6eca2ddb567984e2d7d9e6df14008c774d73f0d76129da6c8edc6955c",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
},
"CreatedTime": 1655150389630
}
uj5u.com熱心網友回復:
程式二進制本身(在大多數情況下)不是自給自足的;相反,它依賴于許多動態庫(通常至少是一個 C 標準庫)和一個動態聯結器(也稱為解釋器),它知道如何將二進制檔案加載到記憶體中并將其與這些庫鏈接。
有關系統必須使用什么聯結器來啟動特定程式以及程式需要哪些庫的資訊存盤在程式二進制檔案本身中。ldd您可以使用和等工具輕松提取此資訊readelf。例如,您可以通過以下方式找到/bin/ls成功運行所需的所有內容:
$ ldd /bin/ls
linux-vdso.so.1 (0x00007ffec7b46000)
libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f805384c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f8053642000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f80538ae000)
或者,更詳細地說:
$ readelf -a /bin/ls
...
Program Headers:
Type Offset VirtAddr PhysAddr
...
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
Dynamic section at offset 0x22a58 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libcap.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
注意:我的示例取自 Arch box,因此您的結果可能會有所不同,但接近于此。這里的要點是二進制檔案依賴于ld-linux,這對于 Arch 和 Ubuntu 都是如此(見下文)。
當您要求內核執行ls時,它會讀取程式二進制檔案,在檔案系統中查找程式所需的聯結器 ( /lib64/ld-linux-x86-64.so.2) 并運行它。然后聯結器將ls其及其所有依賴項加載到記憶體中;只有在此之后,ls它自己的代碼才會被執行。
問題是不同的 Linux 發行版(以及它們的不同版本)有不同的環境。雖然發行版通常使用 GNU libc ( glibc) 作為 C 標準庫并將其ld-linux用作聯結器,但也有發行版使用其他 libc 變體和其他聯結器。Alpine 就是這樣的發行版之一:它使用musllibc 和它自己的聯結器ld-musl:
$ docker run -it alpine
/ # ldd /bin/ls
/lib/ld-musl-x86_64.so.1 (0x7f40c772d000)
libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f40c772d000)
這意味著 Alpine 沒有/lib64/ld-linux-x86-64.so.2檔案(默認情況下;請參閱運行 glibc 程式)。這就是為什么在 Alpine 容器中運行lsbuilt for glibc-based 系統(在你的情況下是 Ubuntu)失敗的原因:內核讀取二進制檔案,知道它需要/lib64/ld-linux-x86-64.so.2加載這個程式,并且在檔案系統中找不到這樣的檔案。
當內核無法找到程式請求的解釋器時,它會回傳與您要求它執行不存在的檔案時相同的錯誤:
man 2 execve
...
ENOENT The file pathname or a script or ELF interpreter does not exist.
這就是為什么你會得到no such file or directory,這有點誤導,因為它沒有說找不到哪個檔案——聯結器,而不是程式本身。
鑒于它ls沒有很多依賴項,您嘗試使用的技巧很可能適用于內部具有glibc-based 系統的容器:
$ docker run -it -v /bin/ls:/test/ls alpine /test/ls
exec /test/ls: no such file or directory
...
$ docker run -it -v /bin/ls:/test/ls ubuntu /test/ls
bin dev home lib32 libx32 mnt proc run srv test usr
boot etc lib lib64 media opt root sbin sys tmp var
...
$ docker run -it -v /bin/ls:/test/ls archlinux /test/ls
bin dev home lib64 opt root sbin sys tmp var
boot etc lib mnt proc run srv test usr
但是,在容器內運行主機二進制檔案不是您應該做的事情,也不能保證事情不會發生混亂,因此請確保您在使用這些技巧時真正知道自己在做什么。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/490656.html
上一篇:認識JavaWeb
