带有自定义存储(在 chroot 内)的 nix 在 docker 容器内不工作 - 无法解析主机:docker
nix with custom store (inside chroot) not working inside docker container - Could not resolve host: docker
提出了一个问题https://github.com/NixOS/nix/issues/2663
如何重现
- 运行 这在某些终端
docker run --privileged --rm --name some-docker docker:stable-dind
- 保存测试文件
cat > /tmp/test.nix << 'EOL'
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
(ls -al /etc || true)
(cat /etc/nsswitch.conf || true)
(cat /etc/hosts || true)
(cat /etc/resolv.conf || true)
# without --store returns
#
# Kernel IP routing table
# Destination Gateway Genmask Flags MSS Window irtt Iface
# 0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
# 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
#
# with --store returns empty
#
# Kernel IP routing table
# Destination Gateway Genmask Flags MSS Window irtt Iface
netstat --numeric --route
# without --store - returns without error
# with --store - error "Could not resolve host: docker"
curl -v http://docker:2375/v1.39/version
# without --store - returns without error, prints server info
# with --store - error "error during connect: Get http://docker:2375/v1.39/version: dial tcp: lookup docker on [::1]:53: read udp [::1]:39506->[::1]:53: read: connection refused"
docker version
# create dummy package if everything above did work fine
mkdir -p $out
'';
}
EOL
- 它在没有
--store
参数的情况下工作
docker run -it --rm --link some-docker:docker -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh -c 'export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf) && nix-build /tmp/test.nix'
输出 - https://pastebin.com/DZmXrATR
- 它不适用于
--store
参数
docker run -it --rm --link some-docker:docker --privileged -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh -c 'export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf) && nix-build --store /tmp/store /tmp/test.nix'
输出https://pastebin.com/Z4DxtLQr
如何让它发挥作用?
更新:
好像是因为使用--store
时没有挂载/etc/nsswitch.conf
不幸的是,nix 不允许我自己创建它(touch /etc/nsswitch.conf
throws permission denied)
更新:
我发现我可以使用 extra-sandbox-paths
将文件从容器挂载到 nix-build 沙箱
挂载/etc/nsswitch.conf解决curl: (6) Could not resolve host: docker
但我无法修复 * Immediate connect fail for 172.17.0.2: Network is unreachable
错误,我已尝试从 /etc 安装所有与网络相关的文件,但它不起作用
docker run --privileged --rm --name some-docker docker:stable-dind
docker run -it --rm --link some-docker:docker --privileged -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh
nix-env -i curl nettools
# works
curl -v http://172.17.0.2:2375/v1.39/version
# works
curl -v http://docker:2375/v1.39/version
# lo and eth
ifconfig -a
# not empty
netstat -rn
export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf)
cat > /etc/nix/nix.conf << 'EOL'
sandbox = false
extra-sandbox-paths = /etc/nsswitch.conf=/etc/nsswitch.conf /etc/resolv.conf=/etc/resolv.conf /etc/hosts=/etc/hosts /etc/protocols=/etc/protocols /etc/udhcpd.conf=/etc/udhcpd.conf /etc/modules=/etc/modules
EOL
cat > /tmp/test.nix << 'EOL'
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
# only lo
ifconfig -a
# empty
netstat --numeric --route
# fails
curl -v http://172.17.0.2:2375/v1.39/version
curl -v http://docker:2375/v1.39/version
docker version
mkdir -p $out
'';
}
EOL
nix-build --store /tmp/store /tmp/test.nix
更新
研究现状
https://gitlab.com/gitlab-org/gitlab-ce/issues/31312#note_138576414
如果您的 installPhase
运行 和 curl
,那您就错了。 Nix 中的推导应该是 纯粹的 :让它们的输出仅依赖于它们声明的输入,而不依赖于其他任何东西。连接到网络的派生本质上是不纯的:其结果将取决于调用给定网络资源时它背后存在的内容。因此,Nix 的沙箱有意(并根据其文档)禁止其构建者访问网络。
考虑以下内容,它仍然不纯,但使用 builtins.fetchurl
代替,因此不会阻止操作:
{ pkgs ? import <nixpkgs> {} }:
with pkgs; let
# WARNING: This is impure; usually, downloads should include an explicit hash
versionFile = builtins.fetchurl http://172.17.0.2:2375/v1.39/version
in stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
cat ${escapeShellArg versionFile}
docker version
mkdir -p "$out"
'';
}
强烈建议您使用 pkgs.dockerTools 仅使用纯 Nix 代码构建与 Docker 兼容的图像,而不是尝试 运行 Docker 在 Nix 派生中.
提出了一个问题https://github.com/NixOS/nix/issues/2663
如何重现
- 运行 这在某些终端
docker run --privileged --rm --name some-docker docker:stable-dind
- 保存测试文件
cat > /tmp/test.nix << 'EOL'
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
(ls -al /etc || true)
(cat /etc/nsswitch.conf || true)
(cat /etc/hosts || true)
(cat /etc/resolv.conf || true)
# without --store returns
#
# Kernel IP routing table
# Destination Gateway Genmask Flags MSS Window irtt Iface
# 0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
# 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
#
# with --store returns empty
#
# Kernel IP routing table
# Destination Gateway Genmask Flags MSS Window irtt Iface
netstat --numeric --route
# without --store - returns without error
# with --store - error "Could not resolve host: docker"
curl -v http://docker:2375/v1.39/version
# without --store - returns without error, prints server info
# with --store - error "error during connect: Get http://docker:2375/v1.39/version: dial tcp: lookup docker on [::1]:53: read udp [::1]:39506->[::1]:53: read: connection refused"
docker version
# create dummy package if everything above did work fine
mkdir -p $out
'';
}
EOL
- 它在没有
--store
参数的情况下工作
docker run -it --rm --link some-docker:docker -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh -c 'export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf) && nix-build /tmp/test.nix'
输出 - https://pastebin.com/DZmXrATR
- 它不适用于
--store
参数
docker run -it --rm --link some-docker:docker --privileged -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh -c 'export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf) && nix-build --store /tmp/store /tmp/test.nix'
输出https://pastebin.com/Z4DxtLQr
如何让它发挥作用?
更新:
好像是因为使用--store
不幸的是,nix 不允许我自己创建它(touch /etc/nsswitch.conf
throws permission denied)
更新:
我发现我可以使用 extra-sandbox-paths
将文件从容器挂载到 nix-build 沙箱
挂载/etc/nsswitch.conf解决curl: (6) Could not resolve host: docker
但我无法修复 * Immediate connect fail for 172.17.0.2: Network is unreachable
错误,我已尝试从 /etc 安装所有与网络相关的文件,但它不起作用
docker run --privileged --rm --name some-docker docker:stable-dind
docker run -it --rm --link some-docker:docker --privileged -v /tmp/test.nix:/tmp/test.nix nixos/nix@sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357 sh
nix-env -i curl nettools
# works
curl -v http://172.17.0.2:2375/v1.39/version
# works
curl -v http://docker:2375/v1.39/version
# lo and eth
ifconfig -a
# not empty
netstat -rn
export DOCKER_HOST=tcp://docker:2375/ && (echo "hosts: files dns" > /etc/nsswitch.conf)
cat > /etc/nix/nix.conf << 'EOL'
sandbox = false
extra-sandbox-paths = /etc/nsswitch.conf=/etc/nsswitch.conf /etc/resolv.conf=/etc/resolv.conf /etc/hosts=/etc/hosts /etc/protocols=/etc/protocols /etc/udhcpd.conf=/etc/udhcpd.conf /etc/modules=/etc/modules
EOL
cat > /tmp/test.nix << 'EOL'
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
# only lo
ifconfig -a
# empty
netstat --numeric --route
# fails
curl -v http://172.17.0.2:2375/v1.39/version
curl -v http://docker:2375/v1.39/version
docker version
mkdir -p $out
'';
}
EOL
nix-build --store /tmp/store /tmp/test.nix
更新
研究现状
https://gitlab.com/gitlab-org/gitlab-ce/issues/31312#note_138576414
如果您的 installPhase
运行 和 curl
,那您就错了。 Nix 中的推导应该是 纯粹的 :让它们的输出仅依赖于它们声明的输入,而不依赖于其他任何东西。连接到网络的派生本质上是不纯的:其结果将取决于调用给定网络资源时它背后存在的内容。因此,Nix 的沙箱有意(并根据其文档)禁止其构建者访问网络。
考虑以下内容,它仍然不纯,但使用 builtins.fetchurl
代替,因此不会阻止操作:
{ pkgs ? import <nixpkgs> {} }:
with pkgs; let
# WARNING: This is impure; usually, downloads should include an explicit hash
versionFile = builtins.fetchurl http://172.17.0.2:2375/v1.39/version
in stdenv.mkDerivation {
pname = "test";
version = "0.0.1";
DOCKER_HOST = builtins.getEnv "DOCKER_HOST";
buildInputs = [docker curl nettools];
phases = "installPhase";
installPhase = ''
cat ${escapeShellArg versionFile}
docker version
mkdir -p "$out"
'';
}
强烈建议您使用 pkgs.dockerTools 仅使用纯 Nix 代码构建与 Docker 兼容的图像,而不是尝试 运行 Docker 在 Nix 派生中.