test image for hono server

This commit is contained in:
dal 2025-08-19 11:03:14 -06:00
parent eb9a87e14b
commit 9efd1f49ff
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
2 changed files with 177 additions and 44 deletions

View File

@ -0,0 +1,115 @@
name: Build and Push Server Docker Image
on:
push:
branches: [main, staging]
paths:
- 'apps/server/**'
- 'packages/**'
- 'pnpm-lock.yaml'
- '.github/workflows/docker-build-server.yml'
env:
REGISTRY: ghcr.io
IMAGE_NAME: buster-so/buster-server
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
TURBO_REMOTE_ONLY: true
jobs:
build-and-push:
runs-on: blacksmith-8vcpu-ubuntu-2204
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 9.15.0
- name: Setup Node.js
uses: useblacksmith/setup-node@v5
with:
node-version: 22
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Mount pnpm store sticky disk
uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-docker-pnpm-store
path: ${{ env.STORE_PATH }}
- name: Mount Turbo cache sticky disk
uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-docker-turbo-cache
path: ./.turbo
- name: Set up Docker Builder with Blacksmith cache
uses: useblacksmith/setup-docker-builder@v1
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata and determine tags
id: meta
run: |
SHA_SHORT=$(git rev-parse --short HEAD)
echo "sha_short=${SHA_SHORT}" >> $GITHUB_OUTPUT
if [[ "${{ github.ref_name }}" == "main" ]]; then
# For main: use commit SHA and latest
echo "tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${SHA_SHORT},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref_name }}" == "staging" ]]; then
# For staging: use staging-SHA and staging
echo "tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging-${SHA_SHORT},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging" >> $GITHUB_OUTPUT
fi
# Set build timestamp
echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: useblacksmith/build-push-action@v2
with:
context: .
file: ./apps/server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.created=${{ steps.meta.outputs.timestamp }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
build-args: |
TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}
TURBO_TEAM=${{ vars.TURBO_TEAM }}
COMMIT_SHA=${{ steps.meta.outputs.sha_short }}
BUILD_DATE=${{ steps.meta.outputs.timestamp }}
- name: Output image details
run: |
echo "✅ Docker image built and pushed successfully!"
echo "📦 Image tags:"
echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n' | sed 's/^/ - /'
echo ""
echo "🔧 To use in Porter:"
if [[ "${{ github.ref_name }}" == "main" ]]; then
echo " Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.sha_short }}"
else
echo " Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging-${{ steps.meta.outputs.sha_short }}"
fi

View File

@ -1,10 +1,28 @@
# Fresh build Dockerfile without caching layers
# ================================================================
# This Dockerfile handles:
# - Fresh dependency installation (no cached base image)
# - Source code building
# - Production runtime
# Optimized Dockerfile with proper layer caching
# ================================================================
# Stage 1: Dependencies
# This stage only rebuilds when package files change
FROM node:22-alpine AS deps
WORKDIR /app
# Install pnpm and bun
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN npm install -g bun@1.2.15
# Copy only package files for dependency resolution
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY packages/*/package.json ./packages/*/
COPY apps/server/package.json ./apps/server/
# Install dependencies with frozen lockfile
# This layer is cached and only rebuilds when dependencies change
RUN pnpm install --frozen-lockfile --ignore-scripts --no-optional
# ================================================================
# Stage 2: Builder
# This stage rebuilds when source code changes
FROM node:22-alpine AS builder
WORKDIR /app
@ -12,71 +30,71 @@ WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN npm install -g bun@1.2.15
# Set build environment to skip runtime validation
# Set build environment
ENV DOCKER_BUILD=true
ENV CI=true
ARG TURBO_TOKEN
ARG TURBO_TEAM
ARG COMMIT_SHA
ARG BUILD_DATE
RUN echo "=== FRESH BUILD START ==="
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/packages/*/node_modules ./packages/*/node_modules
COPY --from=deps /app/apps/server/node_modules ./apps/server/node_modules
# Copy all package files for fresh install
COPY package.json pnpm-lock.yaml* turbo.json* pnpm-workspace.yaml* ./
COPY packages/ ./packages/
COPY apps/server/ ./apps/server/
# Copy all source files
COPY . .
# Fresh install - no caching, clean install every time
RUN START=$(date +%s) && \
echo "=== Starting fresh dependency installation ===" && \
rm -rf node_modules && \
rm -rf ~/.pnpm-store && \
time pnpm install --frozen-lockfile --ignore-scripts --no-optional && \
END=$(date +%s) && \
echo "Finished fresh dependency installation in $((END - START)) seconds"
# Build with Turbo (uses remote cache if available)
RUN if [ -n "$TURBO_TOKEN" ] && [ -n "$TURBO_TEAM" ]; then \
echo "Building with Turbo remote cache" && \
turbo run build --filter=@buster-app/server; \
else \
echo "Building without Turbo remote cache" && \
turbo run build --filter=@buster-app/server --force; \
fi
# Force fresh turbo build without cache
RUN START=$(date +%s) && \
echo "=== Starting fresh turbo build ===" && \
rm -rf .turbo && \
time turbo run build --filter=@buster-app/server --force && \
END=$(date +%s) && \
echo "Finished fresh turbo build in $((END - START)) seconds"
# Build the application (fresh bun build)
RUN START=$(date +%s) && \
echo "=== Starting fresh application build ===" && \
cd apps/server && \
rm -rf dist && \
time bun build src/index.ts --outdir ./dist --target bun --external pino-pretty && \
# Build the final server bundle
WORKDIR /app/apps/server
RUN bun build src/index.ts --outdir ./dist --target bun --external pino-pretty && \
echo "Build complete - output:" && \
ls -la dist/ && \
END=$(date +%s) && \
echo "Finished fresh application build in $((END - START)) seconds"
ls -la dist/
# Production runtime (minimal bun image)
# ================================================================
# Stage 3: Production Runtime
# Minimal image with only what's needed to run
FROM oven/bun:1.2.15-alpine AS runtime
WORKDIR /app
# Set production environment
ENV NODE_ENV=production
# Add build metadata as labels
ARG COMMIT_SHA
ARG BUILD_DATE
LABEL org.opencontainers.image.revision="${COMMIT_SHA}"
LABEL org.opencontainers.image.created="${BUILD_DATE}"
# Create non-root user
RUN addgroup --system --gid 1001 bunuser && \
adduser --system --uid 1001 bunuser
# Copy built application and dependencies
# Copy only the necessary files from builder
COPY --from=builder --chown=bunuser:bunuser /app/apps/server/dist ./dist
COPY --from=builder --chown=bunuser:bunuser /app/apps/server/package.json ./
COPY --from=builder --chown=bunuser:bunuser /app/node_modules ./node_modules
# Show final stats
RUN echo "=== Fresh production image prepared ===" && \
# Show image size info
RUN echo "=== Production image size ===" && \
du -sh /app && \
echo "Ready to run with no cached artifacts!"
echo "Commit: ${COMMIT_SHA:-unknown}" && \
echo "Built: ${BUILD_DATE:-unknown}"
USER bunuser
EXPOSE 3002
# Health check for production
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD bun -e "fetch('http://localhost:' + (process.env.SERVER_PORT || 3002) + '/healthcheck').then(r => r.ok ? process.exit(0) : process.exit(1))"