diff --git a/k8s/Dockerfile b/k8s/Dockerfile index 57270e3e..048cdfaa 100644 --- a/k8s/Dockerfile +++ b/k8s/Dockerfile @@ -17,27 +17,18 @@ ARG ELIXIR_VERSION=1.19.4 ARG OTP_VERSION=28.3 ARG DEBIAN_VERSION=trixie-20251229-slim -ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" -ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}" +# Use custom base images with pre-installed dependencies for faster builds +ARG BUILDER_IMAGE="registry.gitlab.com/towerops/towerops/elixir-builder:latest" +ARG RUNNER_IMAGE="registry.gitlab.com/towerops/towerops/debian-runtime:latest" FROM ${BUILDER_IMAGE} AS builder -ENV MIX_OS_DEPS_COMPILE_PARTITION_COUNT=6 -# install build dependencies -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential git \ - && rm -rf /var/lib/apt/lists/* - -# prepare build dir -WORKDIR /app - -# install hex + rebar -RUN mix local.hex --force \ - && mix local.rebar --force - -# set build ENV -ENV MIX_ENV="prod" +# Base image already has: +# - build-essential and git installed +# - hex and rebar installed +# - MIX_OS_DEPS_COMPILE_PARTITION_COUNT=6 +# - MIX_ENV="prod" +# - WORKDIR /app # install mix dependencies COPY mix.exs mix.lock ./ @@ -80,21 +71,11 @@ RUN mix release # the compiled release and other runtime necessities FROM ${RUNNER_IMAGE} AS final -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends libstdc++6 openssl libncurses6 locales ca-certificates iputils-ping \ - && rm -rf /var/lib/apt/lists/* - -# Set the locale -RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \ - && locale-gen - -ENV LANG=en_US.UTF-8 -ENV LANGUAGE=en_US:en -ENV LC_ALL=en_US.UTF-8 - -WORKDIR "/app" -RUN chown nobody /app +# Base image already has: +# - All runtime dependencies installed (libstdc++6, openssl, libncurses6, locales, ca-certificates, iputils-ping) +# - Locale configured (en_US.UTF-8) +# - /app directory created and owned by nobody +# - WORKDIR "/app" # set runner ENV ENV MIX_ENV="prod" diff --git a/k8s/base-image/Dockerfile b/k8s/base-image/Dockerfile index 825f396a..04e307c7 100644 --- a/k8s/base-image/Dockerfile +++ b/k8s/base-image/Dockerfile @@ -1,59 +1,66 @@ -# Minimal Debian 13 (Trixie) with Erlang/OTP and Elixir runtime -# Uses official hexpm/elixir images as builder for reliability +# Multi-stage base images for Towerops Phoenix app +# Pre-bakes all the setup from k8s/Dockerfile so app deploys are faster # # This image is designed to be rebuilt regularly to get latest security updates +ARG ELIXIR_VERSION=1.19.4 +ARG OTP_VERSION=28.3 ARG DEBIAN_VERSION=trixie-20251229-slim -ARG ERLANG_VERSION=28.3 -ARG ELIXIR_VERSION=1.19.5 -# Use official Elixir image as builder (more reliable than erlang-solutions repo) -FROM docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${ERLANG_VERSION}-debian-${DEBIAN_VERSION} as builder - -# Verify installations in builder -RUN erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell -RUN elixir --version - -# Final minimal runtime image -FROM docker.io/debian:${DEBIAN_VERSION} +# +# BUILDER BASE IMAGE +# Pre-installs build dependencies, hex, and rebar so every deploy is faster +# +FROM docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION} AS builder LABEL maintainer="towerops" -LABEL description="Minimal Debian 13 with Erlang/OTP and Elixir runtime" +LABEL description="Elixir builder base with pre-installed build tools" -# Copy Erlang and Elixir from builder (hexpm image uses /usr/local) -COPY --from=builder /usr/local/lib/erlang /usr/local/lib/erlang -COPY --from=builder /usr/local/lib/elixir /usr/local/lib/elixir +# Set parallel compilation +ENV MIX_OS_DEPS_COMPILE_PARTITION_COUNT=6 -# Copy all Erlang/Elixir binaries (they're symlinks to lib dirs) -COPY --from=builder /usr/local/bin/erl /usr/local/bin/erl -COPY --from=builder /usr/local/bin/erlc /usr/local/bin/erlc -COPY --from=builder /usr/local/bin/escript /usr/local/bin/escript -COPY --from=builder /usr/local/bin/epmd /usr/local/bin/epmd -COPY --from=builder /usr/local/bin/elixir /usr/local/bin/elixir -COPY --from=builder /usr/local/bin/elixirc /usr/local/bin/elixirc -COPY --from=builder /usr/local/bin/iex /usr/local/bin/iex -COPY --from=builder /usr/local/bin/mix /usr/local/bin/mix - -# Install only essential runtime dependencies -# This is the absolute minimum needed for Erlang/Elixir + Phoenix apps +# Install build dependencies (matches k8s/Dockerfile builder stage exactly) +# This step takes ~30 seconds on every deploy, so we bake it in RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - # Erlang runtime dependencies - libssl3 \ - libsctp1 \ - libncurses6 \ - libstdc++6 \ - # System utilities - ca-certificates \ - locales \ - # Network utilities (minimal set) - iputils-ping \ - iproute2 \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get clean + build-essential \ + git \ + && rm -rf /var/lib/apt/lists/* -# Configure locale (required for proper string handling) +# Install hex + rebar (matches k8s/Dockerfile exactly) +# This step takes ~10 seconds on every deploy, so we bake it in +RUN mix local.hex --force \ + && mix local.rebar --force + +# Set build ENV +ENV MIX_ENV="prod" + +WORKDIR /app + +# +# RUNTIME BASE IMAGE +# Pre-installs runtime dependencies and configures locale +# +FROM docker.io/debian:${DEBIAN_VERSION} AS runtime + +LABEL maintainer="towerops" +LABEL description="Debian 13 runtime base with pre-installed system packages and locale" + +# Install runtime dependencies (matches k8s/Dockerfile runner stage exactly) +# This step takes ~30-60 seconds on every deploy, so we bake it in +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + libstdc++6 \ + openssl \ + libncurses6 \ + locales \ + ca-certificates \ + iputils-ping \ + && rm -rf /var/lib/apt/lists/* + +# Configure locale (matches k8s/Dockerfile exactly) RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \ && locale-gen @@ -61,15 +68,6 @@ ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 -# Add nobody user for security (already exists in Debian) -RUN mkdir -p /app && chown nobody:nogroup /app - -WORKDIR /app -USER nobody - -# Verify everything works -RUN erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell -RUN elixir --version - -# Default command - override in application Dockerfile -CMD ["/bin/bash"] +# Set up /app directory (matches k8s/Dockerfile exactly) +WORKDIR "/app" +RUN chown nobody /app diff --git a/k8s/base-image/Makefile b/k8s/base-image/Makefile index 053fbb90..cd9cca9b 100644 --- a/k8s/base-image/Makefile +++ b/k8s/base-image/Makefile @@ -5,10 +5,12 @@ CONTAINER_CMD := $(shell command -v podman 2>/dev/null || command -v docker 2>/d REGISTRY ?= registry.gitlab.com/towerops/towerops DOCKERHUB_REGISTRY ?= docker.io/gmcintire -IMAGE_NAME ?= elixir-runtime -ERLANG_VERSION ?= 28.3 -ELIXIR_VERSION ?= 1.19.5 -TAG ?= $(ERLANG_VERSION)-elixir-$(ELIXIR_VERSION)-debian-trixie +BUILDER_IMAGE_NAME ?= elixir-builder +RUNTIME_IMAGE_NAME ?= debian-runtime +ELIXIR_VERSION ?= 1.19.4 +OTP_VERSION ?= 28.3 +DEBIAN_VERSION ?= trixie-20251229-slim +TAG ?= $(ELIXIR_VERSION)-erlang-$(OTP_VERSION)-debian-$(DEBIAN_VERSION) help: ## Show this help message @echo "Available targets:" @@ -20,41 +22,57 @@ build: ## Build the base image with latest packages update: build ## Alias for build (rebuilds with latest packages) -test: ## Test the built image - @echo "Testing Erlang..." - @$(CONTAINER_CMD) run --rm $(REGISTRY)/$(IMAGE_NAME):latest erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell - @echo "Testing Elixir..." - @$(CONTAINER_CMD) run --rm $(REGISTRY)/$(IMAGE_NAME):latest elixir --version - @echo "Testing locale..." - @$(CONTAINER_CMD) run --rm $(REGISTRY)/$(IMAGE_NAME):latest locale +test: ## Test the built images + @echo "Testing builder image..." + @$(CONTAINER_CMD) run --rm $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest mix --version + @echo "Testing runtime image..." + @$(CONTAINER_CMD) run --rm $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest locale | grep "en_US.UTF-8" @echo "✅ All tests passed!" -push: ## Push image to GitLab and Docker Hub - @echo "Pushing to GitLab registry..." - @$(CONTAINER_CMD) push $(REGISTRY)/$(IMAGE_NAME):$(TAG) - @$(CONTAINER_CMD) push $(REGISTRY)/$(IMAGE_NAME):latest +push: ## Push images to GitLab and Docker Hub + @echo "Pushing builder image to GitLab registry..." + @$(CONTAINER_CMD) push $(REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) push $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest + @echo "Pushing runtime image to GitLab registry..." + @$(CONTAINER_CMD) push $(REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) push $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest @echo "Tagging for Docker Hub..." - @$(CONTAINER_CMD) tag $(REGISTRY)/$(IMAGE_NAME):$(TAG) $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):$(TAG) - @$(CONTAINER_CMD) tag $(REGISTRY)/$(IMAGE_NAME):latest $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):latest + @$(CONTAINER_CMD) tag $(REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) tag $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):latest + @$(CONTAINER_CMD) tag $(REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) tag $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):latest @echo "Pushing to Docker Hub..." - @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):$(TAG) - @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):latest + @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):latest + @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) + @$(CONTAINER_CMD) push $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):latest -pull: ## Pull latest image from registry - @$(CONTAINER_CMD) pull $(REGISTRY)/$(IMAGE_NAME):latest +pull: ## Pull latest images from registry + @$(CONTAINER_CMD) pull $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest + @$(CONTAINER_CMD) pull $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest inspect: ## Show image details (size, layers, labels) - @echo "Image size:" - @$(CONTAINER_CMD) images $(REGISTRY)/$(IMAGE_NAME):latest --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" + @echo "Builder image size:" + @$(CONTAINER_CMD) images $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" @echo "" - @echo "Image labels:" - @$(CONTAINER_CMD) inspect $(REGISTRY)/$(IMAGE_NAME):latest --format '{{range $$k, $$v := .Config.Labels}}{{$$k}}={{$$v}}{{println}}{{end}}' + @echo "Runtime image size:" + @$(CONTAINER_CMD) images $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" + @echo "" + @echo "Builder image labels:" + @$(CONTAINER_CMD) inspect $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest --format '{{range $$k, $$v := .Config.Labels}}{{$$k}}={{$$v}}{{println}}{{end}}' + @echo "" + @echo "Runtime image labels:" + @$(CONTAINER_CMD) inspect $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest --format '{{range $$k, $$v := .Config.Labels}}{{$$k}}={{$$v}}{{println}}{{end}}' clean: ## Remove local images - @$(CONTAINER_CMD) rmi $(REGISTRY)/$(IMAGE_NAME):$(TAG) || true - @$(CONTAINER_CMD) rmi $(REGISTRY)/$(IMAGE_NAME):latest || true - @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):$(TAG) || true - @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(IMAGE_NAME):latest || true + @$(CONTAINER_CMD) rmi $(REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) || true + @$(CONTAINER_CMD) rmi $(REGISTRY)/$(BUILDER_IMAGE_NAME):latest || true + @$(CONTAINER_CMD) rmi $(REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) || true + @$(CONTAINER_CMD) rmi $(REGISTRY)/$(RUNTIME_IMAGE_NAME):latest || true + @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):$(TAG) || true + @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(BUILDER_IMAGE_NAME):latest || true + @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):$(TAG) || true + @$(CONTAINER_CMD) rmi $(DOCKERHUB_REGISTRY)/$(RUNTIME_IMAGE_NAME):latest || true @echo "✅ Cleaned local images" login: ## Login to GitLab container registry diff --git a/k8s/base-image/build.sh b/k8s/base-image/build.sh index bdf7a581..07d1b495 100755 --- a/k8s/base-image/build.sh +++ b/k8s/base-image/build.sh @@ -16,107 +16,149 @@ fi # Configuration REGISTRY="${REGISTRY:-registry.gitlab.com/towerops/towerops}" -IMAGE_NAME="${IMAGE_NAME:-elixir-runtime}" -ERLANG_VERSION="${ERLANG_VERSION:-28.3}" -ELIXIR_VERSION="${ELIXIR_VERSION:-1.19.5}" +ELIXIR_VERSION="${ELIXIR_VERSION:-1.19.4}" +OTP_VERSION="${OTP_VERSION:-28.3}" DEBIAN_VERSION="${DEBIAN_VERSION:-trixie-20251229-slim}" # Build timestamp for tracking BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") GIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") +# Image names +BUILDER_IMAGE_NAME="elixir-builder" +RUNTIME_IMAGE_NAME="debian-runtime" + # Image tags -TAG_FULL="${ERLANG_VERSION}-elixir-${ELIXIR_VERSION}-debian-trixie" +TAG_FULL="${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" TAG_LATEST="latest" TAG_DATED="${TAG_FULL}-${BUILD_DATE//[:-]*/}" # YYYY-MM-DD format echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Building Minimal Debian Base Image" +echo "Building Base Images for Towerops" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Container: ${CONTAINER_CMD}" echo "Registry: ${REGISTRY}" -echo "Image: ${IMAGE_NAME}" -echo "Erlang: ${ERLANG_VERSION}" +echo "Builder Image: ${BUILDER_IMAGE_NAME}" +echo "Runtime Image: ${RUNTIME_IMAGE_NAME}" echo "Elixir: ${ELIXIR_VERSION}" +echo "Erlang: ${OTP_VERSION}" echo "Debian: ${DEBIAN_VERSION}" echo "Build Date: ${BUILD_DATE}" echo "Git SHA: ${GIT_SHA}" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -# Build the image with no cache to ensure latest packages +# Build builder image (no cache to ensure latest packages) echo "" -echo "🔨 Building image (no cache, pulling latest packages)..." +echo "🔨 Building builder image (no cache, pulling latest packages)..." $CONTAINER_CMD build \ --no-cache \ --pull \ - --build-arg DEBIAN_VERSION="${DEBIAN_VERSION}" \ - --build-arg ERLANG_VERSION="${ERLANG_VERSION}" \ + --target builder \ --build-arg ELIXIR_VERSION="${ELIXIR_VERSION}" \ + --build-arg OTP_VERSION="${OTP_VERSION}" \ + --build-arg DEBIAN_VERSION="${DEBIAN_VERSION}" \ --label "build.date=${BUILD_DATE}" \ --label "build.git-sha=${GIT_SHA}" \ - --label "erlang.version=${ERLANG_VERSION}" \ --label "elixir.version=${ELIXIR_VERSION}" \ - -t "${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" \ - -t "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" \ - -t "${REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" \ + --label "erlang.version=${OTP_VERSION}" \ + --label "debian.version=${DEBIAN_VERSION}" \ + -t "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" \ + -t "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" \ + -t "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" \ + -f Dockerfile \ + . + +# Build runtime image +echo "" +echo "🔨 Building runtime image..." +$CONTAINER_CMD build \ + --no-cache \ + --pull \ + --target runtime \ + --build-arg DEBIAN_VERSION="${DEBIAN_VERSION}" \ + --label "build.date=${BUILD_DATE}" \ + --label "build.git-sha=${GIT_SHA}" \ + --label "debian.version=${DEBIAN_VERSION}" \ + -t "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" \ + -t "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" \ + -t "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" \ -f Dockerfile \ . echo "" echo "✅ Build complete!" echo "" -echo "Image tags created:" -echo " - ${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" -echo " - ${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" -echo " - ${REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" +echo "Builder image tags:" +echo " - ${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" +echo " - ${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" +echo " - ${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" +echo "" +echo "Runtime image tags:" +echo " - ${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" +echo " - ${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" +echo " - ${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" echo "" -# Show image size -echo "📦 Image size:" -$CONTAINER_CMD images "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" +# Show image sizes +echo "📦 Image sizes:" +$CONTAINER_CMD images "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" +$CONTAINER_CMD images "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" echo "" -# Verify image works -echo "🔍 Verifying image..." -$CONTAINER_CMD run --rm "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" erl -eval 'io:format("Erlang/OTP: ~s~n", [erlang:system_info(otp_release)]), halt().' -noshell -$CONTAINER_CMD run --rm "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" elixir --version +# Verify images work +echo "🔍 Verifying builder image..." +$CONTAINER_CMD run --rm "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" mix --version +echo "" +echo "🔍 Verifying runtime image..." +$CONTAINER_CMD run --rm "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" locale | grep "en_US.UTF-8" echo "" # Ask if user wants to push read -p "Push to registries? (y/N) " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "🚀 Pushing to GitLab registry..." - $CONTAINER_CMD push "${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" - $CONTAINER_CMD push "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" - $CONTAINER_CMD push "${REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" + echo "🚀 Pushing builder image to GitLab registry..." + $CONTAINER_CMD push "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD push "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD push "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" + + echo "🚀 Pushing runtime image to GitLab registry..." + $CONTAINER_CMD push "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD push "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD push "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" echo "" echo "🚀 Tagging for Docker Hub..." DOCKERHUB_REGISTRY="docker.io/gmcintire" - $CONTAINER_CMD tag "${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" - $CONTAINER_CMD tag "${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" - $CONTAINER_CMD tag "${REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" + $CONTAINER_CMD tag "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD tag "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD tag "${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" + $CONTAINER_CMD tag "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD tag "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD tag "${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" echo "🚀 Pushing to Docker Hub..." - $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" - $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" - $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_DATED}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_FULL}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" + $CONTAINER_CMD push "${DOCKERHUB_REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_DATED}" echo "" echo "✅ Pushed successfully to both registries!" echo "" echo "Update your main Dockerfile to use:" - echo " GitLab: ARG RUNNER_IMAGE=\"${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}\"" - echo " Docker Hub: ARG RUNNER_IMAGE=\"${DOCKERHUB_REGISTRY}/${IMAGE_NAME}:${TAG_FULL}\"" + echo " Builder: ARG BUILDER_IMAGE=\"${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}\"" + echo " Runtime: ARG RUNNER_IMAGE=\"${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}\"" else - echo "⏭️ Skipping push. To push later, run:" - echo " $CONTAINER_CMD push ${REGISTRY}/${IMAGE_NAME}:${TAG_FULL}" - echo " $CONTAINER_CMD push ${REGISTRY}/${IMAGE_NAME}:${TAG_LATEST}" - echo " $CONTAINER_CMD push ${REGISTRY}/${IMAGE_NAME}:${TAG_DATED}" - echo " $CONTAINER_CMD push docker.io/gmcintire/${IMAGE_NAME}:${TAG_FULL}" - echo " $CONTAINER_CMD push docker.io/gmcintire/${IMAGE_NAME}:${TAG_LATEST}" - echo " $CONTAINER_CMD push docker.io/gmcintire/${IMAGE_NAME}:${TAG_DATED}" + echo "⏭️ Skipping push. To push later:" + echo " GitLab:" + echo " $CONTAINER_CMD push ${REGISTRY}/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" + echo " $CONTAINER_CMD push ${REGISTRY}/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" + echo " Docker Hub:" + echo " $CONTAINER_CMD push docker.io/gmcintire/${BUILDER_IMAGE_NAME}:${TAG_LATEST}" + echo " $CONTAINER_CMD push docker.io/gmcintire/${RUNTIME_IMAGE_NAME}:${TAG_LATEST}" fi echo ""