【问题标题】:nix with custom store (inside chroot) not working inside docker container - Could not resolve host: docker带有自定义存储(在 chroot 内)的 nix 在 docker 容器内不起作用 - 无法解析主机:docker
【发布时间】:2019-02-02 14:14:28
【问题描述】:

提出问题https://github.com/NixOS/nix/issues/2663


如何复制

  1. 在某个终端运行它

docker run --privileged --rm --name some-docker docker:stable-dind

  1. 保存测试文件
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

  1. 它可以在没有 --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

  1. 它不适用于--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 抛出权限被拒绝)


更新:

我发现我可以使用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

【问题讨论】:

  • (foo || true) 成语中的子shell 有什么意义,而只是foo || true
  • 无论如何,Nix 应该将其构建者与网络访问隔离开来。这是一个特性,而不是一个错误;它迫使您告诉 nix 进行带外下载,以便将内容进行哈希处理并放置在商店中,或者使用超时的 TTL 进行缓存。

标签: docker nix


【解决方案1】:

如果您的 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 兼容的映像,而不是尝试在 Nix 派生中运行 Docker。

【讨论】:

  • 你是个天才,看起来很有前途,而不是在外部世界中构建完全依赖于 docker:dind 的测试结果,我将使用测试代码构建一个脚本,然后针对 docker:dind 运行该脚本
  • 如果您使用dockerTools.pullImage 拉取docker:dind,则可以从Nix 使用它(f/e,在dockerTools.buildImage 中指定拉取的图像作为其fromImage 参数)--只要指定了上游图片的具体sha256,就不算不纯了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多