feat: create builder and runtime base images for faster deploys
Instead of installing system packages and tools on every deploy, we now have two base images that pre-bake all the slow setup steps. Base Images Created: 1. elixir-builder:latest - Builder stage base - hexpm/elixir with build-essential and git pre-installed - hex and rebar pre-installed - Saves ~40 seconds per deploy 2. debian-runtime:latest - Runtime stage base - Debian with all runtime packages pre-installed - Locale pre-configured (en_US.UTF-8) - /app directory pre-created - Saves ~60 seconds per deploy Main Dockerfile Changes: - Use elixir-builder:latest instead of hexpm/elixir - Use debian-runtime:latest instead of debian:trixie-slim - Remove apt-get install steps (now in base images) - Remove hex/rebar install (now in builder base) - Remove locale setup (now in runtime base) Build System: - build.sh builds both images with podman/docker auto-detect - Pushes to both GitLab registry and Docker Hub - Makefile targets for build/test/push/clean Total Time Saved Per Deploy: ~100 seconds (1m40s) Benefits: - Faster CI/CD builds (no repeated apt-get install) - Faster local development builds - Consistent build environment across all deploys - Security updates centralized in base image rebuilds
This commit is contained in:
parent
26a3b39edd
commit
edd64479df
4 changed files with 201 additions and 162 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue