Last active
September 2, 2022 06:21
-
-
Save allex/1ca3d49d817928ccab0a3317a18354c1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# vim: set ft=sh fdm=marker ts=2 sw=2 sts=2 tw=85 et: | |
set -eu | |
# ================================================ | |
# Description: Enhanced docker build with some helper parameters, such as --env, --build-arg-file | |
# | |
# Usage: | |
# docker-build [ -t tag_list ] [ -f Dockerfile ] [ ... ] [ --env <env_file> ] [ --build-arg-file <args_file> ] | |
# | |
# Last Modified: Sat May 14, 2022 14:46 | |
# Author: Allex Wang ([email protected]) | |
# | |
# GistID: 1ca3d49d817928ccab0a3317a18354c1 | |
# GistURL: https://gist.github.com/1ca3d49d817928ccab0a3317a18354c1 | |
# ================================================ | |
PROG=$(basename "$0") | |
SH_DIR=$(cd -P -- "$(dirname -- "$(readlink -f "$0")")" && pwd -P) | |
WORKDIR=$(mktemp -d) | |
BUILDER_EXEC="docker buildx" | |
tag_list= | |
platform=linux/amd64,linux/arm64 | |
env_file= | |
build_arg_list=() | |
docker_file=./Dockerfile | |
base_image= | |
patch_image= | |
# verbose for trace logs | |
verbose= | |
### Helper & ARGS {{{ | |
die () { | |
[ "${1-}" ] && echo >&2 "fatal: ${1}" | |
exit "${2-1}" | |
} | |
log () { | |
echo "${*}" | |
} | |
error () { | |
echo >&2 "Error: ${*}" | |
} | |
show_usage () { | |
cat <<-HELP | |
Enhanced docker build based on buildx, add some shortcut options, such as --env, --build-arg-file | |
Usage: ${PROG} [ -t tag_list ] [ -f Dockerfile ] [ ... ] [ --env <env_file> ] [ --build-arg-file <args_file> ] | |
Options: | |
--env, --env-file <ENV_FILE> Specify an alternate environment file 'ENV' instruction | |
--build-arg-file <arg_file> A file with k/v touples transform to docker build '--build-arg' | |
--base-image <base_image> The base image, only to be used when none Dockerfile | |
--patch-image <patch_image> The patch image to be apply to final Dockerfile | |
--platform <platform_list> Set platform, multiple platforms sep by comma[,] (default "linux/amd64,linux/arm64") | |
-h Show this help info | |
For more options please refer to 'docker buildx build -h' | |
HELP | |
exit 1 | |
} | |
handle_exit () { | |
local ec=$? | |
if [ -d "$WORKDIR" ]; then rm -rf "$WORKDIR"; fi | |
trap - INT TERM EXIT | |
# declare -F on_exit, not avaiable in alipine/sh | |
if type on_exit >/dev/null 2>&1; then on_exit; fi | |
exit $ec | |
} | |
trap handle_exit 0 1 2 3 6 15 | |
if [ $# -eq 0 ]; then | |
show_usage | |
fi | |
args=() | |
while [ $# -gt 0 ]; do | |
OPT=$1 | |
[ "$OPT" = "--" ] && break | |
[ "$OPT" = "${OPT##-*}" ] && { | |
args+=("$OPT") | |
shift | |
continue | |
} | |
if [ "${OPT##=*}" = "$OPT" ]; then | |
OPTARG="${2-}" | |
if [ "${OPTARG##-*}" = "${OPTARG}" ]; then | |
shift | |
else | |
OPTARG= | |
fi | |
else | |
OPT=$(echo "$1" | awk -F= '{print $1}') | |
OPTARG=$(echo "$1" | awk -F= '{print $2}') | |
fi | |
case $OPT in | |
# builtin parameters | |
-t | --tag) | |
tag_list="${OPTARG}" | |
;; | |
-f) | |
docker_file=${OPTARG} | |
;; | |
--platform) | |
platform=${OPTARG} | |
;; | |
# enhanced parameters | |
--base-image) | |
base_image=${OPTARG} | |
;; | |
--patch-image) | |
patch_image=${OPTARG} | |
;; | |
--env | --env-file) | |
env_file=${OPTARG} | |
;; | |
--build-arg) | |
build_arg_list+=(--build-arg "${OPTARG}") | |
;; | |
--build-arg-file) | |
[ -n "$OPTARG" ] || die "Invalid parameter \"$OPT <arg_file>\" value" | |
while read -r line; do build_arg_list+=(--build-arg "\"${line%=*}=${line#*=}\""); done < "$OPTARG" | |
;; | |
--builder) | |
[ -n "$OPTARG" ] && BUILDER_EXEC=$OPTARG | |
;; | |
# misc | |
-x | --debug) verbose=1 ;; | |
-h | --help) show_usage ;; | |
-*) | |
args+=("$OPT") | |
[ "$OPTARG" ] && args+=("\"$OPTARG\"") | |
;; | |
esac | |
[ $# -gt 0 ] && shift | |
done | |
[ -n "$tag_list" ] || die "Invalid parameter \"-t <tag_list>\" value" | |
### }}} | |
gen_dockerfile () { | |
log "Build Dockerfile ..." | |
#1 copy supplied Dockerfile if exists. | |
#2 build from base image if not #1 | |
#3 add patch image stuffs by `patch_image` | |
docker_file_spec= | |
if [ -f "$docker_file" ]; then | |
docker_file_spec=$(cat "${docker_file}") | |
elif [ "$base_image" ]; then | |
docker_file_spec="FROM $base_image" | |
fi | |
# transform .env file | |
env_spec= | |
env_patch= | |
[ -f "$env_file" ] && { | |
env_spec=$(sed -e '/^#/d;/^\s*$/d' "$env_file" | tr '\n' ' ') | |
} | |
if [ "$patch_image" ]; then | |
log "Extract patch image ENV... ($patch_image)" | |
docker pull "${patch_image}" > /dev/null | |
env_patch="$(docker inspect "${patch_image}" --format='{{range $k, $v := .Config.Env}}{{$v}}{{"\n"}}{{end}}'|while read -r line; do if [ -n "$line" ]; then echo "${line%=*}=\"${line#*=}\""; fi; done |tr '\n' ' ')" | |
docker rmi -f "${patch_image}" >/dev/null | |
log "Parse image ENV success." | |
fi | |
tmp="$(cat <<-__DOCKERFILE__ |sed '{/^$/d}' | |
${patch_image:+FROM ${patch_image}} | |
$docker_file_spec | |
${env_patch:+ENV $env_patch} | |
${env_spec:+ENV $env_spec} | |
${patch_image:+COPY --from=0 / /} | |
__DOCKERFILE__ | |
)" | |
# evaluate environs | |
vars="$(envsubst -v "$tmp" | sort | uniq | awk '{if(ENVIRON[$0])print "${"$0"}"}')" | |
echo "$tmp" | envsubst "$vars" > "$WORKDIR/Dockerfile" | |
echo "-----------" | |
cat "$WORKDIR/Dockerfile" | |
echo "-----------" | |
echo | |
} | |
build () { | |
log "Start to build docker image ..." | |
local specfile=$WORKDIR/Dockerfile | |
# fix buildx args | |
local platform=${platform} | |
[ "$platform" ] && args+=("--platform" "$platform") | |
export BUILDX_NO_DEFAULT_LOAD=false | |
eval "(${verbose:+set -x;}${BUILDER_EXEC} build -t $tag_list ${build_arg_list:+${build_arg_list[@]}} -f $specfile ${args:+${args[@]}})" | |
log "Build done${tag_list:+ => ${tag_list}}" | |
} | |
gen_dockerfile \ | |
&& build "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment