From c45e58c73291e7e357504a3d0c94628e434e5b1c Mon Sep 17 00:00:00 2001 From: suphicakir Date: Thu, 5 Nov 2026 01:08:10 +0300 Subject: [PATCH] =?UTF-8?q?chore(docker):=20lokal=20MongoDB=20replica=20se?= =?UTF-8?q?t=20ve=20=C3=BCretim=20Dockerfile'=C4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .dockerignore | 24 +++++++++++++++++++++ Dockerfile | 54 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 39 +++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c3b48fc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +# Bağımlılıklar ve build çıktıları imaj içinde yeniden üretilir +node_modules +.next +out +coverage +*.tsbuildinfo +next-env.d.ts + +# Sırlar ve kullanıcı verisi asla imaja girmez +.env* +!.env.example +uploads + +# Geliştirme araçları +.git +.gitignore +.vscode +.claude +docker-compose.yml +Dockerfile +.dockerignore +*.md +!README.md +npm-debug.log* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..61b686e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# syntax=docker/dockerfile:1 +# BÜTÇEM — çok aşamalı üretim imajı (Next.js standalone çıktı). +# Build: docker build --build-arg APP_COMMIT=$(git rev-parse --short HEAD) -t butcem . +# Çalıştır: docker run -p 3000:3000 --env-file .env.production -v butcem-uploads:/app/uploads butcem + +ARG NODE_VERSION=26 + +# 1) Bağımlılıklar — yalnızca lock dosyası değişince yeniden çalışır. +FROM node:${NODE_VERSION}-alpine AS deps +WORKDIR /app +RUN apk add --no-cache libc6-compat +COPY package.json package-lock.json ./ +RUN npm ci --no-audit --no-fund + +# 2) Build +FROM node:${NODE_VERSION}-alpine AS builder +WORKDIR /app +ARG APP_VERSION="" +ARG APP_COMMIT="unknown" +ENV NEXT_TELEMETRY_DISABLED=1 \ + APP_VERSION=${APP_VERSION} \ + APP_COMMIT=${APP_COMMIT} +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm run build + +# 3) Çalışma zamanı — yalnızca standalone çıktı, root olmayan kullanıcı. +FROM node:${NODE_VERSION}-alpine AS runner +WORKDIR /app +ARG APP_VERSION="" +ARG APP_COMMIT="unknown" +ENV NODE_ENV=production \ + NEXT_TELEMETRY_DISABLED=1 \ + PORT=3000 \ + HOSTNAME=0.0.0.0 \ + UPLOAD_DIR=/app/uploads \ + APP_VERSION=${APP_VERSION} \ + APP_COMMIT=${APP_COMMIT} + +RUN addgroup -S -g 1001 nodejs && adduser -S -u 1001 -G nodejs nextjs \ + && mkdir -p /app/uploads && chown nextjs:nodejs /app/uploads + +COPY --from=builder --chown=nextjs:nodejs /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs +VOLUME ["/app/uploads"] +EXPOSE 3000 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ + CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||3000)+'/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e166893 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +# Lokal geliştirme: MongoDB tek düğümlü replica set (rs0) — transaction için zorunlu. +# Başlat: npm run db:up Durdur: npm run db:down Veriyi sil: docker compose down -v +name: butcem + +services: + mongo: + image: mongo:9 + container_name: butcem-mongo + command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--port", "27017"] + ports: + # Yalnızca bu makineden erişilebilir. Host portu 27019 (27017/27018 bu makinede dolu); + # değiştirmek için: BUTCEM_MONGO_PORT=xxxxx npm run db:up + - "127.0.0.1:${BUTCEM_MONGO_PORT:-27019}:27017" + volumes: + - mongo-data:/data/db + - mongo-config:/data/configdb + restart: unless-stopped + # Healthcheck replica set'i ilk çalıştırmada başlatır; düğüm PRIMARY olana kadar "unhealthy" kalır. + # Üye adresi konteyner içinden "localhost:27017"; uygulama host'tan directConnection=true ile + # bağlandığı için üye listesini kullanmaz, port eşlemesi sorun olmaz. + healthcheck: + test: + - CMD + - mongosh + - --quiet + - --eval + - >- + try { rs.status() } catch (e) { + rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] }) } + if (!db.hello().isWritablePrimary) { quit(1) } + interval: 5s + timeout: 10s + start_period: 20s + start_interval: 2s + retries: 30 + +volumes: + mongo-data: + mongo-config: