Browse code

Add tool to conver disk image into Docker image

dockerize-image tool takes a virtual disk image file
and creates a Docker image based on it. You can
specify a base Docker image to make this tool create
an image that will contain only filesystem diff
instead of full filesystem.
See tools usage for details.

Signed-off-by: Maxim Kulkin <maxim.kulkin@gmail.com>

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