github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/contrib/mkimage/debootstrap (about)

     1  #!/usr/bin/env bash
     2  set -e
     3  
     4  mkimgdeb="$(basename "$0")"
     5  mkimg="$(dirname "$0").sh"
     6  
     7  usage() {
     8  	echo >&2 "usage: $mkimgdeb rootfsDir suite [debootstrap-args]"
     9  	echo >&2 " note: $mkimgdeb meant to be used from $mkimg"
    10  	exit 1
    11  }
    12  
    13  rootfsDir="$1"
    14  if [ -z "$rootfsDir" ]; then
    15  	echo >&2 "error: rootfsDir is missing"
    16  	echo >&2
    17  	usage
    18  fi
    19  shift
    20  
    21  # we have to do a little fancy footwork to make sure "rootfsDir" becomes the second non-option argument to debootstrap
    22  
    23  before=()
    24  while [ $# -gt 0 ] && [[ "$1" == -* ]]; do
    25  	before+=("$1")
    26  	shift
    27  done
    28  
    29  suite="$1"
    30  if [ -z "$suite" ]; then
    31  	echo >&2 "error: suite is missing"
    32  	echo >&2
    33  	usage
    34  fi
    35  shift
    36  
    37  # get path to "chroot" in our current PATH
    38  chrootPath="$(type -P chroot || :)"
    39  if [ -z "$chrootPath" ]; then
    40  	echo >&2 "error: chroot not found. Are you root?"
    41  	echo >&2
    42  	usage
    43  fi
    44  
    45  rootfs_chroot() {
    46  	# "chroot" doesn't set PATH, so we need to set it explicitly to something our new debootstrap chroot can use appropriately!
    47  
    48  	# set PATH and chroot away!
    49  	PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' \
    50  		"$chrootPath" "$rootfsDir" "$@"
    51  }
    52  
    53  # allow for DEBOOTSTRAP=qemu-debootstrap ./mkimage.sh ...
    54  : ${DEBOOTSTRAP:=debootstrap}
    55  
    56  (
    57  	set -x
    58  	$DEBOOTSTRAP "${before[@]}" "$suite" "$rootfsDir" "$@"
    59  )
    60  
    61  # now for some Docker-specific tweaks
    62  
    63  # prevent init scripts from running during install/update
    64  echo >&2 "+ echo exit 101 > '$rootfsDir/usr/sbin/policy-rc.d'"
    65  cat > "$rootfsDir/usr/sbin/policy-rc.d" <<- 'EOF'
    66  	#!/bin/sh
    67  
    68  	# For most Docker users, "apt-get install" only happens during "docker build",
    69  	# where starting services doesn't work and often fails in humorous ways. This
    70  	# prevents those failures by stopping the services from attempting to start.
    71  
    72  	exit 101
    73  EOF
    74  chmod +x "$rootfsDir/usr/sbin/policy-rc.d"
    75  
    76  # prevent upstart scripts from running during install/update
    77  (
    78  	set -x
    79  	rootfs_chroot dpkg-divert --local --rename --add /sbin/initctl
    80  	cp -a "$rootfsDir/usr/sbin/policy-rc.d" "$rootfsDir/sbin/initctl"
    81  	sed -i 's/^exit.*/exit 0/' "$rootfsDir/sbin/initctl"
    82  )
    83  
    84  # shrink a little, since apt makes us cache-fat (wheezy: ~157.5MB vs ~120MB)
    85  (
    86  	set -x
    87  	rootfs_chroot apt-get clean
    88  )
    89  
    90  # this file is one APT creates to make sure we don't "autoremove" our currently
    91  # in-use kernel, which doesn't really apply to debootstraps/Docker images that
    92  # don't even have kernels installed
    93  rm -f "$rootfsDir/etc/apt/apt.conf.d/01autoremove-kernels"
    94  
    95  # Ubuntu 10.04 sucks... :)
    96  if strings "$rootfsDir/usr/bin/dpkg" | grep -q unsafe-io; then
    97  	# force dpkg not to call sync() after package extraction (speeding up installs)
    98  	echo >&2 "+ echo force-unsafe-io > '$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup'"
    99  	cat > "$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup" <<- 'EOF'
   100  		# For most Docker users, package installs happen during "docker build", which
   101  		# doesn't survive power loss and gets restarted clean afterwards anyhow, so
   102  		# this minor tweak gives us a nice speedup (much nicer on spinning disks,
   103  		# obviously).
   104  
   105  		force-unsafe-io
   106  	EOF
   107  fi
   108  
   109  if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then
   110  	# _keep_ us lean by effectively running "apt-get clean" after every install
   111  	aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";'
   112  	echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-clean'"
   113  	cat > "$rootfsDir/etc/apt/apt.conf.d/docker-clean" <<- EOF
   114  		# Since for most Docker users, package installs happen in "docker build" steps,
   115  		# they essentially become individual layers due to the way Docker handles
   116  		# layering, especially using CoW filesystems.  What this means for us is that
   117  		# the caches that APT keeps end up just wasting space in those layers, making
   118  		# our layers unnecessarily large (especially since we'll normally never use
   119  		# these caches again and will instead just "docker build" again and make a brand
   120  		# new image).
   121  
   122  		# Ideally, these would just be invoking "apt-get clean", but in our testing,
   123  		# that ended up being cyclic and we got stuck on APT's lock, so we get this fun
   124  		# creation that's essentially just "apt-get clean".
   125  		DPkg::Post-Invoke { ${aptGetClean} };
   126  		APT::Update::Post-Invoke { ${aptGetClean} };
   127  
   128  		Dir::Cache::pkgcache "";
   129  		Dir::Cache::srcpkgcache "";
   130  
   131  		# Note that we do realize this isn't the ideal way to do this, and are always
   132  		# open to better suggestions (https://github.com/demonoid81/moby/issues).
   133  	EOF
   134  
   135  	# remove apt-cache translations for fast "apt-get update"
   136  	echo >&2 "+ echo Acquire::Languages 'none' > '$rootfsDir/etc/apt/apt.conf.d/docker-no-languages'"
   137  	cat > "$rootfsDir/etc/apt/apt.conf.d/docker-no-languages" <<- 'EOF'
   138  		# In Docker, we don't often need the "Translations" files, so we're just wasting
   139  		# time and space by downloading them, and this inhibits that.  For users that do
   140  		# need them, it's a simple matter to delete this file and "apt-get update". :)
   141  
   142  		Acquire::Languages "none";
   143  	EOF
   144  
   145  	echo >&2 "+ echo Acquire::GzipIndexes 'true' > '$rootfsDir/etc/apt/apt.conf.d/docker-gzip-indexes'"
   146  	cat > "$rootfsDir/etc/apt/apt.conf.d/docker-gzip-indexes" <<- 'EOF'
   147  		# Since Docker users using "RUN apt-get update && apt-get install -y ..." in
   148  		# their Dockerfiles don't go delete the lists files afterwards, we want them to
   149  		# be as small as possible on-disk, so we explicitly request "gz" versions and
   150  		# tell Apt to keep them gzipped on-disk.
   151  
   152  		# For comparison, an "apt-get update" layer without this on a pristine
   153  		# "debian:wheezy" base image was "29.88 MB", where with this it was only
   154  		# "8.273 MB".
   155  
   156  		Acquire::GzipIndexes "true";
   157  		Acquire::CompressionTypes::Order:: "gz";
   158  	EOF
   159  
   160  	# update "autoremove" configuration to be aggressive about removing suggests deps that weren't manually installed
   161  	echo >&2 "+ echo Apt::AutoRemove::SuggestsImportant 'false' > '$rootfsDir/etc/apt/apt.conf.d/docker-autoremove-suggests'"
   162  	cat > "$rootfsDir/etc/apt/apt.conf.d/docker-autoremove-suggests" <<- 'EOF'
   163  		# Since Docker users are looking for the smallest possible final images, the
   164  		# following emerges as a very common pattern:
   165  
   166  		#   RUN apt-get update \
   167  		#       && apt-get install -y <packages> \
   168  		#       && <do some compilation work> \
   169  		#       && apt-get purge -y --auto-remove <packages>
   170  
   171  		# By default, APT will actually _keep_ packages installed via Recommends or
   172  		# Depends if another package Suggests them, even and including if the package
   173  		# that originally caused them to be installed is removed.  Setting this to
   174  		# "false" ensures that APT is appropriately aggressive about removing the
   175  		# packages it added.
   176  
   177  		# https://aptitude.alioth.debian.org/doc/en/ch02s05s05.html#configApt-AutoRemove-SuggestsImportant
   178  		Apt::AutoRemove::SuggestsImportant "false";
   179  	EOF
   180  fi
   181  
   182  if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then
   183  	# tweak sources.list, where appropriate
   184  	lsbDist=
   185  	if [ -z "$lsbDist" -a -r "$rootfsDir/etc/os-release" ]; then
   186  		lsbDist="$(. "$rootfsDir/etc/os-release" && echo "$ID")"
   187  	fi
   188  	if [ -z "$lsbDist" -a -r "$rootfsDir/etc/lsb-release" ]; then
   189  		lsbDist="$(. "$rootfsDir/etc/lsb-release" && echo "$DISTRIB_ID")"
   190  	fi
   191  	if [ -z "$lsbDist" -a -r "$rootfsDir/etc/debian_version" ]; then
   192  		lsbDist='Debian'
   193  	fi
   194  	# normalize to lowercase for easier matching
   195  	lsbDist="$(echo "$lsbDist" | tr '[:upper:]' '[:lower:]')"
   196  	case "$lsbDist" in
   197  		debian)
   198  			# updates and security!
   199  			if curl -o /dev/null -s --head --location --fail "http://security.debian.org/dists/$suite/updates/main/binary-$(rootfs_chroot dpkg --print-architecture)/Packages.gz"; then
   200  				(
   201  					set -x
   202  					sed -i "
   203  						p;
   204  						s/ $suite / ${suite}-updates /
   205  					" "$rootfsDir/etc/apt/sources.list"
   206  					echo "deb http://security.debian.org $suite/updates main" >> "$rootfsDir/etc/apt/sources.list"
   207  				)
   208  			fi
   209  			;;
   210  		ubuntu)
   211  			# add the updates and security repositories
   212  			(
   213  				set -x
   214  				sed -i "
   215  					p;
   216  					s/ $suite / ${suite}-updates /; p;
   217  					s/ $suite-updates / ${suite}-security /
   218  				" "$rootfsDir/etc/apt/sources.list"
   219  			)
   220  			;;
   221  		tanglu)
   222  			# add the updates repository
   223  			if [ "$suite" != 'devel' ]; then
   224  				(
   225  					set -x
   226  					sed -i "
   227  						p;
   228  						s/ $suite / ${suite}-updates /
   229  					" "$rootfsDir/etc/apt/sources.list"
   230  				)
   231  			fi
   232  			;;
   233  		steamos)
   234  			# add contrib and non-free if "main" is the only component
   235  			(
   236  				set -x
   237  				sed -i "s/ $suite main$/ $suite main contrib non-free/" "$rootfsDir/etc/apt/sources.list"
   238  			)
   239  			;;
   240  	esac
   241  fi
   242  
   243  (
   244  	set -x
   245  
   246  	# make sure we're fully up-to-date
   247  	rootfs_chroot sh -xc 'apt-get update && apt-get dist-upgrade -y'
   248  
   249  	# delete all the apt list files since they're big and get stale quickly
   250  	rm -rf "$rootfsDir/var/lib/apt/lists"/*
   251  	# this forces "apt-get update" in dependent images, which is also good
   252  
   253  	mkdir "$rootfsDir/var/lib/apt/lists/partial" # Lucid... "E: Lists directory /var/lib/apt/lists/partial is missing."
   254  )