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