Skip to content

Instantly share code, notes, and snippets.

@wjordan
Last active June 22, 2020 15:47
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wjordan/f9f640727c06d46172e6 to your computer and use it in GitHub Desktop.
Save wjordan/f9f640727c06d46172e6 to your computer and use it in GitHub Desktop.
Dockerize: A tiny replacement for Dockerfiles
#!/bin/sh
####
# Dockerize: A tiny replacement for Dockerfiles
# This script leverages `docker run` and `docker commit` to provide a usable workaround for
# restrictions of `docker build` and Dockerfile syntax to strictly host-independent builds.
#
# See these discussions:
# https://github.com/docker/docker/pull/1124
# https://github.com/docker/docker/issues/3156
# https://github.com/docker/docker/issues/3949
# https://github.com/docker/docker/issues/14080
#
#
# To use, copy this script into the same directory as your build script and use the `#!./dockerize.sh` shebang.
# Set relevant environment variables before a second shebang line marking the start of your Docker installation.
# FROM, RUNDIR, and VOLUME variables will be automatically passed to `docker run`.
# TAG, EXPOSE, and WORKDIR variables will be automatically passed to `docker commit`.
# All other variables will be passed as environment arguments to `docker run`,
# making them available within your build script.
# For example, this dockerize code will cache and reuse Alpine Linux packages between builds:
#
# #!./dockerize.sh
# FROM=alpine
# TAG=${TAG:-wjordan/my-image}
# WORKDIR=/var/cache/dockerize
# CACHE=/var/cache/docker
# EXPOSE=3001
# VOLUME="${HOME}/.docker-cache:${CACHE} ${PWD}:${WORKDIR}:ro /tmp"
# #!/bin/sh
# ln -s ${CACHE}/apk /var/cache/apk
# ln -s ${CACHE}/apk /etc/apk/cache
# set -e
# apk --update add gcc g++ make libc-dev python
# [...etc etc build...]
####
SCRIPT=$1
set -a
# eval the script until the second hashbang
SCRIPT_F=$(cat ${SCRIPT} | sed '1d;/#!/q')
export1_f=$(mktemp)
export2_f=$(mktemp)
export -p | sort > ${export1_f}
eval "${SCRIPT_F}"
export -p | sort > ${export2_f}
EXPORTS=$(
comm -13 ${export1_f} ${export2_f} \
| sed '/FROM/d' \
| sed '/TAG/d' \
| sed '/EXPOSE/d' \
| sed '/VOLUME/d' \
| sed '/RUNDIR/d' \
| sed '/CMD/d'
)
rm -f ${export1_f} ${export2_f}
# Value of second hashbang
SH=$(sed -n '1d;/#!/s/#!//p' ${SCRIPT})
# Script from the second hashbang
SH_SCRIPT=$(sed '1,/#!/d' ${SCRIPT})
# Add VOLUME and WORKDIR to docker run
VOLUME_S=$(test -n "${VOLUME:=}" && echo ${VOLUME} | tr '\n' ' ' | xargs -n 1 printf '-v %s ')
RUNDIR_S=$(test -n "${RUNDIR:=}" && echo -w ${RUNDIR})
# Add all other added variables as -e
ENV_S=$(echo ${EXPORTS} | sed 's/export/-e/g' | tr '\n' ' ' | sed "s/'//g")
# Add Dockerfile parameters to docker commit
EXPOSE_S=$(test -n "${EXPOSE:=}" && echo --change=\"EXPOSE ${EXPOSE}\")
WORKDIR_S=$(test -n "${WORKDIR:=}" && echo --change=\"WORKDIR ${WORKDIR}\")
CMD_S=$(test -n "${CMD:=}" && echo --change=\'CMD ${CMD}\')
# Ensure container is stopped/removed when script finishes/aborts
CID=$(mktemp -u)
trap 'docker rm -f $(cat ${CID}) > /dev/null 2>&1' EXIT INT TERM HUP
docker run -t --cidfile=${CID} \
${ENV_S} \
${VOLUME_S} \
${RUNDIR_S} \
${FROM:-scratch} \
/bin/sh -c "echo \"${SH_SCRIPT}\" | ${SH}" && \
/bin/sh -c "docker commit ${WORKDIR_S} ${EXPOSE_S} ${CMD_S} $(cat ${CID}) ${TAG:-}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment