feat: Enable multi-platform Docker builds and dynamic image tagging
- Detect host architecture to set build platform - Support multi-platform builds when MULTI_PLATFORM=1 or CONTAINER_REGISTRY is set - Dynamically set image tag based on registry and platform - Pull pushed images for local validation - Update all docker run and inspect commands to use dynamic image tag
This commit is contained in:
@@ -52,21 +52,21 @@ load_env() {
|
|||||||
# Function to substitute environment variables in template files
|
# Function to substitute environment variables in template files
|
||||||
substitute_templates() {
|
substitute_templates() {
|
||||||
print_info "Processing template files..."
|
print_info "Processing template files..."
|
||||||
|
|
||||||
# Create temporary directory
|
# Create temporary directory
|
||||||
mkdir -p "$TEMP_DIR"
|
mkdir -p "$TEMP_DIR"
|
||||||
|
|
||||||
# Process each template file
|
# Process each template file
|
||||||
for template_file in "$K8S_DIR"/*.template; do
|
for template_file in "$K8S_DIR"/*.template; do
|
||||||
if [[ -f "$template_file" ]]; then
|
if [[ -f "$template_file" ]]; then
|
||||||
local filename=$(basename "$template_file" .template)
|
local filename=$(basename "$template_file" .template)
|
||||||
local output_file="$TEMP_DIR/$filename"
|
local output_file="$TEMP_DIR/$filename"
|
||||||
|
|
||||||
print_info "Processing template: $filename"
|
print_info "Processing template: $filename"
|
||||||
|
|
||||||
# Substitute environment variables
|
# Substitute environment variables
|
||||||
envsubst < "$template_file" > "$output_file"
|
envsubst < "$template_file" > "$output_file"
|
||||||
|
|
||||||
print_success "Generated: $output_file"
|
print_success "Generated: $output_file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -76,13 +76,13 @@ substitute_templates() {
|
|||||||
validate_env() {
|
validate_env() {
|
||||||
local required_vars=("INGRESS_HOST")
|
local required_vars=("INGRESS_HOST")
|
||||||
local missing_vars=()
|
local missing_vars=()
|
||||||
|
|
||||||
for var in "${required_vars[@]}"; do
|
for var in "${required_vars[@]}"; do
|
||||||
if [[ -z "${!var:-}" ]]; then
|
if [[ -z "${!var:-}" ]]; then
|
||||||
missing_vars+=("$var")
|
missing_vars+=("$var")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
||||||
print_error "Missing required environment variables:"
|
print_error "Missing required environment variables:"
|
||||||
for var in "${missing_vars[@]}"; do
|
for var in "${missing_vars[@]}"; do
|
||||||
@@ -108,15 +108,15 @@ ensure_namespace() {
|
|||||||
# Function to apply Kubernetes manifests
|
# Function to apply Kubernetes manifests
|
||||||
apply_manifests() {
|
apply_manifests() {
|
||||||
local manifest_dir="$1"
|
local manifest_dir="$1"
|
||||||
|
|
||||||
print_info "Applying Kubernetes manifests from $manifest_dir"
|
print_info "Applying Kubernetes manifests from $manifest_dir"
|
||||||
|
|
||||||
# Apply static files that don't have template counterparts
|
# Apply static files that don't have template counterparts
|
||||||
for manifest_file in "$K8S_DIR"/*.yaml; do
|
for manifest_file in "$K8S_DIR"/*.yaml; do
|
||||||
if [[ -f "$manifest_file" && ! "$manifest_file" =~ \.template$ ]]; then
|
if [[ -f "$manifest_file" && ! "$manifest_file" =~ \.template$ ]]; then
|
||||||
local basename_file=$(basename "$manifest_file")
|
local basename_file=$(basename "$manifest_file")
|
||||||
local template_file="$K8S_DIR/${basename_file}.template"
|
local template_file="$K8S_DIR/${basename_file}.template"
|
||||||
|
|
||||||
# Only apply if there's no corresponding template file
|
# Only apply if there's no corresponding template file
|
||||||
if [[ ! -f "$template_file" ]]; then
|
if [[ ! -f "$template_file" ]]; then
|
||||||
print_info "Applying static file: $basename_file"
|
print_info "Applying static file: $basename_file"
|
||||||
@@ -124,7 +124,7 @@ apply_manifests() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Apply processed template files
|
# Apply processed template files
|
||||||
if [[ -d "$TEMP_DIR" ]]; then
|
if [[ -d "$TEMP_DIR" ]]; then
|
||||||
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
||||||
@@ -148,19 +148,19 @@ cleanup() {
|
|||||||
show_status() {
|
show_status() {
|
||||||
print_info "Deployment Status:"
|
print_info "Deployment Status:"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Pods:"
|
print_info "Pods:"
|
||||||
kubectl get pods -l app=rxminder -n "$NAMESPACE"
|
kubectl get pods -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Services:"
|
print_info "Services:"
|
||||||
kubectl get services -l app=rxminder -n "$NAMESPACE"
|
kubectl get services -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Ingress:"
|
print_info "Ingress:"
|
||||||
kubectl get ingress -l app=rxminder -n "$NAMESPACE"
|
kubectl get ingress -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
||||||
print_success "Application should be available at: http://$INGRESS_HOST"
|
print_success "Application should be available at: http://$INGRESS_HOST"
|
||||||
fi
|
fi
|
||||||
@@ -190,7 +190,7 @@ main() {
|
|||||||
local dry_run=false
|
local dry_run=false
|
||||||
local status_only=false
|
local status_only=false
|
||||||
local cleanup_only=false
|
local cleanup_only=false
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -221,54 +221,56 @@ main() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Handle cleanup only
|
# Handle cleanup only
|
||||||
if [[ "$cleanup_only" == true ]]; then
|
if [[ "$cleanup_only" == true ]]; then
|
||||||
cleanup
|
cleanup
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Handle status only
|
# Handle status only
|
||||||
if [[ "$status_only" == true ]]; then
|
if [[ "$status_only" == true ]]; then
|
||||||
|
load_env "$env_file"
|
||||||
|
NAMESPACE="${NAMESPACE:-rxminder}"
|
||||||
show_status
|
show_status
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if kubectl is available
|
# Check if kubectl is available
|
||||||
if ! command -v kubectl &> /dev/null; then
|
if ! command -v kubectl &> /dev/null; then
|
||||||
print_error "kubectl is not installed or not in PATH"
|
print_error "kubectl is not installed or not in PATH"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if we can connect to Kubernetes cluster
|
# Check if we can connect to Kubernetes cluster
|
||||||
if ! kubectl cluster-info &> /dev/null; then
|
if ! kubectl cluster-info &> /dev/null; then
|
||||||
print_error "Cannot connect to Kubernetes cluster"
|
print_error "Cannot connect to Kubernetes cluster"
|
||||||
print_info "Make sure your kubectl is configured correctly"
|
print_info "Make sure your kubectl is configured correctly"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "🚀 Deploying Medication Reminder App to Kubernetes"
|
print_info "🚀 Deploying Medication Reminder App to Kubernetes"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
load_env "$env_file"
|
load_env "$env_file"
|
||||||
|
|
||||||
# Set default namespace if not provided in environment
|
# Set default namespace if not provided in environment
|
||||||
NAMESPACE="${NAMESPACE:-rxminder}"
|
NAMESPACE="${NAMESPACE:-rxminder}"
|
||||||
|
|
||||||
# Validate required environment variables
|
# Validate required environment variables
|
||||||
validate_env
|
validate_env
|
||||||
|
|
||||||
# Ensure namespace exists
|
# Ensure namespace exists
|
||||||
ensure_namespace
|
ensure_namespace
|
||||||
|
|
||||||
# Process templates
|
# Process templates
|
||||||
substitute_templates
|
substitute_templates
|
||||||
|
|
||||||
if [[ "$dry_run" == true ]]; then
|
if [[ "$dry_run" == true ]]; then
|
||||||
print_info "Dry run mode - showing generated manifests:"
|
print_info "Dry run mode - showing generated manifests:"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
||||||
if [[ -f "$manifest_file" ]]; then
|
if [[ -f "$manifest_file" ]]; then
|
||||||
echo "=== $(basename "$manifest_file") ==="
|
echo "=== $(basename "$manifest_file") ==="
|
||||||
@@ -279,14 +281,14 @@ main() {
|
|||||||
else
|
else
|
||||||
# Apply manifests
|
# Apply manifests
|
||||||
apply_manifests "$K8S_DIR"
|
apply_manifests "$K8S_DIR"
|
||||||
|
|
||||||
print_success "Deployment completed!"
|
print_success "Deployment completed!"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show status
|
# Show status
|
||||||
show_status
|
show_status
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
cleanup
|
cleanup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ print_success "Environment files exist"
|
|||||||
|
|
||||||
# Validate environment consistency
|
# Validate environment consistency
|
||||||
print_status "2. Checking environment variable consistency..."
|
print_status "2. Checking environment variable consistency..."
|
||||||
./validate-env.sh
|
./scripts/validate-env.sh
|
||||||
|
|
||||||
print_status "3. Setting up Docker Buildx..."
|
print_status "3. Setting up Docker Buildx..."
|
||||||
|
|
||||||
@@ -80,9 +80,35 @@ docker buildx use meds-builder
|
|||||||
|
|
||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
# Build the image with buildx for multiple platforms
|
# Determine host platform
|
||||||
|
HOST_ARCH="$(uname -m)"
|
||||||
|
case "$HOST_ARCH" in
|
||||||
|
x86_64) HOST_PLATFORM="linux/amd64" ;;
|
||||||
|
aarch64|arm64) HOST_PLATFORM="linux/arm64" ;;
|
||||||
|
*) HOST_PLATFORM="linux/amd64" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Decide build strategy:
|
||||||
|
# Enable multi-platform (push) if MULTI_PLATFORM=1 or CONTAINER_REGISTRY is set
|
||||||
|
if [[ "${MULTI_PLATFORM:-0}" == "1" || -n "${CONTAINER_REGISTRY:-}" ]]; then
|
||||||
|
BUILD_PLATFORMS="linux/amd64,linux/arm64"
|
||||||
|
EXPORT_MODE="--push"
|
||||||
|
# If CONTAINER_REGISTRY provided, ensure trailing slash
|
||||||
|
if [[ -n "${CONTAINER_REGISTRY:-}" && "${CONTAINER_REGISTRY}" != */ ]]; then
|
||||||
|
CONTAINER_REGISTRY="${CONTAINER_REGISTRY}/"
|
||||||
|
fi
|
||||||
|
IMAGE_TAG="${IMAGE_TAG:-${CONTAINER_REGISTRY:-}meds-validation:latest}"
|
||||||
|
print_status "Multi-platform build enabled (platforms: $BUILD_PLATFORMS) -> push $IMAGE_TAG"
|
||||||
|
else
|
||||||
|
BUILD_PLATFORMS="$HOST_PLATFORM"
|
||||||
|
EXPORT_MODE="--load"
|
||||||
|
IMAGE_TAG="${IMAGE_TAG:-meds-validation}"
|
||||||
|
print_status "Single-platform build ($BUILD_PLATFORMS) -> load locally as $IMAGE_TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Perform build
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform linux/amd64,linux/arm64 \
|
--platform "$BUILD_PLATFORMS" \
|
||||||
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
||||||
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
||||||
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
||||||
@@ -95,10 +121,16 @@ docker buildx build --no-cache \
|
|||||||
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
||||||
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
||||||
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
||||||
-t meds-validation \
|
-t "$IMAGE_TAG" \
|
||||||
--load \
|
$EXPORT_MODE \
|
||||||
.
|
.
|
||||||
|
|
||||||
|
# If we pushed (multi-platform), pull the host-specific image for local tests
|
||||||
|
if [[ "$EXPORT_MODE" == "--push" ]]; then
|
||||||
|
print_status "Pulling image $IMAGE_TAG for local validation..."
|
||||||
|
docker pull "$IMAGE_TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
print_success "Docker image built successfully"
|
print_success "Docker image built successfully"
|
||||||
|
|
||||||
print_status "5. Testing container startup and health..."
|
print_status "5. Testing container startup and health..."
|
||||||
@@ -107,7 +139,7 @@ print_status "5. Testing container startup and health..."
|
|||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name meds-validation-test \
|
--name meds-validation-test \
|
||||||
meds-validation
|
"$IMAGE_TAG"
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
@@ -176,13 +208,13 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "9. Checking image size..."
|
print_status "9. Checking image size..."
|
||||||
IMAGE_SIZE=$(docker image inspect meds-validation --format='{{.Size}}' | numfmt --to=iec)
|
IMAGE_SIZE=$(docker image inspect "$IMAGE_TAG" --format='{{.Size}}' | numfmt --to=iec)
|
||||||
print_success "Image size: $IMAGE_SIZE"
|
print_success "Image size: $IMAGE_SIZE"
|
||||||
|
|
||||||
print_status "10. Validating security configuration..."
|
print_status "10. Validating security configuration..."
|
||||||
|
|
||||||
# Check if image runs as non-root
|
# Check if image runs as non-root
|
||||||
USER_INFO=$(docker run --rm meds-validation whoami)
|
USER_INFO=$(docker run --rm "$IMAGE_TAG" whoami)
|
||||||
if [[ "$USER_INFO" != "root" ]]; then
|
if [[ "$USER_INFO" != "root" ]]; then
|
||||||
print_success "Container runs as non-root user: $USER_INFO"
|
print_success "Container runs as non-root user: $USER_INFO"
|
||||||
else
|
else
|
||||||
@@ -190,7 +222,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check nginx configuration
|
# Check nginx configuration
|
||||||
if docker run --rm meds-validation nginx -t 2>/dev/null; then
|
if docker run --rm "$IMAGE_TAG" nginx -t 2>/dev/null; then
|
||||||
print_success "Nginx configuration is valid"
|
print_success "Nginx configuration is valid"
|
||||||
else
|
else
|
||||||
print_error "Nginx configuration has issues"
|
print_error "Nginx configuration has issues"
|
||||||
|
|||||||
Reference in New Issue
Block a user