dockerize-disk.sh 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #!/usr/bin/env bash
  2. set -e
  3. if ! command -v qemu-nbd &> /dev/null; then
  4. echo >&2 'error: "qemu-nbd" not found!'
  5. exit 1
  6. fi
  7. usage() {
  8. echo "Convert disk image to docker image"
  9. echo ""
  10. echo "usage: $0 image-name disk-image-file [ base-image ]"
  11. echo " ie: $0 cirros:0.3.3 cirros-0.3.3-x86_64-disk.img"
  12. echo " $0 ubuntu:cloud ubuntu-14.04-server-cloudimg-amd64-disk1.img ubuntu:14.04"
  13. }
  14. if [ "$#" -lt 2 ]; then
  15. usage
  16. exit 1
  17. fi
  18. CURDIR=$(pwd)
  19. image_name="${1%:*}"
  20. image_tag="${1#*:}"
  21. if [ "$image_tag" == "$1" ]; then
  22. image_tag="latest"
  23. fi
  24. disk_image_file="$2"
  25. docker_base_image="$3"
  26. block_device=/dev/nbd0
  27. builddir=$(mktemp -d)
  28. cleanup() {
  29. umount "$builddir/disk_image" || true
  30. umount "$builddir/workdir" || true
  31. qemu-nbd -d $block_device &> /dev/null || true
  32. rm -rf $builddir
  33. }
  34. trap cleanup EXIT
  35. # Mount disk image
  36. modprobe nbd max_part=63
  37. qemu-nbd -rc ${block_device} -P 1 "$disk_image_file"
  38. mkdir "$builddir/disk_image"
  39. mount -o ro ${block_device} "$builddir/disk_image"
  40. mkdir "$builddir/workdir"
  41. mkdir "$builddir/diff"
  42. base_image_mounts=""
  43. # Unpack base image
  44. if [ -n "$docker_base_image" ]; then
  45. mkdir -p "$builddir/base"
  46. docker pull "$docker_base_image"
  47. docker save "$docker_base_image" | tar -xC "$builddir/base"
  48. image_id=$(docker inspect -f "{{.Id}}" "$docker_base_image")
  49. while [ -n "$image_id" ]; do
  50. mkdir -p "$builddir/base/$image_id/layer"
  51. tar -xf "$builddir/base/$image_id/layer.tar" -C "$builddir/base/$image_id/layer"
  52. base_image_mounts="${base_image_mounts}:$builddir/base/$image_id/layer=ro+wh"
  53. image_id=$(docker inspect -f "{{.Parent}}" "$image_id")
  54. done
  55. fi
  56. # Mount work directory
  57. mount -t aufs -o "br=$builddir/diff=rw${base_image_mounts},dio,xino=/dev/shm/aufs.xino" none "$builddir/workdir"
  58. # Update files
  59. cd $builddir
  60. LC_ALL=C diff -rq disk_image workdir \
  61. | 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" \
  62. | while read action entry; do
  63. case "$action" in
  64. ADD|UPDATE)
  65. cp -a "disk_image$entry" "workdir$entry"
  66. ;;
  67. DEL)
  68. rm -rf "workdir$entry"
  69. ;;
  70. *)
  71. echo "Error: unknown diff line: $action $entry" >&2
  72. ;;
  73. esac
  74. done
  75. # Pack new image
  76. new_image_id="$(for i in $(seq 1 32); do printf "%02x" $(($RANDOM % 256)); done)"
  77. mkdir -p $builddir/result/$new_image_id
  78. cd diff
  79. tar -cf $builddir/result/$new_image_id/layer.tar *
  80. echo "1.0" > $builddir/result/$new_image_id/VERSION
  81. cat > $builddir/result/$new_image_id/json <<-EOS
  82. { "docker_version": "1.4.1"
  83. , "id": "$new_image_id"
  84. , "created": "$(date -u +%Y-%m-%dT%H:%M:%S.%NZ)"
  85. EOS
  86. if [ -n "$docker_base_image" ]; then
  87. image_id=$(docker inspect -f "{{.Id}}" "$docker_base_image")
  88. echo ", \"parent\": \"$image_id\"" >> $builddir/result/$new_image_id/json
  89. fi
  90. echo "}" >> $builddir/result/$new_image_id/json
  91. echo "{\"$image_name\":{\"$image_tag\":\"$new_image_id\"}}" > $builddir/result/repositories
  92. cd $builddir/result
  93. # mkdir -p $CURDIR/$image_name
  94. # cp -r * $CURDIR/$image_name
  95. tar -c * | docker load