portage: Add a Portage-volume-exporting image
authorW. Trevor King <wking@tremily.us>
Fri, 13 Dec 2013 23:31:27 +0000 (15:31 -0800)
committerW. Trevor King <wking@tremily.us>
Thu, 2 Jan 2014 02:03:32 +0000 (18:03 -0800)
This builds the Portage snapshot into a stand-alone volume, which can
be mounted using -volumes-from.  There's currently no
Dockerfile-supported way to mount this for builds, so gentoo-portage
still goes the emerge-webrsync route.

We need something to fill the role of /bin/sh in the Portage-snapshot
container, so I'm using the /bin/busybox from the 'gentoo' image.  As
of 2013-12-12, it's:

  sys-apps/busybox-1.21.0
    USE="ipv6 pam static -livecd -make-symlinks -math -mdev -savedconfig
         (-selinux) -sep-usr -syslog -systemd"

build.sh
portage/.gitignore [new file with mode: 0644]
portage/Dockerfile.template [new file with mode: 0644]
portage/README.md [new file with mode: 0644]

index e527ec69be20f42c47768ca7788b628ecaabc042..9c72780500e118b5dde198cae97cf65942d149ae 100755 (executable)
--- a/build.sh
+++ b/build.sh
 
 AUTHOR="${AUTHOR:-W. Trevor King <wking@tremily.us>}"
 NAMESPACE="${NAMESPACE:-wking}"
-#PORTAGE="${PORTAGE:-/usr/portage}"
 DATE="${DATE:-20131212}"
 MIRROR="${MIRROR:-http://mirror.mcs.anl.gov/pub/gentoo/}"
-ARCH_URL="${ARCH_URL:-${MIRROR}/releases/amd64/current-stage3/}"
+ARCH_URL="${ARCH_URL:-${MIRROR}releases/amd64/current-stage3/}"
 STAGE3="${STAGE3:-stage3-amd64-${DATE}.tar.bz2}"
 STAGE3_CONTENTS="${STAGE3_CONTENTS:-${STAGE3}.CONTENTS}"
 STAGE3_DIGESTS="${STAGE3_DIGESTS:-${STAGE3}.DIGESTS.asc}"
+PORTAGE_URL="${PORTAGE_URL:-${MIRROR}snapshots/}"
+PORTAGE="${PORTAGE:-portage-${DATE}.tar.xz}"
+PORTAGE_SIG="${PORTAGE_SIG:-${PORTAGE}.gpgsig}"
 
-REPOS="
+REPOS="${REPOS:-
+       portage
        gentoo-portage
        gentoo-en-us
        gentoo-syslog
@@ -43,7 +46,7 @@ REPOS="
        elasticsearch
        postgresql
        redis
-       "
+       }"
 
 die()
 {
@@ -58,7 +61,7 @@ if [ -z "${STAGE3_MATCHES}" ]; then
 
        for FILE in "${STAGE3}" "${STAGE3_CONTENTS}" "${STAGE3_DIGESTS}"; do
                if [ ! -f "downloads/${FILE}" ]; then
-                       wget -O "downloads/${FILE}" "${ARCH_URL}/${FILE}"
+                       wget -O "downloads/${FILE}" "${ARCH_URL}${FILE}"
                fi
        done
 
@@ -75,6 +78,30 @@ fi
 
 docker tag -f "${NAMESPACE}/gentoo:${DATE}" "${NAMESPACE}/gentoo:latest" || die "failed to tag"
 
+PORTAGE_IMAGES=$(docker images "${NAMESPACE}/portage-import")
+PORTAGE_MATCHES=$(echo "${PORTAGE_IMAGES}" | grep "${DATE}")
+if [ -z "${PORTAGE_MATCHES}" ]; then
+       # import portage image from Gentoo mirrors
+
+       for FILE in "${PORTAGE}" "${PORTAGE_SIG}"; do
+               if [ ! -f "downloads/${FILE}" ]; then
+                       wget -O "downloads/${FILE}" "${PORTAGE_URL}${FILE}"
+               fi
+       done
+
+       gpg --verify "downloads/${PORTAGE_SIG}" "downloads/${PORTAGE}" || die "insecure digests"
+
+       docker import - "${NAMESPACE}/portage-import:${DATE}" < "downloads/${PORTAGE}" || die "failed to import"
+fi
+
+docker tag -f "${NAMESPACE}/portage-import:${DATE}" "${NAMESPACE}/portage-import:latest" || die "failed to tag"
+
+# extract Busybox for the portage image
+THIS_DIR=$(dirname $(realpath $0))
+CONTAINER="${NAMESPACE}-gentoo-${DATE}-extract-busybox"
+docker run -name "${CONTAINER}" -v "${THIS_DIR}/portage/":/tmp "${NAMESPACE}/gentoo:${DATE}" cp /bin/busybox /tmp/
+docker rm "${CONTAINER}"
+
 for REPO in ${REPOS}; do
        REPO_IMAGES=$(docker images "${NAMESPACE}/${REPO}")
        REPO_MATCHES=$(echo "${REPO_IMAGES}" | grep "${DATE}")
diff --git a/portage/.gitignore b/portage/.gitignore
new file mode 100644 (file)
index 0000000..a1a4c36
--- /dev/null
@@ -0,0 +1 @@
+busybox
diff --git a/portage/Dockerfile.template b/portage/Dockerfile.template
new file mode 100644 (file)
index 0000000..65d1520
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2013 W. Trevor King <wking@tremily.us>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+FROM NAMESPACE/portage-import:TAG
+MAINTAINER A. U. Thor <author@example.com>
+
+# -volumes-from doesn't map names, so we need to shift /portage to
+#  /usr/portage.  Add a statically-linked BusyBox for RUN commands.
+ADD busybox /bin/sh
+ENTRYPOINT ["/bin/sh"]
+RUN mkdir /usr/
+RUN mv /portage /usr/portage
+VOLUME ["/usr/portage"]
+
+# We need a dummy process for this container
+CMD ["tail", "-f", "/portage/profiles/repo_name"]
diff --git a/portage/README.md b/portage/README.md
new file mode 100644 (file)
index 0000000..534124a
--- /dev/null
@@ -0,0 +1,48 @@
+Use volume mounts to avoid including the Portage tree in your images:
+
+    $ docker run -d -name portage wking/portage
+
+This exports a [VOLUME][] which you can [mount][volumes-from] from
+another container:
+
+    $ docker run -volumes-from portage -i -t wking/gentoo /bin/bash
+    d1a49abc4b3c / # ls /usr/portage/
+    app-accessibility  dev-python        mail-mta         sci-mathematics
+    …
+
+Changes (e.g. distfiles downloads) are preserved between mounts by the
+continuously-running `portage` container.  Let's install something in
+the first container:
+
+    d1a49abc4b3c / # emerge -av netcat
+    …
+    These are the packages that would be fetched, in order:
+
+    Calculating dependencies... done!
+    [ebuild  N     ] dev-libs/libmix-2.05-r6  USE="-static-libs" 78 kB
+    [ebuild  N     ] net-analyzer/netcat-110-r9  USE="crypt ipv6 -static" 108 kB
+
+    Total: 2 packages (2 new), Size of downloads: 186 kB
+
+Now kill that container and spin up another one:
+
+    $ docker run -volumes-from portage -i -t wking/gentoo /bin/bash
+    187adaf8babd / # emerge -pv netcat
+    …
+    These are the packages that would be merged, in order:
+
+    Calculating dependencies... done!
+    [ebuild  N     ] dev-libs/libmix-2.05-r6  USE="-static-libs" 0 kB
+    [ebuild  N     ] net-analyzer/netcat-110-r9  USE="crypt ipv6 -static" 0 kB
+
+    Total: 2 packages (2 new), Size of downloads: 0 kB
+    …
+
+The local Portage cache, read news items, etc. stored outside of
+`/usr/portage` (e.g. in `/var/cache/edb`, `/var/lib/gentoo/news`, …)
+will still be local to your client containers, so you'll get
+promptings for reading the news on both `d1a49abc4b3c` and
+`187adaf8babd`.
+
+[VOLUME]: http://docs.docker.io/en/latest/use/builder/#volume
+[volumes-from]: http://docs.docker.io/en/latest/use/working_with_volumes/#mount-volumes-from-an-existing-container