mirror of https://github.com/buster-so/buster.git
test image for hono server
This commit is contained in:
parent
eb9a87e14b
commit
9efd1f49ff
|
@ -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
|
|
@ -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,73 +30,73 @@ 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))"
|
||||
|
||||
# Start the application
|
||||
CMD ["bun", "run", "dist/index.js"]
|
||||
CMD ["bun", "run", "dist/index.js"]
|
Loading…
Reference in New Issue