#!/usr/bin/env bash set -e if ! command -v qemu-nbd &> /dev/null { echo >&2 'error: "qemu-nbd" not found!>&2 'error: "qemu-nbd" not found!' exit 1 } proc usage { echo "Convert disk image to docker image" echo "" echo "usage: $0 image-name disk-image-file [ base-image ]" echo " ie: $0 cirros:0.3.3 cirros-0.3.3-x86_64-disk.img" echo " $0 ubuntu:cloud ubuntu-14.04-server-cloudimg-amd64-disk1.img ubuntu:14.04" } if test "$Argc" -lt 2 { usage exit 1 } setvar CURDIR = $(pwd) setvar image_name = "${1%:*}" setvar image_tag = "${1#*:}" if test $image_tag == $1 { setvar image_tag = ""latest"" } setvar disk_image_file = "$2" setvar docker_base_image = "$3" setvar block_device = '/dev/nbd0' setvar builddir = $(mktemp -d) proc cleanup { umount "$builddir/disk_image" || true umount "$builddir/workdir" || true qemu-nbd -d $block_device &> /dev/null || true rm -rf $builddir } trap cleanup EXIT # Mount disk image modprobe nbd max_part=63 qemu-nbd -rc ${block_device} -P 1 $disk_image_file mkdir "$builddir/disk_image" mount -o ro ${block_device} "$builddir/disk_image" mkdir "$builddir/workdir" mkdir "$builddir/diff" setvar base_image_mounts = """" # Unpack base image if test -n $docker_base_image { mkdir -p "$builddir/base" docker pull $docker_base_image docker save $docker_base_image | tar -xC "$builddir/base" setvar image_id = $(docker inspect -f "{{.Id}}" "$docker_base_image") while test -n $image_id { mkdir -p "$builddir/base/$image_id/layer" tar -xf "$builddir/base/$image_id/layer.tar" -C "$builddir/base/$image_id/layer" setvar base_image_mounts = ""${base_image_mounts}:$builddir/base/$image_id/layer=ro+wh"" setvar image_id = $(docker inspect -f "{{.Parent}}" "$image_id") } } # Mount work directory mount -t aufs -o "br=$builddir/diff=rw${base_image_mounts},dio,xino=/dev/shm/aufs.xino" none "$builddir/workdir" # Update files cd $builddir' LC_ALL=C' diff -rq disk_image workdir \ | sed -re "s|Only in workdir(.*?): |DEL \1/|g;s|Only in disk_image(.*?): |ADD \1/|g;s|Files disk_image/(.+) and workdir/(.+) differ|UPDATE /\1|g" \ | while read action entry { case (action) { ADD|UPDATE { cp -a "disk_image$entry" "workdir$entry" } DEL { rm -rf "workdir$entry" } * { echo "Error: unknown diff line: $action $entry" >&2 } } } # Pack new image setvar new_image_id = "$(for i in $(seq 1 32); do printf "%02x" $(($RANDOM % 256)); done)" mkdir -p $builddir/result/$new_image_id cd diff tar -cf $builddir/result/$new_image_id/layer.tar * echo "1.0" > $builddir/result/$new_image_id/VERSION cat > $builddir/result/$new_image_id/json <<< """ { "docker_version": "1.4.1" , "id": "$new_image_id" , "created": "$(date -u +%Y-%m-%dT%H:%M:%S.%NZ)" """ if test -n $docker_base_image { setvar image_id = $(docker inspect -f "{{.Id}}" "$docker_base_image") echo ", \"parent\": \"$image_id\"" >> $builddir/result/$new_image_id/json } echo "}" >> $builddir/result/$new_image_id/json echo "{\"$image_name\":{\"$image_tag\":\"$new_image_id\"}}" > $builddir/result/repositories cd $builddir/result # mkdir -p $CURDIR/$image_name # cp -r * $CURDIR/$image_name tar -c * | docker load