refactor: simplify Docker and CI/CD to use unified config

- Replace symlinked Dockerfile with simplified version in root
- Reduce Docker build args (unified config provides defaults)
- Update CI/CD workflows to use minimal build arguments
- Add nginx.conf to root directory (replace docker/nginx.conf)
- Remove docker-bake references from CI/CD workflows
- Focus on essential runtime overrides only
- Let unified config handle smart defaults
This commit is contained in:
William Valentin
2025-09-08 21:24:20 -07:00
parent a8647ff33d
commit 190cffb61b
5 changed files with 251 additions and 34 deletions

View File

@@ -1 +0,0 @@
docker/.dockerignore

113
.dockerignore Normal file
View File

@@ -0,0 +1,113 @@
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Build outputs
dist/
build/
.cache/
# Environment files
.env
.env.local
.env.*.local
# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Git
.git/
.gitignore
# Documentation
README.md
*.md
docs/
# Test files
tests/
test-results/
coverage/
playwright-report/
# Development files
.husky/
.github/
.gitea/
# Logs
logs/
*.log
# Runtime data
pids/
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
*.lcov
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
# Storybook build outputs
.out
.storybook-out
# Temporary folders
tmp/
temp/
# Configuration files not needed in container
*.config.js
*.config.ts
!vite.config.ts
!jest.config.json

View File

@@ -47,31 +47,19 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./docker
context: .
platforms: linux/amd64,linux/arm64
push: ${{ gitea.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VITE_COUCHDB_URL=${{ vars.VITE_COUCHDB_URL || 'http://localhost:5984' }}
VITE_COUCHDB_USER=${{ vars.VITE_COUCHDB_USER || 'admin' }}
VITE_COUCHDB_PASSWORD=${{ secrets.VITE_COUCHDB_PASSWORD || 'change-this-secure-password' }}
APP_BASE_URL=${{ vars.APP_BASE_URL || 'http://localhost:8080' }}
VITE_GOOGLE_CLIENT_ID=${{ vars.VITE_GOOGLE_CLIENT_ID || '' }}
VITE_GITHUB_CLIENT_ID=${{ vars.VITE_GITHUB_CLIENT_ID || '' }}
NODE_ENV=production
VITE_COUCHDB_URL=${{ vars.VITE_COUCHDB_URL }}
VITE_COUCHDB_USER=${{ vars.VITE_COUCHDB_USER }}
VITE_COUCHDB_PASSWORD=${{ secrets.VITE_COUCHDB_PASSWORD }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
- name: Build with Bake (Alternative)
if: false # Set to true to use bake instead
uses: docker/bake-action@v4
with:
workdir: ./docker
files: docker-bake.hcl
targets: prod
push: ${{ gitea.event_name != 'pull_request' }}
test:
runs-on: ubuntu-latest
container:

View File

@@ -45,31 +45,19 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./docker
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VITE_COUCHDB_URL=${{ vars.VITE_COUCHDB_URL || 'http://localhost:5984' }}
VITE_COUCHDB_USER=${{ vars.VITE_COUCHDB_USER || 'admin' }}
VITE_COUCHDB_PASSWORD=${{ secrets.VITE_COUCHDB_PASSWORD || 'change-this-secure-password' }}
APP_BASE_URL=${{ vars.APP_BASE_URL || 'http://localhost:8080' }}
VITE_GOOGLE_CLIENT_ID=${{ vars.VITE_GOOGLE_CLIENT_ID || '' }}
VITE_GITHUB_CLIENT_ID=${{ vars.VITE_GITHUB_CLIENT_ID || '' }}
NODE_ENV=production
VITE_COUCHDB_URL=${{ vars.VITE_COUCHDB_URL }}
VITE_COUCHDB_USER=${{ vars.VITE_COUCHDB_USER }}
VITE_COUCHDB_PASSWORD=${{ secrets.VITE_COUCHDB_PASSWORD }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build with Bake (Alternative)
if: false # Set to true to use bake instead
uses: docker/bake-action@v4
with:
workdir: ./docker
files: docker-bake.hcl
targets: prod
push: ${{ github.event_name != 'pull_request' }}
test:
runs-on: ubuntu-latest
needs: build

View File

@@ -1 +0,0 @@
docker/Dockerfile

81
Dockerfile Normal file
View File

@@ -0,0 +1,81 @@
# Multi-stage Dockerfile for Medication Reminder App
FROM node:20-slim AS base
# Install system dependencies
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Bun
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:$PATH"
# Set working directory
WORKDIR /app
# Create non-root user
RUN groupadd --gid 1001 nodeuser && \
useradd --uid 1001 --gid nodeuser --shell /bin/bash --create-home nodeuser
# Builder stage
FROM base AS builder
# Copy package files
COPY --chown=nodeuser:nodeuser package.json bun.lock* ./
# Install dependencies
RUN bun install --frozen-lockfile
# Copy source code
COPY --chown=nodeuser:nodeuser . ./
# Build arguments for environment configuration
# Build Environment - unified config will handle the rest
ARG NODE_ENV=production
# Only essential runtime variables that override unified config defaults
ARG VITE_COUCHDB_URL
ARG VITE_COUCHDB_USER
ARG VITE_COUCHDB_PASSWORD
# Set environment variables for build process
# Unified config handles defaults, only set essential runtime overrides
ENV NODE_ENV=$NODE_ENV
ENV VITE_COUCHDB_URL=$VITE_COUCHDB_URL
ENV VITE_COUCHDB_USER=$VITE_COUCHDB_USER
ENV VITE_COUCHDB_PASSWORD=$VITE_COUCHDB_PASSWORD
ENV NODE_ENV=$NODE_ENV
# Build the application
RUN bun run build
# Production stage
FROM nginx:alpine AS production
# Install curl for health checks
RUN apk add --no-cache curl
# Copy built files from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Set proper permissions for nginx
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /etc/nginx/conf.d
# Switch to nginx user
USER nginx
# Expose port
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/health || exit 1
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

49
nginx.conf Normal file
View File

@@ -0,0 +1,49 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate auth;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Handle React Router (SPA)
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Disable access to hidden files
location ~ /\. {
deny all;
}
}