docker tools: fix pull image function

+56 -119
+6 -10
pkgs/build-support/docker/examples.nix
··· 83 83 }; 84 84 85 85 # 4. example of pulling an image. could be used as a base for other images 86 - # 87 - # ***** Currently broken, getting 404s. Perhaps the docker API has changed? 88 - # 89 - # 90 - # debian = pullImage { 91 - # imageName = "debian"; 92 - # imageTag = "jessie"; 93 - # # this hash will need change if the tag is updated at docker hub 94 - # sha256 = "18kd495lc2k35h03bpcbdjnix17nlqbwf6nmq3sb161blf0dk14q"; 95 - # }; 86 + nix = pullImage { 87 + imageName = "nixos/nix"; 88 + imageTag = "1.11"; 89 + # this hash will need change if the tag is updated at docker hub 90 + sha256 = "1gk4bq05vl3rj3mh4mlbl4iicgndmimlv8jvkhdk4hrv0r44bwr3"; 91 + }; 96 92 97 93 # 5. example of multiple contents, emacs and vi happily coexisting 98 94 editors = buildImage {
+24 -33
pkgs/build-support/docker/pull.nix
··· 1 - { stdenv, lib, curl, jshon, python, runCommand }: 2 - 3 - # Inspired and simplified version of fetchurl. 1 + { stdenv, lib, docker, vmTools, utillinux, curl, kmod, dhcp, cacert, e2fsprogs }: 2 + let 3 + nameReplace = name: builtins.replaceStrings ["/" ":"] ["-" "-"] name; 4 + in 4 5 # For simplicity we only support sha256. 6 + { imageName, imageTag ? "latest", imageId ? "${imageName}:${imageTag}" 7 + , sha256, name ? (nameReplace "docker-image-${imageName}-${imageTag}.tar") }: 8 + let 9 + pullImage = vmTools.runInLinuxVM ( 10 + stdenv.mkDerivation { 11 + inherit name imageId; 5 12 6 - # Currently only registry v1 is supported, compatible with Docker Hub. 13 + certs = "${cacert}/etc/ssl/certs/ca-bundle.crt"; 7 14 8 - { imageName, imageTag ? "latest", imageId ? null 9 - , sha256, name ? "${imageName}-${imageTag}" 10 - , indexUrl ? "https://index.docker.io" 11 - , registryVersion ? "v1" 12 - , curlOpts ? "" }: 15 + builder = ./pull.sh; 13 16 14 - assert registryVersion == "v1"; 17 + buildInputs = [ curl utillinux docker kmod dhcp cacert e2fsprogs ]; 15 18 16 - let layer = stdenv.mkDerivation { 17 - inherit name imageName imageTag imageId 18 - indexUrl registryVersion curlOpts; 19 + outputHashAlgo = "sha256"; 20 + outputHash = sha256; 19 21 20 - builder = ./pull.sh; 21 - detjson = ./detjson.py; 22 + impureEnvVars = lib.fetchers.proxyImpureEnvVars; 22 23 23 - buildInputs = [ curl jshon python ]; 24 - 25 - outputHashAlgo = "sha256"; 26 - outputHash = sha256; 27 - outputHashMode = "recursive"; 28 - 29 - impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ 30 - # This variable allows the user to pass additional options to curl 31 - "NIX_CURL_FLAGS" 32 - ]; 33 - 34 - # Doing the download on a remote machine just duplicates network 35 - # traffic, so don't do that. 36 - preferLocalBuild = true; 37 - }; 24 + preVM = vmTools.createEmptyImage { 25 + size = 2048; 26 + fullName = "${name}-disk"; 27 + }; 38 28 39 - in runCommand "${name}.tar.gz" {} '' 40 - tar -C ${layer} -czf $out . 41 - '' 29 + QEMU_OPTS = "-netdev user,id=net0 -device virtio-net-pci,netdev=net0"; 30 + }); 31 + in 32 + pullImage
+26 -76
pkgs/build-support/docker/pull.sh
··· 1 - # Reference: docker src contrib/download-frozen-image.sh 2 - 3 1 source $stdenv/setup 4 2 5 - # Curl flags to handle redirects, not use EPSV, handle cookies for 6 - # servers to need them during redirects, and work on SSL without a 7 - # certificate (this isn't a security problem because we check the 8 - # cryptographic hash of the output anyway). 9 - curl=$(command -v curl) 10 - curl() { 11 - [[ -n ${token:-} ]] && set -- -H "Authorization: Token $token" "$@" 12 - $curl \ 13 - --location --max-redirs 20 \ 14 - --retry 3 \ 15 - --fail \ 16 - --disable-epsv \ 17 - --cookie-jar cookies \ 18 - --insecure \ 19 - $curlOpts \ 20 - $NIX_CURL_FLAGS \ 21 - "$@" 22 - } 3 + mkdir -p /var/lib/docker 4 + mkfs.ext4 /dev/vda 5 + mount -t ext4 /dev/vda /var/lib/docker 23 6 24 - fetchLayer() { 25 - local url="$1" 26 - local dest="$2" 27 - local curlexit=18; 28 - 29 - # if we get error code 18, resume partial download 30 - while [ $curlexit -eq 18 ]; do 31 - # keep this inside an if statement, since on failure it doesn't abort the script 32 - if curl -C - "$url" --output "$dest"; then 33 - return 0 34 - else 35 - curlexit=$?; 36 - fi 37 - done 38 - 39 - return $curlexit 40 - } 41 - 42 - headers=$(curl -o /dev/null -D- -H 'X-Docker-Token: true' \ 43 - "$indexUrl/$registryVersion/repositories/$imageName/images") 44 - 45 - header() { 46 - grep $1 <<< "$headers" | tr -d '\r' | cut -d ' ' -f 2 47 - } 48 - 49 - # this only takes the first endpoint, more may be provided 50 - # https://docs.docker.com/v1.6/reference/api/docker-io_api/ 51 - if ! registryUrl=$(header X-Docker-Endpoints); then 52 - echo "error: index returned no endpoint" 53 - exit 1 54 - fi 55 - baseUrl="https://$registryUrl/$registryVersion" 7 + modprobe virtio_net 8 + dhclient eth0 56 9 57 - token="$(header X-Docker-Token || true)"; 10 + mkdir -p /etc/ssl/certs/ 11 + cp "$certs" "/etc/ssl/certs/" 58 12 59 - if [ -z "$imageId" ]; then 60 - imageId="$(curl "$baseUrl/repositories/$imageName/tags/$imageTag")" 61 - imageId="${imageId//\"/}" 62 - if [ -z "$imageId" ]; then 63 - echo "error: no image ID found for ${imageName}:${imageTag}" 64 - exit 1 13 + # from https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount 14 + mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup 15 + cd /sys/fs/cgroup 16 + for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do 17 + mkdir -p $sys 18 + if ! mountpoint -q $sys; then 19 + if ! mount -n -t cgroup -o $sys cgroup $sys; then 20 + rmdir $sys || true 65 21 fi 22 + fi 23 + done 66 24 67 - echo "found image ${imageName}:${imageTag}@$imageId" 68 - fi 25 + # run docker daemon 26 + dockerd -H tcp://127.0.0.1:5555 -H unix:///var/run/docker.sock & 69 27 70 - mkdir -p $out 28 + until $(curl --output /dev/null --silent --connect-timeout 2 http://127.0.0.1:5555); do 29 + printf '.' 30 + sleep 1 31 + done 71 32 72 - jshon -n object \ 73 - -n object -s "$imageId" -i "$imageTag" \ 74 - -i "$imageName" > $out/repositories 33 + rm -r $out 75 34 76 - curl "$baseUrl/images/$imageId/ancestry" -o ancestry.json 77 - 78 - layerIds=$(jshon -a -u < ancestry.json) 79 - for layerId in $layerIds; do 80 - echo "fetching layer $layerId" 81 - 82 - mkdir "$out/$layerId" 83 - echo '1.0' > "$out/$layerId/VERSION" 84 - curl "$baseUrl/images/$layerId/json" | python $detjson > "$out/$layerId/json" 85 - fetchLayer "$baseUrl/images/$layerId/layer" "$out/$layerId/layer.tar" 86 - done 35 + docker pull ${imageId} 36 + docker save ${imageId} > $out