From 76bd7b4756e049a9bd35d0110f9c8963cfbbfddf Mon Sep 17 00:00:00 2001 From: kurihada Date: Wed, 25 Feb 2026 12:10:32 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E6=B7=BB=E5=8A=A0=20Docker=20+=20Jenkins?= =?UTF-8?q?=20=E8=87=AA=E5=8A=A8=E5=8C=96=E9=83=A8=E7=BD=B2=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dockerfile 多阶段构建,standalone 模式输出 - Jenkinsfile 定义 GitLab 触发的 CI/CD 流水线 - docker-compose.yml 简化部署 - next.config.ts 开启 standalone 输出 --- .dockerignore | 8 +++++ Dockerfile | 38 ++++++++++++++++++++++++ Jenkinsfile | 73 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 15 ++++++++++ next.config.ts | 1 + 5 files changed, 135 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Jenkinsfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bf31963 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +.next +.git +.gitignore +*.md +.env*.local +prisma/dev.db +prisma/dev.db-journal diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..513b917 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM node:20-alpine AS base + +# --- Dependencies --- +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci + +# --- Build --- +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npx prisma generate +RUN npm run build + +# --- Production --- +FROM base AS runner +WORKDIR /app +ENV NODE_ENV=production +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public +COPY --from=builder /app/prisma ./prisma + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +RUN mkdir -p /app/data && chown nextjs:nodejs /app/data + +USER nextjs +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["sh", "-c", "cp -n prisma/schema.prisma /app/data/ 2>/dev/null; npx prisma migrate deploy 2>/dev/null || npx prisma db push --skip-generate; node server.js"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..9766ac7 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,73 @@ +pipeline { + agent any + + environment { + APP_NAME = 'no-whatever' + DEPLOY_HOST = credentials('deploy-server-host') // 在 Jenkins 凭据中配置 + DEPLOY_USER = credentials('deploy-server-user') + } + + triggers { + gitlab(triggerOnPush: true, branchFilterType: 'All') + } + + stages { + stage('Checkout') { + steps { + checkout scm + } + } + + stage('Build Docker Image') { + steps { + script { + docker.build("${APP_NAME}:${BUILD_NUMBER}") + docker.build("${APP_NAME}:latest") + } + } + } + + stage('Deploy') { + steps { + script { + // 方案 A: Jenkins 和部署机是同一台服务器 + sh """ + docker stop ${APP_NAME} || true + docker rm ${APP_NAME} || true + docker run -d \ + --name ${APP_NAME} \ + -p 3000:3000 \ + -v ${APP_NAME}-data:/app/data \ + --restart unless-stopped \ + ${APP_NAME}:latest + """ + + // 方案 B: 部署到远程服务器 (取消注释并注释掉方案 A) + // sh """ + // docker save ${APP_NAME}:latest | \ + // ssh ${DEPLOY_USER}@${DEPLOY_HOST} 'docker load' + // ssh ${DEPLOY_USER}@${DEPLOY_HOST} << 'EOF' + // docker stop ${APP_NAME} || true + // docker rm ${APP_NAME} || true + // docker run -d \ + // --name ${APP_NAME} \ + // -p 3000:3000 \ + // -v ${APP_NAME}-data:/app/data \ + // --restart unless-stopped \ + // ${APP_NAME}:latest + // EOF + // """ + } + } + } + } + + post { + success { + echo "Deployed ${APP_NAME} build #${BUILD_NUMBER} successfully" + } + failure { + echo "Build #${BUILD_NUMBER} failed" + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..671e207 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + app: + build: . + image: no-whatever:latest + container_name: no-whatever + ports: + - "3000:3000" + volumes: + - app-data:/app/data + environment: + - DATABASE_URL=file:/app/data/dev.db + restart: unless-stopped + +volumes: + app-data: diff --git a/next.config.ts b/next.config.ts index a9194aa..4ff14d0 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,6 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { + output: "standalone", images: { remotePatterns: [ {