Optimize docker build workflow
This commit is contained in:
209
.github/workflows/docker-build-publish.yml
vendored
209
.github/workflows/docker-build-publish.yml
vendored
@@ -101,63 +101,166 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SSH_FLAGS=""
|
SSH_FLAGS=()
|
||||||
if [ -n "${SSH_AUTH_SOCK:-}" ]; then
|
if [ -n "${SSH_AUTH_SOCK:-}" ]; then
|
||||||
SSH_FLAGS="--ssh default"
|
SSH_FLAGS+=(--ssh default)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$IMAGES" | jq -c '.[]' | while read -r img; do
|
RAW_REF="${{ github.ref }}"
|
||||||
IMAGE_NAME=$(echo "$img" | jq -r '.name')
|
SHA_FULL="${{ github.sha }}"
|
||||||
FULL_IMAGE="${{ inputs.registry_host }}/${IMAGE_NAME}"
|
SHA_SHORT="${SHA_FULL:0:12}"
|
||||||
CACHE_REF="${{ inputs.registry_host }}/$(echo "$img" | jq -r '.cache_ref')"
|
|
||||||
CONTEXT=$(echo "$img" | jq -r '.context')
|
|
||||||
DOCKERFILE=$(echo "$img" | jq -r '.dockerfile')
|
|
||||||
TARGET=$(echo "$img" | jq -r '.target')
|
|
||||||
RAW_REF="${{ github.ref }}"
|
|
||||||
SHA_FULL="${{ github.sha }}"
|
|
||||||
SHA_SHORT="${SHA_FULL:0:12}"
|
|
||||||
|
|
||||||
echo "==== Building $FULL_IMAGE ===="
|
VERSION_TAGS=()
|
||||||
|
if [[ "$RAW_REF" =~ ^refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||||
|
VERSION_TAGS+=("v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}")
|
||||||
|
VERSION_TAGS+=("v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}")
|
||||||
|
VERSION_TAGS+=("v${BASH_REMATCH[1]}")
|
||||||
|
VERSION_TAGS+=("latest")
|
||||||
|
fi
|
||||||
|
|
||||||
TAGS=()
|
BUILD_ARG_FLAGS=()
|
||||||
TAGS+=("$FULL_IMAGE:sha-$SHA_SHORT")
|
BUILD_ARGS_JSON="{}"
|
||||||
if [[ "$RAW_REF" =~ ^refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
if [ -n "$BUILD_ARGS" ]; then
|
||||||
TAGS+=("$FULL_IMAGE:v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}")
|
for arg in $BUILD_ARGS; do
|
||||||
TAGS+=("$FULL_IMAGE:v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}")
|
if [[ "$arg" != *=* ]]; then
|
||||||
TAGS+=("$FULL_IMAGE:v${BASH_REMATCH[1]}")
|
echo "Invalid build arg: $arg" >&2
|
||||||
TAGS+=("$FULL_IMAGE:latest")
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
BUILD_ARG_FLAGS+=(--build-arg "$arg")
|
||||||
|
|
||||||
TAG_ARGS=$(printf -- "--tag %s " "${TAGS[@]}")
|
key="${arg%%=*}"
|
||||||
BUILD_ARG_FLAGS=""
|
val="${arg#*=}"
|
||||||
if [ -n "$BUILD_ARGS" ]; then
|
BUILD_ARGS_JSON=$(jq --arg k "$key" --arg v "$val" '. + {($k): $v}' <<<"$BUILD_ARGS_JSON")
|
||||||
BUILD_ARG_FLAGS=$(printf -- "--build-arg %s " $BUILD_ARGS)
|
|
||||||
fi
|
|
||||||
|
|
||||||
TARGET_FLAG=""
|
|
||||||
if [ -n "$TARGET" ] && [ "$TARGET" != "null" ]; then
|
|
||||||
TARGET_FLAG="--target $TARGET"
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker buildx build \
|
|
||||||
--file "$DOCKERFILE" \
|
|
||||||
$TARGET_FLAG \
|
|
||||||
--cache-from "type=registry,ref=$CACHE_REF" \
|
|
||||||
--cache-to "type=registry,ref=$CACHE_REF,mode=max" \
|
|
||||||
$SSH_FLAGS \
|
|
||||||
--load \
|
|
||||||
$TAG_ARGS \
|
|
||||||
$BUILD_ARG_FLAGS \
|
|
||||||
"$CONTEXT"
|
|
||||||
|
|
||||||
echo "==== Trivy scan for $FULL_IMAGE ===="
|
|
||||||
trivy image \
|
|
||||||
--severity "$TRIVY_SEVERITY" \
|
|
||||||
--exit-code 1 \
|
|
||||||
"${TAGS[0]}"
|
|
||||||
|
|
||||||
echo "==== Pushing $FULL_IMAGE ===="
|
|
||||||
for tag in "${TAGS[@]}"; do
|
|
||||||
docker push "$tag"
|
|
||||||
done
|
done
|
||||||
done
|
fi
|
||||||
|
|
||||||
|
while read -r group; do
|
||||||
|
GROUP_COUNT=$(echo "$group" | jq 'length')
|
||||||
|
CONTEXT=$(echo "$group" | jq -r '.[0].context')
|
||||||
|
DOCKERFILE=$(echo "$group" | jq -r '.[0].dockerfile')
|
||||||
|
|
||||||
|
if [ "$GROUP_COUNT" -gt 1 ]; then
|
||||||
|
echo "==== Building $GROUP_COUNT images from $DOCKERFILE (bake) ===="
|
||||||
|
|
||||||
|
CACHE_REF_SUFFIXES=$(echo "$group" | jq -c 'map(.cache_ref // empty) | map(select(length > 0)) | unique')
|
||||||
|
CACHE_REF_SUFFIX=$(echo "$CACHE_REF_SUFFIXES" | jq -r '.[0] // empty')
|
||||||
|
UNIQUE_CACHE_COUNT=$(echo "$CACHE_REF_SUFFIXES" | jq -r 'length')
|
||||||
|
if [ "$UNIQUE_CACHE_COUNT" -gt 1 ]; then
|
||||||
|
echo "Warning: multiple cache_ref values for the same dockerfile. Using $CACHE_REF_SUFFIX." >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
CACHE_REF=""
|
||||||
|
if [ -n "$CACHE_REF_SUFFIX" ]; then
|
||||||
|
CACHE_REF="${{ inputs.registry_host }}/$CACHE_REF_SUFFIX"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGETS_JSON="{}"
|
||||||
|
TARGET_NAMES=()
|
||||||
|
|
||||||
|
while read -r entry; do
|
||||||
|
IDX=$(echo "$entry" | jq -r '.key')
|
||||||
|
IMG=$(echo "$entry" | jq -c '.value')
|
||||||
|
|
||||||
|
IMAGE_NAME=$(echo "$IMG" | jq -r '.name')
|
||||||
|
TARGET=$(echo "$IMG" | jq -r '.target // empty')
|
||||||
|
FULL_IMAGE="${{ inputs.registry_host }}/${IMAGE_NAME}"
|
||||||
|
|
||||||
|
TAGS=()
|
||||||
|
TAGS+=("$FULL_IMAGE:sha-$SHA_SHORT")
|
||||||
|
for ver in "${VERSION_TAGS[@]}"; do
|
||||||
|
TAGS+=("$FULL_IMAGE:$ver")
|
||||||
|
done
|
||||||
|
TAGS_JSON=$(printf '%s\n' "${TAGS[@]}" | jq -R . | jq -s .)
|
||||||
|
|
||||||
|
TARGET_NAME="img_${IDX}"
|
||||||
|
TARGET_NAMES+=("$TARGET_NAME")
|
||||||
|
|
||||||
|
TARGET_OBJ=$(jq -n \
|
||||||
|
--arg context "$CONTEXT" \
|
||||||
|
--arg dockerfile "$DOCKERFILE" \
|
||||||
|
--arg target "$TARGET" \
|
||||||
|
--argjson tags "$TAGS_JSON" \
|
||||||
|
--argjson args "$BUILD_ARGS_JSON" \
|
||||||
|
--arg cache_ref "$CACHE_REF" \
|
||||||
|
'{
|
||||||
|
context: $context,
|
||||||
|
dockerfile: $dockerfile,
|
||||||
|
tags: $tags,
|
||||||
|
args: $args
|
||||||
|
}
|
||||||
|
+ ( ($target != "" and $target != "null") ? {target: $target} : {} )
|
||||||
|
+ ( ($cache_ref != "") ? {"cache-from": ["type=registry,ref=" + $cache_ref], "cache-to": ["type=registry,ref=" + $cache_ref + ",mode=max"]} : {} )')
|
||||||
|
|
||||||
|
TARGETS_JSON=$(jq -n --arg name "$TARGET_NAME" --argjson target "$TARGET_OBJ" --argjson targets "$TARGETS_JSON" '$targets + {($name): $target}')
|
||||||
|
done < <(echo "$group" | jq -c 'to_entries[]')
|
||||||
|
|
||||||
|
GROUP_TARGETS_JSON=$(printf '%s\n' "${TARGET_NAMES[@]}" | jq -R . | jq -s .)
|
||||||
|
BAKE_JSON=$(jq -n --argjson targets "$TARGETS_JSON" --argjson group_targets "$GROUP_TARGETS_JSON" '{target:$targets, group:{default:{targets:$group_targets}}}')
|
||||||
|
BAKE_FILE=$(mktemp)
|
||||||
|
echo "$BAKE_JSON" > "$BAKE_FILE"
|
||||||
|
|
||||||
|
docker buildx bake --file "$BAKE_FILE" --push "${SSH_FLAGS[@]}"
|
||||||
|
rm -f "$BAKE_FILE"
|
||||||
|
|
||||||
|
while read -r img; do
|
||||||
|
IMAGE_NAME=$(echo "$img" | jq -r '.name')
|
||||||
|
FULL_IMAGE="${{ inputs.registry_host }}/${IMAGE_NAME}"
|
||||||
|
|
||||||
|
echo "==== Trivy scan for $FULL_IMAGE ===="
|
||||||
|
trivy image \
|
||||||
|
--severity "$TRIVY_SEVERITY" \
|
||||||
|
--exit-code 1 \
|
||||||
|
"$FULL_IMAGE:sha-$SHA_SHORT"
|
||||||
|
done < <(echo "$group" | jq -c '.[]')
|
||||||
|
else
|
||||||
|
img=$(echo "$group" | jq -c '.[0]')
|
||||||
|
|
||||||
|
IMAGE_NAME=$(echo "$img" | jq -r '.name')
|
||||||
|
FULL_IMAGE="${{ inputs.registry_host }}/${IMAGE_NAME}"
|
||||||
|
CACHE_REF_SUFFIX=$(echo "$img" | jq -r '.cache_ref // empty')
|
||||||
|
CONTEXT=$(echo "$img" | jq -r '.context')
|
||||||
|
DOCKERFILE=$(echo "$img" | jq -r '.dockerfile')
|
||||||
|
TARGET=$(echo "$img" | jq -r '.target // empty')
|
||||||
|
|
||||||
|
TAGS=()
|
||||||
|
TAGS+=("$FULL_IMAGE:sha-$SHA_SHORT")
|
||||||
|
for ver in "${VERSION_TAGS[@]}"; do
|
||||||
|
TAGS+=("$FULL_IMAGE:$ver")
|
||||||
|
done
|
||||||
|
|
||||||
|
TAG_ARGS=()
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
TAG_ARGS+=(--tag "$tag")
|
||||||
|
done
|
||||||
|
|
||||||
|
TARGET_FLAGS=()
|
||||||
|
if [ -n "$TARGET" ] && [ "$TARGET" != "null" ]; then
|
||||||
|
TARGET_FLAGS+=(--target "$TARGET")
|
||||||
|
fi
|
||||||
|
|
||||||
|
CACHE_FLAGS=()
|
||||||
|
if [ -n "$CACHE_REF_SUFFIX" ]; then
|
||||||
|
CACHE_REF="${{ inputs.registry_host }}/${CACHE_REF_SUFFIX}"
|
||||||
|
CACHE_FLAGS+=(--cache-from "type=registry,ref=$CACHE_REF")
|
||||||
|
CACHE_FLAGS+=(--cache-to "type=registry,ref=$CACHE_REF,mode=max")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==== Building $FULL_IMAGE ===="
|
||||||
|
|
||||||
|
docker buildx build \
|
||||||
|
--file "$DOCKERFILE" \
|
||||||
|
"${TARGET_FLAGS[@]}" \
|
||||||
|
"${CACHE_FLAGS[@]}" \
|
||||||
|
"${SSH_FLAGS[@]}" \
|
||||||
|
--push \
|
||||||
|
"${TAG_ARGS[@]}" \
|
||||||
|
"${BUILD_ARG_FLAGS[@]}" \
|
||||||
|
"$CONTEXT"
|
||||||
|
|
||||||
|
echo "==== Trivy scan for $FULL_IMAGE ===="
|
||||||
|
trivy image \
|
||||||
|
--severity "$TRIVY_SEVERITY" \
|
||||||
|
--exit-code 1 \
|
||||||
|
"${TAGS[0]}"
|
||||||
|
fi
|
||||||
|
done < <(echo "$IMAGES" | jq -c 'sort_by(.context, .dockerfile) | group_by([.context, .dockerfile])[]')
|
||||||
|
|||||||
Reference in New Issue
Block a user