From ab95e35ea4f5c32723f5b36ef228df07d69142d1 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 20:53:34 +0900 Subject: [PATCH 01/15] add production deployment manifests --- deploy/overlays/production/deployment.yaml | 65 +++++++++++++++++++ .../overlays/production/external-secret.yaml | 16 +++++ deploy/overlays/production/ingress.yaml | 29 +++++++++ deploy/overlays/production/kustomization.yaml | 12 ++++ deploy/overlays/production/namespace.yaml | 7 ++ deploy/overlays/production/secret-store.yaml | 16 +++++ deploy/overlays/production/service.yaml | 17 +++++ 7 files changed, 162 insertions(+) create mode 100644 deploy/overlays/production/deployment.yaml create mode 100644 deploy/overlays/production/external-secret.yaml create mode 100644 deploy/overlays/production/ingress.yaml create mode 100644 deploy/overlays/production/kustomization.yaml create mode 100644 deploy/overlays/production/namespace.yaml create mode 100644 deploy/overlays/production/secret-store.yaml create mode 100644 deploy/overlays/production/service.yaml diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml new file mode 100644 index 0000000..41d5d7b --- /dev/null +++ b/deploy/overlays/production/deployment.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: profanity-api + namespace: profanity-production + labels: + app: profanity-api + environment: production +spec: + replicas: 2 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + selector: + matchLabels: + app: profanity-api + template: + metadata: + labels: + app: profanity-api + environment: production + spec: + containers: + - name: profanity-api + image: ghcr.io/whale0928/profanity-api:main-SHA + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: SERVER_PORT + value: "8080" + - name: ACTUATOR_PATH + value: "/health" + - name: SPRING_PROFILES_ACTIVE + value: "prod" + envFrom: + - secretRef: + name: profanity-secrets + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "250m" + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 diff --git a/deploy/overlays/production/external-secret.yaml b/deploy/overlays/production/external-secret.yaml new file mode 100644 index 0000000..053e03e --- /dev/null +++ b/deploy/overlays/production/external-secret.yaml @@ -0,0 +1,16 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: profanity-secrets + namespace: profanity-production +spec: + refreshInterval: 1h + secretStoreRef: + name: onepassword-store + kind: SecretStore + target: + name: profanity-secrets + creationPolicy: Owner + dataFrom: + - extract: + key: profanity-api-production diff --git a/deploy/overlays/production/ingress.yaml b/deploy/overlays/production/ingress.yaml new file mode 100644 index 0000000..717b190 --- /dev/null +++ b/deploy/overlays/production/ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: profanity-api + namespace: profanity-production + labels: + app: profanity-api + environment: production + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" +spec: + ingressClassName: nginx + tls: + - hosts: + - api-profanity.kr-filter.com + secretName: profanity-api-tls + rules: + - host: api-profanity.kr-filter.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: profanity-api + port: + number: 80 diff --git a/deploy/overlays/production/kustomization.yaml b/deploy/overlays/production/kustomization.yaml new file mode 100644 index 0000000..8b33fc8 --- /dev/null +++ b/deploy/overlays/production/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: profanity-production + +resources: + - namespace.yaml + - deployment.yaml + - service.yaml + - ingress.yaml + - secret-store.yaml + - external-secret.yaml diff --git a/deploy/overlays/production/namespace.yaml b/deploy/overlays/production/namespace.yaml new file mode 100644 index 0000000..0118bb9 --- /dev/null +++ b/deploy/overlays/production/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: profanity-production + labels: + app: profanity-api + environment: production diff --git a/deploy/overlays/production/secret-store.yaml b/deploy/overlays/production/secret-store.yaml new file mode 100644 index 0000000..cc155c9 --- /dev/null +++ b/deploy/overlays/production/secret-store.yaml @@ -0,0 +1,16 @@ +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: onepassword-store + namespace: profanity-production +spec: + provider: + onepassword: + connectHost: http://onepassword-connect.external-secrets-system.svc.cluster.local:8080 + vaults: + profanity: 1 + auth: + secretRef: + connectTokenSecretRef: + name: op-token + key: token diff --git a/deploy/overlays/production/service.yaml b/deploy/overlays/production/service.yaml new file mode 100644 index 0000000..0d36ea3 --- /dev/null +++ b/deploy/overlays/production/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: profanity-api + namespace: profanity-production + labels: + app: profanity-api + environment: production +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: 8080 + protocol: TCP + selector: + app: profanity-api From b37b4d90238dab97756daad424c99c057d1336c5 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 20:56:55 +0900 Subject: [PATCH 02/15] add argocd application manifest --- deploy/application.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 deploy/application.yaml diff --git a/deploy/application.yaml b/deploy/application.yaml new file mode 100644 index 0000000..3a3a0dc --- /dev/null +++ b/deploy/application.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: profanity-production + namespace: argocd +spec: + project: default + source: + repoURL: https://github.com/Whale0928/profanity-filter-api + path: deploy/overlays/production + targetRevision: deploy + destination: + server: https://kubernetes.default.svc + namespace: profanity-production + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true From 963767e866831846251361471cf2858b5176f479 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 21:04:14 +0900 Subject: [PATCH 03/15] rename argocd application to profanity-filter --- deploy/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/application.yaml b/deploy/application.yaml index 3a3a0dc..c766bc9 100644 --- a/deploy/application.yaml +++ b/deploy/application.yaml @@ -1,7 +1,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: profanity-production + name: profanity-filter namespace: argocd spec: project: default From 071f89c0216517debc7848c4b2a739852a551b5a Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 21:06:51 +0900 Subject: [PATCH 04/15] fix external-secrets api version to v1 --- deploy/overlays/production/external-secret.yaml | 2 +- deploy/overlays/production/secret-store.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/overlays/production/external-secret.yaml b/deploy/overlays/production/external-secret.yaml index 053e03e..f516780 100644 --- a/deploy/overlays/production/external-secret.yaml +++ b/deploy/overlays/production/external-secret.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: profanity-secrets diff --git a/deploy/overlays/production/secret-store.yaml b/deploy/overlays/production/secret-store.yaml index cc155c9..e982571 100644 --- a/deploy/overlays/production/secret-store.yaml +++ b/deploy/overlays/production/secret-store.yaml @@ -1,4 +1,4 @@ -apiVersion: external-secrets.io/v1beta1 +apiVersion: external-secrets.io/v1 kind: SecretStore metadata: name: onepassword-store From 877aa7d8278644c105705efd7a0b04e69bf6dfc5 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 21:25:25 +0900 Subject: [PATCH 05/15] fix vault name to profanity-filter --- deploy/overlays/production/secret-store.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/overlays/production/secret-store.yaml b/deploy/overlays/production/secret-store.yaml index e982571..4d0447f 100644 --- a/deploy/overlays/production/secret-store.yaml +++ b/deploy/overlays/production/secret-store.yaml @@ -8,7 +8,7 @@ spec: onepassword: connectHost: http://onepassword-connect.external-secrets-system.svc.cluster.local:8080 vaults: - profanity: 1 + profanity-filter: 1 auth: secretRef: connectTokenSecretRef: From 60f3909cd4e05ed09f031d56b8c65da3f2a0a063 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 21:47:04 +0900 Subject: [PATCH 06/15] update image tag to deploy-877aa7d --- deploy/overlays/production/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml index 41d5d7b..accd966 100644 --- a/deploy/overlays/production/deployment.yaml +++ b/deploy/overlays/production/deployment.yaml @@ -24,7 +24,7 @@ spec: spec: containers: - name: profanity-api - image: ghcr.io/whale0928/profanity-api:main-SHA + image: ghcr.io/whale0928/profanity-api:deploy-877aa7d imagePullPolicy: Always ports: - name: http From e317a26829c53e8b582c008ec6c21c9f32bd49d0 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 21:58:20 +0900 Subject: [PATCH 07/15] feat: add imagePullSecrets for GHCR authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GHCR 이미지를 pull하기 위한 imagePullSecrets 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- deploy/overlays/production/deployment.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml index accd966..ea99122 100644 --- a/deploy/overlays/production/deployment.yaml +++ b/deploy/overlays/production/deployment.yaml @@ -22,6 +22,8 @@ spec: app: profanity-api environment: production spec: + imagePullSecrets: + - name: ghcr-secret containers: - name: profanity-api image: ghcr.io/whale0928/profanity-api:deploy-877aa7d From cbfee0074f3d7ce86d34f758ad677d6ce96cfe66 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 22:07:45 +0900 Subject: [PATCH 08/15] fix: increase health check initialDelaySeconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 애플리케이션 시작 시간이 100초 이상 소요되어 health check 타임아웃 발생 - livenessProbe initialDelaySeconds: 60 -> 120 - readinessProbe initialDelaySeconds: 30 -> 90 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- deploy/overlays/production/deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml index ea99122..281f961 100644 --- a/deploy/overlays/production/deployment.yaml +++ b/deploy/overlays/production/deployment.yaml @@ -53,7 +53,7 @@ spec: httpGet: path: /health port: 8080 - initialDelaySeconds: 60 + initialDelaySeconds: 120 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 @@ -61,7 +61,7 @@ spec: httpGet: path: /health port: 8080 - initialDelaySeconds: 30 + initialDelaySeconds: 90 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 From 9fa371235342a0da7590fb0ce7b154553ef0e4d7 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 22:12:14 +0900 Subject: [PATCH 09/15] deps: version sync --- module.platform | 2 +- module.secrets | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module.platform b/module.platform index 00dfc41..686fd99 160000 --- a/module.platform +++ b/module.platform @@ -1 +1 @@ -Subproject commit 00dfc418b570b365fe8e5dacd608e9ec813f041c +Subproject commit 686fd99e86c4f835ef23623ae5c3dd81edabe94d diff --git a/module.secrets b/module.secrets index 2fc25db..9fed138 160000 --- a/module.secrets +++ b/module.secrets @@ -1 +1 @@ -Subproject commit 2fc25db8b6d8acc55af4b81dbc817bee998a8ffb +Subproject commit 9fed138ab832382a30fb205222587459f0c05f81 From 15f0113c958e64121d637ef18f787379fa50985c Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 22:54:50 +0900 Subject: [PATCH 10/15] feat: document k3s migration completion and deployment status --- plan/2025.11.21-k3s-migration.md | 212 ++++++++++++++++++++++++------- 1 file changed, 167 insertions(+), 45 deletions(-) diff --git a/plan/2025.11.21-k3s-migration.md b/plan/2025.11.21-k3s-migration.md index d4ca986..6b44b62 100644 --- a/plan/2025.11.21-k3s-migration.md +++ b/plan/2025.11.21-k3s-migration.md @@ -1,3 +1,14 @@ +``` +╔══════════════════════════════════════════════════════════════╗ +║ ║ +║ ✅ k3s 마이그레이션 완료 ║ +║ ║ +║ 완료일: 2025.11.21 ║ +║ 상태: 운영 환경 배포 완료 및 정상 작동 확인 ║ +║ ║ +╚══════════════════════════════════════════════════════════════╝ +``` + # k3s 마이그레이션 계획 ## 개요 @@ -13,6 +24,8 @@ - 모노레포: 애플리케이션 코드 + K8s 매니페스트 - 이유: 코드와 배포 설정의 버전을 함께 관리하여 일관성 유지 - 위치: `deploy/overlays/production/` +- 브랜치 전략: `deploy` 브랜치를 ArgoCD가 추적 + - 이유: main 브랜치와 분리하여 배포 설정 변경 관리 - 플랫폼: `module.platform` 서브모듈 (https://github.com/Whale0928/k8s-platform.git) - 이유: 공통 인프라를 서브모듈로 참조하여 bottlenote와 일관성 유지 @@ -20,44 +33,52 @@ - ghcr.io 사용 (ECR 불필요) - 이유: 무료, GitHub Actions 통합 용이, 토큰 갱신 불필요 (bottlenote의 ECR CronJob 제거) -- 이미지: `ghcr.io/whale0928/profanity-api:main-SHA` +- 이미지: `ghcr.io/whale0928/profanity-api:deploy-SHA` +- imagePullSecrets: `ghcr-secret` (GHCR 인증용) ### 3. 비밀 관리 - External Secrets Operator + 1Password Connect - 이유: bottlenote의 AWS Secrets Manager 대신 1Password 사용, 플랫폼 공통 컴포넌트로 관리 - 1Password Connect는 platform에 배포 (`platform/external-secrets/onepassword-connect/`) +- 자동 동기화: 1시간마다 1Password vault에서 Kubernetes Secret으로 동기화 - 주의: credentials, token은 절대 Git 커밋 금지 (공개 레포) ### 4. 배포 -- ArgoCD GitOps + Webhook - - 이유: Image Updater 대신 webhook 사용으로 즉각 반응, 경량화 -- GitHub Actions에서 이미지 태그 업데이트 후 ArgoCD webhook 호출 +- ArgoCD GitOps + 자동 동기화 + - 자동 동기화 활성화: `prune: true`, `selfHeal: true` + - Git 폴링 주기: 3분마다 + - Webhook: 선택사항 (더 빠른 배포를 원할 경우) +- GitHub Actions에서 이미지 태그 업데이트 후 deploy 브랜치에 push - 네임스페이스: `profanity-production` - 리소스: 512Mi/250m, 레플리카 2 - 이유: bottlenote(768Mi/500m)보다 경량화 +- Health Check: + - livenessProbe: initialDelaySeconds 120초 (애플리케이션 시작 시간 고려) + - readinessProbe: initialDelaySeconds 90초 - 도메인: `api-profanity.kr-filter.com` - - 테스트 완료 후 기존 도메인으로 변경 ## 디렉토리 구조 ``` profanity-filter-api/ -└── deploy/overlays/production/ - ├── namespace.yaml - ├── deployment.yaml - ├── service.yaml - ├── ingress.yaml (cert-manager TLS) - ├── secret-store.yaml (1Password Connect 참조) - └── external-secret.yaml (1Password vault 참조) - -module.platform/ (서브모듈 - 추가할 항목) -├── argocd/ -│ └── webhook-config.yaml (ArgoCD webhook 설정) +├── deploy/ +│ ├── application.yaml (ArgoCD Application 정의) +│ └── overlays/production/ +│ ├── kustomization.yaml +│ ├── namespace.yaml +│ ├── deployment.yaml (imagePullSecrets 포함) +│ ├── service.yaml +│ ├── ingress.yaml (cert-manager TLS) +│ ├── secret-store.yaml (1Password Connect 참조) +│ └── external-secret.yaml (1Password vault 참조) + +module.platform/ (서브모듈) +├── argocd/ (기존 활용) └── platform/ └── external-secrets/ - └── onepassword-connect/ + └── onepassword-connect/ (기존 활용) ├── namespace.yaml (external-secrets-system) ├── deployment.yaml ├── service.yaml @@ -66,14 +87,21 @@ module.platform/ (서브모듈 - 추가할 항목) ## 배포 흐름 +### 현재 (수동 배포) +1. 로컬에서 Docker 이미지 빌드 +2. ghcr.io에 이미지 푸시 (태그: deploy-SHA) +3. `deploy/overlays/production/deployment.yaml` 이미지 태그 수동 업데이트 +4. Git commit & push to deploy 브랜치 +5. ArgoCD 자동 감지 및 배포 (최대 3분 이내) + +### 향후 (자동화 예정) 1. 개발자 커밋 (main 브랜치) 2. GitHub Actions 자동 실행: - 빌드 및 테스트 - - ghcr.io에 이미지 푸시 (태그: main-SHA) - - deployment.yaml 이미지 태그 업데이트 (sed) - - Git commit & push (매니페스트 변경) - - ArgoCD webhook 호출 (즉시 배포 트리거) -3. ArgoCD: Git 변경 감지 후 즉시 sync 및 배포 (Rolling Update) + - ghcr.io에 이미지 푸시 (태그: deploy-SHA) + - deployment.yaml 이미지 태그 업데이트 + - Git commit & push to deploy 브랜치 +3. ArgoCD: Git 변경 감지 후 자동 sync 및 배포 (Rolling Update) ## 환경변수 @@ -88,37 +116,48 @@ module.platform/ (서브모듈 - 추가할 항목) - 1password-credentials.json - Connect token - 모든 패스워드, API 키 +- GitHub Personal Access Token -### 수동 생성 (kubectl) +### 수동 생성 (kubectl) - 1회성 작업 ```bash -# 1Password Connect credentials -kubectl create secret generic onepassword-credentials \ - --from-file=credentials.json \ +# 1Password Connect token (external-secrets-system에 생성) +kubectl create secret generic op-token \ + --from-literal=token= \ -n external-secrets-system -# Connect token -kubectl create secret generic op-token \ - --from-literal=token=TOKEN \ +# GHCR imagePullSecret (profanity-production에 생성) +kubectl create secret docker-registry ghcr-secret \ + --docker-server=ghcr.io \ + --docker-username= \ + --docker-password= \ -n profanity-production ``` +### 자동 관리되는 Secret + +```bash +# profanity-secrets (ExternalSecret이 1시간마다 동기화) +# 1Password vault: profanity-filter > profanity-api-production +kubectl get secret profanity-secrets -n profanity-production +``` + ## GitHub Actions -### 필요한 Secrets +### 필요한 Secrets (향후 설정) - GHCR_TOKEN: ghcr.io 푸시 권한 -- ARGOCD_TOKEN: ArgoCD API 토큰 (webhook 호출용) -- ARGOCD_SERVER: ArgoCD 서버 주소 +- (선택) ARGOCD_TOKEN: ArgoCD API 토큰 (webhook 호출용) +- (선택) ARGOCD_SERVER: ArgoCD 서버 주소 -### 워크플로우 +### 워크플로우 (향후 구현) - 트리거: push to main - 빌드 및 테스트 - 이미지 빌드 및 ghcr.io 푸시 -- deployment.yaml 이미지 태그 업데이트 (sed) -- Git commit & push -- ArgoCD webhook 호출 (curl) +- deployment.yaml 이미지 태그 업데이트 +- Git commit & push to deploy 브랜치 +- ArgoCD 자동 감지 및 배포 ## Platform 인프라 @@ -129,16 +168,99 @@ k8s-platform의 공통 인프라를 활용하여 별도 설치 불필요: - cert-manager: Let's Encrypt SSL 자동 발급 및 갱신 - monitoring: Prometheus metrics 자동 수집 - ArgoCD: GitOps 기반 배포 관리 +- External Secrets Operator: 1Password Connect 연동 +- 1Password Connect: Secret 관리 + +--- + +## 최종 배포 상태 + +### 배포 일시 +- 2025.11.21 + +### Namespace +``` +✅ profanity-production (생성 완료) +``` + +### ArgoCD Application +``` +NAME: profanity-filter +STATUS: Synced ✅ +HEALTH: Healthy ✅ +TARGET REVISION: deploy 브랜치 +SYNC POLICY: Automated (prune: true, selfHeal: true) +``` + +### Deployment +``` +NAME: profanity-api +REPLICAS: 2/2 (Ready) +IMAGE: ghcr.io/whale0928/profanity-api:deploy-877aa7d +RESOURCES: + - CPU: 250m (requests/limits) + - Memory: 512Mi (requests/limits) +HEALTH CHECKS: + - livenessProbe: /health (initialDelaySeconds: 120s) + - readinessProbe: /health (initialDelaySeconds: 90s) +``` + +### Pods +``` +NAME READY STATUS RESTARTS AGE +profanity-api-77bf8d6485-27499 1/1 Running 0 정상 작동 +profanity-api-77bf8d6485-w45xb 1/1 Running 0 정상 작동 +``` + +### Service +``` +NAME: profanity-api +TYPE: ClusterIP +PORT: 80/TCP +``` + +### Ingress +``` +HOST: api-profanity.kr-filter.com +TLS: cert-manager 자동 관리 +HTTPS: ✅ 정상 작동 +``` + +### Secrets +``` +✅ ghcr-secret (imagePullSecrets) - 수동 관리 +✅ profanity-secrets (애플리케이션 환경변수) - ExternalSecret 자동 관리 +✅ profanity-api-tls (HTTPS 인증서) - cert-manager 자동 관리 +✅ op-token (1Password Connect) - 수동 관리 +``` + +### External Secrets +``` +NAME: profanity-secrets +STATUS: SecretSynced ✅ +READY: True ✅ +REFRESH INTERVAL: 1시간 +SOURCE: 1Password vault (profanity-filter > profanity-api-production) +``` + +### 1Password Connect +``` +NAMESPACE: external-secrets-system +POD: onepassword-connect +STATUS: 2/2 Running ✅ +``` + +--- -### 추가 필요 (platform 레포에 등록) +## 다음 단계 -profanity 프로젝트를 위해 platform에 추가할 컴포넌트: +### 자동화 구현 필요 +- [ ] GitHub Actions workflow 생성 (이미지 빌드 + 배포 자동화) +- [ ] ArgoCD Webhook 설정 (즉시 배포) -1. 1Password Connect (`platform/external-secrets/onepassword-connect/`) - - 1Password vault와 K8s 연동을 위한 Connect 서버 - - Deployment, Service 매니페스트 - - credentials Secret은 수동 생성 (Git 제외) +### 모니터링 +- [ ] Prometheus metrics 확인 +- [ ] Grafana 대시보드 설정 -2. ArgoCD Webhook 설정 (`argocd/webhook-config.yaml`) - - GitHub Actions에서 배포 트리거용 - - API Token 생성 및 webhook endpoint 구성 +### 도메인 전환 +- [ ] 테스트 완료 후 기존 도메인으로 변경 From aa4d2008205cf08416f8e96b0c89e4956ca271e9 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 23:15:40 +0900 Subject: [PATCH 11/15] fix: update external-secret to use multiple sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 두 개의 1Password 항목에서 필드를 병합 - secret-source (DATABASE) - database-source (DATABASE) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- deploy/overlays/production/external-secret.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deploy/overlays/production/external-secret.yaml b/deploy/overlays/production/external-secret.yaml index f516780..3a1877f 100644 --- a/deploy/overlays/production/external-secret.yaml +++ b/deploy/overlays/production/external-secret.yaml @@ -13,4 +13,6 @@ spec: creationPolicy: Owner dataFrom: - extract: - key: profanity-api-production + key: secret-source + - extract: + key: database-source From 41e5c0f48ef623c52b53189635570ec9ee755e7b Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 23:25:58 +0900 Subject: [PATCH 12/15] fix: adjust indentation and add nodeSelector for ARM64 architecture --- deploy/overlays/production/deployment.yaml | 84 +++++++++++----------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml index 281f961..1946c62 100644 --- a/deploy/overlays/production/deployment.yaml +++ b/deploy/overlays/production/deployment.yaml @@ -23,45 +23,47 @@ spec: environment: production spec: imagePullSecrets: - - name: ghcr-secret + - name: ghcr-secret + nodeSelector: + kubernetes.io/arch: arm64 containers: - - name: profanity-api - image: ghcr.io/whale0928/profanity-api:deploy-877aa7d - imagePullPolicy: Always - ports: - - name: http - containerPort: 8080 - protocol: TCP - env: - - name: SERVER_PORT - value: "8080" - - name: ACTUATOR_PATH - value: "/health" - - name: SPRING_PROFILES_ACTIVE - value: "prod" - envFrom: - - secretRef: - name: profanity-secrets - resources: - requests: - memory: "512Mi" - cpu: "250m" - limits: - memory: "512Mi" - cpu: "250m" - livenessProbe: - httpGet: - path: /health - port: 8080 - initialDelaySeconds: 120 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - httpGet: - path: /health - port: 8080 - initialDelaySeconds: 90 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 3 + - name: profanity-api + image: ghcr.io/whale0928/profanity-api:deploy-877aa7d + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: SERVER_PORT + value: "8080" + - name: ACTUATOR_PATH + value: "/health" + - name: SPRING_PROFILES_ACTIVE + value: "prod" + envFrom: + - secretRef: + name: profanity-secrets + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "250m" + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 90 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 From c59ab7eb7adf137f7bc174fc3bd94dce0bc44a12 Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 23:58:16 +0900 Subject: [PATCH 13/15] feat: restructure kustomization and add resources.yaml for profanity API deployment --- deploy/overlays/production/ingress.yaml | 29 -------- deploy/overlays/production/kustomization.yaml | 5 +- deploy/overlays/production/namespace.yaml | 7 -- deploy/overlays/production/resources.yaml | 72 +++++++++++++++++++ deploy/overlays/production/secret-store.yaml | 16 ----- deploy/overlays/production/service.yaml | 17 ----- 6 files changed, 73 insertions(+), 73 deletions(-) delete mode 100644 deploy/overlays/production/ingress.yaml delete mode 100644 deploy/overlays/production/namespace.yaml create mode 100644 deploy/overlays/production/resources.yaml delete mode 100644 deploy/overlays/production/secret-store.yaml delete mode 100644 deploy/overlays/production/service.yaml diff --git a/deploy/overlays/production/ingress.yaml b/deploy/overlays/production/ingress.yaml deleted file mode 100644 index 717b190..0000000 --- a/deploy/overlays/production/ingress.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: profanity-api - namespace: profanity-production - labels: - app: profanity-api - environment: production - annotations: - cert-manager.io/cluster-issuer: "letsencrypt-prod" - nginx.ingress.kubernetes.io/ssl-redirect: "true" - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" -spec: - ingressClassName: nginx - tls: - - hosts: - - api-profanity.kr-filter.com - secretName: profanity-api-tls - rules: - - host: api-profanity.kr-filter.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: profanity-api - port: - number: 80 diff --git a/deploy/overlays/production/kustomization.yaml b/deploy/overlays/production/kustomization.yaml index 8b33fc8..5d9274c 100644 --- a/deploy/overlays/production/kustomization.yaml +++ b/deploy/overlays/production/kustomization.yaml @@ -4,9 +4,6 @@ kind: Kustomization namespace: profanity-production resources: - - namespace.yaml + - resources.yaml - deployment.yaml - - service.yaml - - ingress.yaml - - secret-store.yaml - external-secret.yaml diff --git a/deploy/overlays/production/namespace.yaml b/deploy/overlays/production/namespace.yaml deleted file mode 100644 index 0118bb9..0000000 --- a/deploy/overlays/production/namespace.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: profanity-production - labels: - app: profanity-api - environment: production diff --git a/deploy/overlays/production/resources.yaml b/deploy/overlays/production/resources.yaml new file mode 100644 index 0000000..77042e4 --- /dev/null +++ b/deploy/overlays/production/resources.yaml @@ -0,0 +1,72 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: profanity-production + labels: + app: profanity-api + environment: production +--- +apiVersion: v1 +kind: Service +metadata: + name: profanity-api + namespace: profanity-production + labels: + app: profanity-api + environment: production +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: 8080 + protocol: TCP + selector: + app: profanity-api +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: profanity-api + namespace: profanity-production + labels: + app: profanity-api + environment: production + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" +spec: + ingressClassName: nginx + tls: + - hosts: + - api-profanity.kr-filter.com + secretName: profanity-api-tls + rules: + - host: api-profanity.kr-filter.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: profanity-api + port: + number: 80 +--- +apiVersion: external-secrets.io/v1 +kind: SecretStore +metadata: + name: onepassword-store + namespace: profanity-production +spec: + provider: + onepassword: + connectHost: http://onepassword-connect.external-secrets-system.svc.cluster.local:8080 + vaults: + profanity-filter: 1 + auth: + secretRef: + connectTokenSecretRef: + name: op-token + key: token diff --git a/deploy/overlays/production/secret-store.yaml b/deploy/overlays/production/secret-store.yaml deleted file mode 100644 index 4d0447f..0000000 --- a/deploy/overlays/production/secret-store.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: external-secrets.io/v1 -kind: SecretStore -metadata: - name: onepassword-store - namespace: profanity-production -spec: - provider: - onepassword: - connectHost: http://onepassword-connect.external-secrets-system.svc.cluster.local:8080 - vaults: - profanity-filter: 1 - auth: - secretRef: - connectTokenSecretRef: - name: op-token - key: token diff --git a/deploy/overlays/production/service.yaml b/deploy/overlays/production/service.yaml deleted file mode 100644 index 0d36ea3..0000000 --- a/deploy/overlays/production/service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: profanity-api - namespace: profanity-production - labels: - app: profanity-api - environment: production -spec: - type: ClusterIP - ports: - - name: http - port: 80 - targetPort: 8080 - protocol: TCP - selector: - app: profanity-api From 8f3f3ef41623dc167f0ec134c7b82fddbfbc036d Mon Sep 17 00:00:00 2001 From: hgkim Date: Fri, 21 Nov 2025 23:58:53 +0900 Subject: [PATCH 14/15] fix: update project name in application.yaml for profanity filter deployment --- deploy/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/application.yaml b/deploy/application.yaml index c766bc9..7f097ca 100644 --- a/deploy/application.yaml +++ b/deploy/application.yaml @@ -4,7 +4,7 @@ metadata: name: profanity-filter namespace: argocd spec: - project: default + project: profanity source: repoURL: https://github.com/Whale0928/profanity-filter-api path: deploy/overlays/production From cc017e61d273ce7d28fcbaeee525a8bc028d8051 Mon Sep 17 00:00:00 2001 From: hgkim Date: Sat, 22 Nov 2025 15:53:31 +0900 Subject: [PATCH 15/15] fix: update hostnames in resources.yaml for profanity API deployment --- deploy/overlays/production/resources.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/overlays/production/resources.yaml b/deploy/overlays/production/resources.yaml index 77042e4..f8435bd 100644 --- a/deploy/overlays/production/resources.yaml +++ b/deploy/overlays/production/resources.yaml @@ -40,10 +40,10 @@ spec: ingressClassName: nginx tls: - hosts: - - api-profanity.kr-filter.com + - api.profanity.kr-filter.com secretName: profanity-api-tls rules: - - host: api-profanity.kr-filter.com + - host: api.profanity.kr-filter.com http: paths: - path: /