diff --git a/Dockerfile b/Dockerfile index 5ed95cf..9d51679 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,64 +1,147 @@ -# Build stage -FROM golang:1.21-alpine AS builder +# ============================================================================= +# meta-core Standalone Container +# Multi-stage build for meta-core as a standalone service +# +# Includes: +# - Bash-based leader election script (flock on shared volume) +# - meta-core Go binary (HTTP API, Mount API, Watcher) +# - nginx (dashboard, WebDAV, API proxy) +# - Redis (managed by supervisord on leader) +# - rclone (remote mount daemon) +# - supervisord (process management - runs on leader only) +# +# Architecture: +# - leader-election.sh handles flock, starts supervisord on leader +# - Followers remain dormant, retry flock every 5s +# - Only leader runs Redis, meta-core, nginx, rclone, mount-watcher +# ============================================================================= + +# ----------------------------------------------------------------------------- +# Stage 1: Build Go binary +# ----------------------------------------------------------------------------- +FROM golang:1.21-alpine AS go-builder -# Install build dependencies RUN apk add --no-cache git WORKDIR /build # Copy go mod files first for caching COPY go.mod go.sum ./ -RUN go mod download # Copy source code COPY . . +# Download dependencies and update go.sum +RUN go mod tidy && go mod download + # Build the binary RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o meta-core ./cmd/meta-core -# Runtime stage +# ----------------------------------------------------------------------------- +# Stage 2: Build Dashboard +# ----------------------------------------------------------------------------- +FROM node:21-alpine AS dashboard-builder +WORKDIR /app +COPY dashboard/package*.json ./ +RUN npm install +COPY dashboard/ . +RUN npm run build + +# ----------------------------------------------------------------------------- +# Stage 3: Build Metadata Editor (standalone) +# ----------------------------------------------------------------------------- +FROM node:21-alpine AS editor-builder +WORKDIR /app +COPY editor/package*.json ./ +RUN npm install +COPY editor/ . +RUN npm run build + +# ----------------------------------------------------------------------------- +# Stage 4: Final runtime image +# ----------------------------------------------------------------------------- FROM alpine:3.19 # Container registry metadata LABEL org.opencontainers.image.source=https://github.com/worph/meta-core -LABEL org.opencontainers.image.description="MetaMesh meta-core sidecar - leader election, Redis management, HTTP API" +LABEL org.opencontainers.image.description="MetaMesh meta-core - centralized data layer with leader election, Redis, WebDAV, mounts" LABEL org.opencontainers.image.licenses=MIT # Install runtime dependencies RUN apk add --no-cache \ + # Core services redis \ + nginx \ + nginx-mod-http-dav-ext \ + supervisor \ + rclone \ + fuse3 \ + # Mount utilities + nfs-utils \ + cifs-utils \ + # Tools bash \ - ca-certificates + curl \ + python3 \ + ca-certificates \ + apache2-utils \ + # Process utilities + procps -# Create non-root user -RUN addgroup -S metacore && adduser -S metacore -G metacore - -# Copy binary from builder -COPY --from=builder /build/meta-core /usr/local/bin/meta-core - -# Set permissions +# Copy Go binary from builder +COPY --from=go-builder /build/meta-core /usr/local/bin/meta-core RUN chmod +x /usr/local/bin/meta-core # Create directories -RUN mkdir -p /meta-core/locks /meta-core/db/redis /meta-core/services && \ - chown -R metacore:metacore /meta-core +RUN mkdir -p \ + /meta-core/locks \ + /meta-core/db/redis \ + /meta-core/services \ + /meta-core/mounts/errors \ + /files \ + /app/dashboard/dist \ + /app/editor/dist \ + /var/log/supervisor \ + /var/run/supervisor \ + /etc/nginx/ssl -# Switch to non-root user -USER metacore +# Copy configuration files +COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY docker/nginx.conf /etc/nginx/nginx.conf +COPY docker/mount-watcher.sh /app/scripts/mount-watcher.sh +COPY docker/leader-election.sh /app/scripts/leader-election.sh +COPY docker/entrypoint.sh /entrypoint.sh + +# Copy dashboard static files from builder +COPY --from=dashboard-builder /app/dist /app/dashboard/dist + +# Copy editor static files from builder +COPY --from=editor-builder /app/dist /app/editor/dist + +# Set permissions +RUN chmod +x /app/scripts/mount-watcher.sh /app/scripts/leader-election.sh /entrypoint.sh + +# Create htpasswd for rclone basic auth (admin:admin) +RUN htpasswd -bc /etc/nginx/.htpasswd admin admin # Environment defaults ENV META_CORE_PATH=/meta-core \ FILES_PATH=/files \ SERVICE_NAME=meta-core \ + SERVICE_VERSION=1.0.0 \ META_CORE_HTTP_PORT=9000 \ - REDIS_PORT=6379 + META_CORE_HTTP_HOST=0.0.0.0 \ + REDIS_PORT=6379 \ + WATCH_INTERVAL_MS=1000 -# Expose HTTP API port -EXPOSE 9000 +# Expose ports +# 80: nginx (dashboard + API proxy + WebDAV) +# 6379: Redis (for other services) +EXPOSE 80 6379 # Health check -HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \ - CMD wget -q --spider http://localhost:9000/health || exit 1 +HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \ + CMD curl -sf http://localhost/health || exit 1 -# Run the binary -ENTRYPOINT ["/usr/local/bin/meta-core"] +ENTRYPOINT ["/entrypoint.sh"] +CMD ["/app/scripts/leader-election.sh"] diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 9d51679..0000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,147 +0,0 @@ -# ============================================================================= -# meta-core Standalone Container -# Multi-stage build for meta-core as a standalone service -# -# Includes: -# - Bash-based leader election script (flock on shared volume) -# - meta-core Go binary (HTTP API, Mount API, Watcher) -# - nginx (dashboard, WebDAV, API proxy) -# - Redis (managed by supervisord on leader) -# - rclone (remote mount daemon) -# - supervisord (process management - runs on leader only) -# -# Architecture: -# - leader-election.sh handles flock, starts supervisord on leader -# - Followers remain dormant, retry flock every 5s -# - Only leader runs Redis, meta-core, nginx, rclone, mount-watcher -# ============================================================================= - -# ----------------------------------------------------------------------------- -# Stage 1: Build Go binary -# ----------------------------------------------------------------------------- -FROM golang:1.21-alpine AS go-builder - -RUN apk add --no-cache git - -WORKDIR /build - -# Copy go mod files first for caching -COPY go.mod go.sum ./ - -# Copy source code -COPY . . - -# Download dependencies and update go.sum -RUN go mod tidy && go mod download - -# Build the binary -RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o meta-core ./cmd/meta-core - -# ----------------------------------------------------------------------------- -# Stage 2: Build Dashboard -# ----------------------------------------------------------------------------- -FROM node:21-alpine AS dashboard-builder -WORKDIR /app -COPY dashboard/package*.json ./ -RUN npm install -COPY dashboard/ . -RUN npm run build - -# ----------------------------------------------------------------------------- -# Stage 3: Build Metadata Editor (standalone) -# ----------------------------------------------------------------------------- -FROM node:21-alpine AS editor-builder -WORKDIR /app -COPY editor/package*.json ./ -RUN npm install -COPY editor/ . -RUN npm run build - -# ----------------------------------------------------------------------------- -# Stage 4: Final runtime image -# ----------------------------------------------------------------------------- -FROM alpine:3.19 - -# Container registry metadata -LABEL org.opencontainers.image.source=https://github.com/worph/meta-core -LABEL org.opencontainers.image.description="MetaMesh meta-core - centralized data layer with leader election, Redis, WebDAV, mounts" -LABEL org.opencontainers.image.licenses=MIT - -# Install runtime dependencies -RUN apk add --no-cache \ - # Core services - redis \ - nginx \ - nginx-mod-http-dav-ext \ - supervisor \ - rclone \ - fuse3 \ - # Mount utilities - nfs-utils \ - cifs-utils \ - # Tools - bash \ - curl \ - python3 \ - ca-certificates \ - apache2-utils \ - # Process utilities - procps - -# Copy Go binary from builder -COPY --from=go-builder /build/meta-core /usr/local/bin/meta-core -RUN chmod +x /usr/local/bin/meta-core - -# Create directories -RUN mkdir -p \ - /meta-core/locks \ - /meta-core/db/redis \ - /meta-core/services \ - /meta-core/mounts/errors \ - /files \ - /app/dashboard/dist \ - /app/editor/dist \ - /var/log/supervisor \ - /var/run/supervisor \ - /etc/nginx/ssl - -# Copy configuration files -COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY docker/nginx.conf /etc/nginx/nginx.conf -COPY docker/mount-watcher.sh /app/scripts/mount-watcher.sh -COPY docker/leader-election.sh /app/scripts/leader-election.sh -COPY docker/entrypoint.sh /entrypoint.sh - -# Copy dashboard static files from builder -COPY --from=dashboard-builder /app/dist /app/dashboard/dist - -# Copy editor static files from builder -COPY --from=editor-builder /app/dist /app/editor/dist - -# Set permissions -RUN chmod +x /app/scripts/mount-watcher.sh /app/scripts/leader-election.sh /entrypoint.sh - -# Create htpasswd for rclone basic auth (admin:admin) -RUN htpasswd -bc /etc/nginx/.htpasswd admin admin - -# Environment defaults -ENV META_CORE_PATH=/meta-core \ - FILES_PATH=/files \ - SERVICE_NAME=meta-core \ - SERVICE_VERSION=1.0.0 \ - META_CORE_HTTP_PORT=9000 \ - META_CORE_HTTP_HOST=0.0.0.0 \ - REDIS_PORT=6379 \ - WATCH_INTERVAL_MS=1000 - -# Expose ports -# 80: nginx (dashboard + API proxy + WebDAV) -# 6379: Redis (for other services) -EXPOSE 80 6379 - -# Health check -HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \ - CMD curl -sf http://localhost/health || exit 1 - -ENTRYPOINT ["/entrypoint.sh"] -CMD ["/app/scripts/leader-election.sh"]