-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild_docker_images
executable file
·166 lines (137 loc) · 6.47 KB
/
build_docker_images
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/bash
###################################################################################
# build_docker_images: Recursively build and tag docker images in a directory #
# Copyright (C) 2023 Heather Ward - DNAstack #
# #
# This program is free software; you can redistribute it and/or #
# modify it under the terms of the GNU General Public License #
# as published by the Free Software Foundation, version 2 of the #
# License. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
###################################################################################
set -eEuo pipefail
DEFAULT_DOCKER_CONTEXT_DIR=$(readlink -f "$(dirname "$0")")
usage() {
cat << EOF
Recursively build and tag docker images in a directory.
Docker definitions are discovered by identifying build.env files in the docker_context_dir. build.env must define at minimum IMAGE_NAME and IMAGE_TAG variables.
Usage: $0 -d docker_context_dir [OPTIONS]
OPTIONS
-h Display this message and exit
-d Directory to find Dockerfiles/build contexts in [${DEFAULT_DOCKER_CONTEXT_DIR}]
-c Container registry
-p Also push built images
-x Use the 'docker buildx' command to build AMD-64 images (for example from an ARM-based Mac)
-b Comma-separated global build arguments (VAR=value,VAR2=value2). Will be passed to every image build.
EOF
}
log() {
echo "$(tput bold)$(tput setaf 110)[$(date +'%Y-%m-%dT%H:%M:%S%z')] $*$(tput sgr0)" >&1
}
err() {
echo "$(tput bold)$(tput setaf 203)[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*$(tput sgr0)" >&2
}
build_docker_image() {
local build_env_file="$1"
local global_build_args="$2"
local docker_context_dir=$(dirname "${build_env_file}")
local -a build_args
(
# Ensure we're pulling these variables from the build_env_file
unset IMAGE_NAME IMAGE_TAG DOCKERFILE NOBUILD CONDA_ENVIRONMENT_TEMPLATE
set -a
. "${build_env_file}"
set +a
IMAGE_NAME=${IMAGE_NAME:-}
IMAGE_TAG=${IMAGE_TAG:-}
DOCKERFILE=${DOCKERFILE:-}
NOBUILD=${NOBUILD:-false}
CONDA_ENVIRONMENT_TEMPLATE=${CONDA_ENVIRONMENT_TEMPLATE:-}
if [[ "${NOBUILD}" == "true" ]]; then
log "No-build set for docker context [${docker_context_dir}]; skipping"
return
fi
# Find the Dockerfile, either in the same directory as the build.env file or using the DOCKERFILE variable from build.env
if [[ -z "${DOCKERFILE}" ]]; then
dockerfile=$(find "${docker_context_dir}" -type f -name Dockerfile)
else
dockerfile="${docker_context_dir}/${DOCKERFILE}"
fi
if [[ ! -s "${dockerfile}" ]]; then
err "[ERROR] Dockerfile not found; either create ${docker_context_dir}/Dockerfile or define the DOCKERFILE variable in ${build_env_file}"
exit 1
fi
# Ensure that at minimum IMAGE_NAME and IMAGE_TAG are defined
if [[ -z "${IMAGE_NAME}" ]]; then
err "[ERROR] No IMAGE_NAME defined for docker context [${docker_context_dir}]"
err "[ERROR] Set IMAGE_NAME in [${build_env_file}] and try again."
exit 1
fi
if [[ -z "${IMAGE_TAG}" ]]; then
err "[ERROR] No IMAGE_TAG defined for docker context [${docker_context_dir}]"
err "[ERROR] Set IMAGE_TAG in [${build_env_file}] and try again."
exit 1
fi
# Make all varaiables defined in build.env available as build args
while read -r varname || [[ -n "${varname}" ]]; do
build_args+=(--build-arg "${varname}=${!varname}")
done < <(grep -v -e '^#' -e '^$' "${build_env_file}" | cut -d '=' -f 1)
# If a conda environment template is specified, generate a populated version of the file to be copied into the image
conda_environment_template="${docker_context_dir}/${CONDA_ENVIRONMENT_TEMPLATE}"
if [[ -n "${CONDA_ENVIRONMENT_TEMPLATE}" ]] && [[ -s "${conda_environment_template}" ]]; then
populated_conda_environment=${docker_context_dir}/${IMAGE_NAME}.populated.yaml
log "Generating populated conda environment [${populated_conda_environment}]"
envsubst \
< "${conda_environment_template}" \
> "${populated_conda_environment}"
fi
# Add global build args provided on the command line
while read -r global_build_arg || [[ -n "${global_build_arg}" ]]; do
build_args+=(--build-arg "${global_build_arg}")
done < <(echo -n "${global_build_args}" | tr ',' '\n')
tagged_image="${CONTAINER_REGISTRY:+"${CONTAINER_REGISTRY}/"}${IMAGE_NAME}:${IMAGE_TAG}"
log "Building ${tagged_image}"
${DOCKER_BUILD_COMMAND} \
--rm \
"${build_args[@]}" \
-t "${tagged_image}" \
-f "${dockerfile}" \
"${docker_context_dir}"
if [[ "${PUSH_IMAGES}" == 'true' ]]; then
log "Pushing ${tagged_image}"
docker push "${tagged_image}"
fi
)
}
while getopts "hd:c:pxb:" OPTION; do
case ${OPTION} in
h) usage; exit ;;
d) DOCKER_CONTEXT_DIR=${OPTARG} ;;
c) CONTAINER_REGISTRY=${OPTARG};;
p) PUSH_IMAGES='true' ;;
x) DOCKER_BUILD_COMMAND='docker buildx build --platform linux/amd64' ;;
b) GLOBAL_BUILD_ARGS=${OPTARG};;
\?) usage; exit ;;
esac
done
DOCKER_CONTEXT_DIR=${DOCKER_CONTEXT_DIR:-"${DEFAULT_DOCKER_CONTEXT_DIR}"}
PUSH_IMAGES=${PUSH_IMAGES:-'false'}
DOCKER_BUILD_COMMAND=${DOCKER_BUILD_COMMAND:-'docker build'}
GLOBAL_BUILD_ARGS=${GLOBAL_BUILD_ARGS:-}
readonly DOCKER_CONTEXT_DIR CONTAINER_REGISTRY PUSH_IMAGES DOCKER_BUILD_COMMAND GLOBAL_BUILD_ARGS
IMAGES_TO_BUILD=$(find "${DOCKER_CONTEXT_DIR}" -type f -name build.env)
if [[ "${#IMAGES_TO_BUILD}" -eq 0 ]]; then
usage
exit
fi
while read -r build_env_file; do
build_docker_image "${build_env_file}" "${GLOBAL_BUILD_ARGS}"
done <<< "${IMAGES_TO_BUILD}"