diff --git a/.github/workflows/terraform-apply.yml b/.github/workflows/terraform-apply.yml
index 73a4c8e..e4f2358 100644
--- a/.github/workflows/terraform-apply.yml
+++ b/.github/workflows/terraform-apply.yml
@@ -4,14 +4,14 @@ name: PinHouse Terraform Apply 파이프라인
on:
workflow_dispatch:
inputs:
- environment:
- description: "적용할 환경을 선택합니다. dev, staging, prod 중 하나를 사용합니다."
+ target:
+ description: "적용할 대상을 선택합니다. all을 선택하면 dev와 prod를 병렬로 적용합니다."
required: true
type: choice
options:
- dev
- - staging
- prod
+ - all
confirm:
description: '"apply"를 입력해야 실제 적용이 진행됩니다.'
required: true
@@ -22,18 +22,50 @@ permissions:
contents: read
id-token: write
-env:
- GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
- GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- TERRAFORM_STATE_BUCKET: ${{ secrets.TERRAFORM_STATE_BUCKET }}
- TERRAFORM_TFVARS_DEV: ${{ secrets.TERRAFORM_TFVARS_DEV }}
- TERRAFORM_TFVARS_PROD: ${{ secrets.TERRAFORM_TFVARS_PROD }}
-
jobs:
+ prepare-matrix:
+ name: 적용 대상 준비
+ runs-on: ubuntu-latest
+ outputs:
+ matrix: ${{ steps.prepare.outputs.matrix }}
+
+ steps:
+ - name: 적용 대상 Matrix 생성
+ id: prepare
+ run: |
+ case "${{ github.event.inputs.target }}" in
+ dev)
+ MATRIX='[{"terraform_environment":"dev","github_environment":"PinHouse_dev"}]'
+ ;;
+ prod)
+ MATRIX='[{"terraform_environment":"prod","github_environment":"PinHouse_prod"}]'
+ ;;
+ all)
+ MATRIX='[{"terraform_environment":"dev","github_environment":"PinHouse_dev"},{"terraform_environment":"prod","github_environment":"PinHouse_prod"}]'
+ ;;
+ *)
+ echo "오류: 지원하지 않는 대상입니다: ${{ github.event.inputs.target }}"
+ exit 1
+ ;;
+ esac
+
+ echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
+
terraform-apply:
- name: Apply - ${{ github.event.inputs.environment }}
+ name: Apply - ${{ matrix.terraform_environment }}
runs-on: ubuntu-latest
- environment: ${{ github.event.inputs.environment }}
+ needs: prepare-matrix
+ if: needs.prepare-matrix.outputs.matrix != ''
+ strategy:
+ fail-fast: false
+ matrix:
+ include: ${{ fromJson(needs.prepare-matrix.outputs.matrix) }}
+ environment: ${{ matrix.github_environment }}
+ env:
+ GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
+ GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
+ TERRAFORM_STATE_BUCKET: ${{ secrets.TERRAFORM_STATE_BUCKET }}
+ TERRAFORM_TFVARS: ${{ secrets.TERRAFORM_TFVARS }}
steps:
- name: 적용 확인 값 검증
@@ -63,44 +95,33 @@ jobs:
- name: State 버킷 변수 확인
run: |
if [ -z "${{ env.TERRAFORM_STATE_BUCKET }}" ]; then
- echo "오류: GitHub Secrets에 TERRAFORM_STATE_BUCKET을 설정해야 합니다."
+ echo "오류: GitHub Environment Secret TERRAFORM_STATE_BUCKET을 설정해야 합니다."
exit 1
fi
- name: Terraform 초기화
id: init
- working-directory: terraform/environments/${{ github.event.inputs.environment }}
+ working-directory: terraform/environments/${{ matrix.terraform_environment }}
run: |
terraform init \
-backend-config="bucket=${{ env.TERRAFORM_STATE_BUCKET }}" \
- -backend-config="prefix=terraform/${{ github.event.inputs.environment }}/state"
+ -backend-config="prefix=terraform/${{ matrix.terraform_environment }}/state"
- name: Terraform tfvars 복원
id: tfvars
- working-directory: terraform/environments/${{ github.event.inputs.environment }}
+ working-directory: terraform/environments/${{ matrix.terraform_environment }}
run: |
- case "${{ github.event.inputs.environment }}" in
- prod)
- TFVARS_CONTENT="${TERRAFORM_TFVARS_PROD}"
- SECRET_NAME="TERRAFORM_TFVARS_PROD"
- ;;
- *)
- echo "오류: 지원하지 않는 환경입니다: ${{ github.event.inputs.environment }}"
- exit 1
- ;;
- esac
-
- if [ -z "${TFVARS_CONTENT}" ]; then
- echo "오류: GitHub Secret ${SECRET_NAME}를 설정해야 합니다."
+ if [ -z "${TERRAFORM_TFVARS}" ]; then
+ echo "오류: GitHub Environment Secret TERRAFORM_TFVARS를 설정해야 합니다."
exit 1
fi
- printf '%s\n' "${TFVARS_CONTENT}" > terraform.tfvars
+ printf '%s\n' "${TERRAFORM_TFVARS}" > terraform.tfvars
chmod 600 terraform.tfvars
- name: Terraform Plan 실행
id: plan
- working-directory: terraform/environments/${{ github.event.inputs.environment }}
+ working-directory: terraform/environments/${{ matrix.terraform_environment }}
run: |
terraform plan -no-color -out=tfplan
terraform show -no-color tfplan > plan_output.txt
@@ -108,14 +129,14 @@ jobs:
- name: Plan 결과 업로드
uses: actions/upload-artifact@v4
with:
- name: tfplan-${{ github.event.inputs.environment }}-${{ github.run_number }}
+ name: tfplan-${{ matrix.terraform_environment }}-${{ github.run_number }}
path: |
- terraform/environments/${{ github.event.inputs.environment }}/tfplan
- terraform/environments/${{ github.event.inputs.environment }}/plan_output.txt
+ terraform/environments/${{ matrix.terraform_environment }}/tfplan
+ terraform/environments/${{ matrix.terraform_environment }}/plan_output.txt
- name: Terraform Apply 실행
id: apply
- working-directory: terraform/environments/${{ github.event.inputs.environment }}
+ working-directory: terraform/environments/${{ matrix.terraform_environment }}
run: |
terraform apply -auto-approve tfplan 2>&1 | tee apply_output.txt
@@ -123,25 +144,26 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
- name: tfapply-${{ github.event.inputs.environment }}-${{ github.run_number }}
- path: terraform/environments/${{ github.event.inputs.environment }}/apply_output.txt
+ name: tfapply-${{ matrix.terraform_environment }}-${{ github.run_number }}
+ path: terraform/environments/${{ matrix.terraform_environment }}/apply_output.txt
- name: 배포 요약 생성
if: always()
run: |
- echo "## Terraform Apply 요약 - ${{ github.event.inputs.environment }}" >> $GITHUB_STEP_SUMMARY
+ echo "## Terraform Apply 요약 - ${{ matrix.terraform_environment }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
- echo "**환경:** ${{ github.event.inputs.environment }}" >> $GITHUB_STEP_SUMMARY
+ echo "**환경:** ${{ matrix.terraform_environment }}" >> $GITHUB_STEP_SUMMARY
+ echo "**GitHub Environment:** ${{ matrix.github_environment }}" >> $GITHUB_STEP_SUMMARY
echo "**실행 결과:** ${{ steps.apply.outcome }}" >> $GITHUB_STEP_SUMMARY
echo "**실행 사용자:** @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "**커밋 SHA:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
- if [ -f terraform/environments/${{ github.event.inputs.environment }}/apply_output.txt ]; then
+ if [ -f terraform/environments/${{ matrix.terraform_environment }}/apply_output.txt ]; then
echo "Apply 출력 보기
" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- cat terraform/environments/${{ github.event.inputs.environment }}/apply_output.txt >> $GITHUB_STEP_SUMMARY
+ cat terraform/environments/${{ matrix.terraform_environment }}/apply_output.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo " " >> $GITHUB_STEP_SUMMARY
fi
@@ -149,5 +171,5 @@ jobs:
- name: 실패 시 워크플로우 종료
if: failure()
run: |
- echo "::error::${{ github.event.inputs.environment }} 환경 Terraform apply 실행에 실패했습니다."
+ echo "::error::${{ matrix.terraform_environment }} 환경 Terraform apply 실행에 실패했습니다."
exit 1
diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml
index 9114cf6..ed7d5b5 100644
--- a/.github/workflows/terraform-plan.yml
+++ b/.github/workflows/terraform-plan.yml
@@ -24,6 +24,7 @@ jobs:
GCP_WORKLOAD_IDENTITY_PROVIDER: ""
GCP_SERVICE_ACCOUNT: ""
TERRAFORM_STATE_BUCKET: ""
+ TERRAFORM_TFVARS_DEV: ""
TERRAFORM_TFVARS_PROD: ""
outputs:
environments: ${{ steps.detect.outputs.environments || '[]' }}
@@ -45,11 +46,16 @@ jobs:
# 변경된 환경 목록을 배열로 수집합니다.
ENVIRONMENTS=()
+ if echo "$CHANGED_FILES" | grep -q "terraform/environments/dev/"; then
+ ENVIRONMENTS+=("dev")
+ fi
+
if echo "$CHANGED_FILES" | grep -q "terraform/environments/prod/"; then
ENVIRONMENTS+=("prod")
fi
if echo "$CHANGED_FILES" | grep -q "terraform/modules/"; then
+ ENVIRONMENTS+=("dev")
ENVIRONMENTS+=("prod")
fi
@@ -73,6 +79,7 @@ jobs:
GCP_WORKLOAD_IDENTITY_PROVIDER: ""
GCP_SERVICE_ACCOUNT: ""
TERRAFORM_STATE_BUCKET: ""
+ TERRAFORM_TFVARS_DEV: ""
TERRAFORM_TFVARS_PROD: ""
steps:
@@ -99,11 +106,12 @@ jobs:
runs-on: ubuntu-22.04
needs: detect-changes
if: (needs.detect-changes.outputs.environments || '[]') != '[]' # 변경된 환경이 있을 때만 실행합니다.
+ environment: ${{ matrix.environment == 'dev' && 'PinHouse_dev' || matrix.environment == 'prod' && 'PinHouse_prod' }}
env:
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
TERRAFORM_STATE_BUCKET: ${{ secrets.TERRAFORM_STATE_BUCKET }}
- TERRAFORM_TFVARS_PROD: ${{ secrets.TERRAFORM_TFVARS_PROD }}
+ TERRAFORM_TFVARS: ${{ secrets.TERRAFORM_TFVARS }}
strategy:
fail-fast: false # 한 환경 실패가 다른 환경 확인을 막지 않도록 유지합니다.
matrix:
@@ -140,7 +148,7 @@ jobs:
id: state-bucket
run: |
if [ -z "${{ env.TERRAFORM_STATE_BUCKET }}" ]; then
- echo "오류: GitHub Secrets에 TERRAFORM_STATE_BUCKET을 설정해야 합니다."
+ echo "오류: GitHub Environment Secret TERRAFORM_STATE_BUCKET을 설정해야 합니다."
exit 1
fi
@@ -158,15 +166,12 @@ jobs:
if: steps.init.outcome == 'success'
working-directory: terraform/environments/${{ matrix.environment }}
run: |
- TFVARS_CONTENT="${TERRAFORM_TFVARS_PROD}"
- SECRET_NAME="TERRAFORM_TFVARS_PROD"
-
- if [ -z "${TFVARS_CONTENT}" ]; then
- echo "오류: GitHub Secret ${SECRET_NAME}를 설정해야 합니다."
+ if [ -z "${TERRAFORM_TFVARS}" ]; then
+ echo "오류: GitHub Environment Secret TERRAFORM_TFVARS를 설정해야 합니다."
exit 1
fi
- printf '%s\n' "${TFVARS_CONTENT}" > terraform.tfvars
+ printf '%s\n' "${TERRAFORM_TFVARS}" > terraform.tfvars
chmod 600 terraform.tfvars
- name: Terraform 유효성 검사
diff --git a/k8s-argocd/applications/dev/app.yaml b/k8s-argocd/applications/dev/app.yaml
new file mode 100644
index 0000000..071252a
--- /dev/null
+++ b/k8s-argocd/applications/dev/app.yaml
@@ -0,0 +1,41 @@
+# ===================================
+# Dev App Root
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: app-root-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: app
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-argocd/applications/dev/app
+ directory:
+ recurse: false
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/app/backend.yaml b/k8s-argocd/applications/dev/app/backend.yaml
new file mode 100644
index 0000000..08c1965
--- /dev/null
+++ b/k8s-argocd/applications/dev/app/backend.yaml
@@ -0,0 +1,50 @@
+# ===================================
+# Dev Backend
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: backend-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/image-updater: enabled
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+ annotations:
+ argocd-image-updater.argoproj.io/image-list: asia-northeast3-docker.pkg.dev/dev-pinhouse/pinhouse-dev-be/pinhouse-server
+ argocd-image-updater.argoproj.io/backend.update-strategy: newest-build
+ argocd-image-updater.argoproj.io/backend.allow-tags: regexp:^[0-9]{8}_[0-9]{6}-[a-f0-9]{7}$
+ argocd-image-updater.argoproj.io/backend.kustomize.image-name: REPLACE_ME
+ argocd-image-updater.argoproj.io/write-back-method: git
+ argocd-image-updater.argoproj.io/git-branch: main
+
+ notifications.argoproj.io/subscribe.on-sync-running.backend-nonprod: ""
+ notifications.argoproj.io/subscribe.on-deployed.backend-nonprod: ""
+ notifications.argoproj.io/subscribe.on-sync-failed.backend-nonprod: ""
+ notifications.argoproj.io/subscribe.on-health-degraded.backend-nonprod: ""
+
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/overlays/dev/backend
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: dev-app
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/app/frontend.yaml b/k8s-argocd/applications/dev/app/frontend.yaml
new file mode 100644
index 0000000..ae58cd7
--- /dev/null
+++ b/k8s-argocd/applications/dev/app/frontend.yaml
@@ -0,0 +1,49 @@
+# ===================================
+# Dev Frontend
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: frontend-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/image-updater: enabled
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+ annotations:
+ argocd-image-updater.argoproj.io/image-list: asia-northeast3-docker.pkg.dev/dev-pinhouse/pinhouse-dev-fe/pinhouse-web
+ argocd-image-updater.argoproj.io/frontend.update-strategy: newest-build
+ argocd-image-updater.argoproj.io/frontend.allow-tags: regexp:^[0-9]{8}_[0-9]{6}-[a-f0-9]{7}$
+ argocd-image-updater.argoproj.io/frontend.kustomize.image-name: REPLACE_ME
+ argocd-image-updater.argoproj.io/write-back-method: git
+ argocd-image-updater.argoproj.io/git-branch: main
+
+ notifications.argoproj.io/subscribe.on-deployed.frontend-nonprod: ""
+ notifications.argoproj.io/subscribe.on-sync-failed.frontend-nonprod: ""
+ notifications.argoproj.io/subscribe.on-health-degraded.frontend-nonprod: ""
+
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/overlays/dev/frontend
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: dev-app
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/app/image-updater.yaml b/k8s-argocd/applications/dev/app/image-updater.yaml
new file mode 100644
index 0000000..9e5261b
--- /dev/null
+++ b/k8s-argocd/applications/dev/app/image-updater.yaml
@@ -0,0 +1,21 @@
+# ===================================
+# Image Updator
+# ===================================
+
+apiVersion: argocd-image-updater.argoproj.io/v1alpha1
+kind: ImageUpdater
+
+# 기본 정보
+metadata:
+ name: dev-applications
+ namespace: argocd
+
+spec:
+ # 라벨을 기준으로 Image Updater 적용 대상을 찾습니다.
+ applicationRefs:
+ - namePattern: "*"
+ labelSelectors:
+ matchLabels:
+ pinhouse.co.kr/image-updater: enabled
+ pinhouse.co.kr/environment: dev
+ useAnnotations: true
diff --git a/k8s-argocd/applications/dev/monitoring.yaml b/k8s-argocd/applications/dev/monitoring.yaml
new file mode 100644
index 0000000..c1cc55a
--- /dev/null
+++ b/k8s-argocd/applications/dev/monitoring.yaml
@@ -0,0 +1,41 @@
+# ===================================
+# Dev Monitoring Root
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: monitoring-root-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: monitoring
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-argocd/applications/dev/monitoring
+ directory:
+ recurse: false
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/monitoring/monitoring-alloy.yaml b/k8s-argocd/applications/dev/monitoring/monitoring-alloy.yaml
new file mode 100644
index 0000000..0779ec0
--- /dev/null
+++ b/k8s-argocd/applications/dev/monitoring/monitoring-alloy.yaml
@@ -0,0 +1,45 @@
+# ===================================
+# Dev Monitoring Alloy
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: monitoring-alloy-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: monitoring
+ pinhouse.co.kr/monitoring-component: alloy
+ annotations:
+ argocd.argoproj.io/sync-wave: "2"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-helm/releases/monitoring-alloy
+ helm:
+ releaseName: monitoring-alloy
+ valueFiles:
+ - values-dev-gitops.yaml
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: monitoring
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/monitoring/monitoring-core.yaml b/k8s-argocd/applications/dev/monitoring/monitoring-core.yaml
new file mode 100644
index 0000000..20529d6
--- /dev/null
+++ b/k8s-argocd/applications/dev/monitoring/monitoring-core.yaml
@@ -0,0 +1,52 @@
+# ===================================
+# Dev Monitoring Core
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: monitoring-core-dev
+ namespace: argocd
+
+ # 라벨 추가
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: monitoring
+ pinhouse.co.kr/monitoring-component: core
+
+ # 어노테이션 메타데이터
+ annotations:
+ argocd.argoproj.io/sync-wave: "0"
+
+ # Finalizers를 설정하면 Application 삭제 시 관련 리소스도 함께 삭제됨
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+spec:
+ project: default
+
+ # Helm 소스 설정
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-helm/releases/monitoring-core
+ helm:
+ releaseName: monitoring-core
+ valueFiles:
+ - values-dev-gitops.yaml
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: monitoring
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/monitoring/monitoring-loki.yaml b/k8s-argocd/applications/dev/monitoring/monitoring-loki.yaml
new file mode 100644
index 0000000..00fbab3
--- /dev/null
+++ b/k8s-argocd/applications/dev/monitoring/monitoring-loki.yaml
@@ -0,0 +1,45 @@
+# ===================================
+# Dev Monitoring Loki
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: monitoring-loki-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: monitoring
+ pinhouse.co.kr/monitoring-component: loki
+ annotations:
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-helm/releases/monitoring-loki
+ helm:
+ releaseName: monitoring-loki
+ valueFiles:
+ - values-dev-gitops.yaml
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: monitoring
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/monitoring/monitoring-tempo.yaml b/k8s-argocd/applications/dev/monitoring/monitoring-tempo.yaml
new file mode 100644
index 0000000..f604655
--- /dev/null
+++ b/k8s-argocd/applications/dev/monitoring/monitoring-tempo.yaml
@@ -0,0 +1,45 @@
+# ===================================
+# Dev Monitoring Tempo
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: monitoring-tempo-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: monitoring
+ pinhouse.co.kr/monitoring-component: tempo
+ annotations:
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-helm/releases/monitoring-tempo
+ helm:
+ releaseName: monitoring-tempo
+ valueFiles:
+ - values-dev-gitops.yaml
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: monitoring
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/platform.yaml b/k8s-argocd/applications/dev/platform.yaml
new file mode 100644
index 0000000..ba6bc01
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform.yaml
@@ -0,0 +1,41 @@
+# ===================================
+# Dev Platform Root
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-root-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-argocd/applications/dev/platform
+ directory:
+ recurse: false
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/platform/argocd-config.yaml b/k8s-argocd/applications/dev/platform/argocd-config.yaml
new file mode 100644
index 0000000..51a313f
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/argocd-config.yaml
@@ -0,0 +1,42 @@
+# ===================================
+# Dev Platform Argo CD Config
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-argocd-config-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # Gateway와 인증서가 준비된 뒤 Argo CD HTTPRoute를 연결합니다.
+ argocd.argoproj.io/sync-wave: "3"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Kustomize 오버레이로 Argo CD 부가 설정을 적용합니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/platform/argocd/overlays/dev
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/platform/cert-manager.yaml b/k8s-argocd/applications/dev/platform/cert-manager.yaml
new file mode 100644
index 0000000..a1b4568
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/cert-manager.yaml
@@ -0,0 +1,50 @@
+# ===================================
+# Dev Platform cert-manager
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-cert-manager-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # cert-manager는 platform-chart가 생성하는 Certificate보다 먼저 준비되어야 합니다.
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # 외부 Helm chart와 Git 저장소 values 파일을 함께 사용합니다.
+ sources:
+ - repoURL: https://charts.jetstack.io
+ chart: cert-manager
+ targetRevision: v1.16.2
+ helm:
+ releaseName: cert-manager
+ valueFiles:
+ - $values/k8s-helm/releases/cert-manager/values-dev.yaml
+ - repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ ref: values
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: cert-manager
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/platform/external-secret.yaml b/k8s-argocd/applications/dev/platform/external-secret.yaml
new file mode 100644
index 0000000..d93be4c
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/external-secret.yaml
@@ -0,0 +1,51 @@
+# ===================================
+# Dev Platform External Secrets Operator
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-external-secret-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # ExternalSecret 리소스를 해석할 컨트롤러를 먼저 준비합니다.
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # 외부 Helm chart와 Git 저장소 values 파일을 함께 사용합니다.
+ sources:
+ - repoURL: https://charts.external-secrets.io
+ chart: external-secrets
+ targetRevision: 0.20.4
+ helm:
+ releaseName: external-secrets
+ valueFiles:
+ - $values/k8s-helm/releases/external-secret/values-dev.yaml
+ - repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ ref: values
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: external-secrets
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
+ - Replace=true
diff --git a/k8s-argocd/applications/dev/platform/gateway-api.yaml b/k8s-argocd/applications/dev/platform/gateway-api.yaml
new file mode 100644
index 0000000..b5c3844
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/gateway-api.yaml
@@ -0,0 +1,43 @@
+# ===================================
+# Dev Platform Gateway API CRD
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-gateway-api-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # GatewayClass, Gateway, HTTPRoute보다 먼저 CRD를 설치해야 합니다.
+ argocd.argoproj.io/sync-wave: "0"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Gateway API CRD를 GitHub에서 직접 가져옵니다.
+ source:
+ repoURL: https://github.com/kubernetes-sigs/gateway-api
+ targetRevision: v1.2.1
+ path: config/crd/standard
+
+ # CRD는 cluster-scoped 리소스라 argocd 네임스페이스로 보냅니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/platform/gce-pd-csi-driver.yaml b/k8s-argocd/applications/dev/platform/gce-pd-csi-driver.yaml
new file mode 100644
index 0000000..8ea8a2d
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/gce-pd-csi-driver.yaml
@@ -0,0 +1,43 @@
+# ===================================
+# Dev Platform GCE PD CSI Driver
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-gce-pd-csi-driver-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # StorageClass보다 먼저 CSI Driver를 설치해야 합니다.
+ argocd.argoproj.io/sync-wave: "-1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Kustomize 소스 설정
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/platform/gce-pd-csi-driver
+
+ # CSI Driver는 gce-pd-csi-driver 네임스페이스에 배포됩니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: gce-pd-csi-driver
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/platform/metrics-server.yaml b/k8s-argocd/applications/dev/platform/metrics-server.yaml
new file mode 100644
index 0000000..1a59e62
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/metrics-server.yaml
@@ -0,0 +1,50 @@
+# ===================================
+# Dev Platform Metrics Server
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-metrics-server-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # kube-system에 설치되는 공용 컨트롤러이므로 플랫폼 계층에서 관리합니다.
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # 외부 Helm chart와 Git 저장소 values 파일을 함께 사용합니다.
+ sources:
+ - repoURL: https://kubernetes-sigs.github.io/metrics-server/
+ chart: metrics-server
+ targetRevision: 3.13.0
+ helm:
+ releaseName: metrics-server
+ valueFiles:
+ - $values/k8s-helm/releases/metrics-server/values-dev.yaml
+ - repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ ref: values
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: kube-system
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/platform/monitoring-httproute.yaml b/k8s-argocd/applications/dev/platform/monitoring-httproute.yaml
new file mode 100644
index 0000000..0e159e9
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/monitoring-httproute.yaml
@@ -0,0 +1,42 @@
+# ===================================
+# Dev Platform Monitoring HTTPRoute
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-monitoring-httproute-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # Gateway와 인증서가 준비된 뒤 HTTPRoute를 연결합니다.
+ argocd.argoproj.io/sync-wave: "3"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Grafana HTTPRoute 설정
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/platform/monitoring/overlays/dev
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: monitoring
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/platform/nginx-gateway-fabric.yaml b/k8s-argocd/applications/dev/platform/nginx-gateway-fabric.yaml
new file mode 100644
index 0000000..de12fcd
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/nginx-gateway-fabric.yaml
@@ -0,0 +1,50 @@
+# ===================================
+# Dev Platform NGINX Gateway Fabric
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-nginx-gateway-fabric-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # Gateway API CRD 설치 이후에 게이트웨이 컨트롤러를 배포합니다.
+ argocd.argoproj.io/sync-wave: "1"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # 외부 Helm chart와 Git 저장소 values 파일을 함께 사용합니다.
+ sources:
+ - repoURL: ghcr.io/nginx/charts
+ chart: nginx-gateway-fabric
+ targetRevision: 2.4.2
+ helm:
+ releaseName: ngf
+ valueFiles:
+ - $values/k8s-helm/releases/nginx-gateway-fabric/values-dev.yaml
+ - repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ ref: values
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: nginx-gateway
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ - ServerSideApply=true
diff --git a/k8s-argocd/applications/dev/platform/platform-resources.yaml b/k8s-argocd/applications/dev/platform/platform-resources.yaml
new file mode 100644
index 0000000..c57018a
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/platform-resources.yaml
@@ -0,0 +1,46 @@
+# ===================================
+# Dev Platform Resources
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-resources-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # 컨트롤러가 준비된 뒤 Gateway, Certificate, ExternalSecret 같은 실제 리소스를 생성합니다.
+ argocd.argoproj.io/sync-wave: "2"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # 로컬 Helm chart를 사용해 플랫폼 공통 리소스를 배포합니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-helm/platform-chart
+ helm:
+ releaseName: pinhouse-platform
+ valueFiles:
+ - values-dev.yaml
+
+ # 배포 대상 클러스터
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: platform-system
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/applications/dev/platform/storageclass.yaml b/k8s-argocd/applications/dev/platform/storageclass.yaml
new file mode 100644
index 0000000..bb1cb87
--- /dev/null
+++ b/k8s-argocd/applications/dev/platform/storageclass.yaml
@@ -0,0 +1,42 @@
+# ===================================
+# Dev Platform StorageClass
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: platform-storageclass-dev
+ namespace: argocd
+ labels:
+ pinhouse.co.kr/environment: dev
+ pinhouse.co.kr/component: platform
+ annotations:
+ # PVC를 사용하는 워크로드보다 먼저 StorageClass를 준비합니다.
+ argocd.argoproj.io/sync-wave: "0"
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Kustomize 소스 설정
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-kustomize/platform/storageclass
+
+ # StorageClass는 cluster-scoped 리소스라 argocd 네임스페이스로 보냅니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # 동기화 정책
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/root-apps/root-dev.yaml b/k8s-argocd/root-apps/root-dev.yaml
new file mode 100644
index 0000000..32807c6
--- /dev/null
+++ b/k8s-argocd/root-apps/root-dev.yaml
@@ -0,0 +1,39 @@
+# ===================================
+# App of Apps 패턴
+# Dev 환경의 모든 애플리케이션을 관리
+# ===================================
+
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+
+# 기본 정보
+metadata:
+ name: root-dev
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+
+# 스펙
+spec:
+ project: default
+
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
+ source:
+ repoURL: https://github.com/PinHouse/PinHouse_CLOUD
+ targetRevision: main
+ path: k8s-argocd/applications/dev
+ directory:
+ recurse: false
+
+ # 배포 대상 클러스터와 네임스페이스입니다.
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: argocd
+
+ # Git 기준으로 자동 동기화합니다.
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/k8s-argocd/root-apps/root-prod.yaml b/k8s-argocd/root-apps/root-prod.yaml
index 5b9206a..6cbef48 100644
--- a/k8s-argocd/root-apps/root-prod.yaml
+++ b/k8s-argocd/root-apps/root-prod.yaml
@@ -19,6 +19,7 @@ spec:
project: default
# GitOps 소 설정
+ # Git 저장소에서 관리하는 매니페스트 경로입니다.
source:
# Git 리포지토리 URL
repoURL: https://github.com/PinHouse/PinHouse_CLOUD
@@ -32,11 +33,13 @@ spec:
recurse: false
# 배포 대상 클러스터
+ # 배포 대상 클러스터와 네임스페이스입니다.
destination:
server: https://kubernetes.default.svc
namespace: argocd
# 동기화 정책
+ # Git 기준으로 자동 동기화합니다.
syncPolicy:
# GitOps 자동 동기화 설정
automated:
diff --git a/k8s-helm/.gitignore b/k8s-helm/.gitignore
index 799419b..95a7ef5 100644
--- a/k8s-helm/.gitignore
+++ b/k8s-helm/.gitignore
@@ -4,6 +4,7 @@
platform-chart/**/*.yaml
platform-chart/**/README.md
!platform-chart/**/values.yaml
+!platform-chart/**/values-dev.yaml
!platform-chart/**/values-nonprod.yaml
!platform-chart/**/values-prod.yaml
!platform-chart/templates/**/*.yaml
@@ -19,6 +20,7 @@ releases/**/secrets/*.yaml
# ========================================
releases/argocd/values-*.yaml
!releases/argocd/*.yaml.example
+!releases/argocd/values-dev.yaml
# ========================================
# Monitoring 로컬 오버라이드
@@ -26,6 +28,8 @@ releases/argocd/values-*.yaml
releases/monitoring-*/values-*.yaml
releases/monitoring-*/README.md
!releases/monitoring-*/values-prod-gitops.yaml
+!releases/monitoring-*/values-dev-gitops.yaml
+!releases/monitoring-*/values-nonprod-gitops.yaml
# ========================================
# 로컬 오버라이드 파일
diff --git a/k8s-helm/platform-chart/values-dev.yaml b/k8s-helm/platform-chart/values-dev.yaml
new file mode 100644
index 0000000..1d387df
--- /dev/null
+++ b/k8s-helm/platform-chart/values-dev.yaml
@@ -0,0 +1,205 @@
+# Dev values
+
+# SSL 매니저
+certManager:
+ enabled: true
+
+ # 실제 이메일 주소로 변경
+ acmeEmail: "pinhousekr@gmail.com"
+
+ # 비운영 환경에서는 Let's Encrypt Staging issuer로 검증합니다.
+ letsencrypt:
+ staging:
+ enabled: true
+ production:
+ enabled: false
+
+ # DNS-01 Challenge (CloudDNS)
+ cloudDNS:
+ projectId: "dev-pinhouse"
+
+# 게이트웨이
+gateway:
+ enabled: true
+ name: pinhouse-gateway
+ namespace: nginx-gateway
+ gatewayClassName: nginx
+
+ http:
+ enabled: true
+ port: 80
+
+ # HTTP to HTTPS 리다이렉트 (301 Permanent Redirect)
+ http_redirect:
+ enabled: true
+
+ # 환경별 리스너
+ environments:
+ - name: dev
+ enabled: true
+ tlsSecretName: pinhouse-tls-dev
+ services:
+ - name: web
+ hostname: dev.pinhouse.co.kr
+ - name: api
+ hostname: api.dev.pinhouse.co.kr
+
+ - name: stg
+ enabled: false
+ tlsSecretName: pinhouse-tls-stg
+ services:
+ - name: web
+ hostname: stg.pinhouse.co.kr
+ - name: api
+ hostname: api.stg.pinhouse.co.kr
+
+ # 추가 리스너
+ listeners:
+ argo:
+ enabled: true
+ domain: argo.dev.pinhouse.co.kr
+ tlsSecretName: pinhouse-tls-argo
+
+ grafana:
+ enabled: true
+ domain: grafana.dev.pinhouse.co.kr
+ tlsSecretName: pinhouse-tls-grafana
+
+# 접근 제어 (Access Control) - 비운영도 운영과 같은 기준으로 차단
+accessControl:
+ enabled: true
+ blockedPaths:
+ - name: api-dev-swagger
+ hostnames: ["api.dev.pinhouse.co.kr"]
+ paths:
+ - "/swagger-ui"
+ - "/v3/api-docs"
+
+ - name: api-dev-management
+ hostnames: ["api.dev.pinhouse.co.kr"]
+ paths:
+ - "/actuator"
+ - "/metrics"
+ - "/prometheus"
+
+ - name: common-dev-metrics
+ hostnames: ["dev.pinhouse.co.kr"]
+ paths:
+ - "/api/metrics"
+ - "/prometheus"
+
+# 네트워크 정책
+networkPolicy:
+ enabled: false
+
+ database:
+ rds:
+ cidr: "192.168.0.0/16"
+ ec2:
+ ip: "172.16.10.81/32"
+
+ ports:
+ frontend: 3000
+ backend: 8080
+ ai: 8000
+ postgres: 5432
+ redis: 6379
+ rabbitmq: 5672
+ dns: 53
+ http: 80
+ https: 443
+
+ namespaces:
+ - name: nginx-gateway
+ enabled: true
+ - name: app
+ enabled: true
+
+# 인증서
+certificates:
+ enabled: true
+ issuer: letsencrypt-staging
+
+ certs:
+ - name: pinhouse-tls-dev
+ namespace: nginx-gateway
+ dnsNames:
+ - dev.pinhouse.co.kr
+ - api.dev.pinhouse.co.kr
+ enabled: true
+
+ - name: pinhouse-tls-stg
+ namespace: nginx-gateway
+ dnsNames:
+ - stg.pinhouse.co.kr
+ - api.stg.pinhouse.co.kr
+ enabled: false
+
+ - name: pinhouse-tls-argo
+ namespace: nginx-gateway
+ dnsNames:
+ - argo.dev.pinhouse.co.kr
+ enabled: true
+
+ - name: pinhouse-tls-grafana
+ namespace: nginx-gateway
+ dnsNames:
+ - grafana.dev.pinhouse.co.kr
+ enabled: true
+
+# GCP Secret Manager 기반 시크릿 적용
+externalSecrets:
+ enabled: true
+
+ secretStores:
+ - kind: ClusterSecretStore
+ name: gcp-secret-manager
+ spec:
+ provider:
+ gcpsm:
+ projectID: dev-pinhouse
+
+ secrets:
+ - name: backend-secret-kv
+ namespace: dev-app
+ spec:
+ refreshInterval: 1h
+ secretStoreRef:
+ name: gcp-secret-manager
+ kind: ClusterSecretStore
+ target:
+ name: backend-secret-kv
+ creationPolicy: Owner
+ deletionPolicy: Retain
+ dataFrom:
+ - find:
+ name:
+ regexp: "^Dev_BE_"
+ conversionStrategy: Default
+ decodingStrategy: None
+ rewrite:
+ - regexp:
+ source: "^Dev_BE_(.*)$"
+ target: "$1"
+
+ - name: monitoring-secret-kv
+ namespace: monitoring
+ spec:
+ refreshInterval: 1h
+ secretStoreRef:
+ name: gcp-secret-manager
+ kind: ClusterSecretStore
+ target:
+ name: monitoring-secret-kv
+ creationPolicy: Owner
+ deletionPolicy: Retain
+ dataFrom:
+ - find:
+ name:
+ regexp: "^Dev_MONITORING_"
+ conversionStrategy: Default
+ decodingStrategy: None
+ rewrite:
+ - regexp:
+ source: "^Dev_MONITORING_(.*)$"
+ target: "$1"
diff --git a/k8s-helm/releases/argocd/values-dev.yaml b/k8s-helm/releases/argocd/values-dev.yaml
new file mode 100644
index 0000000..70bdbe4
--- /dev/null
+++ b/k8s-helm/releases/argocd/values-dev.yaml
@@ -0,0 +1,18 @@
+# Dev 환경용 Argo CD 설정
+global:
+ domain: argo.dev.pinhouse.co.kr
+
+configs:
+ cm:
+ # Git/Helm 변경 감지 주기.
+ timeout.reconciliation: "60s"
+ timeout.reconciliation.jitter: "15s"
+
+ # TLS Termination을 Gateway에서 수행하므로 ArgoCD Server는 insecure 모드로 실행
+ params:
+ server.insecure: "true"
+
+# ArgoCD Server에 --insecure 플래그 추가
+server:
+ extraArgs:
+ - --insecure
diff --git a/k8s-helm/releases/calico/values-dev.yaml b/k8s-helm/releases/calico/values-dev.yaml
new file mode 100644
index 0000000..f3e2e1f
--- /dev/null
+++ b/k8s-helm/releases/calico/values-dev.yaml
@@ -0,0 +1,8 @@
+installation:
+ calicoNetwork:
+ bgp: Disabled
+ ipPools:
+ - cidr: 192.168.0.0/16
+ encapsulation: VXLAN
+ natOutgoing: Enabled
+ nodeSelector: all()
diff --git a/k8s-helm/releases/cert-manager/values-dev.yaml b/k8s-helm/releases/cert-manager/values-dev.yaml
new file mode 100644
index 0000000..d9d6f2b
--- /dev/null
+++ b/k8s-helm/releases/cert-manager/values-dev.yaml
@@ -0,0 +1,4 @@
+config:
+ enableGatewayAPI: true
+crds:
+ enabled: true
\ No newline at end of file
diff --git a/k8s-helm/releases/external-secret/values-dev.yaml b/k8s-helm/releases/external-secret/values-dev.yaml
new file mode 100644
index 0000000..5393cb9
--- /dev/null
+++ b/k8s-helm/releases/external-secret/values-dev.yaml
@@ -0,0 +1,11 @@
+installCRDs: true
+
+replicaCount: 2
+
+resources:
+ requests:
+ cpu: 100m
+ memory: 128Mi
+ limits:
+ cpu: 200m
+ memory: 256Mi
diff --git a/k8s-helm/releases/metrics-server/values-dev.yaml b/k8s-helm/releases/metrics-server/values-dev.yaml
new file mode 100644
index 0000000..cf9876b
--- /dev/null
+++ b/k8s-helm/releases/metrics-server/values-dev.yaml
@@ -0,0 +1,22 @@
+# ========================================
+# Metrics Server 비운영 값
+# ========================================
+replicas: 1
+
+# kubeadm 기반 노드에서 kubelet 메트릭을 안정적으로 수집하기 위한 기본 인자입니다.
+defaultArgs:
+ - --cert-dir=/tmp
+ - --secure-port=10250
+ - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
+ - --kubelet-use-node-status-port
+ - --kubelet-insecure-tls
+ - --metric-resolution=15s
+
+# 기본 클러스터 규모에 맞춘 리소스 요청값입니다.
+resources:
+ requests:
+ cpu: 100m
+ memory: 200Mi
+ limits:
+ cpu: 200m
+ memory: 300Mi
diff --git a/k8s-helm/releases/monitoring-alloy/values-dev-gitops.yaml b/k8s-helm/releases/monitoring-alloy/values-dev-gitops.yaml
new file mode 100644
index 0000000..d74fb61
--- /dev/null
+++ b/k8s-helm/releases/monitoring-alloy/values-dev-gitops.yaml
@@ -0,0 +1,21 @@
+# ========================================
+# Dev Monitoring Alloy GitOps 값
+# ========================================
+
+# 애플리케이션 OTLP 엔드포인트 예시
+# gRPC: monitoring-alloy.monitoring.svc.cluster.local:4317
+# HTTP: http://monitoring-alloy.monitoring.svc.cluster.local:4318/v1/traces
+
+global:
+ # Alloy가 Loki로 보내는 로그 라벨과 공통 식별값에 사용합니다.
+ clusterName: "pinhouse-dev"
+ environment: "dev"
+
+alloy:
+ resources:
+ requests:
+ cpu: 300m
+ memory: 512Mi
+ limits:
+ cpu: 1000m
+ memory: 1Gi
diff --git a/k8s-helm/releases/monitoring-core/values-dev-gitops.yaml b/k8s-helm/releases/monitoring-core/values-dev-gitops.yaml
new file mode 100644
index 0000000..96ea569
--- /dev/null
+++ b/k8s-helm/releases/monitoring-core/values-dev-gitops.yaml
@@ -0,0 +1,91 @@
+# ========================================
+# Dev Monitoring Core GitOps 값
+# ========================================
+
+kube-prometheus-stack:
+ grafana:
+ # Grafana 관리자 계정은 ExternalSecret이 만든 Kubernetes Secret을 사용합니다.
+ admin:
+ existingSecret: monitoring-secret-kv
+ userKey: GRAFANA_ADMIN_USER
+ passwordKey: GRAFANA_ADMIN_PASSWORD
+
+ # Grafana Sidecar를 통한 대시보드 자동 로딩 설정
+ sidecar:
+ dashboards:
+ enabled: true
+ # ConfigMap에서 찾을 라벨
+ label: grafana_dashboard
+ labelValue: "1"
+ # 모든 네임스페이스에서 대시보드 ConfigMap 검색
+ searchNamespace: ALL
+ # 폴더 어노테이션 지원
+ folderAnnotation: grafana_folder
+ # 대시보드 프로비저닝 설정
+ provider:
+ foldersFromFilesStructure: true
+
+ # 비운영도 데이터 보존과 설정 확인을 위해 PVC를 사용합니다.
+ persistence:
+ enabled: true
+ type: sts
+ size: 20Gi
+ storageClassName: "gce-standard-rwo"
+
+ prometheus:
+ prometheusSpec:
+ # 비운영 환경 기준 메트릭 보관 기간과 최대 디스크 사용량입니다.
+ retention: 15d
+ retentionSize: 50GB
+ # 실제 scrape는 Alloy가 수행하고, Prometheus는 remote write receiver로 메트릭을 받습니다.
+ enableRemoteWriteReceiver: true
+
+ # Prometheus가 직접 ServiceMonitor/PodMonitor/Probe를 scrape하지 않도록 둡니다.
+ serviceMonitorSelectorNilUsesHelmValues: false
+ serviceMonitorSelector:
+ matchLabels:
+ "pinhouse.co.kr/scrape-via": "prometheus"
+ serviceMonitorNamespaceSelector: {}
+
+ podMonitorSelectorNilUsesHelmValues: false
+ podMonitorSelector:
+ matchLabels:
+ "pinhouse.co.kr/scrape-via": "prometheus"
+ podMonitorNamespaceSelector: {}
+
+ probeSelectorNilUsesHelmValues: false
+ probeSelector:
+ matchLabels:
+ "pinhouse.co.kr/scrape-via": "prometheus"
+ probeNamespaceSelector: {}
+
+ # 메트릭 보관을 위해 PVC를 사용합니다.
+ storageSpec:
+ volumeClaimTemplate:
+ spec:
+ storageClassName: "gce-standard-rwo"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 50Gi
+
+ alertmanager:
+ # Alertmanager는 알림 라우팅 전용이라 상대적으로 작은 리소스로 시작합니다.
+ # 비어 있는 map을 유지해 차트 기본값과 타입 충돌이 나지 않도록 합니다.
+ alertmanagerSpec: {}
+
+ prometheusOperator:
+ # Operator는 scrape 주체는 아니지만 Prometheus/Alertmanager 리소스를 생성하므로 계속 필요합니다.
+ # 비어 있는 map을 유지해 차트 기본값을 그대로 사용합니다.
+ resources: {}
+
+ kube-state-metrics:
+ # Kubernetes 리소스 상태 수집용 컴포넌트입니다.
+ # 비어 있는 map을 유지해 차트 기본값을 그대로 사용합니다.
+ resources: {}
+
+ prometheus-node-exporter:
+ # 노드 메트릭 수집기라서 가볍게 시작하되 과도한 사용을 막기 위해 제한을 둡니다.
+ # 비어 있는 map을 유지해 차트 기본값을 그대로 사용합니다.
+ resources: {}
diff --git a/k8s-helm/releases/monitoring-loki/values-dev-gitops.yaml b/k8s-helm/releases/monitoring-loki/values-dev-gitops.yaml
new file mode 100644
index 0000000..5828237
--- /dev/null
+++ b/k8s-helm/releases/monitoring-loki/values-dev-gitops.yaml
@@ -0,0 +1,46 @@
+# ========================================
+# Dev Monitoring Loki GitOps 값
+# ========================================
+
+loki:
+ # Loki 공용 ServiceAccount 이름을 고정해 두면 추후 인증 방식 전환 시 추적이 쉽습니다.
+ serviceAccount:
+ create: true
+ name: monitoring-loki-sa
+ annotations: {}
+
+ loki:
+ # 로그 보관 기간은 14일로 유지합니다.
+ limits_config:
+ retention_period: 336h
+
+ # Loki 로그 청크와 인덱스는 GCS 버킷에 저장합니다.
+ storage:
+ bucketNames:
+ chunks: "pinhouse-dev-loki"
+ ruler: "pinhouse-dev-loki"
+ admin: "pinhouse-dev-loki"
+ gcs:
+ bucket_name: "pinhouse-dev-loki"
+
+ singleBinary:
+ replicas: 1
+
+ persistence:
+ enabled: true
+ size: 30Gi
+ storageClass: "gce-standard-rwo"
+
+ resources:
+ requests:
+ cpu: 500m
+ memory: 512Mi
+ limits:
+ cpu: 2000m
+ memory: 1Gi
+
+ chunksCache:
+ enabled: false
+
+ resultsCache:
+ allocatedMemory: 256
diff --git a/k8s-helm/releases/monitoring-tempo/values-dev-gitops.yaml b/k8s-helm/releases/monitoring-tempo/values-dev-gitops.yaml
new file mode 100644
index 0000000..a9fa73a
--- /dev/null
+++ b/k8s-helm/releases/monitoring-tempo/values-dev-gitops.yaml
@@ -0,0 +1,100 @@
+# ========================================
+# Dev Monitoring Tempo GitOps 값
+# ========================================
+
+tempo:
+ # Tempo 공용 ServiceAccount 이름을 고정해 두면 인증 설정을 추적하기 쉽습니다.
+ serviceAccount:
+ create: true
+ name: monitoring-tempo-sa
+ annotations: {}
+
+ storage:
+ # 트레이스 원본 데이터는 GCS 버킷에 저장합니다.
+ trace:
+ gcs:
+ bucket_name: "pinhouse-dev-tempo"
+ block:
+ retention: 336h
+
+ ingester:
+ replicas: 1
+ persistence:
+ enabled: true
+ size: 20Gi
+ storageClass: "gce-standard-rwo"
+ resources:
+ requests:
+ cpu: 500m
+ memory: 1Gi
+ limits:
+ cpu: 1000m
+ memory: 2Gi
+
+ distributor:
+ replicas: 1
+ resources:
+ requests:
+ cpu: 200m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+
+ compactor:
+ replicas: 1
+ config:
+ compaction:
+ block_retention: 336h
+ resources:
+ requests:
+ cpu: 200m
+ memory: 512Mi
+ limits:
+ cpu: 500m
+ memory: 1Gi
+
+ querier:
+ replicas: 1
+ resources:
+ requests:
+ cpu: 200m
+ memory: 512Mi
+ limits:
+ cpu: 500m
+ memory: 1Gi
+
+ queryFrontend:
+ replicas: 1
+ resources:
+ requests:
+ cpu: 200m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+
+ overrides:
+ defaults:
+ metrics_generator:
+ processors:
+ - span-metrics
+ - local-blocks
+
+ metricsGenerator:
+ enabled: true
+ replicas: 1
+ resources:
+ requests:
+ cpu: 200m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 1Gi
+ config:
+ processor:
+ local_blocks:
+ flush_to_storage: true
+ storage:
+ remote_write:
+ - url: http://monitoring-core-kube-prome-prometheus.monitoring.svc.cluster.local:9090/api/v1/write
diff --git a/k8s-helm/releases/nginx-gateway-fabric/values-dev.yaml b/k8s-helm/releases/nginx-gateway-fabric/values-dev.yaml
new file mode 100644
index 0000000..3692f1e
--- /dev/null
+++ b/k8s-helm/releases/nginx-gateway-fabric/values-dev.yaml
@@ -0,0 +1,16 @@
+fullnameOverride: ngf-nginx-gateway-fabric
+
+# GatewayClass 설정
+nginxGateway:
+ gatewayClassName: nginx
+ gatewayControllerName: gateway.nginx.org/nginx-gateway-controller
+
+# Service 설정
+nginx:
+ service:
+ type: NodePort
+ nodePorts:
+ - port: 30080
+ listenerPort: 80
+ - port: 30443
+ listenerPort: 443
diff --git a/k8s-kustomize/overlays/dev/backend/deployment.yaml b/k8s-kustomize/overlays/dev/backend/deployment.yaml
new file mode 100644
index 0000000..d75dad0
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/backend/deployment.yaml
@@ -0,0 +1,19 @@
+apiVersion: apps/v1
+kind: Deployment
+
+# 기본 설정
+metadata:
+ name: pinhouse-be
+
+# 스펙
+spec:
+ replicas: 1
+
+ template:
+ metadata:
+ labels:
+ environment: dev
+
+ spec:
+ containers:
+ - name: pinhouse-be
diff --git a/k8s-kustomize/overlays/dev/backend/httproute.yaml b/k8s-kustomize/overlays/dev/backend/httproute.yaml
new file mode 100644
index 0000000..8d34bd5
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/backend/httproute.yaml
@@ -0,0 +1,26 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+
+# 기본 설정
+metadata:
+ name: backend
+
+# 스펙
+spec:
+ parentRefs:
+ - name: pinhouse-gateway
+ namespace: nginx-gateway
+
+ # 도메인 명
+ hostnames:
+ - "api.dev.pinhouse.co.kr"
+
+ # 참조 규칙
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: backend-service-dev
+ port: 80
diff --git a/k8s-kustomize/overlays/dev/backend/kustomization.yaml b/k8s-kustomize/overlays/dev/backend/kustomization.yaml
new file mode 100644
index 0000000..b31c68e
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/backend/kustomization.yaml
@@ -0,0 +1,27 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+# 네임 스페이스
+namespace: dev-app
+
+resources:
+ - ../../../base/backend
+ - httproute.yaml
+
+nameSuffix: -dev
+
+# 이미지 수정
+# ArgoCD Image Updater가 자동으로 newTag를 업데이트
+images:
+ - name: REPLACE_ME
+ newName: asia-northeast3-docker.pkg.dev/dev-pinhouse/pinhouse-dev-be/pinhouse-server
+ newTag: latest
+
+# overlays 수정내용 반영
+patches:
+ - path: deployment.yaml
+ target:
+ group: apps
+ version: v1
+ kind: Deployment
+ name: pinhouse-be
diff --git a/k8s-kustomize/overlays/dev/frontend/deployment.yaml b/k8s-kustomize/overlays/dev/frontend/deployment.yaml
new file mode 100644
index 0000000..9aa95b0
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/frontend/deployment.yaml
@@ -0,0 +1,19 @@
+apiVersion: apps/v1
+kind: Deployment
+
+# 기본 설정
+metadata:
+ name: pinhouse-fe
+
+# 스펙
+spec:
+ replicas: 2
+
+ template:
+ metadata:
+ labels:
+ environment: dev
+
+ spec:
+ containers:
+ - name: pinhouse-fe
diff --git a/k8s-kustomize/overlays/dev/frontend/httproute.yaml b/k8s-kustomize/overlays/dev/frontend/httproute.yaml
new file mode 100644
index 0000000..2efbd11
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/frontend/httproute.yaml
@@ -0,0 +1,26 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+
+# 기본 설정
+metadata:
+ name: frontend
+
+# 스펙
+spec:
+ parentRefs:
+ - name: pinhouse-gateway
+ namespace: nginx-gateway
+
+ # 도메인 명
+ hostnames:
+ - "dev.pinhouse.co.kr"
+
+ # 참조 규칙
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: frontend-service-dev
+ port: 80
diff --git a/k8s-kustomize/overlays/dev/frontend/kustomization.yaml b/k8s-kustomize/overlays/dev/frontend/kustomization.yaml
new file mode 100644
index 0000000..62d6eb8
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/frontend/kustomization.yaml
@@ -0,0 +1,27 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+# 네임 스페이스
+namespace: dev-app
+
+resources:
+ - ../../../base/frontend
+ - httproute.yaml
+
+nameSuffix: -dev
+
+# 이미지 수정
+# ArgoCD Image Updater가 자동으로 newTag를 업데이트
+images:
+ - name: REPLACE_ME
+ newName: asia-northeast3-docker.pkg.dev/dev-pinhouse/pinhouse-dev-fe/pinhouse-web
+ newTag: latest
+
+# overlays 수정내용 반영
+patches:
+ - path: deployment.yaml
+ target:
+ group: apps
+ version: v1
+ kind: Deployment
+ name: pinhouse-fe
diff --git a/k8s-kustomize/overlays/dev/kustomization.yaml b/k8s-kustomize/overlays/dev/kustomization.yaml
new file mode 100644
index 0000000..6b53bca
--- /dev/null
+++ b/k8s-kustomize/overlays/dev/kustomization.yaml
@@ -0,0 +1,7 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+# 반영하는 리소스
+resources:
+ - frontend
+ - backend
diff --git a/k8s-kustomize/platform/argocd/overlays/dev/httproute.yaml b/k8s-kustomize/platform/argocd/overlays/dev/httproute.yaml
new file mode 100644
index 0000000..9e6e879
--- /dev/null
+++ b/k8s-kustomize/platform/argocd/overlays/dev/httproute.yaml
@@ -0,0 +1,27 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+
+# 기본 설정
+metadata:
+ name: argocd
+ namespace: argocd
+
+# 스펙
+spec:
+ parentRefs:
+ - name: pinhouse-gateway
+ namespace: nginx-gateway
+
+ # 도메인 명
+ hostnames:
+ - "argo.dev.pinhouse.co.kr"
+
+ # 참조 규칙
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: argocd-server
+ port: 80
diff --git a/k8s-kustomize/platform/argocd/overlays/dev/kustomization.yaml b/k8s-kustomize/platform/argocd/overlays/dev/kustomization.yaml
new file mode 100644
index 0000000..5b89931
--- /dev/null
+++ b/k8s-kustomize/platform/argocd/overlays/dev/kustomization.yaml
@@ -0,0 +1,9 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+resources:
+ - ../../base
+ - httproute.yaml
+
+patches:
+ - path: notifications-cm-context-patch.yaml
diff --git a/k8s-kustomize/platform/argocd/overlays/dev/notifications-cm-context-patch.yaml b/k8s-kustomize/platform/argocd/overlays/dev/notifications-cm-context-patch.yaml
new file mode 100644
index 0000000..5bc15e4
--- /dev/null
+++ b/k8s-kustomize/platform/argocd/overlays/dev/notifications-cm-context-patch.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: argocd-notifications-cm
+ namespace: argocd
+
+data:
+ context.argocdUrl: "https://argo.dev.pinhouse.co.kr"
diff --git a/k8s-kustomize/platform/monitoring/overlays/dev/httproute.yaml b/k8s-kustomize/platform/monitoring/overlays/dev/httproute.yaml
new file mode 100644
index 0000000..bd5fb43
--- /dev/null
+++ b/k8s-kustomize/platform/monitoring/overlays/dev/httproute.yaml
@@ -0,0 +1,27 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+
+# 기본 설정
+metadata:
+ name: grafana
+ namespace: monitoring
+
+# 스펙
+spec:
+ parentRefs:
+ - name: pinhouse-gateway
+ namespace: nginx-gateway
+
+ # 도메인 명
+ hostnames:
+ - "grafana.dev.pinhouse.co.kr"
+
+ # 참조 규칙
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: monitoring-core-grafana
+ port: 80
diff --git a/k8s-kustomize/platform/monitoring/overlays/dev/kustomization.yaml b/k8s-kustomize/platform/monitoring/overlays/dev/kustomization.yaml
new file mode 100644
index 0000000..157f4b0
--- /dev/null
+++ b/k8s-kustomize/platform/monitoring/overlays/dev/kustomization.yaml
@@ -0,0 +1,9 @@
+# ========================================
+# Grafana HTTPRoute (Dev)
+# ========================================
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+resources:
+ - httproute.yaml
diff --git a/terraform/environments/dev/artifact-registry.tf b/terraform/environments/dev/artifact-registry.tf
new file mode 100644
index 0000000..a4e49cc
--- /dev/null
+++ b/terraform/environments/dev/artifact-registry.tf
@@ -0,0 +1,14 @@
+# ========================================
+# Artifact Registry 모듈
+# ========================================
+module "artifact_registry" {
+ source = "../../modules/artifact-registry"
+
+ project_id = var.project_id
+ default_location = var.artifact_registry_location
+ common_tags = var.common_tags
+
+ repositories = var.artifact_registry_repositories
+ repository_iam_bindings = var.artifact_registry_repository_iam_bindings
+ repository_iam_members = var.artifact_registry_repository_iam_members
+}
diff --git a/terraform/environments/dev/backend.tf b/terraform/environments/dev/backend.tf
new file mode 100644
index 0000000..9a9d37b
--- /dev/null
+++ b/terraform/environments/dev/backend.tf
@@ -0,0 +1,9 @@
+# ========================================
+# Terraform Backend 설정
+# ========================================
+terraform {
+ backend "gcs" {
+ bucket = "pinhouse-dev-state-bucket"
+ prefix = "terraform/dev/state"
+ }
+}
diff --git a/terraform/environments/dev/compute.tf b/terraform/environments/dev/compute.tf
new file mode 100644
index 0000000..7965cfe
--- /dev/null
+++ b/terraform/environments/dev/compute.tf
@@ -0,0 +1,100 @@
+# ========================================
+# Kubernetes 마스터 노드 컴퓨트 모듈
+# ========================================
+module "k8s_master_nodes" {
+ source = "../../modules/compute"
+
+ name_prefix = "${var.project}-${var.environment}-k8s-master"
+ network = module.vpc.vpc_self_link
+ subnetwork = module.vpc.subnets["app"].self_link
+
+ # 관리형 인스턴스 그룹 설정
+ create_instance_template = true
+ create_instance_group = true
+
+ instance_group_zone = "${var.region}-a"
+ instance_group_target_size = var.k8s_master_instance_group_size
+
+ # 마스터 노드는 단일 인스턴스로 고정 운영합니다.
+ enable_autoscaling = false
+
+ # 공통 인스턴스 설정
+ machine_type = var.k8s_master_machine_type
+ source_image = var.k8s_node_source_image
+ boot_disk_size_gb = var.k8s_node_boot_disk_size_gb
+ boot_disk_type = "pd-balanced"
+ enable_external_ip = false
+ startup_script = templatefile("${path.module}/scripts/k8s-master-init.sh", {
+ k8s_pod_cidr = var.k8s_pod_cidr
+ k8s_service_cidr = var.k8s_service_cidr
+ calico_version = var.calico_version
+ })
+ tags = ["k8s-master", var.environment]
+
+ # 태그
+ common_tags = merge(var.common_tags, {
+ Service = "Kubernetes"
+ Role = "Master"
+ })
+
+ # 서비스 계정 설정
+ service_account_email = var.service_account_email
+ service_account_scopes = [
+ "https://www.googleapis.com/auth/cloud-platform"
+ ]
+}
+
+# ========================================
+# Kubernetes 워커 노드 컴퓨트 모듈
+# ========================================
+module "k8s_worker_nodes" {
+ source = "../../modules/compute"
+
+ name_prefix = "${var.project}-${var.environment}-k8s-workers"
+ network = module.vpc.vpc_self_link
+ subnetwork = module.vpc.subnets["app"].self_link
+
+ # 관리형 인스턴스 그룹 설정
+ create_instance_template = true
+ create_instance_group = true
+
+ instance_group_zone = "${var.region}-a"
+ instance_group_target_size = var.k8s_worker_instance_group_size
+
+ # target_size가 0이면 워커 MIG를 완전히 비워둘 수 있도록 오토스케일러를 비활성화합니다.
+ enable_autoscaling = var.k8s_worker_instance_group_size > 0 ? var.enable_autoscaling : false
+ autoscaling_min_replicas = var.autoscaling_min_replicas
+ autoscaling_max_replicas = var.autoscaling_max_replicas
+ autoscaling_cpu_target = 0.7
+
+ # 공통 인스턴스 설정
+ machine_type = var.k8s_worker_machine_type
+ source_image = var.k8s_node_source_image
+ boot_disk_size_gb = var.k8s_node_boot_disk_size_gb
+ boot_disk_type = "pd-balanced"
+ enable_external_ip = false
+ startup_script = file("${path.module}/scripts/k8s-worker-init.sh")
+ named_ports = [
+ {
+ name = "ngf-http"
+ port = var.nginx_gateway_http_node_port
+ },
+ {
+ name = "ngf-https"
+ port = var.nginx_gateway_https_node_port
+ }
+ ]
+ tags = ["k8s-worker", var.environment]
+
+ # 태그
+ common_tags = merge(var.common_tags, {
+ Service = "Kubernetes"
+ Role = "Worker"
+ })
+
+ # 서비스 계정 설정
+ service_account_email = var.service_account_email
+ service_account_scopes = [
+ "https://www.googleapis.com/auth/cloud-platform"
+ ]
+}
diff --git a/terraform/environments/dev/firewall.tf b/terraform/environments/dev/firewall.tf
new file mode 100644
index 0000000..ad0c134
--- /dev/null
+++ b/terraform/environments/dev/firewall.tf
@@ -0,0 +1,176 @@
+# ========================================
+# 개발 환경 방화벽 규칙
+# ========================================
+locals {
+ gcp_load_balancer_health_check_source_ranges = [
+ "35.191.0.0/16",
+ "130.211.0.0/22",
+ ]
+
+ dev_firewall_rules = merge(
+ var.create_load_balancer ? {
+ # 외부 프록시 NLB와 헬스 체크가 워커 NodePort로 접근할 수 있도록 허용합니다.
+ allow_nginx_gateway_nodeports = {
+ name = "${var.vpc_name}-allow-nginx-gateway-nodeports"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = [
+ tostring(var.nginx_gateway_http_node_port),
+ tostring(var.nginx_gateway_https_node_port),
+ ]
+ }
+ ]
+ source_ranges = concat(
+ local.gcp_load_balancer_health_check_source_ranges,
+ [var.load_balancer_proxy_only_subnet_cidr]
+ )
+ target_tags = ["k8s-worker"]
+ priority = 1000
+ }
+ } : {},
+ {
+ # 마스터와 워커 노드가 Kubernetes API 서버에 접근할 수 있도록 허용합니다.
+ allow_k8s_api_from_nodes = {
+ name = "${var.vpc_name}-allow-k8s-api-from-nodes"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["6443"]
+ }
+ ]
+ source_tags = ["k8s-master", "k8s-worker"]
+ target_tags = ["k8s-master"]
+ priority = 1000
+ }
+
+ # 마스터 노드 간 etcd와 컨트롤 플레인 포트를 허용합니다.
+ allow_k8s_control_plane = {
+ name = "${var.vpc_name}-allow-k8s-control-plane"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["2379-2380", "10250", "10257", "10259"]
+ }
+ ]
+ source_tags = ["k8s-master"]
+ target_tags = ["k8s-master"]
+ priority = 1000
+ }
+
+ # 마스터 노드가 워커 노드 kubelet에 접근할 수 있도록 허용합니다.
+ allow_kubelet_from_control_plane = {
+ name = "${var.vpc_name}-allow-kubelet-from-control-plane"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["10250"]
+ }
+ ]
+ source_tags = ["k8s-master"]
+ target_tags = ["k8s-worker"]
+ priority = 1000
+ }
+
+ # 노드 간 kube-proxy 헬스 및 프록시 포트를 허용합니다.
+ allow_kube_proxy_from_nodes = {
+ name = "${var.vpc_name}-allow-kube-proxy-from-nodes"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["10256"]
+ }
+ ]
+ source_tags = ["k8s-master", "k8s-worker"]
+ target_tags = ["k8s-worker"]
+ priority = 1000
+ }
+
+ # Calico BGP 피어링에 필요한 TCP 179 포트를 허용합니다.
+ allow_calico_bgp = {
+ name = "${var.vpc_name}-allow-calico-bgp"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["179"]
+ }
+ ]
+ source_tags = ["k8s-master", "k8s-worker"]
+ target_tags = ["k8s-master", "k8s-worker"]
+ priority = 1000
+ }
+
+ # Calico VXLAN 터널링 트래픽을 허용합니다.
+ allow_calico_vxlan = {
+ name = "${var.vpc_name}-allow-calico-vxlan"
+ allow = [
+ {
+ protocol = "udp"
+ ports = ["4789"]
+ }
+ ]
+ source_tags = ["k8s-master", "k8s-worker"]
+ target_tags = ["k8s-master", "k8s-worker"]
+ priority = 1000
+ }
+
+ # Pod CIDR 대역에서 노드로 들어오는 Calico 워크로드 트래픽을 허용합니다.
+ allow_calico_pod_cidr = {
+ name = "${var.vpc_name}-allow-calico-pod-cidr"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["0-65535"]
+ },
+ {
+ protocol = "udp"
+ ports = ["0-65535"]
+ },
+ {
+ protocol = "icmp"
+ }
+ ]
+ source_ranges = [var.k8s_pod_cidr]
+ target_tags = ["k8s-master", "k8s-worker"]
+ priority = 1000
+ }
+ },
+ var.enable_iap_ssh ? {
+ # IAP TCP 터널을 통한 SSH 접근을 허용합니다.
+ allow_iap_ssh = {
+ name = "${var.vpc_name}-allow-iap-ssh"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["22"]
+ }
+ ]
+ source_ranges = var.iap_ssh_source_ranges
+ target_tags = var.management_target_tags
+ priority = 1000
+ }
+ } : {},
+ {
+ # Kubernetes 노드 태그를 가진 인스턴스끼리 내부 통신을 허용합니다.
+ allow_internal = {
+ name = "${var.vpc_name}-allow-internal"
+ allow = [
+ {
+ protocol = "tcp"
+ ports = ["0-65535"]
+ },
+ {
+ protocol = "udp"
+ ports = ["0-65535"]
+ },
+ {
+ protocol = "icmp"
+ }
+ ]
+ source_tags = ["k8s-master", "k8s-worker"]
+ target_tags = ["k8s-master", "k8s-worker"]
+ priority = 65534
+ }
+ }
+ )
+}
diff --git a/terraform/environments/dev/iap.tf b/terraform/environments/dev/iap.tf
new file mode 100644
index 0000000..3e564ff
--- /dev/null
+++ b/terraform/environments/dev/iap.tf
@@ -0,0 +1,13 @@
+# ========================================
+# IAP SSH 접근 모듈
+# ========================================
+module "iap_access" {
+ source = "../../modules/iap-access"
+
+ project_id = var.project_id
+
+ enable_iap_ssh = var.enable_iap_ssh
+ iap_ssh_members = var.iap_ssh_members
+ iap_ssh_admin_members = var.iap_ssh_admin_members
+ service_account_email = var.service_account_email
+}
diff --git a/terraform/environments/dev/load-balancer.tf b/terraform/environments/dev/load-balancer.tf
new file mode 100644
index 0000000..1f11677
--- /dev/null
+++ b/terraform/environments/dev/load-balancer.tf
@@ -0,0 +1,174 @@
+# ========================================
+# 외부 프록시 NLB 기본 로컬 값
+# ========================================
+locals {
+ load_balancer_name_prefix = "${var.project}-${var.environment}-nlb"
+}
+
+# ========================================
+# 외부 프록시 NLB용 proxy-only 서브넷
+# ========================================
+resource "google_compute_subnetwork" "load_balancer_proxy_only" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-proxy-only-subnet"
+ ip_cidr_range = var.load_balancer_proxy_only_subnet_cidr
+ region = var.region
+ network = module.vpc.vpc_self_link
+ description = "개발 환경 외부 프록시 NLB용 proxy-only subnet"
+ purpose = "REGIONAL_MANAGED_PROXY"
+ role = "ACTIVE"
+}
+
+# ========================================
+# 외부 프록시 NLB 공인 IP
+# ========================================
+resource "google_compute_address" "load_balancer_ip" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-ip"
+ region = var.region
+ network_tier = "PREMIUM"
+}
+
+# ========================================
+# HTTP NodePort 헬스 체크
+# ========================================
+resource "google_compute_region_health_check" "nginx_gateway_http" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-http-health-check"
+ region = var.region
+ check_interval_sec = 5
+ timeout_sec = 5
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ tcp_health_check {
+ port = var.nginx_gateway_http_node_port
+ }
+}
+
+# ========================================
+# HTTPS NodePort 헬스 체크
+# ========================================
+resource "google_compute_region_health_check" "nginx_gateway_https" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-https-health-check"
+ region = var.region
+ check_interval_sec = 5
+ timeout_sec = 5
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ tcp_health_check {
+ port = var.nginx_gateway_https_node_port
+ }
+}
+
+# ========================================
+# HTTP 백엔드 서비스
+# ========================================
+resource "google_compute_region_backend_service" "nginx_gateway_http" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-http-backend-service"
+ region = var.region
+ protocol = "TCP"
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+ port_name = "ngf-http"
+ timeout_sec = 30
+ session_affinity = "CLIENT_IP"
+ health_checks = [google_compute_region_health_check.nginx_gateway_http[0].id]
+
+ backend {
+ group = module.k8s_worker_nodes.instance_group_instance_group
+ balancing_mode = "UTILIZATION"
+ max_utilization = 0.6
+ capacity_scaler = 1.0
+ }
+}
+
+# ========================================
+# HTTPS 백엔드 서비스
+# ========================================
+resource "google_compute_region_backend_service" "nginx_gateway_https" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-https-backend-service"
+ region = var.region
+ protocol = "TCP"
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+ port_name = "ngf-https"
+ timeout_sec = 30
+ session_affinity = "CLIENT_IP"
+ health_checks = [google_compute_region_health_check.nginx_gateway_https[0].id]
+
+ backend {
+ group = module.k8s_worker_nodes.instance_group_instance_group
+ balancing_mode = "UTILIZATION"
+ max_utilization = 0.8
+ capacity_scaler = 1.0
+ }
+}
+
+# ========================================
+# HTTP 타깃 TCP 프록시
+# ========================================
+resource "google_compute_region_target_tcp_proxy" "nginx_gateway_http" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-http-proxy"
+ region = var.region
+ backend_service = google_compute_region_backend_service.nginx_gateway_http[0].id
+}
+
+# ========================================
+# HTTPS 타깃 TCP 프록시
+# ========================================
+resource "google_compute_region_target_tcp_proxy" "nginx_gateway_https" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-https-proxy"
+ region = var.region
+ backend_service = google_compute_region_backend_service.nginx_gateway_https[0].id
+}
+
+# ========================================
+# HTTP 포워딩 규칙
+# ========================================
+resource "google_compute_forwarding_rule" "nginx_gateway_http" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-http-forwarding-rule"
+ region = var.region
+ ip_protocol = "TCP"
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+ network = module.vpc.vpc_self_link
+ port_range = "80"
+ target = google_compute_region_target_tcp_proxy.nginx_gateway_http[0].id
+ network_tier = "PREMIUM"
+ ip_address = google_compute_address.load_balancer_ip[0].address
+
+ depends_on = [google_compute_subnetwork.load_balancer_proxy_only]
+}
+
+# ========================================
+# HTTPS 포워딩 규칙
+# ========================================
+resource "google_compute_forwarding_rule" "nginx_gateway_https" {
+ count = var.create_load_balancer ? 1 : 0
+
+ name = "${local.load_balancer_name_prefix}-https-forwarding-rule"
+ region = var.region
+ ip_protocol = "TCP"
+ load_balancing_scheme = "EXTERNAL_MANAGED"
+ network = module.vpc.vpc_self_link
+ port_range = "443"
+ target = google_compute_region_target_tcp_proxy.nginx_gateway_https[0].id
+ network_tier = "PREMIUM"
+ ip_address = google_compute_address.load_balancer_ip[0].address
+
+ depends_on = [google_compute_subnetwork.load_balancer_proxy_only]
+}
diff --git a/terraform/environments/dev/outputs.tf b/terraform/environments/dev/outputs.tf
new file mode 100644
index 0000000..caae922
--- /dev/null
+++ b/terraform/environments/dev/outputs.tf
@@ -0,0 +1,139 @@
+# ========================================
+# VPC 출력값
+# ========================================
+output "vpc_id" {
+ description = "생성된 VPC 네트워크 ID입니다."
+ value = module.vpc.vpc_id
+}
+
+output "vpc_name" {
+ description = "생성된 VPC 네트워크 이름입니다."
+ value = module.vpc.vpc_name
+}
+
+output "vpc_self_link" {
+ description = "생성된 VPC 네트워크 self link입니다."
+ value = module.vpc.vpc_self_link
+}
+
+output "subnets" {
+ description = "생성된 서브넷 정보입니다."
+ value = module.vpc.subnets
+}
+
+# ========================================
+# 스토리지 출력값
+# ========================================
+output "storage_buckets" {
+ description = "생성된 스토리지 버킷 정보입니다."
+ value = module.storage.buckets
+}
+
+output "bucket_urls" {
+ description = "생성된 버킷 URL 목록입니다."
+ value = module.storage.bucket_urls
+}
+
+# ========================================
+# Artifact Registry 출력값
+# ========================================
+output "artifact_registry_repositories" {
+ description = "생성된 Artifact Registry 저장소 정보입니다."
+ value = module.artifact_registry.repositories
+}
+
+output "artifact_registry_docker_repository_urls" {
+ description = "생성된 Docker Artifact Registry 저장소 URL 목록입니다."
+ value = module.artifact_registry.docker_repository_urls
+}
+
+# ========================================
+# Secret Manager 출력값
+# ========================================
+output "secret_manager_secrets" {
+ description = "생성된 Secret Manager secret 정보입니다."
+ value = module.secret_manager.secrets
+}
+
+output "secret_manager_secret_ids" {
+ description = "생성된 Secret Manager secret ID 목록입니다."
+ value = module.secret_manager.secret_ids
+}
+
+# ========================================
+# Artifact Registry 네트워크 출력값
+# ========================================
+output "artifact_registry_private_access" {
+ description = "Artifact Registry용 Private Google Access 구성 정보입니다."
+ value = {
+ domain_option = module.artifact_registry_private_access.google_api_domain_option
+ googleapis_private_zone_name = module.artifact_registry_private_access.googleapis_private_zone_name
+ pkg_dev_private_zone_name = module.artifact_registry_private_access.pkg_dev_private_zone_name
+ google_api_route_name = module.artifact_registry_private_access.google_api_route_name
+ direct_connectivity_route_name = module.artifact_registry_private_access.google_api_direct_connectivity_route_name
+ }
+}
+
+# ========================================
+# Kubernetes 출력값
+# ========================================
+output "k8s_master_instances" {
+ description = "생성된 Kubernetes 마스터 인스턴스 정보입니다."
+ value = module.k8s_master_nodes.instances
+}
+
+output "k8s_worker_instances" {
+ description = "생성된 Kubernetes 워커 인스턴스 정보입니다."
+ value = module.k8s_worker_nodes.instances
+}
+
+output "k8s_master_instance_group_id" {
+ description = "생성된 Kubernetes 마스터 인스턴스 그룹 ID입니다."
+ value = module.k8s_master_nodes.instance_group_id
+}
+
+output "k8s_worker_instance_group_id" {
+ description = "생성된 Kubernetes 워커 인스턴스 그룹 ID입니다."
+ value = module.k8s_worker_nodes.instance_group_id
+}
+
+output "instance_group_id" {
+ description = "생성된 Kubernetes 워커 인스턴스 그룹 ID입니다."
+ value = module.k8s_worker_nodes.instance_group_id
+}
+
+# ========================================
+# 로드 밸런서 출력값
+# ========================================
+output "load_balancer_ip" {
+ description = "로드 밸런서 IP 주소입니다."
+ value = var.create_load_balancer ? google_compute_address.load_balancer_ip[0].address : null
+}
+
+# ========================================
+# Kubernetes 네트워크 출력값
+# ========================================
+output "k8s_network_configuration" {
+ description = "Kubernetes 및 Calico 네트워크 구성 정보입니다."
+ value = {
+ pod_cidr = var.k8s_pod_cidr
+ service_cidr = var.k8s_service_cidr
+ calico_version = var.calico_version
+ encapsulation = "IPIP"
+ }
+}
+
+# ========================================
+# IAP 접근 출력값
+# ========================================
+output "iap_ssh_configuration" {
+ description = "IAP SSH 접근 구성 정보입니다."
+ value = {
+ enabled = var.enable_iap_ssh
+ source_ranges = var.enable_iap_ssh ? var.iap_ssh_source_ranges : []
+ target_tags = var.management_target_tags
+ members = module.iap_access.iap_access_members
+ admin_members = module.iap_access.iap_admin_members
+ direct_ssh_ranges = var.ssh_source_ranges
+ }
+}
diff --git a/terraform/environments/dev/private-google-access.tf b/terraform/environments/dev/private-google-access.tf
new file mode 100644
index 0000000..0787d44
--- /dev/null
+++ b/terraform/environments/dev/private-google-access.tf
@@ -0,0 +1,14 @@
+# ========================================
+# Artifact Registry Private Google Access 모듈
+# ========================================
+module "artifact_registry_private_access" {
+ source = "../../modules/private-google-access"
+
+ project_id = var.project_id
+ network_self_link = module.vpc.vpc_self_link
+ name_prefix = "${var.environment}-artifact-registry"
+ google_api_domain_option = var.google_api_domain_option
+
+ # Cloud NAT를 사용하므로 route_tags는 비어있습니다.
+ route_tags = []
+}
diff --git a/terraform/environments/dev/provider.tf b/terraform/environments/dev/provider.tf
new file mode 100644
index 0000000..b98e2ca
--- /dev/null
+++ b/terraform/environments/dev/provider.tf
@@ -0,0 +1,7 @@
+# ========================================
+# Google Provider 설정
+# ========================================
+provider "google" {
+ project = var.project_id
+ region = var.region
+}
diff --git a/terraform/environments/dev/scripts/k8s-master-init.sh b/terraform/environments/dev/scripts/k8s-master-init.sh
new file mode 100755
index 0000000..f0417e7
--- /dev/null
+++ b/terraform/environments/dev/scripts/k8s-master-init.sh
@@ -0,0 +1,174 @@
+#!/usr/bin/env bash
+set -euxo pipefail
+
+# ========================================
+# 기본 환경 점검
+# ========================================
+if [ "$(id -u)" -ne 0 ]; then
+ echo "이 스크립트는 root 권한으로 실행해야 합니다."
+ exit 1
+fi
+
+export DEBIAN_FRONTEND=noninteractive
+
+# ========================================
+# Ubuntu 기본 패키지 업데이트
+# ========================================
+apt-get update -y
+apt-get upgrade -y
+apt-get install -y apt-transport-https ca-certificates curl gpg containerd
+
+# ========================================
+# swap 비활성화
+# ========================================
+swapoff -a
+sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
+
+# ========================================
+# Kubernetes 네트워크용 커널 모듈 및 sysctl 설정
+# ========================================
+mkdir -p /etc/modules-load.d /etc/sysctl.d /etc/apt/keyrings /etc/containerd
+
+cat <<'EOF' >/etc/modules-load.d/k8s.conf
+overlay
+br_netfilter
+EOF
+
+modprobe overlay
+modprobe br_netfilter
+
+cat <<'EOF' >/etc/sysctl.d/99-kubernetes-cri.conf
+net.bridge.bridge-nf-call-iptables = 1
+net.bridge.bridge-nf-call-ip6tables = 1
+net.ipv4.ip_forward = 1
+EOF
+
+sysctl --system
+
+# ========================================
+# containerd 설정
+# ========================================
+containerd config default >/etc/containerd/config.toml
+sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
+systemctl daemon-reload
+systemctl enable --now containerd
+
+# ========================================
+# Kubernetes apt 저장소 설정
+# ========================================
+curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
+echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' >/etc/apt/sources.list.d/kubernetes.list
+
+# ========================================
+# Kubernetes 패키지 설치
+# ========================================
+apt-get update -y
+apt-get install -y kubelet kubeadm kubectl
+apt-mark hold kubelet kubeadm kubectl
+
+# ========================================
+# kubelet Artifact Registry credential provider 설정
+# ========================================
+mkdir -p /etc/kubernetes /opt/image-credential-provider
+
+cat <<'PROVIDER_EOF' >/opt/image-credential-provider/gcp-artifact-registry-provider
+#!/usr/bin/env bash
+set -euo pipefail
+
+# kubelet 요청 본문은 현재 인증 계산에 사용하지 않으므로 읽고 종료합니다.
+cat >/dev/null
+
+token_response="$(curl -fsSL -H 'Metadata-Flavor: Google' \
+ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token)"
+access_token="$(printf '%s' "$${token_response}" | sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
+
+if [ -z "$${access_token}" ]; then
+ echo "메타데이터 서버에서 Artifact Registry access token을 가져오지 못했습니다." >&2
+ exit 1
+fi
+
+cat </etc/kubernetes/credential-provider-config.yaml
+apiVersion: kubelet.config.k8s.io/v1
+kind: CredentialProviderConfig
+providers:
+ - name: gcp-artifact-registry-provider
+ apiVersion: credentialprovider.kubelet.k8s.io/v1
+ matchImages:
+ - "*.pkg.dev"
+ defaultCacheDuration: "30m"
+EOF
+
+cat <<'EOF' >/etc/default/kubelet
+KUBELET_EXTRA_ARGS="--image-credential-provider-config=/etc/kubernetes/credential-provider-config.yaml --image-credential-provider-bin-dir=/opt/image-credential-provider"
+EOF
+
+# ========================================
+# 서비스 활성화
+# ========================================
+systemctl enable --now kubelet
+
+# ========================================
+# kubeadm 및 Calico 초기 설정 파일 생성
+# ========================================
+cat </root/kubeadm-config.yaml
+apiVersion: kubeadm.k8s.io/v1beta4
+kind: ClusterConfiguration
+networking:
+ podSubnet: ${k8s_pod_cidr}
+ serviceSubnet: ${k8s_service_cidr}
+---
+apiVersion: kubelet.config.k8s.io/v1beta1
+kind: KubeletConfiguration
+cgroupDriver: systemd
+EOF
+
+cat </root/calico-custom-resources.yaml
+apiVersion: operator.tigera.io/v1
+kind: Installation
+metadata:
+ name: default
+spec:
+ calicoNetwork:
+ ipPools:
+ - blockSize: 26
+ cidr: ${k8s_pod_cidr}
+ encapsulation: IPIP
+ natOutgoing: Enabled
+ nodeSelector: all()
+EOF
+
+cat </root/install-calico.sh
+#!/usr/bin/env bash
+set -euxo pipefail
+
+kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/${calico_version}/manifests/operator-crds.yaml
+kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/${calico_version}/manifests/tigera-operator.yaml
+kubectl create -f /root/calico-custom-resources.yaml
+EOF
+
+chmod +x /root/install-calico.sh
+
+# ========================================
+# 후속 작업 안내
+# ========================================
+echo "마스터 노드 초기 설정이 완료되었습니다."
+echo "1. kubeadm init --config /root/kubeadm-config.yaml --upload-certs"
+echo "2. mkdir -p \$HOME/.kube && cp /etc/kubernetes/admin.conf \$HOME/.kube/config && chown \$(id -u):\$(id -g) \$HOME/.kube/config"
+echo "3. /root/install-calico.sh"
diff --git a/terraform/environments/dev/scripts/k8s-worker-init.sh b/terraform/environments/dev/scripts/k8s-worker-init.sh
new file mode 100755
index 0000000..372d12e
--- /dev/null
+++ b/terraform/environments/dev/scripts/k8s-worker-init.sh
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+set -euxo pipefail
+
+# ========================================
+# 기본 환경 점검
+# ========================================
+if [ "$(id -u)" -ne 0 ]; then
+ echo "이 스크립트는 root 권한으로 실행해야 합니다."
+ exit 1
+fi
+
+export DEBIAN_FRONTEND=noninteractive
+
+# ========================================
+# Ubuntu 기본 패키지 업데이트
+# ========================================
+apt-get update -y
+apt-get upgrade -y
+apt-get install -y apt-transport-https ca-certificates curl gpg containerd
+
+# ========================================
+# swap 비활성화
+# ========================================
+swapoff -a
+sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
+
+# ========================================
+# Kubernetes 네트워크용 커널 모듈 및 sysctl 설정
+# ========================================
+mkdir -p /etc/modules-load.d /etc/sysctl.d /etc/apt/keyrings /etc/containerd
+
+cat <<'EOF' >/etc/modules-load.d/k8s.conf
+overlay
+br_netfilter
+EOF
+
+modprobe overlay
+modprobe br_netfilter
+
+cat <<'EOF' >/etc/sysctl.d/99-kubernetes-cri.conf
+net.bridge.bridge-nf-call-iptables = 1
+net.bridge.bridge-nf-call-ip6tables = 1
+net.ipv4.ip_forward = 1
+EOF
+
+sysctl --system
+
+# ========================================
+# containerd 설정
+# ========================================
+containerd config default >/etc/containerd/config.toml
+sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
+systemctl daemon-reload
+systemctl enable --now containerd
+
+# ========================================
+# Kubernetes apt 저장소 설정
+# ========================================
+curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
+echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' >/etc/apt/sources.list.d/kubernetes.list
+
+# ========================================
+# Kubernetes 패키지 설치
+# ========================================
+apt-get update -y
+apt-get install -y kubelet kubeadm
+apt-mark hold kubelet kubeadm
+
+# ========================================
+# kubelet Artifact Registry credential provider 설정
+# ========================================
+mkdir -p /etc/kubernetes /opt/image-credential-provider
+
+cat <<'PROVIDER_EOF' >/opt/image-credential-provider/gcp-artifact-registry-provider
+#!/usr/bin/env bash
+set -euo pipefail
+
+# kubelet 요청 본문은 현재 인증 계산에 사용하지 않으므로 읽고 종료합니다.
+cat >/dev/null
+
+token_response="$(curl -fsSL -H 'Metadata-Flavor: Google' \
+ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token)"
+access_token="$(printf '%s' "${token_response}" | sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
+
+if [ -z "${access_token}" ]; then
+ echo "메타데이터 서버에서 Artifact Registry access token을 가져오지 못했습니다." >&2
+ exit 1
+fi
+
+cat </etc/kubernetes/credential-provider-config.yaml
+apiVersion: kubelet.config.k8s.io/v1
+kind: CredentialProviderConfig
+providers:
+ - name: gcp-artifact-registry-provider
+ apiVersion: credentialprovider.kubelet.k8s.io/v1
+ matchImages:
+ - "*.pkg.dev"
+ defaultCacheDuration: "30m"
+EOF
+
+cat <<'EOF' >/etc/default/kubelet
+KUBELET_EXTRA_ARGS="--image-credential-provider-config=/etc/kubernetes/credential-provider-config.yaml --image-credential-provider-bin-dir=/opt/image-credential-provider"
+EOF
+
+# ========================================
+# 서비스 활성화
+# ========================================
+systemctl enable --now kubelet
+
+# ========================================
+# 후속 작업 안내
+# ========================================
+echo "워커 노드 초기 설정이 완료되었습니다. 이후 kubeadm join 명령을 실행하세요."
diff --git a/terraform/environments/dev/secret-manager.tf b/terraform/environments/dev/secret-manager.tf
new file mode 100644
index 0000000..fb2c4c9
--- /dev/null
+++ b/terraform/environments/dev/secret-manager.tf
@@ -0,0 +1,13 @@
+# ========================================
+# Secret Manager 모듈
+# ========================================
+module "secret_manager" {
+ source = "../../modules/secret-manager"
+
+ project_id = var.project_id
+ common_tags = var.common_tags
+
+ secret_ids = var.secret_manager_secret_ids
+ secret_iam_bindings = var.secret_manager_secret_iam_bindings
+ secret_iam_members = var.secret_manager_secret_iam_members
+}
diff --git a/terraform/environments/dev/storage.tf b/terraform/environments/dev/storage.tf
new file mode 100644
index 0000000..56890ad
--- /dev/null
+++ b/terraform/environments/dev/storage.tf
@@ -0,0 +1,75 @@
+# ========================================
+# 스토리지 모듈
+# ========================================
+module "storage" {
+ source = "../../modules/storage"
+
+ project_id = var.project_id
+ default_location = var.storage_location
+
+ # 태그
+ common_tags = merge(var.common_tags, {
+ Service = "Storage"
+ })
+
+ # 버킷 정의
+ buckets = merge(
+
+ # 기본 버킷 추가
+ var.create_storage_buckets ? tomap({
+ static_assets = {
+ name = "${var.project}-${var.environment}"
+ storage_class = "STANDARD"
+ uniform_bucket_level_access = true
+ versioning_enabled = true
+ force_destroy = true # 개발 환경에서는 빠른 정리를 위해 강제 삭제를 허용합니다.
+ public_access_prevention = "enforced"
+
+ # 365일이 지난 정적 파일은 Nearline 클래스로 이동합니다.
+ lifecycle_rules = [
+ {
+ action = {
+ type = "SetStorageClass"
+ storage_class = "NEARLINE"
+ }
+ condition = {
+ age = 365
+ }
+ }
+ ]
+
+ # 정적 자산 제공을 위한 CORS 설정입니다.
+ cors = length(var.allowed_cors_origins) > 0 ? [
+ {
+ origin = var.allowed_cors_origins
+ method = ["GET", "HEAD"]
+ response_header = ["Content-Type"]
+ max_age_seconds = 3600
+ }
+ ] : []
+ }
+ }) : tomap({}),
+
+ # 모니터링 버킷 추가
+ var.create_monitoring_buckets ? tomap({
+ loki = {
+ name = "${var.project}-${var.environment}-${var.monitoring_loki}"
+ storage_class = "STANDARD"
+ uniform_bucket_level_access = true
+ versioning_enabled = true
+ force_destroy = true # 개발 환경에서는 빠른 정리를 위해 강제 삭제를 허용합니다.
+ public_access_prevention = "enforced"
+ cors = []
+ }
+ tempo = {
+ name = "${var.project}-${var.environment}-${var.monitoring_tempo}"
+ storage_class = "STANDARD"
+ uniform_bucket_level_access = true
+ versioning_enabled = true
+ force_destroy = true # 개발 환경에서는 빠른 정리를 위해 강제 삭제를 허용합니다.
+ public_access_prevention = "enforced"
+ cors = []
+ }
+ }) : tomap({}),
+ )
+}
diff --git a/terraform/environments/dev/terraform.tfvars.example b/terraform/environments/dev/terraform.tfvars.example
new file mode 100644
index 0000000..d0e6689
--- /dev/null
+++ b/terraform/environments/dev/terraform.tfvars.example
@@ -0,0 +1,102 @@
+# ========================================
+# 프로젝트 기본 값
+# ========================================
+project_id = "your-prod-gcp-project-id"
+project = "pinhouse"
+
+# ========================================
+# 배포 환경 기본 값
+# ========================================
+region = "asia-northeast3"
+environment = "dev"
+
+# ========================================
+# VPC 관련 값
+# ========================================
+vpc_name = "dev-vpc"
+
+# 직접 SSH를 열지 않고 IAP만 사용할 경우 빈 배열로 둡니다.
+ssh_source_ranges = []
+
+enable_iap_ssh = true
+iap_ssh_members = ["group:platform@example.com"]
+iap_ssh_admin_members = ["group:sre-admin@example.com"]
+
+enable_nat = true
+
+# ========================================
+# Artifact Registry 관련 값
+# ========================================
+artifact_registry_location = "asia-northeast3"
+
+artifact_registry_repositories = {
+ fe = {
+ repository_id = "pinhouse-dev-fe"
+ format = "DOCKER"
+ description = "프로덕션 환경용 프런트엔드 이미지 저장소"
+ immutable_tags = false
+ }
+ be = {
+ repository_id = "pinhouse-dev-be"
+ format = "DOCKER"
+ description = "프로덕션 환경용 백엔드 이미지 저장소"
+ immutable_tags = false
+ }
+}
+
+google_api_domain_option = "private.googleapis.com"
+
+# ========================================
+# Kubernetes 컴퓨트 관련 값
+# ========================================
+k8s_master_instance_group_size = 1
+k8s_worker_instance_group_size = 2
+
+enable_autoscaling = true
+autoscaling_min_replicas = 2
+autoscaling_max_replicas = 5
+
+k8s_master_machine_type = "e2-custom-2-4096"
+k8s_worker_machine_type = "e2-custom-2-4096"
+k8s_node_boot_disk_size_gb = 50
+k8s_node_source_image = "ubuntu-os-cloud/ubuntu-2204-lts"
+k8s_pod_cidr = "192.168.0.0/16"
+k8s_service_cidr = "10.96.0.0/12"
+calico_version = "v3.31.4"
+
+# ========================================
+# 스토리지 관련 값
+# ========================================
+create_storage_buckets = true
+create_monitoring_buckets = true
+storage_location = "ASIA-NORTHEAST3"
+
+# CORS 허용 Origin
+allowed_cors_origins = [
+ "https://www.example.com",
+ "https://api.example.com",
+]
+
+# ========================================
+# 로드 밸런서 관련 값
+# ========================================
+create_load_balancer = true
+load_balancer_proxy_only_subnet_cidr = "10.2.10.0/23"
+nginx_gateway_http_node_port = 30080
+nginx_gateway_https_node_port = 30443
+
+# ========================================
+# Secret Manager 관련 값
+# ========================================
+secret_manager_secret_ids = [
+ "Dev_BE_DB_URL"
+ ]
+
+ESO 또는 특정 서비스 계정에 접근 권한을 줄 때만 아래 값을 채웁니다.
+secret_manager_secret_iam_members = {
+ eso = {
+ secret_id = "Dev_BE_DB_URL"
+ role = "roles/secretmanager.secretAccessor"
+ member = "serviceAccount:example-secrets@example-pinhouse.iam.gserviceaccount.com"
+ }
+}
\ No newline at end of file
diff --git a/terraform/environments/dev/variables.tf b/terraform/environments/dev/variables.tf
new file mode 100644
index 0000000..e44f027
--- /dev/null
+++ b/terraform/environments/dev/variables.tf
@@ -0,0 +1,339 @@
+# ========================================
+# 프로젝트 기본 변수
+# ========================================
+variable "project_id" {
+ description = "배포 대상 GCP 프로젝트 ID입니다."
+ type = string
+ default = "dev-pinhouse"
+}
+
+variable "project" {
+ description = "현재 프로젝트 이름입니다."
+ type = string
+ default = "pinhouse"
+}
+
+variable "region" {
+ description = "인프라를 배포할 GCP 리전입니다."
+ type = string
+ default = "asia-northeast3"
+}
+
+variable "environment" {
+ description = "현재 Terraform 환경 이름입니다."
+ type = string
+ default = "dev"
+}
+
+# ========================================
+# VPC 관련 변수
+# ========================================
+variable "vpc_name" {
+ description = "생성할 VPC 네트워크 이름입니다."
+ type = string
+ default = "dev-vpc"
+}
+
+variable "ssh_source_ranges" {
+ description = "직접 SSH 접근을 허용할 CIDR 목록입니다. 비워두면 IAP만 허용합니다."
+ type = list(string)
+ default = []
+}
+
+variable "enable_iap_ssh" {
+ description = "IAP TCP 터널 기반 SSH 접근 허용 여부입니다."
+ type = bool
+ default = true
+}
+
+variable "iap_ssh_source_ranges" {
+ description = "IAP TCP 터널이 인스턴스로 접근할 때 허용할 Google 관리 소스 CIDR 목록입니다."
+ type = list(string)
+ default = ["35.235.240.0/20"]
+}
+
+variable "management_target_tags" {
+ description = "SSH 및 IAP 관리 접근을 허용할 인스턴스 태그 목록입니다."
+ type = list(string)
+ default = ["k8s-master", "k8s-worker"]
+}
+
+variable "enable_nat" {
+ description = "Cloud NAT 사용 여부입니다."
+ type = bool
+ default = true
+}
+
+# ========================================
+# IAP 관련 변수
+# ========================================
+variable "iap_ssh_members" {
+ description = "IAP 터널과 일반 OS Login 권한을 부여할 IAM 주체 목록입니다."
+ type = list(string)
+ default = []
+}
+
+variable "iap_ssh_admin_members" {
+ description = "IAP 터널과 관리자 OS Login 권한을 부여할 IAM 주체 목록입니다."
+ type = list(string)
+ default = []
+}
+
+# ========================================
+# Artifact Registry 관련 변수
+# ========================================
+variable "artifact_registry_location" {
+ description = "Artifact Registry 저장소 기본 생성 위치입니다."
+ type = string
+ default = "asia-northeast3"
+}
+
+variable "artifact_registry_repositories" {
+ description = "생성할 Artifact Registry 저장소 정의 목록입니다."
+ type = map(object({
+ repository_id = string
+ format = string
+ description = optional(string)
+ location = optional(string)
+ immutable_tags = optional(bool)
+ common_tags = optional(map(string))
+ }))
+ default = {
+ fe = {
+ repository_id = "pinhouse-dev-fe"
+ format = "DOCKER"
+ description = "개발 환경용 프런트엔드 이미지 저장소"
+ immutable_tags = false
+ }
+ be = {
+ repository_id = "pinhouse-dev-be"
+ format = "DOCKER"
+ description = "개발 환경용 백엔드 이미지 저장소"
+ immutable_tags = false
+ }
+ }
+}
+
+variable "artifact_registry_repository_iam_bindings" {
+ description = "Artifact Registry 저장소 IAM 바인딩 정의 목록입니다."
+ type = map(object({
+ repository_key = string
+ role = string
+ members = list(string)
+ }))
+ default = {}
+}
+
+variable "artifact_registry_repository_iam_members" {
+ description = "Artifact Registry 저장소 IAM 멤버 정의 목록입니다."
+ type = map(object({
+ repository_key = string
+ role = string
+ member = string
+ }))
+ default = {}
+}
+
+# ========================================
+# Secret Manager 관련 변수
+# ========================================
+variable "secret_manager_secret_ids" {
+ description = "생성할 Secret Manager 비밀 ID 목록입니다."
+ type = list(string)
+ default = []
+}
+
+variable "secret_manager_secret_iam_bindings" {
+ description = "Secret Manager 비밀 IAM 바인딩 정의 목록입니다."
+ type = map(object({
+ secret_id = string
+ role = string
+ members = list(string)
+ }))
+ default = {}
+}
+
+variable "secret_manager_secret_iam_members" {
+ description = "Secret Manager 비밀 IAM 멤버 정의 목록입니다."
+ type = map(object({
+ secret_id = string
+ role = string
+ member = string
+ }))
+ default = {}
+}
+
+# ========================================
+# Private Google Access 관련 변수
+# ========================================
+variable "google_api_domain_option" {
+ description = "Artifact Registry와 Google APIs에 사용할 Private Google Access 도메인 옵션입니다."
+ type = string
+ default = "private.googleapis.com"
+
+ validation {
+ condition = contains(["private.googleapis.com", "restricted.googleapis.com"], var.google_api_domain_option)
+ error_message = "google_api_domain_option은 private.googleapis.com 또는 restricted.googleapis.com 중 하나여야 합니다."
+ }
+}
+
+# ========================================
+# 스토리지 관련 변수
+# ========================================
+variable "create_storage_buckets" {
+ description = "스토리지 버킷 생성 여부입니다."
+ type = bool
+ default = true
+}
+
+variable "create_monitoring_buckets" {
+ description = "모니터링 버킷 생성 여부입니다."
+ type = bool
+ default = false
+}
+
+variable "monitoring_loki" {
+ description = "Loki에서 사용할 모니터링 라벨입니다."
+ type = string
+ default = "loki"
+}
+
+variable "monitoring_tempo" {
+ description = "Tempo에서 사용할 모니터링 라벨입니다."
+ type = string
+ default = "tempo"
+}
+
+variable "storage_location" {
+ description = "스토리지 버킷을 생성할 위치입니다."
+ type = string
+ default = "ASIA-NORTHEAST3"
+}
+
+variable "allowed_cors_origins" {
+ description = "정적 자산 버킷에서 허용할 CORS Origin 목록입니다."
+ type = list(string)
+ default = []
+}
+
+# ========================================
+# 컴퓨트 관련 변수
+# ========================================
+variable "k8s_master_instance_group_size" {
+ description = "Kubernetes 마스터 관리형 인스턴스 그룹의 목표 인스턴스 수입니다."
+ type = number
+ default = 1
+}
+
+variable "k8s_worker_instance_group_size" {
+ description = "Kubernetes 워커 관리형 인스턴스 그룹의 목표 인스턴스 수입니다."
+ type = number
+ default = 1 # 개발 환경에서는 비용 절감을 위해 1개로 설정합니다.
+}
+
+variable "enable_autoscaling" {
+ description = "오토스케일링 사용 여부입니다."
+ type = bool
+ default = false # 개발 환경에서는 비활성화합니다.
+}
+
+variable "autoscaling_min_replicas" {
+ description = "오토스케일링 최소 인스턴스 수입니다."
+ type = number
+ default = 1
+}
+
+variable "autoscaling_max_replicas" {
+ description = "오토스케일링 최대 인스턴스 수입니다."
+ type = number
+ default = 3 # 개발 환경에서는 3개로 제한합니다.
+}
+
+variable "k8s_master_machine_type" {
+ description = "Kubernetes 마스터 노드에 사용할 머신 타입입니다."
+ type = string
+ default = "e2-custom-2-4096"
+}
+
+variable "k8s_worker_machine_type" {
+ description = "Kubernetes 워커 노드에 사용할 머신 타입입니다."
+ type = string
+ default = "e2-custom-2-4096"
+}
+
+variable "k8s_node_boot_disk_size_gb" {
+ description = "Kubernetes 노드 부팅 디스크 크기(GB)입니다."
+ type = number
+ default = 50
+}
+
+variable "k8s_node_source_image" {
+ description = "Kubernetes 노드 부팅 디스크에 사용할 이미지입니다."
+ type = string
+ default = "ubuntu-os-cloud/ubuntu-2204-lts"
+}
+
+variable "k8s_pod_cidr" {
+ description = "Kubernetes Pod CIDR 대역입니다. Calico IPPool과 kubeadm podSubnet에 동일하게 사용합니다."
+ type = string
+ default = "192.168.0.0/16"
+}
+
+variable "k8s_service_cidr" {
+ description = "Kubernetes Service CIDR 대역입니다."
+ type = string
+ default = "10.96.0.0/12"
+}
+
+variable "calico_version" {
+ description = "초기 설치에 사용할 Calico 오픈소스 릴리스 버전입니다."
+ type = string
+ default = "v3.31.4"
+}
+
+variable "service_account_email" {
+ description = "인스턴스에 연결할 서비스 계정 이메일입니다."
+ type = string
+ default = null
+}
+
+# ========================================
+# 로드 밸런서 관련 변수
+# ========================================
+variable "create_load_balancer" {
+ description = "로드 밸런서 생성 여부입니다."
+ type = bool
+ default = false
+}
+
+variable "load_balancer_proxy_only_subnet_cidr" {
+ description = "외부 프록시 NLB용 proxy-only 서브넷 CIDR 대역입니다."
+ type = string
+ default = "10.0.10.0/23"
+}
+
+variable "nginx_gateway_http_node_port" {
+ description = "NGINX Gateway Fabric HTTP NodePort 포트입니다."
+ type = number
+ default = 30080
+}
+
+variable "nginx_gateway_https_node_port" {
+ description = "NGINX Gateway Fabric HTTPS NodePort 포트입니다."
+ type = number
+ default = 30443
+}
+
+# ========================================
+# 공통 태그 변수
+# ========================================
+variable "common_tags" {
+ description = "공통 태그입니다."
+ type = map(string)
+ default = {
+ Project = "pinhouse"
+ Environment = "dev"
+ Version = "v1"
+ ManagedBy = "terraform"
+ }
+}
diff --git a/terraform/environments/dev/versions.tf b/terraform/environments/dev/versions.tf
new file mode 100644
index 0000000..49f0907
--- /dev/null
+++ b/terraform/environments/dev/versions.tf
@@ -0,0 +1,13 @@
+# ========================================
+# Terraform 공통 설정
+# ========================================
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = "~> 5.0"
+ }
+ }
+}
diff --git a/terraform/environments/dev/vpc.tf b/terraform/environments/dev/vpc.tf
new file mode 100644
index 0000000..1f4cd82
--- /dev/null
+++ b/terraform/environments/dev/vpc.tf
@@ -0,0 +1,45 @@
+# ========================================
+# VPC 모듈
+# ========================================
+module "vpc" {
+ source = "../../modules/vpc"
+
+ vpc_name = var.vpc_name
+ description = "개발 환경용 VPC 네트워크"
+ routing_mode = "REGIONAL"
+
+ # 서브넷 정의
+ subnets = {
+ web = {
+ name = "${var.vpc_name}-web-subnet"
+ ip_cidr_range = "10.0.1.0/24"
+ region = var.region
+ description = "웹 서버용 서브넷"
+ private_ip_google_access = true
+ }
+ app = {
+ name = "${var.vpc_name}-app-subnet"
+ ip_cidr_range = "10.0.2.0/24"
+ region = var.region
+ description = "애플리케이션 서버용 서브넷"
+ private_ip_google_access = true
+ }
+ db = {
+ name = "${var.vpc_name}-db-subnet"
+ ip_cidr_range = "10.0.3.0/24"
+ region = var.region
+ description = "데이터베이스용 서브넷"
+ private_ip_google_access = true
+ }
+ }
+
+ # 방화벽 규칙 정의
+ firewall_rules = local.dev_firewall_rules
+
+ # Cloud NAT 설정
+ enable_nat = var.enable_nat
+ nat_region = var.region
+ router_asn = 64514
+ nat_log_enable = true
+ nat_log_filter = "ERRORS_ONLY"
+}