mkimage-debootstrap.sh 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #!/usr/bin/env bash
  2. set -e
  3. variant='minbase'
  4. include='iproute,iputils-ping'
  5. arch='amd64' # intentionally undocumented for now
  6. skipDetection=
  7. strictDebootstrap=
  8. justTar=
  9. usage() {
  10. echo >&2
  11. echo >&2 "usage: $0 [options] repo suite [mirror]"
  12. echo >&2
  13. echo >&2 'options: (not recommended)'
  14. echo >&2 " -p set an http_proxy for debootstrap"
  15. echo >&2 " -v $variant # change default debootstrap variant"
  16. echo >&2 " -i $include # change default package includes"
  17. echo >&2 " -d # strict debootstrap (do not apply any docker-specific tweaks)"
  18. echo >&2 " -s # skip version detection and tagging (ie, precise also tagged as 12.04)"
  19. echo >&2 " # note that this will also skip adding universe and/or security/updates to sources.list"
  20. echo >&2 " -t # just create a tarball, especially for dockerbrew (uses repo as tarball name)"
  21. echo >&2
  22. echo >&2 " ie: $0 username/debian squeeze"
  23. echo >&2 " $0 username/debian squeeze http://ftp.uk.debian.org/debian/"
  24. echo >&2
  25. echo >&2 " ie: $0 username/ubuntu precise"
  26. echo >&2 " $0 username/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
  27. echo >&2
  28. echo >&2 " ie: $0 -t precise.tar.bz2 precise"
  29. echo >&2 " $0 -t wheezy.tgz wheezy"
  30. echo >&2 " $0 -t wheezy-uk.tar.xz wheezy http://ftp.uk.debian.org/debian/"
  31. echo >&2
  32. }
  33. # these should match the names found at http://www.debian.org/releases/
  34. debianStable=wheezy
  35. debianUnstable=sid
  36. # this should match the name found at http://releases.ubuntu.com/
  37. ubuntuLatestLTS=trusty
  38. # this should match the name found at http://releases.tanglu.org/
  39. tangluLatest=aequorea
  40. while getopts v:i:a:p:dst name; do
  41. case "$name" in
  42. p)
  43. http_proxy="$OPTARG"
  44. ;;
  45. v)
  46. variant="$OPTARG"
  47. ;;
  48. i)
  49. include="$OPTARG"
  50. ;;
  51. a)
  52. arch="$OPTARG"
  53. ;;
  54. d)
  55. strictDebootstrap=1
  56. ;;
  57. s)
  58. skipDetection=1
  59. ;;
  60. t)
  61. justTar=1
  62. ;;
  63. ?)
  64. usage
  65. exit 0
  66. ;;
  67. esac
  68. done
  69. shift $(($OPTIND - 1))
  70. repo="$1"
  71. suite="$2"
  72. mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
  73. if [ ! "$repo" ] || [ ! "$suite" ]; then
  74. usage
  75. exit 1
  76. fi
  77. # some rudimentary detection for whether we need to "sudo" our docker calls
  78. docker=''
  79. if docker version > /dev/null 2>&1; then
  80. docker='docker'
  81. elif sudo docker version > /dev/null 2>&1; then
  82. docker='sudo docker'
  83. elif command -v docker > /dev/null 2>&1; then
  84. docker='docker'
  85. else
  86. echo >&2 "warning: either docker isn't installed, or your current user cannot run it;"
  87. echo >&2 " this script is not likely to work as expected"
  88. sleep 3
  89. docker='docker' # give us a command-not-found later
  90. fi
  91. # make sure we have an absolute path to our final tarball so we can still reference it properly after we change directory
  92. if [ "$justTar" ]; then
  93. if [ ! -d "$(dirname "$repo")" ]; then
  94. echo >&2 "error: $(dirname "$repo") does not exist"
  95. exit 1
  96. fi
  97. repo="$(cd "$(dirname "$repo")" && pwd -P)/$(basename "$repo")"
  98. fi
  99. # will be filled in later, if [ -z "$skipDetection" ]
  100. lsbDist=''
  101. target="/tmp/docker-rootfs-debootstrap-$suite-$$-$RANDOM"
  102. cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
  103. returnTo="$(pwd -P)"
  104. if [ "$suite" = 'lucid' ]; then
  105. # lucid fails and doesn't include gpgv in minbase; "apt-get update" fails
  106. include+=',gpgv'
  107. fi
  108. set -x
  109. # bootstrap
  110. mkdir -p "$target"
  111. sudo http_proxy=$http_proxy debootstrap --verbose --variant="$variant" --include="$include" --arch="$arch" "$suite" "$target" "$mirror"
  112. cd "$target"
  113. if [ -z "$strictDebootstrap" ]; then
  114. # prevent init scripts from running during install/update
  115. # policy-rc.d (for most scripts)
  116. echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
  117. sudo chmod +x usr/sbin/policy-rc.d
  118. # initctl (for some pesky upstart scripts)
  119. sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
  120. sudo ln -sf /bin/true sbin/initctl
  121. # see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
  122. # shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
  123. sudo chroot . apt-get clean
  124. if strings usr/bin/dpkg | grep -q unsafe-io; then
  125. # while we're at it, apt is unnecessarily slow inside containers
  126. # this forces dpkg not to call sync() after package extraction and speeds up install
  127. # the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
  128. echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
  129. # we have this wrapped up in an "if" because the "force-unsafe-io"
  130. # option was added in dpkg 1.15.8.6
  131. # (see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=584254#82),
  132. # and ubuntu lucid/10.04 only has 1.15.5.6
  133. fi
  134. # we want to effectively run "apt-get clean" after every install to keep images small (see output of "apt-get clean -s" for context)
  135. {
  136. aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";'
  137. echo "DPkg::Post-Invoke { ${aptGetClean} };"
  138. echo "APT::Update::Post-Invoke { ${aptGetClean} };"
  139. echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";'
  140. } | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
  141. # and remove the translations, too
  142. echo 'Acquire::Languages "none";' | sudo tee etc/apt/apt.conf.d/no-languages > /dev/null
  143. # helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
  144. # rm /usr/sbin/policy-rc.d
  145. # rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
  146. # rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
  147. # rm /etc/apt/apt.conf.d/no-cache
  148. # rm /etc/apt/apt.conf.d/no-languages
  149. if [ -z "$skipDetection" ]; then
  150. # see also rudimentary platform detection in hack/install.sh
  151. lsbDist=''
  152. if [ -r etc/lsb-release ]; then
  153. lsbDist="$(. etc/lsb-release && echo "$DISTRIB_ID")"
  154. fi
  155. if [ -z "$lsbDist" ] && [ -r etc/debian_version ]; then
  156. lsbDist='Debian'
  157. fi
  158. case "$lsbDist" in
  159. Debian)
  160. # add the updates and security repositories
  161. if [ "$suite" != "$debianUnstable" -a "$suite" != 'unstable' ]; then
  162. # ${suite}-updates only applies to non-unstable
  163. sudo sed -i "p; s/ $suite main$/ ${suite}-updates main/" etc/apt/sources.list
  164. # same for security updates
  165. echo "deb http://security.debian.org/ $suite/updates main" | sudo tee -a etc/apt/sources.list > /dev/null
  166. fi
  167. ;;
  168. Ubuntu)
  169. # add the universe, updates, and security repositories
  170. sudo sed -i "
  171. s/ $suite main$/ $suite main universe/; p;
  172. s/ $suite main/ ${suite}-updates main/; p;
  173. s/ $suite-updates main/ ${suite}-security main/
  174. " etc/apt/sources.list
  175. ;;
  176. Tanglu)
  177. # add the updates repository
  178. if [ "$suite" = "$tangluLatest" ]; then
  179. # ${suite}-updates only applies to stable Tanglu versions
  180. sudo sed -i "p; s/ $suite main$/ ${suite}-updates main/" etc/apt/sources.list
  181. fi
  182. ;;
  183. SteamOS)
  184. # add contrib and non-free
  185. sudo sed -i "s/ $suite main$/ $suite main contrib non-free/" etc/apt/sources.list
  186. ;;
  187. esac
  188. fi
  189. # make sure our packages lists are as up to date as we can get them
  190. sudo chroot . apt-get update
  191. sudo chroot . apt-get dist-upgrade -y
  192. fi
  193. if [ "$justTar" ]; then
  194. # create the tarball file so it has the right permissions (ie, not root)
  195. touch "$repo"
  196. # fill the tarball
  197. sudo tar --numeric-owner -caf "$repo" .
  198. else
  199. # create the image (and tag $repo:$suite)
  200. sudo tar --numeric-owner -c . | $docker import - $repo:$suite
  201. # test the image
  202. $docker run -i -t $repo:$suite echo success
  203. if [ -z "$skipDetection" ]; then
  204. case "$lsbDist" in
  205. Debian)
  206. if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
  207. # tag latest
  208. $docker tag $repo:$suite $repo:latest
  209. if [ -r etc/debian_version ]; then
  210. # tag the specific debian release version (which is only reasonable to tag on debian stable)
  211. ver=$(cat etc/debian_version)
  212. $docker tag $repo:$suite $repo:$ver
  213. fi
  214. fi
  215. ;;
  216. Ubuntu)
  217. if [ "$suite" = "$ubuntuLatestLTS" ]; then
  218. # tag latest
  219. $docker tag $repo:$suite $repo:latest
  220. fi
  221. if [ -r etc/lsb-release ]; then
  222. lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
  223. if [ "$lsbRelease" ]; then
  224. # tag specific Ubuntu version number, if available (12.04, etc.)
  225. $docker tag $repo:$suite $repo:$lsbRelease
  226. fi
  227. fi
  228. ;;
  229. Tanglu)
  230. if [ "$suite" = "$tangluLatest" ]; then
  231. # tag latest
  232. $docker tag $repo:$suite $repo:latest
  233. fi
  234. if [ -r etc/lsb-release ]; then
  235. lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
  236. if [ "$lsbRelease" ]; then
  237. # tag specific Tanglu version number, if available (1.0, 2.0, etc.)
  238. $docker tag $repo:$suite $repo:$lsbRelease
  239. fi
  240. fi
  241. ;;
  242. SteamOS)
  243. if [ -r etc/lsb-release ]; then
  244. lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
  245. if [ "$lsbRelease" ]; then
  246. # tag specific SteamOS version number, if available (1.0, 2.0, etc.)
  247. $docker tag $repo:$suite $repo:$lsbRelease
  248. fi
  249. fi
  250. ;;
  251. esac
  252. fi
  253. fi
  254. # cleanup
  255. cd "$returnTo"
  256. sudo rm -rf "$target"