CHORE(app): init

This commit is contained in:
2025-11-30 10:44:12 +09:00
commit b4ce36ba3b
19 changed files with 1123 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: jaejadle
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: jaejadle=ghcr.io/mayne0213/jaejadle
argocd-image-updater.argoproj.io/jaejadle.update-strategy: latest
argocd-image-updater.argoproj.io/write-back-method: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/Mayne0213/jaejadle.git
targetRevision: main
path: deploy/k8s/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: jaejadle
syncPolicy:
automated:
prune: true # 매니페스트에서 제거된 리소스 자동 삭제
selfHeal: true # 클러스터에서 수동 변경 시 자동 복구
allowEmpty: false
syncOptions:
- CreateNamespace=true # namespace가 없으면 자동 생성
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10

View File

@@ -0,0 +1,29 @@
# trunk-ignore-all(checkov/CKV_DOCKER_3)
FROM node:20-alpine AS base
# Install dependencies for development
RUN apk add --no-cache libc6-compat curl
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
# Install all dependencies (including dev dependencies)
RUN npm ci
# Copy source code
COPY . .
# Generate Prisma Client
RUN npx prisma generate
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# Default command (can be overridden in docker-compose)
CMD ["npm", "run", "dev"]

View File

@@ -0,0 +1,65 @@
# Multi-stage build for Next.js application
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json package-lock.json* ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Generate Prisma Client
# Build-time DATABASE_URL (not persisted in final image)
ARG DATABASE_URL="mysql://build:build@localhost:3306/build"
RUN npx prisma generate
# Build the application
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
RUN apk add --no-cache curl
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
# Copy built application
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next && chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Copy Prisma files
COPY --from=builder /app/prisma ./prisma
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]

View File

@@ -0,0 +1,64 @@
services:
# Next.js Application (Development) - Using External Database
app:
image: jaejadle-app-dev
build:
context: ../../services/nextjs
dockerfile: ../../deploy/docker/Dockerfile.dev
container_name: jaejadle-app-dev
restart: unless-stopped
labels:
kompose.namespace: jaejadle-dev
ports:
- "3004:3000"
env_file:
- ../../.env
environment:
- NODE_ENV=development
networks:
- jaejadle-network-dev
volumes:
- ../../services/nextjs:/app
- /app/node_modules
- /app/.next
- app_logs_dev:/app/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
command: >
sh -lc "npx prisma generate && npx prisma db push && npm run dev"
# Prisma Studio - Connects to External Database
prisma-studio:
image: jaejadle-app-dev
container_name: jaejadle-prisma-studio
restart: unless-stopped
labels:
kompose.namespace: jaejadle-dev
ports:
- "5557:5555"
env_file:
- ../../.env
environment:
- NODE_ENV=development
networks:
- jaejadle-network-dev
volumes:
- ../../services/nextjs:/app
- /app/node_modules
command: npx prisma studio --port 5555 --hostname 0.0.0.0
volumes:
# Named volumes for data persistence
app_logs_dev:
driver: local
networks:
jaejadle-network-dev:
driver: bridge
ipam:
config:
- subnet: 172.25.0.0/16

View File

@@ -0,0 +1,39 @@
services:
# Next.js Application - Using External Database
app:
image: jaejadle-app
build:
context: ../../services/nextjs
dockerfile: ../../deploy/docker/Dockerfile.prod
container_name: jaejadle-app
restart: unless-stopped
labels:
kompose.namespace: jaejadle
ports:
- 3004:3000
env_file:
- ../../.env
environment:
- NODE_ENV=production
networks:
- jaejadle-network
volumes:
- app_logs:/app/logs
healthcheck:
test: [CMD, curl, -f, http://localhost:3000/api/health]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes:
# Named volumes for data persistence
app_logs:
driver: local
networks:
jaejadle-network:
driver: bridge
ipam:
config:
- subnet: 172.24.0.0/16

View File

@@ -0,0 +1,86 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaejadle-app
labels:
app: jaejadle-app
spec:
replicas: 1
selector:
matchLabels:
app: jaejadle-app
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: jaejadle-app
spec:
containers:
- name: jaejadle-app
image: ghcr.io/mayne0213/jaejadle:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
protocol: TCP
env:
- name: NODE_ENV
value: production
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: jwt-secret
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: database-url
- name: AWS_REGION
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: aws-region
- name: AWS_S3_BUCKET_NAME
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: aws-s3-bucket-name
- name: AWS_S3_BUCKET_URL
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: aws-s3-bucket-url
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: jaejadle-secret
key: aws-secret-access-key
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "300m"
livenessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
restartPolicy: Always

View File

@@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app.kubernetes.io/name: jaejadle
app.kubernetes.io/component: web
images:
- name: ghcr.io/mayne0213/jaejadle
newTag: latest

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: jaejadle-service
labels:
app: jaejadle-app
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 3000
protocol: TCP
selector:
app: jaejadle-app

View File

@@ -0,0 +1,19 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaejadle-app
labels:
environment: production
spec:
replicas: 1
template:
spec:
containers:
- name: jaejadle-app
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "300m"

View File

@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: jaejadle
resources:
- ../../base
- resourcequota.yaml
commonLabels:
environment: production
# 이미지 태그 설정
images:
- name: ghcr.io/mayne0213/jaejadle
newTag: latest
patchesStrategicMerge:
- deployment-patch.yaml

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: ResourceQuota
metadata:
name: jaejadle-quota
namespace: jaejadle
spec:
hard:
requests.memory: "512Mi"
requests.cpu: "300m"
limits.memory: "1Gi"
limits.cpu: "600m"
pods: "3"