فهرست منبع

build: 添加多阶段 Docker 镜像与数据目录守卫

wangkangyjy 1 روز پیش
والد
کامیت
a78846aec7
4فایلهای تغییر یافته به همراه135 افزوده شده و 0 حذف شده
  1. 25 0
      .dockerignore
  2. 41 0
      Dockerfile
  3. 25 0
      docker/entrypoint.sh
  4. 44 0
      scripts/test-docker-config.sh

+ 25 - 0
.dockerignore

@@ -0,0 +1,25 @@
+.git/
+.github/
+.idea/
+.vscode/
+.codex/
+.reasonix/
+.superpowers/
+
+data/
+backend/data/
+**/*.db
+**/*.db-shm
+**/*.db-wal
+**/*.sqlite
+**/*.sqlite-shm
+**/*.sqlite-wal
+
+**/target/
+**/node_modules/
+frontend/dist/
+
+docs/audit/
+*.log
+*.tmp
+.env

+ 41 - 0
Dockerfile

@@ -0,0 +1,41 @@
+# syntax=docker/dockerfile:1
+
+FROM node:20-bookworm-slim AS frontend-build
+WORKDIR /build/frontend
+COPY frontend/package.json frontend/package-lock.json ./
+RUN npm ci
+COPY frontend/ ./
+RUN npm run build
+
+FROM maven:3.9.9-eclipse-temurin-17 AS backend-build
+WORKDIR /build/backend
+COPY backend/pom.xml ./
+RUN mvn -B dependency:go-offline
+COPY backend/src ./src
+RUN rm -rf src/main/resources/static && mkdir -p src/main/resources/static
+COPY --from=frontend-build /build/frontend/dist ./src/main/resources/static
+RUN mvn -B clean package -DskipTests
+
+FROM eclipse-temurin:17-jre-jammy
+WORKDIR /app
+
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends curl \
+    && rm -rf /var/lib/apt/lists/*
+
+COPY docker/entrypoint.sh /app/entrypoint.sh
+COPY --from=backend-build /build/backend/target/okr-performance-1.0.0.jar /app/okr-performance.jar
+RUN chmod +x /app/entrypoint.sh
+
+ENV APP_DATA_DIR=/app/data \
+    APP_BACKUP_DIR=/app/data/backups \
+    SPRING_DATASOURCE_URL=jdbc:sqlite:/app/data/okr-performance.db
+
+EXPOSE 18080
+VOLUME ["/app/data"]
+
+HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=5 \
+  CMD curl --fail --silent http://127.0.0.1:18080/ >/dev/null || exit 1
+
+ENTRYPOINT ["/app/entrypoint.sh"]
+CMD ["java", "-jar", "/app/okr-performance.jar"]

+ 25 - 0
docker/entrypoint.sh

@@ -0,0 +1,25 @@
+#!/bin/sh
+set -eu
+
+DATA_DIR=${APP_DATA_DIR:-/app/data}
+BACKUP_DIR=${APP_BACKUP_DIR:-$DATA_DIR/backups}
+DATABASE_FILE=${APP_DATABASE_FILE:-$DATA_DIR/okr-performance.db}
+
+umask 027
+mkdir -p "$DATA_DIR" "$BACKUP_DIR"
+
+WRITE_PROBE="$DATA_DIR/.write-probe-$$"
+if ! touch "$WRITE_PROBE" 2>/dev/null; then
+  echo "错误:数据库目录不可写:$DATA_DIR" >&2
+  echo "请确认宿主机目录存在且 Docker 对其拥有写权限。" >&2
+  exit 1
+fi
+rm -f "$WRITE_PROBE"
+
+if [ -f "$DATABASE_FILE" ]; then
+  echo "使用现有 SQLite 数据库:$DATABASE_FILE"
+else
+  echo "未发现 SQLite 数据库,将由应用执行首次初始化:$DATABASE_FILE"
+fi
+
+exec "$@"

+ 44 - 0
scripts/test-docker-config.sh

@@ -0,0 +1,44 @@
+#!/bin/sh
+set -eu
+
+ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+cd "$ROOT_DIR"
+
+assert_file() {
+  if [ ! -f "$1" ]; then
+    echo "缺少文件: $1" >&2
+    exit 1
+  fi
+}
+
+assert_contains() {
+  file=$1
+  expected=$2
+  if ! grep -Fq -- "$expected" "$file"; then
+    echo "$file 缺少配置: $expected" >&2
+    exit 1
+  fi
+}
+
+assert_file Dockerfile
+assert_file compose.yaml
+assert_file docker/entrypoint.sh
+assert_file .dockerignore
+
+assert_contains Dockerfile "FROM node:20"
+assert_contains Dockerfile "FROM maven:3.9"
+assert_contains Dockerfile "COPY --from=frontend-build /build/frontend/dist"
+assert_contains Dockerfile 'ENTRYPOINT ["/app/entrypoint.sh"]'
+
+assert_contains compose.yaml "./data:/app/data"
+assert_contains compose.yaml "SPRING_DATASOURCE_URL: jdbc:sqlite:/app/data/okr-performance.db"
+assert_contains compose.yaml "APP_BACKUP_DIR: /app/data/backups"
+
+assert_contains docker/entrypoint.sh 'mkdir -p "$DATA_DIR" "$BACKUP_DIR"'
+assert_contains docker/entrypoint.sh '数据库目录不可写'
+
+assert_contains .dockerignore "data/"
+assert_contains .dockerignore "**/target/"
+assert_contains .dockerignore "**/node_modules/"
+
+echo "Docker 配置契约检查通过"