refactor: 구조 변경
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{yaml,yml,json,tf,tofu,hcl}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.tf text eol=lf
|
||||||
|
*.tofu text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.jpg binary
|
||||||
|
*.pdf binary
|
||||||
|
*.png binary
|
||||||
|
*.webp binary
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
echo "image_digest must be an immutable sha256 digest" >&2
|
echo "image_digest must be an immutable sha256 digest" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
manifest="clusters/dev-k3s/overlays/workloads/${SERVICE}/kustomization.yaml"
|
manifest="gitops/clusters/dev-k3s/overlays/workloads/${SERVICE}/kustomization.yaml"
|
||||||
temporary="$(mktemp "${manifest}.XXXXXX")"
|
temporary="$(mktemp "${manifest}.XXXXXX")"
|
||||||
awk -v image_name="$image_name" -v image_digest="$IMAGE_DIGEST" '
|
awk -v image_name="$image_name" -v image_digest="$IMAGE_DIGEST" '
|
||||||
$1 == "-" && $2 == "name:" { target = ($3 == image_name) }
|
$1 == "-" && $2 == "name:" { target = ($3 == image_name) }
|
||||||
@@ -85,7 +85,7 @@ jobs:
|
|||||||
git config user.name "gitops-bot"
|
git config user.name "gitops-bot"
|
||||||
git config user.email "gitops-bot@hyeonworks.local"
|
git config user.email "gitops-bot@hyeonworks.local"
|
||||||
git switch -c "$branch"
|
git switch -c "$branch"
|
||||||
git add "clusters/dev-k3s/overlays/workloads/${SERVICE}/kustomization.yaml"
|
git add "gitops/clusters/dev-k3s/overlays/workloads/${SERVICE}/kustomization.yaml"
|
||||||
git commit -m "chore(gitops): promote ${SERVICE} dev digest"
|
git commit -m "chore(gitops): promote ${SERVICE} dev digest"
|
||||||
git push --set-upstream origin "$branch"
|
git push --set-upstream origin "$branch"
|
||||||
echo "PROMOTION_BRANCH=$branch" >>"$GITHUB_ENV"
|
echo "PROMOTION_BRANCH=$branch" >>"$GITHUB_ENV"
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Validate
|
- name: Validate
|
||||||
run: ./hack/validate.sh
|
run: make check
|
||||||
|
|||||||
+51
-7
@@ -1,22 +1,66 @@
|
|||||||
# Terraform working directories and local state
|
# OS and editors
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Local environment and credentials
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
*.p12
|
||||||
|
*.pfx
|
||||||
|
*.jks
|
||||||
|
credentials.json
|
||||||
|
id_dsa
|
||||||
|
id_ecdsa
|
||||||
|
id_ed25519
|
||||||
|
id_rsa
|
||||||
|
|
||||||
|
# Kubernetes local access
|
||||||
|
kubeconfig
|
||||||
|
kubeconfig.*
|
||||||
|
*.kubeconfig
|
||||||
|
|
||||||
|
# Terraform / OpenTofu working directories and local state
|
||||||
**/.terraform/*
|
**/.terraform/*
|
||||||
**/.terraform-state/*
|
**/.terraform-state/*
|
||||||
|
**/.terragrunt-cache/*
|
||||||
*.tfstate
|
*.tfstate
|
||||||
*.tfstate.*
|
*.tfstate.*
|
||||||
*.tfplan
|
*.tfplan
|
||||||
*.tfvars
|
*.tfvars
|
||||||
!*.tfvars.example
|
!*.tfvars.example
|
||||||
|
plan.out
|
||||||
|
.terraform.tfstate.lock.info
|
||||||
crash.log
|
crash.log
|
||||||
crash.*.log
|
crash.*.log
|
||||||
|
override.tf
|
||||||
|
override.tf.json
|
||||||
|
*_override.tf
|
||||||
|
*_override.tf.json
|
||||||
|
*.local.tfvars
|
||||||
|
*.secret.tfvars
|
||||||
|
|
||||||
# Bootstrap material and local operator files
|
# Bootstrap material and local operator files
|
||||||
.local/*
|
.local/*
|
||||||
!.local/.gitkeep
|
!.local/.gitkeep
|
||||||
*init*.json
|
*init*.json
|
||||||
|
|
||||||
# Tool and editor output
|
# Decrypted or generated secret material
|
||||||
.DS_Store
|
.decrypted/
|
||||||
.idea/
|
*.decrypted.yaml
|
||||||
.vscode/
|
*.dec.yaml
|
||||||
*.swp
|
|
||||||
*.tmp
|
# Build, render, and test output
|
||||||
|
.build/
|
||||||
|
.cache/
|
||||||
|
dist/
|
||||||
|
rendered/
|
||||||
|
tmp/
|
||||||
|
coverage/
|
||||||
|
*.log
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
Vault init JSON, unseal/recovery material or plaintext credentials.
|
Vault init JSON, unseal/recovery material or plaintext credentials.
|
||||||
- A Vault API object may be owned by only one Terraform state.
|
- A Vault API object may be owned by only one Terraform state.
|
||||||
- Keep secret payloads outside Terraform resources and data sources.
|
- Keep secret payloads outside Terraform resources and data sources.
|
||||||
- Classify shared capabilities under `platform`, bounded-context backing
|
- Classify shared capabilities under `gitops/platform`, bounded-context
|
||||||
services under `systems`, and first-party runtimes under `workloads`.
|
backing services under `gitops/apps/systems`, and first-party runtimes under
|
||||||
|
`gitops/apps/workloads`.
|
||||||
- Manage child Argo CD Applications through the permission-scoped
|
- Manage child Argo CD Applications through the permission-scoped
|
||||||
ApplicationSets in `platform/control-plane/argocd`; do not add explicit
|
ApplicationSets in `gitops/platform/control-plane/argocd`; do not add explicit
|
||||||
child Applications or use the `default` AppProject.
|
child Applications or use the `default` AppProject.
|
||||||
- Add new ApplicationSet entries with `autoSync: "false"` and open each gate
|
- Add new ApplicationSet entries with `autoSync: "false"` and open each gate
|
||||||
only after its documented external prerequisites have been verified.
|
only after its documented external prerequisites have been verified.
|
||||||
|
|||||||
@@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
## 2026-07-26
|
## 2026-07-26
|
||||||
|
|
||||||
|
- Adopted the `k8s-template` lifecycle layout: bootstrap under
|
||||||
|
`bootstrap/gitops`, Terraform under `infrastructure`, all Kubernetes desired
|
||||||
|
state under `gitops`, automation under `scripts`, and ADRs under
|
||||||
|
`docs/decisions`.
|
||||||
|
- Made `gitops/clusters/dev-k3s` the root Application source while preserving
|
||||||
|
permission-scoped ApplicationSets and their staged `autoSync` gates.
|
||||||
|
- Co-located reusable Terraform modules in `infrastructure/components`,
|
||||||
|
backend examples with each live root, and Vault ACLs with their owning
|
||||||
|
Terraform state.
|
||||||
|
- Added the template catalogs, `_template` directories, examples, security
|
||||||
|
checks, and common validation ahead of project-specific validation.
|
||||||
- Clarified that this repository is an independent GitOps reference lab, not a
|
- Clarified that this repository is an independent GitOps reference lab, not a
|
||||||
shared production platform or an application source monorepo.
|
shared production platform or an application source monorepo.
|
||||||
- Reclassified Kubernetes ownership as `platform`, `systems` and `workloads`;
|
- Reclassified Kubernetes ownership as `platform`, `systems` and `workloads`;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# 기여 가이드
|
||||||
|
|
||||||
|
## 변경 원칙
|
||||||
|
|
||||||
|
1. 변경 대상의 소유 디렉터리를 먼저 확인합니다.
|
||||||
|
2. 재사용 가능한 구현은 catalog 영역에, 환경별 조합과 차이만 live/cluster
|
||||||
|
진입점에 둡니다.
|
||||||
|
3. 하나의 리소스는 하나의 도구와 하나의 디렉터리만 소유합니다.
|
||||||
|
4. 운영 변경에는 영향 범위, 롤백 방법, 검증 결과를 함께 기록합니다.
|
||||||
|
5. `make check`를 통과한 변경만 리뷰를 요청합니다.
|
||||||
|
|
||||||
|
## 이름 규칙
|
||||||
|
|
||||||
|
- 폴더와 리소스: 소문자 `kebab-case`
|
||||||
|
- 환경: `dev`, `staging`, `prod`처럼 조직에서 합의한 고정 어휘
|
||||||
|
- 클러스터: 환경과 위치를 식별할 수 있는 안정적인 이름
|
||||||
|
- 임시 이름, 사람 이름, 티켓 번호를 장기 리소스 이름에 사용하지 않음
|
||||||
|
|
||||||
|
## Pull request 체크리스트
|
||||||
|
|
||||||
|
- [ ] 변경이 올바른 소유권 경계에 위치한다.
|
||||||
|
- [ ] 비밀, kubeconfig, state, plan 파일이 포함되지 않았다.
|
||||||
|
- [ ] 공급자, module, chart, image 버전 변경의 영향을 확인했다.
|
||||||
|
- [ ] `make check` 결과를 확인했다.
|
||||||
|
- [ ] 운영 영향이 있으면 rollback/runbook을 갱신했다.
|
||||||
|
- [ ] 구조적 선택이 바뀌면 ADR을 추가하거나 갱신했다.
|
||||||
|
|
||||||
|
## 배포
|
||||||
|
|
||||||
|
Kubernetes routine 변경은 Git PR로만 반영합니다. Terraform apply는
|
||||||
|
`TF_ROOT`, backend config, 검토된 saved plan과 `APPROVE_APPLY`가 모두
|
||||||
|
준비된 경우에만 실행합니다. `destroy` 진입점은 제공하지 않습니다.
|
||||||
@@ -1,20 +1,45 @@
|
|||||||
.PHONY: bootstrap validate vault-init terraform-init terraform-plan terraform-apply check-terraform-inputs
|
SHELL := /bin/bash
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
.PHONY: help doctor validate check tree bootstrap vault-init terraform-init terraform-plan terraform-apply check-terraform-inputs
|
||||||
|
|
||||||
KUBE_CONTEXT ?=
|
KUBE_CONTEXT ?=
|
||||||
TF_ROOT ?=
|
TF_ROOT ?=
|
||||||
BACKEND_CONFIG ?=
|
BACKEND_CONFIG ?=
|
||||||
TF_DIR = iac/terraform/live/dev-k3s/$(TF_ROOT)
|
TF_DIR = infrastructure/live/dev-k3s/$(TF_ROOT)
|
||||||
PLAN_FILE ?= $(CURDIR)/.local/terraform-plans/dev-k3s-$(TF_ROOT).tfplan
|
PLAN_FILE ?= $(CURDIR)/.local/terraform-plans/dev-k3s-$(TF_ROOT).tfplan
|
||||||
|
|
||||||
bootstrap:
|
help: ## 사용 가능한 명령을 표시합니다.
|
||||||
|
@awk 'BEGIN {FS = ":.*## "; print "Usage: make <target>"} /^[a-zA-Z_-]+:.*## / {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
doctor: ## 현재 로컬 도구 상태를 확인합니다.
|
||||||
|
@./scripts/doctor.sh
|
||||||
|
|
||||||
|
validate: ## 템플릿 구조와 프로젝트별 GitOps/IaC 계약을 검증합니다.
|
||||||
|
@./scripts/validate.sh
|
||||||
|
|
||||||
|
check: validate ## CI와 동일한 전체 검증을 실행합니다.
|
||||||
|
|
||||||
|
tree: ## 생성물과 Git 메타데이터를 제외한 구조를 표시합니다.
|
||||||
|
@find . \
|
||||||
|
\( \
|
||||||
|
-name .build -o \
|
||||||
|
-name .cache -o \
|
||||||
|
-name .git -o \
|
||||||
|
-name .terraform -o \
|
||||||
|
-name .terragrunt-cache -o \
|
||||||
|
-name dist -o \
|
||||||
|
-name rendered -o \
|
||||||
|
-name tmp \
|
||||||
|
\) -prune -o \
|
||||||
|
-print | sort
|
||||||
|
|
||||||
|
bootstrap: ## 확인된 kube context에 Argo CD와 root Application을 설치합니다.
|
||||||
@test -n "$(KUBE_CONTEXT)" || (echo "KUBE_CONTEXT is required" >&2; exit 1)
|
@test -n "$(KUBE_CONTEXT)" || (echo "KUBE_CONTEXT is required" >&2; exit 1)
|
||||||
./hack/bootstrap-argocd.sh --context "$(KUBE_CONTEXT)"
|
./scripts/bootstrap-argocd.sh --context "$(KUBE_CONTEXT)"
|
||||||
|
|
||||||
validate:
|
vault-init: ## 개발 Vault를 최초 초기화합니다.
|
||||||
./hack/validate.sh
|
./scripts/vault-init.sh init
|
||||||
|
|
||||||
vault-init:
|
|
||||||
./hack/vault-init.sh init
|
|
||||||
|
|
||||||
check-terraform-inputs:
|
check-terraform-inputs:
|
||||||
@case "$(TF_ROOT)" in \
|
@case "$(TF_ROOT)" in \
|
||||||
@@ -23,17 +48,17 @@ check-terraform-inputs:
|
|||||||
esac
|
esac
|
||||||
@test -f "$(BACKEND_CONFIG)" || (echo "BACKEND_CONFIG must point to a readable backend file" >&2; exit 1)
|
@test -f "$(BACKEND_CONFIG)" || (echo "BACKEND_CONFIG must point to a readable backend file" >&2; exit 1)
|
||||||
|
|
||||||
terraform-init: check-terraform-inputs
|
terraform-init: check-terraform-inputs ## 선택한 Vault Terraform root를 초기화합니다.
|
||||||
terraform -chdir="$(TF_DIR)" init -input=false -reconfigure -backend-config="$(abspath $(BACKEND_CONFIG))"
|
terraform -chdir="$(TF_DIR)" init -input=false -reconfigure -backend-config="$(abspath $(BACKEND_CONFIG))"
|
||||||
|
|
||||||
terraform-plan: terraform-init
|
terraform-plan: terraform-init ## 검토 가능한 saved Terraform plan을 만듭니다.
|
||||||
@mkdir -p "$(dir $(PLAN_FILE))"
|
@mkdir -p "$(dir $(PLAN_FILE))"
|
||||||
@umask 077; terraform -chdir="$(TF_DIR)" plan \
|
@umask 077; terraform -chdir="$(TF_DIR)" plan \
|
||||||
-input=false \
|
-input=false \
|
||||||
-lock-timeout=5m \
|
-lock-timeout=5m \
|
||||||
-out="$(PLAN_FILE)"
|
-out="$(PLAN_FILE)"
|
||||||
|
|
||||||
terraform-apply: terraform-init
|
terraform-apply: terraform-init ## 명시적으로 승인한 saved Terraform plan을 적용합니다.
|
||||||
@test "$(APPROVE_APPLY)" = "dev-k3s/$(TF_ROOT)" || \
|
@test "$(APPROVE_APPLY)" = "dev-k3s/$(TF_ROOT)" || \
|
||||||
(echo "Set APPROVE_APPLY=dev-k3s/$(TF_ROOT) to continue" >&2; exit 1)
|
(echo "Set APPROVE_APPLY=dev-k3s/$(TF_ROOT) to continue" >&2; exit 1)
|
||||||
@test -f "$(PLAN_FILE)" || \
|
@test -f "$(PLAN_FILE)" || \
|
||||||
|
|||||||
@@ -56,41 +56,54 @@ Plugin 안에서 실행하지 않습니다.
|
|||||||
## 저장소 분류
|
## 저장소 분류
|
||||||
|
|
||||||
```text
|
```text
|
||||||
bootstrap/argocd/ controller 버전, 제한된 AppProject와 단일 root seed
|
bootstrap/
|
||||||
clusters/dev-k3s/
|
foundation/ 외부 state/identity 선행 조건 문서
|
||||||
|
gitops/argocd/ controller 버전, 제한된 AppProject와 단일 root seed
|
||||||
|
infrastructure/
|
||||||
|
components/ 재사용 Vault Terraform component
|
||||||
|
live/dev-k3s/
|
||||||
|
vault-foundation/ mount/auth와 delegated automation policy
|
||||||
|
vault-workloads/ workload ACL, auth role와 Transit key
|
||||||
|
vault-database/ PostgreSQL connection과 dynamic role
|
||||||
|
gitops/clusters/dev-k3s/
|
||||||
|
kustomization.yaml Argo CD가 읽는 유일한 cluster root
|
||||||
overlays/
|
overlays/
|
||||||
platform/ 공유 서비스의 dev-k3s 최종 구성
|
platform/ 공유 서비스의 dev-k3s 최종 구성
|
||||||
systems/ bounded context system의 dev-k3s 최종 구성
|
systems/ bounded-context system의 dev-k3s 최종 구성
|
||||||
workloads/ first-party workload의 dev-k3s 최종 구성
|
workloads/ first-party workload의 dev-k3s 최종 구성
|
||||||
platform/
|
gitops/platform/
|
||||||
control-plane/argocd/ AppProject와 ApplicationSet inventory
|
control-plane/argocd/ AppProject와 ApplicationSet inventory
|
||||||
shared-services/ 여러 system이 사용할 수 있는 cluster capability base
|
shared-services/ 여러 system이 쓰는 cluster capability base
|
||||||
systems/ 특정 bounded context가 소유하는 backing system base
|
gitops/apps/
|
||||||
workloads/ source repository가 따로 있는 실행 애플리케이션 base
|
systems/ bounded-context backing system base
|
||||||
iac/terraform/
|
workloads/ 별도 source repository를 가진 application base
|
||||||
modules/ 재사용 Vault 모듈
|
scripts/ bootstrap, validation, dev Vault init entrypoint
|
||||||
live/dev-k3s/ vault-foundation, vault-workloads, vault-database roots
|
docs/ architecture, ADR, guide와 runbook
|
||||||
backend/dev-k3s/ secret 없는 remote backend 예시
|
examples/, tests/ 템플릿 예제와 저장소 수준 검증 영역
|
||||||
policies/vault/ Terraform이 읽는 Vault ACL 문서
|
|
||||||
hack/ bootstrap, validation, dev Vault init entrypoint
|
|
||||||
docs/ architecture, ADR, migration/operation runbook
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
각 catalog의 `_template`은 새 component를 만들 때 사용하는 복사 원본이며
|
||||||
|
Argo CD가 직접 reconcile하지 않습니다.
|
||||||
|
|
||||||
분류는 제품 종류가 아니라 소비자, 소유자, 변경 주기로 결정합니다.
|
분류는 제품 종류가 아니라 소비자, 소유자, 변경 주기로 결정합니다.
|
||||||
Vault는 공유 capability이므로 `platform/`, Project Auth 전용 PostgreSQL과
|
Vault는 공유 capability이므로 `gitops/platform/`, Project Auth 전용
|
||||||
Keycloak은 `systems/auth-system/`, 직접 빌드하는 서버는 `workloads/`에
|
PostgreSQL과 Keycloak은 `gitops/apps/systems/auth-system/`, 직접 빌드하는
|
||||||
속합니다. namespace, host, image digest, Vault role, NetworkPolicy 같은
|
서버는 `gitops/apps/workloads/`에 속합니다. namespace, host, image digest,
|
||||||
클러스터별 값은 `clusters/dev-k3s/overlays/`에서 완결합니다.
|
Vault role, NetworkPolicy 같은 클러스터별 값은
|
||||||
|
`gitops/clusters/dev-k3s/overlays/`에서 완결합니다. Vault ACL은 소비하는
|
||||||
|
Terraform state의 `policies/`에 함께 둡니다.
|
||||||
|
|
||||||
자세한 판단 기준은
|
자세한 판단 기준은
|
||||||
[repository taxonomy](docs/architecture/repository-taxonomy.md)와
|
[repository taxonomy](docs/architecture/repository-taxonomy.md)와
|
||||||
[ADR 0007](docs/adr/0007-repository-ownership-boundaries.md)을 따릅니다.
|
[ADR 0007](docs/decisions/0007-repository-ownership-boundaries.md)을 따릅니다.
|
||||||
|
|
||||||
## Argo CD 단계 gate
|
## Argo CD 단계 gate
|
||||||
|
|
||||||
Root Application은 `platform/control-plane/argocd`의 AppProject와
|
Root Application은 `gitops/clusters/dev-k3s`만 source로 사용합니다. 이
|
||||||
ApplicationSet을 소유합니다. 각 inventory 항목은 `autoSync`를 quoted
|
cluster root가 `gitops/platform/control-plane/argocd`의 AppProject와
|
||||||
string으로 명시해야 합니다. 새 항목이나 외부 준비 조건이 있는 항목은
|
ApplicationSet을 조립하고, 각 ApplicationSet이 cluster overlay를
|
||||||
|
reconcile합니다. 각 inventory 항목은 `autoSync`를 quoted string으로
|
||||||
|
명시해야 합니다. 새 항목이나 외부 준비 조건이 있는 항목은
|
||||||
`autoSync: "false"`로 시작하고, 선행 controller, Vault 구성, runtime
|
`autoSync: "false"`로 시작하고, 선행 controller, Vault 구성, runtime
|
||||||
secret, database 준비를 확인한 PR에서만 `autoSync: "true"`로 바꿉니다.
|
secret, database 준비를 확인한 PR에서만 `autoSync: "true"`로 바꿉니다.
|
||||||
|
|
||||||
@@ -146,4 +159,4 @@ make terraform-plan \
|
|||||||
- [Terraform state 이관](docs/runbooks/terraform-state-migration.md)
|
- [Terraform state 이관](docs/runbooks/terraform-state-migration.md)
|
||||||
- [Vault backup/recovery](docs/runbooks/vault-backup-restore.md)
|
- [Vault backup/recovery](docs/runbooks/vault-backup-restore.md)
|
||||||
- [Sealed Secrets recovery](docs/runbooks/sealed-secrets-recovery.md)
|
- [Sealed Secrets recovery](docs/runbooks/sealed-secrets-recovery.md)
|
||||||
- [입문 가이드](INTERN_GUIDE.md)
|
- [입문 가이드](docs/guides/intern-guide.md)
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## 저장소에 둘 수 없는 항목
|
||||||
|
|
||||||
|
- 평문 비밀번호, token, access key, private key
|
||||||
|
- base64로만 인코딩한 Kubernetes `Secret`
|
||||||
|
- kubeconfig와 클라우드 provider credential
|
||||||
|
- Terraform/OpenTofu state, plan, 복호화 산출물
|
||||||
|
- 실제 비밀이 포함된 `tfvars`, Helm values, `.env`
|
||||||
|
|
||||||
|
`.gitignore`는 실수 완화 장치일 뿐 보안 통제가 아닙니다. 비밀이 한 번이라도
|
||||||
|
커밋되었다면 history 삭제 여부와 관계없이 즉시 폐기하고 회전합니다.
|
||||||
|
|
||||||
|
## 허용하는 비밀 관리 방식
|
||||||
|
|
||||||
|
프로젝트마다 다음 중 하나를 ADR로 선택하고 CI와 운영 절차를 함께 정의합니다.
|
||||||
|
|
||||||
|
- External Secrets 계열 리소스로 외부 secret manager를 참조
|
||||||
|
- SOPS와 KMS/age를 사용해 암호화한 파일만 저장
|
||||||
|
- 조직에서 승인한 동등한 GitOps 비밀 관리 방식
|
||||||
|
|
||||||
|
SOPS로 암호화한 Kubernetes Secret은 검증 가능한 규칙을 위해
|
||||||
|
`*.sops.yaml`, `*.sops.yml` 또는 `*.sops.json` 이름을 사용합니다.
|
||||||
|
|
||||||
|
암호화 키, 복호화 권한과 secret manager 접근은 workload identity/OIDC와
|
||||||
|
최소 권한 원칙으로 부여합니다. 장기 cloud access key를 CI secret으로
|
||||||
|
사용하지 않습니다.
|
||||||
|
|
||||||
|
## State와 CI
|
||||||
|
|
||||||
|
- remote state는 암호화, locking, versioning을 활성화합니다.
|
||||||
|
- 환경과 독립 장애 영역은 별도 state로 분리합니다.
|
||||||
|
- production apply에는 승인, 직렬화와 감사 로그를 적용합니다.
|
||||||
|
- fork 또는 신뢰하지 않는 PR 코드에 privileged credential을 제공하지 않습니다.
|
||||||
|
- CI action, provider, module, chart와 image 버전을 검토 가능한 방식으로 고정합니다.
|
||||||
|
|
||||||
|
## 노출 사고 대응
|
||||||
|
|
||||||
|
1. 노출된 credential과 파생 token을 폐기하고 회전합니다.
|
||||||
|
2. 영향받은 시스템의 접근 로그와 변경 이력을 확인합니다.
|
||||||
|
3. 저장소 history와 artifact/cache에서 민감 데이터를 제거합니다.
|
||||||
|
4. 원인과 영향 범위, 재발 방지 조치를 incident 문서에 기록합니다.
|
||||||
|
5. 조직의 보안 연락 채널로 보고합니다.
|
||||||
|
|
||||||
|
보안 이슈는 공개 issue 대신 canonical Gitea 저장소의 비공개 보안 채널로
|
||||||
|
보고합니다. 대응 우선순위와 SLA는 운영 환경 도입 전에 별도로 승인합니다.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Bootstrap
|
||||||
|
|
||||||
|
선언형 인프라와 GitOps가 스스로 동작하기 전에 한 번 또는 매우 드물게 수행하는
|
||||||
|
최소 초기화만 둡니다.
|
||||||
|
|
||||||
|
- `foundation`: remote state, locking, 최초 identity 같은 선행 조건
|
||||||
|
- `gitops`: 선택한 controller 설치와 cluster root 연결
|
||||||
|
|
||||||
|
일반 네트워크, Kubernetes cluster, addon과 application을 이곳에 두지 않습니다.
|
||||||
|
부트스트랩 절차는 반복 실행 가능하고 감사 가능해야 하며, 장기 수동 운영 경로가
|
||||||
|
되어서는 안 됩니다.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Foundation Bootstrap
|
||||||
|
|
||||||
|
다른 IaC state가 의존하는 최소 선행 조건을 관리합니다.
|
||||||
|
|
||||||
|
가능한 대상:
|
||||||
|
|
||||||
|
- remote state storage와 locking
|
||||||
|
- state 암호화 key
|
||||||
|
- CI의 최초 workload identity/OIDC trust
|
||||||
|
- 조직 공통 account/project 초기 설정
|
||||||
|
|
||||||
|
## 계약
|
||||||
|
|
||||||
|
- 일반 infrastructure state와 분리합니다.
|
||||||
|
- 변경 권한과 실행 빈도를 최소화합니다.
|
||||||
|
- local state를 장기간 유지하지 않습니다.
|
||||||
|
- output과 후속 `infrastructure/live`가 값을 소비하는 방식을 문서화합니다.
|
||||||
|
- provider credential이나 실제 backend secret을 커밋하지 않습니다.
|
||||||
|
|
||||||
|
조직 공통 foundation이 외부 저장소에 이미 있다면 이 폴더에는 소유 팀, output
|
||||||
|
contract와 복구 절차만 기록합니다.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# GitOps Bootstrap
|
||||||
|
|
||||||
|
Flux, Argo CD 등 **하나의** GitOps controller를 선택해 설치하고 cluster root에
|
||||||
|
연결합니다. 선택하지 않은 controller의 병렬 구조를 만들지 않습니다.
|
||||||
|
|
||||||
|
포함 범위:
|
||||||
|
|
||||||
|
- controller 설치 또는 설치 manifest
|
||||||
|
- source repository/OCI 연결
|
||||||
|
- `gitops/clusters/<...>` root reconcile 선언
|
||||||
|
- controller용 최소 identity와 secret manager 접근 연결
|
||||||
|
|
||||||
|
제외 범위:
|
||||||
|
|
||||||
|
- ingress, certificate, DNS, storage, observability addon
|
||||||
|
- application workload
|
||||||
|
- controller 설치 후 Git으로 관리할 수 있는 일반 Kubernetes 리소스
|
||||||
|
|
||||||
|
bootstrap credential과 recovery 절차는 `docs/runbooks`에 문서화합니다.
|
||||||
+1
-1
@@ -8,7 +8,7 @@ spec:
|
|||||||
source:
|
source:
|
||||||
repoURL: https://git.learn.hyeonworks.com/donghyeon.kang/project-gitops
|
repoURL: https://git.learn.hyeonworks.com/donghyeon.kang/project-gitops
|
||||||
targetRevision: main
|
targetRevision: main
|
||||||
path: platform/control-plane/argocd
|
path: gitops/clusters/dev-k3s
|
||||||
destination:
|
destination:
|
||||||
server: https://kubernetes.default.svc
|
server: https://kubernetes.default.svc
|
||||||
namespace: argocd
|
namespace: argocd
|
||||||
@@ -4,16 +4,16 @@
|
|||||||
|
|
||||||
Controller 설치 후 다음 두 bootstrap object를 순서대로 수동 seed합니다.
|
Controller 설치 후 다음 두 bootstrap object를 순서대로 수동 seed합니다.
|
||||||
|
|
||||||
1. `bootstrap/argocd/control-plane-project.yaml`
|
1. `bootstrap/gitops/argocd/control-plane-project.yaml`
|
||||||
2. `bootstrap/argocd/root-application.yaml`
|
2. `bootstrap/gitops/argocd/root-application.yaml`
|
||||||
|
|
||||||
`gitops-control-plane` AppProject는 canonical Gitea repository와 in-cluster
|
`gitops-control-plane` AppProject는 canonical Gitea repository와 in-cluster
|
||||||
`argocd` namespace, AppProject/ApplicationSet kind만 허용합니다. 단일 root
|
`argocd` namespace, AppProject/ApplicationSet kind만 허용합니다. 단일 root
|
||||||
Application은 이 Project를 사용하고 다음 control-plane 구성을 source로
|
Application은 이 Project를 사용하고 `gitops/clusters/dev-k3s`를 source로
|
||||||
사용합니다.
|
사용합니다. Cluster root는 다음 control-plane 구성을 참조합니다.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
platform/control-plane/argocd
|
gitops/platform/control-plane/argocd
|
||||||
├── projects
|
├── projects
|
||||||
│ ├── platform-addons.yaml
|
│ ├── platform-addons.yaml
|
||||||
│ ├── platform-services.yaml
|
│ ├── platform-services.yaml
|
||||||
@@ -26,7 +26,7 @@ platform/control-plane/argocd
|
|||||||
└── workloads.yaml
|
└── workloads.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Root는 AppProject와 ApplicationSet까지만 직접 소유합니다. 각
|
Cluster root는 AppProject와 ApplicationSet까지만 직접 소유합니다. 각
|
||||||
ApplicationSet의 list inventory가 실제 child Application을 생성합니다.
|
ApplicationSet의 list inventory가 실제 child Application을 생성합니다.
|
||||||
Routine 변경에 category별 root나 직접 `kubectl apply`를 추가하지 않습니다.
|
Routine 변경에 category별 root나 직접 `kubectl apply`를 추가하지 않습니다.
|
||||||
|
|
||||||
@@ -134,8 +134,8 @@ generator가 가장 쉽게 검토됩니다. 존재하지 않는 production이나
|
|||||||
cluster를 위해 Matrix abstraction을 미리 만들지 않습니다.
|
cluster를 위해 Matrix abstraction을 미리 만들지 않습니다.
|
||||||
|
|
||||||
두 번째 실제 cluster가 생겨 `cluster`, `server`와 cluster별 gate를 여러
|
두 번째 실제 cluster가 생겨 `cluster`, `server`와 cluster별 gate를 여러
|
||||||
component에서 반복하게 될 때 `clusters/<cluster>/config.yaml`을 Git files
|
component에서 반복하게 될 때 `gitops/clusters/<cluster>/config.yaml`을 Git
|
||||||
generator로 읽고 component inventory와 Matrix generator로 결합합니다.
|
files generator로 읽고 component inventory와 Matrix generator로 결합합니다.
|
||||||
그때도 AppProject는 ApplicationSet template에 고정하고, cluster별
|
그때도 AppProject는 ApplicationSet template에 고정하고, cluster별
|
||||||
`autoSync`는 quoted string과 승인 gate로 유지합니다.
|
`autoSync`는 quoted string과 승인 gate로 유지합니다.
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,16 @@ registry이며 desired state source가 아닙니다.
|
|||||||
|
|
||||||
| Layer | 역할 |
|
| Layer | 역할 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `platform/control-plane/argocd` | AppProject와 ApplicationSet control plane |
|
| `gitops/clusters/dev-k3s` | bootstrap root가 읽는 유일한 cluster entrypoint |
|
||||||
| `platform/shared-services/*/base` | 환경 중립을 목표로 하는 공유 cluster service base |
|
| `gitops/platform/control-plane/argocd` | AppProject와 ApplicationSet control plane |
|
||||||
| `systems/*/base` | 환경 중립을 목표로 하는 bounded-context backing system base |
|
| `gitops/platform/shared-services/*/base` | 환경 중립을 목표로 하는 공유 cluster service base |
|
||||||
| `workloads/*/base` | first-party 애플리케이션 base |
|
| `gitops/apps/systems/*/base` | 환경 중립을 목표로 하는 bounded-context backing system base |
|
||||||
| `clusters/dev-k3s/overlays/*` | dev namespace, host, digest, Vault role/path, NetworkPolicy를 합친 최종 구성 |
|
| `gitops/apps/workloads/*/base` | first-party 애플리케이션 base |
|
||||||
|
| `gitops/clusters/dev-k3s/overlays/*` | dev namespace, host, digest, Vault role/path, NetworkPolicy를 합친 최종 구성 |
|
||||||
|
|
||||||
현재 concrete ownership은 Vault가 platform shared service,
|
현재 concrete ownership은 Vault가 platform shared service,
|
||||||
PostgreSQL/Keycloak이 `systems/auth-system`, 두 서버가 workload입니다.
|
PostgreSQL/Keycloak이 `gitops/apps/systems/auth-system`, 두 서버가
|
||||||
|
`gitops/apps/workloads`의 workload입니다.
|
||||||
Argo CD Application은 base가 아니라 최종 cluster overlay만 source로
|
Argo CD Application은 base가 아니라 최종 cluster overlay만 source로
|
||||||
사용합니다.
|
사용합니다.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# Repository Structure
|
||||||
|
|
||||||
|
## 설계 목표
|
||||||
|
|
||||||
|
이 구조는 특정 제품의 파일 배치보다 변경 주기와 소유권을 우선합니다.
|
||||||
|
|
||||||
|
- 한 리소스에는 한 명확한 소유자가 있다.
|
||||||
|
- 재사용 구현과 실제 배포 진입점을 분리한다.
|
||||||
|
- 소규모 구성은 선택 영역을 생략할 수 있다.
|
||||||
|
- 규모가 커져도 기존 경계를 바꾸지 않고 같은 종류의 leaf를 추가한다.
|
||||||
|
- 사람이 실행하는 명령과 CI 검증이 같은 진입점을 사용한다.
|
||||||
|
|
||||||
|
## 소유권 매트릭스
|
||||||
|
|
||||||
|
| 대상 | 소유 경로 | 직접 실행 여부 | 변경 주기 |
|
||||||
|
|---|---|---:|---|
|
||||||
|
| state backend, 초기 identity | `bootstrap/foundation` | 예 | 매우 낮음 |
|
||||||
|
| 네트워크, IAM, DNS, 클러스터 | `infrastructure/live` | 예 | 낮음 |
|
||||||
|
| 재사용 IaC 단위 | `infrastructure/components` | 아니요 | 중간 |
|
||||||
|
| 재사용 IaC 조합 | `infrastructure/stacks` | 아니요 | 중간 |
|
||||||
|
| GitOps 컨트롤러와 root 연결 | `bootstrap/gitops` | 예 | 낮음 |
|
||||||
|
| 클러스터 desired state | `gitops/clusters` | reconcile 진입점 | 지속적 |
|
||||||
|
| cluster-wide addon | `gitops/platform` | 아니요 | 중간 |
|
||||||
|
| 애플리케이션 배포 정의 | `gitops/apps` | 아니요 | 높음 |
|
||||||
|
| 정책과 tenant 정의 | `gitops/policies`, `gitops/tenants` | 아니요 | 중간 |
|
||||||
|
|
||||||
|
Catalog 영역(`components`, `stacks`, `platform`, `policies`, `tenants`, `apps`)은
|
||||||
|
직접 배포하지 않습니다. 실제 진입점이 필요한 항목만 조합해서 참조합니다.
|
||||||
|
|
||||||
|
## 의존 방향
|
||||||
|
|
||||||
|
```text
|
||||||
|
bootstrap/foundation
|
||||||
|
│ output
|
||||||
|
▼
|
||||||
|
infrastructure/components ◀── infrastructure/stacks
|
||||||
|
▲ ▲
|
||||||
|
└──────── infrastructure/live ─┘
|
||||||
|
│ cluster endpoint/identity
|
||||||
|
▼
|
||||||
|
bootstrap/gitops
|
||||||
|
│ root reference
|
||||||
|
▼
|
||||||
|
platform ─┐
|
||||||
|
policies ─┼────────▶ gitops/clusters
|
||||||
|
tenants ─┤
|
||||||
|
apps ─┘
|
||||||
|
```
|
||||||
|
|
||||||
|
역방향 의존은 만들지 않습니다. 예를 들어 reusable component가 특정
|
||||||
|
`live/prod` 값을 읽거나, app base가 특정 cluster overlay를 참조하면 안 됩니다.
|
||||||
|
|
||||||
|
## Infrastructure 경계
|
||||||
|
|
||||||
|
### `components`
|
||||||
|
|
||||||
|
네트워크, identity, registry, Kubernetes cluster처럼 작고 응집된 재사용
|
||||||
|
단위입니다. Terraform/OpenTofu를 선택했다면 일반적으로 backend가 없는 child
|
||||||
|
module에 해당합니다.
|
||||||
|
|
||||||
|
### `stacks`
|
||||||
|
|
||||||
|
여러 component를 반복해서 같은 방식으로 조합할 때만 사용합니다. 작은 프로젝트는
|
||||||
|
이 계층 없이 `live`가 component를 직접 호출할 수 있습니다. stack이 다른 stack을
|
||||||
|
깊게 중첩하기보다는 live root에서 평평하게 조합하는 방식을 권장합니다.
|
||||||
|
|
||||||
|
### `live`
|
||||||
|
|
||||||
|
실제로 plan/apply하는 root입니다. leaf 하나는 다음을 만족해야 합니다.
|
||||||
|
|
||||||
|
- 독립된 state와 locking
|
||||||
|
- 명시적인 provider와 backend 설정
|
||||||
|
- 고정된 component/module/chart 버전
|
||||||
|
- 비밀이 아닌 환경 입력만 저장소에 커밋
|
||||||
|
- 출력값과 downstream contract 문서화
|
||||||
|
|
||||||
|
작은 구성은 `live/dev/cluster`로 충분합니다. 계정과 리전이 늘어나면
|
||||||
|
`live/<provider>/<account>/<region>/<environment>/<stack>`처럼 경로를 확장합니다.
|
||||||
|
자동화는 경로의 고정 깊이에 의존하지 말고 실행 가능한 root 파일을 기준으로
|
||||||
|
대상을 찾도록 작성합니다.
|
||||||
|
|
||||||
|
서로 다른 환경의 root가 상대 경로로 다른 환경 구현을 import하면 안 됩니다.
|
||||||
|
공유가 필요하면 versioned component나 명시적인 remote output/data contract를
|
||||||
|
사용합니다.
|
||||||
|
|
||||||
|
## GitOps 경계
|
||||||
|
|
||||||
|
### `clusters`
|
||||||
|
|
||||||
|
클러스터가 reconcile하는 유일한 진입점입니다. 공통 리소스를 복사하지 않고
|
||||||
|
platform, policy, tenant, app catalog에서 필요한 항목만 참조합니다.
|
||||||
|
|
||||||
|
작은 구성은 `clusters/dev/main`, 다중 리전 구성은
|
||||||
|
`clusters/<environment>/<region>/<cluster>` 형태를 사용할 수 있습니다. 여기에도
|
||||||
|
고정된 경로 깊이를 강제하지 않습니다.
|
||||||
|
|
||||||
|
### `platform`
|
||||||
|
|
||||||
|
cluster-wide controller와 addon을 둡니다. 예시는 다음과 같습니다.
|
||||||
|
|
||||||
|
- ingress/gateway, external DNS, certificate
|
||||||
|
- storage class/CSI, autoscaling
|
||||||
|
- metrics, logs, traces, alerting
|
||||||
|
- secret operator와 delivery controller
|
||||||
|
|
||||||
|
각 component는 `base`와 필요한 `overlays`를 같은 디렉터리 안에 응집시킵니다.
|
||||||
|
환경 차이는 전체 파일 복사 대신 Kustomize patch 또는 별도 values로 표현합니다.
|
||||||
|
|
||||||
|
### `policies`, `tenants`, `apps`
|
||||||
|
|
||||||
|
- `policies`: cluster-wide admission 규칙, 거버넌스와 예외
|
||||||
|
- `tenants`: 구체적인 namespace, RBAC, quota, limit range, NetworkPolicy
|
||||||
|
- `apps`: application source code가 아닌 배포 정의
|
||||||
|
|
||||||
|
애플리케이션 팀이 별도 저장소를 소유하면 `apps`에는 그 저장소/OCI artifact를
|
||||||
|
참조하는 GitOps 리소스만 둘 수 있습니다.
|
||||||
|
|
||||||
|
Cloud DNS zone/delegation과 cloud IAM role은 `infrastructure`가 소유합니다.
|
||||||
|
External DNS controller, 동적 record 요청과 Kubernetes ServiceAccount binding은
|
||||||
|
`gitops/platform`이 소유합니다. 두 계층 사이에는 zone ID, role ARN 같은
|
||||||
|
명시적인 output contract만 전달합니다.
|
||||||
|
|
||||||
|
## Bootstrap 경계
|
||||||
|
|
||||||
|
Bootstrap은 선언형 관리가 스스로 시작될 수 없는 최소 범위만 담당합니다.
|
||||||
|
|
||||||
|
- `foundation`: state backend, 최초 CI identity와 같은 선행 조건
|
||||||
|
- `gitops`: Flux 또는 Argo CD 중 선택한 컨트롤러 설치와 root reference
|
||||||
|
|
||||||
|
ingress, cert-manager, observability 같은 addon은 bootstrap이 아니라 GitOps가
|
||||||
|
소유합니다. bootstrap 이후의 변경을 계속 수동 명령으로 누적하지 않습니다.
|
||||||
|
|
||||||
|
## 규모 확장 기준
|
||||||
|
|
||||||
|
| 단계 | 추가하는 것 | 그대로 유지하는 것 |
|
||||||
|
|---|---|---|
|
||||||
|
| 소형 | 단일 live root, 단일 cluster root, 최소 platform | lifecycle/ownership 경계 |
|
||||||
|
| 중형 | reusable stack, staging/prod, 정책, 관측성 | component와 entrypoint 분리 |
|
||||||
|
| 대형 | 계정·리전별 state, 다중 cluster, tenants, CODEOWNERS | 한 리소스 한 소유자 |
|
||||||
|
| 조직 분리 | lifecycle/team별 repository 분리 가능 | 각 repository 내부의 동일한 계약 |
|
||||||
|
|
||||||
|
repository를 분리하는 시점은 폴더 수가 아니라 권한, 배포 주기와 소유 팀이
|
||||||
|
실제로 달라졌을 때입니다.
|
||||||
|
|
||||||
|
## 설계 참고 자료
|
||||||
|
|
||||||
|
- [Kubernetes: Kustomize를 이용한 선언형 객체 관리](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/)
|
||||||
|
- [Flux: GitOps repository 구조](https://fluxcd.io/flux/guides/repository-structure/)
|
||||||
|
- [OpenTofu: reusable module](https://opentofu.org/docs/language/modules/)
|
||||||
|
- [OpenTofu: 평평한 module composition](https://opentofu.org/docs/language/modules/develop/composition/)
|
||||||
@@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
| 분류 | 판단 질문 | 현재 예 |
|
| 분류 | 판단 질문 | 현재 예 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `platform` | GitOps control plane이거나, 둘 이상의 system이 독립 lifecycle로 소비할 cluster capability인가? | Argo inventory, Vault shared service |
|
| `gitops/platform` | GitOps control plane이거나, 둘 이상의 system이 독립 lifecycle로 소비할 cluster capability인가? | Argo inventory, Vault shared service |
|
||||||
| `systems` | 하나의 bounded context가 함께 소유하는 backing system인가? | Project Auth의 PostgreSQL, Keycloak, realm/client sync |
|
| `gitops/apps/systems` | 하나의 bounded context가 함께 소유하는 backing system인가? | Project Auth의 PostgreSQL, Keycloak, realm/client sync |
|
||||||
| `workloads` | 별도 source repository에서 빌드하는 first-party 실행 단위인가? | `auth-server`, `api-server` |
|
| `gitops/apps/workloads` | 별도 source repository에서 빌드하는 first-party 실행 단위인가? | `auth-server`, `api-server` |
|
||||||
| `clusters` | 특정 클러스터의 최종 composition 값인가? | namespace, host, digest, Vault role, NetworkPolicy |
|
| `gitops/clusters` | 특정 클러스터의 최종 composition 값인가? | namespace, host, digest, Vault role, NetworkPolicy |
|
||||||
| `iac` | Kubernetes가 아닌 외부 API 객체를 선언하는가? | Vault mounts, policies, auth roles, database roles |
|
| `infrastructure` | Kubernetes가 아닌 외부 API 객체를 선언하는가? | Vault mounts, policies, auth roles, database roles |
|
||||||
| `bootstrap` | GitOps controller가 존재하기 전에 필요한 최소 seed인가? | Argo CD 설치 버전, 제한된 control-plane AppProject와 root Application |
|
| `bootstrap` | GitOps controller가 존재하기 전에 필요한 최소 seed인가? | Argo CD 설치 버전, 제한된 control-plane AppProject와 root Application |
|
||||||
|
|
||||||
다음 세 질문을 순서대로 사용합니다.
|
다음 세 질문을 순서대로 사용합니다.
|
||||||
@@ -23,9 +23,10 @@
|
|||||||
|
|
||||||
제품 이름만으로 분류하지 않습니다. 예를 들어 Keycloak이 여러 system의
|
제품 이름만으로 분류하지 않습니다. 예를 들어 Keycloak이 여러 system의
|
||||||
공용 identity service가 되고 별도 owner와 release cadence를 갖게 되면
|
공용 identity service가 되고 별도 owner와 release cadence를 갖게 되면
|
||||||
실행 서비스는 `platform/`으로 이동할 수 있습니다. 그래도 Project Auth
|
실행 서비스는 `gitops/platform/`으로 이동할 수 있습니다. 그래도 Project
|
||||||
realm/client 구성은 `systems/auth-system/`에 남습니다. 현재 Keycloak과
|
Auth realm/client 구성은 `gitops/apps/systems/auth-system/`에 남습니다.
|
||||||
PostgreSQL은 Project Auth 전용이므로 모두 system 소유입니다.
|
현재 Keycloak과 PostgreSQL은 Project Auth 전용이므로 모두 system
|
||||||
|
소유입니다.
|
||||||
|
|
||||||
## Path contract
|
## Path contract
|
||||||
|
|
||||||
@@ -33,16 +34,16 @@ PostgreSQL은 Project Auth 전용이므로 모두 system 소유입니다.
|
|||||||
contract입니다.
|
contract입니다.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
platform/shared-services/<name>/base
|
gitops/platform/shared-services/<name>/base
|
||||||
systems/<system>/base
|
gitops/apps/systems/<system>/base
|
||||||
workloads/<workload>/base
|
gitops/apps/workloads/<workload>/base
|
||||||
|
|
||||||
clusters/<cluster>/overlays/platform/<name>
|
gitops/clusters/<cluster>/overlays/platform/<name>
|
||||||
clusters/<cluster>/overlays/systems/<system>
|
gitops/clusters/<cluster>/overlays/systems/<system>
|
||||||
clusters/<cluster>/overlays/workloads/<workload>
|
gitops/clusters/<cluster>/overlays/workloads/<workload>
|
||||||
|
|
||||||
platform/control-plane/argocd/projects
|
gitops/platform/control-plane/argocd/projects
|
||||||
platform/control-plane/argocd/application-sets
|
gitops/platform/control-plane/argocd/application-sets
|
||||||
```
|
```
|
||||||
|
|
||||||
Base에는 재사용 가능한 workload 구조, Service, ServiceAccount와 기본
|
Base에는 재사용 가능한 workload 구조, Service, ServiceAccount와 기본
|
||||||
@@ -68,8 +69,9 @@ Base 내부의 PostgreSQL·Keycloak 참조는 namespace를 포함하지 않은
|
|||||||
Service DNS를 사용하므로 overlay namespace에 재사용할 수 있습니다. 다만
|
Service DNS를 사용하므로 overlay namespace에 재사용할 수 있습니다. 다만
|
||||||
아직 다음 dev/single-node 가정은 남아 있습니다.
|
아직 다음 dev/single-node 가정은 남아 있습니다.
|
||||||
|
|
||||||
- `systems/auth-system/base`의 Keycloak 실행 command가 `start-dev`입니다.
|
- `gitops/apps/systems/auth-system/base`의 Keycloak 실행 command가
|
||||||
- `platform/shared-services/vault/base/files/vault/vault.hcl`이
|
`start-dev`입니다.
|
||||||
|
- `gitops/platform/shared-services/vault/base/files/vault/vault.hcl`이
|
||||||
`tls_disable = 1`과 고정된 single-node `node_id`를 사용합니다.
|
`tls_disable = 1`과 고정된 single-node `node_id`를 사용합니다.
|
||||||
|
|
||||||
이는 숨겨진 환경 중립성이 아니라 명시적인 리팩터링 부채입니다. 두 번째
|
이는 숨겨진 환경 중립성이 아니라 명시적인 리팩터링 부채입니다. 두 번째
|
||||||
@@ -88,14 +90,14 @@ base -> dev-k3s overlay -> ApplicationSet inventory -> generated Application
|
|||||||
- Cluster addon: Kubernetes API를 확장하거나 admission/control-plane
|
- Cluster addon: Kubernetes API를 확장하거나 admission/control-plane
|
||||||
기능을 제공하는 외부 chart. 현재 Sealed Secrets와 Vault Agent Injector가
|
기능을 제공하는 외부 chart. 현재 Sealed Secrets와 Vault Agent Injector가
|
||||||
해당합니다. Inventory는
|
해당합니다. Inventory는
|
||||||
`platform/control-plane/argocd/application-sets/platform-addons.yaml`에
|
`gitops/platform/control-plane/argocd/application-sets/platform-addons.yaml`에
|
||||||
둡니다.
|
둡니다.
|
||||||
- Shared service: 일반 workload처럼 namespace에서 실행되지만 여러 system이
|
- Shared service: 일반 workload처럼 namespace에서 실행되지만 여러 system이
|
||||||
사용할 수 있는 capability. 현재 Vault가 해당합니다.
|
사용할 수 있는 capability. 현재 Vault가 해당합니다.
|
||||||
|
|
||||||
외부 Helm chart를 복사해 base처럼 유지하지 않습니다. chart version과
|
외부 Helm chart를 복사해 base처럼 유지하지 않습니다. chart version과
|
||||||
values는 Argo inventory에서 pin합니다. 저장소가 직접 소유하는 shared
|
values는 Argo inventory에서 pin합니다. 저장소가 직접 소유하는 shared
|
||||||
service manifest만 `platform/shared-services/`에 둡니다.
|
service manifest만 `gitops/platform/shared-services/`에 둡니다.
|
||||||
|
|
||||||
`foundation`은 소유권 분류가 아닙니다. Bootstrap 때 먼저 필요하다는 뜻은
|
`foundation`은 소유권 분류가 아닙니다. Bootstrap 때 먼저 필요하다는 뜻은
|
||||||
분리된 ApplicationSet category, `autoSync` gate와 runbook 순서로
|
분리된 ApplicationSet category, `autoSync` gate와 runbook 순서로
|
||||||
@@ -104,16 +106,16 @@ service manifest만 `platform/shared-services/`에 둡니다.
|
|||||||
|
|
||||||
## System와 workload의 경계
|
## System와 workload의 경계
|
||||||
|
|
||||||
`systems/auth-system`은 인증 bounded context가 함께 책임지는 데이터와
|
`gitops/apps/systems/auth-system`은 인증 bounded context가 함께 책임지는
|
||||||
identity backing services입니다.
|
데이터와 identity backing services입니다.
|
||||||
|
|
||||||
- PostgreSQL StatefulSet와 초기 database contract
|
- PostgreSQL StatefulSet와 초기 database contract
|
||||||
- Keycloak server와 Project Auth realm
|
- Keycloak server와 Project Auth realm
|
||||||
- Keycloak client synchronization
|
- Keycloak client synchronization
|
||||||
|
|
||||||
`workloads/auth-server`와 `workloads/api-server`는 각각 별도 source
|
`gitops/apps/workloads/auth-server`와 `gitops/apps/workloads/api-server`는
|
||||||
repository와 release digest가 있는 애플리케이션입니다. Workload가
|
각각 별도 source repository와 release digest가 있는 애플리케이션입니다.
|
||||||
auth-system을 사용하더라도 두 lifecycle을 합치지 않습니다.
|
Workload가 auth-system을 사용하더라도 두 lifecycle을 합치지 않습니다.
|
||||||
|
|
||||||
Dev namespace도 소유권을 드러냅니다.
|
Dev namespace도 소유권을 드러냅니다.
|
||||||
|
|
||||||
@@ -145,12 +147,12 @@ state가 아닙니다.
|
|||||||
|
|
||||||
| 변경 | 위치 |
|
| 변경 | 위치 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 또 다른 공용 admission controller | `platform/control-plane/argocd/application-sets/platform-addons.yaml` |
|
| 또 다른 공용 admission controller | `gitops/platform/control-plane/argocd/application-sets/platform-addons.yaml` |
|
||||||
| 공용 object storage service base | `platform/shared-services/object-storage/base` |
|
| 공용 object storage service base | `gitops/platform/shared-services/object-storage/base` |
|
||||||
| Project Auth 전용 Redis | `systems/auth-system/base` |
|
| Project Auth 전용 Redis | `gitops/apps/systems/auth-system/base` |
|
||||||
| 새 first-party worker | `workloads/<worker>/base` |
|
| 새 first-party worker | `gitops/apps/workloads/<worker>/base` |
|
||||||
| dev worker digest/secret annotation | `clusters/dev-k3s/overlays/workloads/<worker>` |
|
| dev worker digest/secret annotation | `gitops/clusters/dev-k3s/overlays/workloads/<worker>` |
|
||||||
| Vault workload policy/role | `vault-workloads` Terraform state와 `policies/vault/` |
|
| Vault workload policy/role | `infrastructure/live/dev-k3s/vault-workloads`와 그 아래 `policies/` |
|
||||||
| Vault auth backend | `vault-foundation` Terraform state |
|
| Vault auth backend | `vault-foundation` Terraform state |
|
||||||
|
|
||||||
분류가 애매하면 설치 순서가 아니라 owner와 소비자 경계를 ADR에 먼저
|
분류가 애매하면 설치 순서가 아니라 owner와 소비자 경계를 ADR에 먼저
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ destroy/backup 책임이 정해졌을 때만 다음처럼 별도 machine root를
|
|||||||
추가합니다.
|
추가합니다.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
iac/terraform/live/<cluster>/machine
|
infrastructure/live/<cluster>/machine
|
||||||
iac/terraform/live/<cluster>/vault-foundation
|
infrastructure/live/<cluster>/vault-foundation
|
||||||
iac/terraform/live/<cluster>/vault-workloads
|
infrastructure/live/<cluster>/vault-workloads
|
||||||
iac/terraform/live/<cluster>/vault-database
|
infrastructure/live/<cluster>/vault-database
|
||||||
```
|
```
|
||||||
|
|
||||||
Machine root output을 읽기 위해 Vault state 전체를 공유하지 않습니다.
|
Machine root output을 읽기 위해 Vault state 전체를 공유하지 않습니다.
|
||||||
|
|||||||
+2
-1
@@ -6,7 +6,8 @@ Updated: 2026-07-26
|
|||||||
|
|
||||||
Argo CD 설치 후 bootstrap 전용 `gitops-control-plane` AppProject와 단일
|
Argo CD 설치 후 bootstrap 전용 `gitops-control-plane` AppProject와 단일
|
||||||
root Application을 순서대로 수동 seed합니다. Root는
|
root Application을 순서대로 수동 seed합니다. Root는
|
||||||
`platform/control-plane/argocd`의 AppProject와 ApplicationSet을 소유하고,
|
`gitops/clusters/dev-k3s`를 source로 사용합니다. 이 cluster root가
|
||||||
|
`gitops/platform/control-plane/argocd`의 AppProject와 ApplicationSet을 소유하고,
|
||||||
ApplicationSet이 platform addon/shared service, system, workload
|
ApplicationSet이 platform addon/shared service, system, workload
|
||||||
Application을 생성합니다. Bootstrap Project는 canonical repository,
|
Application을 생성합니다. Bootstrap Project는 canonical repository,
|
||||||
`argocd` namespace와 AppProject/ApplicationSet kind만 허용합니다.
|
`argocd` namespace와 AppProject/ApplicationSet kind만 허용합니다.
|
||||||
@@ -9,16 +9,17 @@ monorepo를 유지합니다. Application source repository와 deployment
|
|||||||
configuration repository는 분리합니다. 이 저장소 자체는 독립 reference
|
configuration repository는 분리합니다. 이 저장소 자체는 독립 reference
|
||||||
lab이며 범용 platform product로 간주하지 않습니다.
|
lab이며 범용 platform product로 간주하지 않습니다.
|
||||||
|
|
||||||
- `platform/`, `systems/`, `workloads/`: ownership별 base; 환경 중립은
|
- `gitops/platform`, `gitops/apps/systems`, `gitops/apps/workloads`:
|
||||||
목표 contract
|
ownership별 base; 환경 중립은 목표 contract
|
||||||
- `clusters/<cluster>/overlays`: cluster-specific final composition
|
- `gitops/clusters/<cluster>`: GitOps controller가 읽는 cluster root
|
||||||
- `platform/control-plane/argocd/projects`: Argo 권한 경계
|
- `gitops/clusters/<cluster>/overlays`: cluster-specific final composition
|
||||||
- `platform/control-plane/argocd/application-sets`: reconciliation inventory
|
- `gitops/platform/control-plane/argocd/projects`: Argo 권한 경계
|
||||||
- `iac/terraform`: Kubernetes manifest와 분리된 external API IaC
|
- `gitops/platform/control-plane/argocd/application-sets`: reconciliation inventory
|
||||||
|
- `infrastructure`: Kubernetes manifest와 분리된 external API IaC
|
||||||
- `bootstrap`: controller가 존재하기 전의 최소 seed
|
- `bootstrap`: controller가 존재하기 전의 최소 seed
|
||||||
|
|
||||||
`clusters`가 배포 가능한 최종 상태를 소유합니다. Argo CD는 top-level
|
`gitops/clusters`가 배포 가능한 최종 상태를 소유합니다. Argo CD는
|
||||||
base를 직접 source로 사용하지 않습니다. `foundation`은 directory
|
catalog base를 직접 source로 사용하지 않습니다. `foundation`은 directory
|
||||||
taxonomy가 아니라 bootstrap ordering/stage이고, 구체적인 ownership 분류는
|
taxonomy가 아니라 bootstrap ordering/stage이고, 구체적인 ownership 분류는
|
||||||
ADR 0007을 따릅니다.
|
ADR 0007을 따릅니다.
|
||||||
|
|
||||||
+11
-11
@@ -21,20 +21,20 @@ Auth를 예제로 한 독립 GitOps reference lab입니다. 따라서 존재하
|
|||||||
|
|
||||||
최상위 Kubernetes desired state를 다음 소유권으로 분류합니다.
|
최상위 Kubernetes desired state를 다음 소유권으로 분류합니다.
|
||||||
|
|
||||||
- `platform`: 여러 system이 사용할 수 있고 독립 lifecycle을 가진 cluster
|
- `gitops/platform`: 여러 system이 사용할 수 있고 독립 lifecycle을 가진
|
||||||
capability
|
cluster capability
|
||||||
- `systems`: 특정 bounded context가 소유하는 backing services와 domain
|
- `gitops/apps/systems`: 특정 bounded context가 소유하는 backing services와
|
||||||
configuration
|
domain configuration
|
||||||
- `workloads`: 별도 source repository와 release digest를 가진 first-party
|
- `gitops/apps/workloads`: 별도 source repository와 release digest를 가진
|
||||||
실행 애플리케이션
|
first-party 실행 애플리케이션
|
||||||
- `clusters/<cluster>/overlays`: 위 base에 namespace, image, host, secret
|
- `gitops/clusters/<cluster>/overlays`: 위 base에 namespace, image, host,
|
||||||
reference, network boundary를 결합한 최종 구성
|
secret reference, network boundary를 결합한 최종 구성
|
||||||
|
|
||||||
Vault는 `platform/shared-services/vault`에 둡니다. Sealed Secrets와 Vault
|
Vault는 `gitops/platform/shared-services/vault`에 둡니다. Sealed Secrets와 Vault
|
||||||
Agent Injector는 cluster addon inventory로 관리합니다. PostgreSQL,
|
Agent Injector는 cluster addon inventory로 관리합니다. PostgreSQL,
|
||||||
Keycloak, realm/client sync는 Project Auth 전용이므로
|
Keycloak, realm/client sync는 Project Auth 전용이므로
|
||||||
`systems/auth-system`으로 이동합니다. `auth-server`와 `api-server`는
|
`gitops/apps/systems/auth-system`으로 이동합니다. `auth-server`와
|
||||||
`workloads`에 유지합니다.
|
`api-server`는 `gitops/apps/workloads`에 유지합니다.
|
||||||
|
|
||||||
Project Auth backing system의 namespace는 `auth-system-dev`로 정하고,
|
Project Auth backing system의 namespace는 `auth-system-dev`로 정하고,
|
||||||
Vault KV 경로도 `systems/auth-system` 또는 실제 workload owner를
|
Vault KV 경로도 `systems/auth-system` 또는 실제 workload owner를
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# ADR 0008: Adopt the Kubernetes template lifecycle layout
|
||||||
|
|
||||||
|
Status: accepted
|
||||||
|
|
||||||
|
Date: 2026-07-26
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
기존 저장소는 `clusters`, `platform`, `systems`, `workloads`, `iac/terraform`,
|
||||||
|
`policies`와 `hack`을 각각 최상위에 두었습니다. 리소스 소유권은 구분했지만
|
||||||
|
bootstrap, infrastructure, GitOps desired state의 수명주기 경계가 저장소
|
||||||
|
최상위에서 일관되게 드러나지 않았습니다.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
`k8s-template`의 수명주기 구조를 canonical repository layout으로 채택합니다.
|
||||||
|
|
||||||
|
- Argo CD 최초 seed는 `bootstrap/gitops/argocd`에 둡니다.
|
||||||
|
- Vault Terraform component와 실행 root는 각각
|
||||||
|
`infrastructure/components`와 `infrastructure/live`에 둡니다.
|
||||||
|
- Kubernetes desired state는 `gitops/platform`, `gitops/apps`,
|
||||||
|
`gitops/clusters` 아래에만 둡니다.
|
||||||
|
- 기존 system/workload 소유권 분류는 `gitops/apps/systems`와
|
||||||
|
`gitops/apps/workloads` 하위에서 유지합니다.
|
||||||
|
- 환경별 Vault ACL은 이를 소비하는 `infrastructure/live` state root의
|
||||||
|
`policies`에 함께 둡니다. Kubernetes admission 정책용
|
||||||
|
`gitops/policies`와 혼합하지 않습니다.
|
||||||
|
- `gitops/clusters/dev-k3s`를 Argo CD bootstrap root의 유일한 source로
|
||||||
|
사용하고, 이 root가 permission-scoped ApplicationSet control plane을
|
||||||
|
조립합니다.
|
||||||
|
- 공통 `_template`, 예제, 구조/보안 검증을 유지하고 프로젝트별 검증을 그
|
||||||
|
위에 추가합니다.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- 최상위 경로만으로 bootstrap, infrastructure, GitOps lifecycle을 구분할
|
||||||
|
수 있습니다.
|
||||||
|
- 기존 AppProject, ApplicationSet, `autoSync` gate와 세 Vault state의
|
||||||
|
소유권은 유지됩니다.
|
||||||
|
- backend 예시는 각 live root에, Vault ACL은 소비 state에 가까이 위치합니다.
|
||||||
|
- Argo CD source path와 Terraform module source가 변경되므로 이미 연결된
|
||||||
|
live 시스템의 이관은 별도 diff, orphan/prune 검토와 승인 없이 실행하지
|
||||||
|
않습니다.
|
||||||
|
- 이 ADR의 구현은 Git 작업 트리에서만 수행하며 live cluster, Vault,
|
||||||
|
Terraform backend를 변경하지 않습니다.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Architecture Decision Records
|
||||||
|
|
||||||
|
프로젝트의 장기 구조에 영향을 주는 선택은 ADR로 남깁니다.
|
||||||
|
|
||||||
|
파일명은 `NNNN-kebab-case-title.md`를 사용하고 다음 형식을 따릅니다.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# NNNN. 제목
|
||||||
|
|
||||||
|
- 상태: 제안 | 승인 | 폐기 | 대체
|
||||||
|
- 날짜: YYYY-MM-DD
|
||||||
|
- 결정자: 팀 또는 역할
|
||||||
|
|
||||||
|
## 배경
|
||||||
|
|
||||||
|
## 결정
|
||||||
|
|
||||||
|
## 결과
|
||||||
|
|
||||||
|
## 대안
|
||||||
|
```
|
||||||
|
|
||||||
|
기존 결정을 바꿀 때 문서를 지우지 말고 새 ADR에서 이전 ADR을 대체했다고
|
||||||
|
표시합니다.
|
||||||
|
|
||||||
|
현재 프로젝트 결정은 이 디렉터리의 `0001`부터 순서대로 관리합니다.
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# Getting Started
|
||||||
|
|
||||||
|
이 문서는 이 저장소가 채택한 공통 템플릿 구조와 새 catalog 항목 생성 규칙을
|
||||||
|
설명합니다. Project GitOps의 실제 입문 순서와 운영 gate는
|
||||||
|
[`intern-guide.md`](intern-guide.md)와 runbook을 우선합니다.
|
||||||
|
|
||||||
|
## 예제를 먼저 확인하기
|
||||||
|
|
||||||
|
실제 파일을 만들기 전에 두 예제를 설계 참고 자료로 사용합니다.
|
||||||
|
|
||||||
|
1. `examples/minimal`에서 단일 환경의 canonical 폴더와 조립 방식을 확인합니다.
|
||||||
|
2. 다음 명령으로 platform과 app이 cluster root에서 합쳐지는 결과를 확인합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl kustomize examples/minimal/gitops/clusters/dev/main
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 다중 계정·리전·클러스터가 필요하면 `examples/scaled/README.md`에서 경로와
|
||||||
|
state 분리 기준을 선택합니다.
|
||||||
|
4. 실제 파일은 `examples`에서 복사하지 않고 각 책임 폴더의 `_template`에서
|
||||||
|
생성합니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
examples ──▶ 구조 선택 ──▶ _template 복사 ──▶ live/clusters 구현
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. 프로젝트 선택 기록
|
||||||
|
|
||||||
|
구현을 추가하기 전에 다음 항목을 결정하고 `docs/decisions`에 ADR을 작성합니다.
|
||||||
|
|
||||||
|
- cloud/on-prem provider와 account/project 구조
|
||||||
|
- Terraform, OpenTofu, Pulumi 등 IaC 엔진
|
||||||
|
- Kustomize 중심 또는 Helm 사용 범위
|
||||||
|
- Flux 또는 Argo CD 등 GitOps 컨트롤러
|
||||||
|
- External Secrets 또는 SOPS 등 비밀 관리 방식
|
||||||
|
- admission policy와 observability 운영 범위
|
||||||
|
|
||||||
|
선택하지 않은 도구의 빈 폴더를 모두 만들 필요는 없습니다.
|
||||||
|
|
||||||
|
Terraform/OpenTofu를 선택했다면 IaC 파일을 추가하기 전에 다음 선택 파일을
|
||||||
|
만들고 한 값만 활성화합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp infrastructure/.iac-engine.example infrastructure/.iac-engine
|
||||||
|
```
|
||||||
|
|
||||||
|
`.iac-engine`에는 주석을 제외하고 `tofu` 또는 `terraform` 한 줄만 남깁니다.
|
||||||
|
선택한 도구와 version을 CI에도 설치·고정하고 project-specific
|
||||||
|
`init -backend=false`/`validate` 검사를 추가합니다.
|
||||||
|
|
||||||
|
## 2. 프로젝트 메타데이터 설정
|
||||||
|
|
||||||
|
1. `README.md`의 제목과 프로젝트 범위를 바꿉니다.
|
||||||
|
2. `.github/CODEOWNERS.example`을 실제 소유자로 수정한 뒤 `CODEOWNERS`로
|
||||||
|
이름을 바꿉니다.
|
||||||
|
3. `SECURITY.md`에 조직의 보안 연락처와 SLA를 추가합니다.
|
||||||
|
4. 선택한 도구 버전을 프로젝트의 버전 관리 방식으로 고정합니다.
|
||||||
|
5. branch protection과 required check를 설정합니다.
|
||||||
|
|
||||||
|
## 3. Foundation bootstrap
|
||||||
|
|
||||||
|
`bootstrap/foundation` 아래에 remote state, locking, 초기 CI identity 등
|
||||||
|
다른 인프라가 의존하는 최소 구성을 작성합니다.
|
||||||
|
|
||||||
|
Foundation은 일반 infrastructure state와 분리하고 변경 권한을 좁게 유지합니다.
|
||||||
|
이미 조직 공통 foundation이 있다면 이 폴더에는 외부 의존 계약과 초기화 방법만
|
||||||
|
문서화해도 됩니다.
|
||||||
|
|
||||||
|
## 4. Infrastructure 작성
|
||||||
|
|
||||||
|
작은 프로젝트는 component와 live root만으로 시작합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -R infrastructure/components/_template infrastructure/components/kubernetes-cluster
|
||||||
|
mkdir -p infrastructure/live/dev
|
||||||
|
cp -R infrastructure/live/_template infrastructure/live/dev/cluster
|
||||||
|
```
|
||||||
|
|
||||||
|
동일한 조합이 여러 환경에서 반복될 때만 stack을 추가합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -R infrastructure/stacks/_template infrastructure/stacks/cluster
|
||||||
|
```
|
||||||
|
|
||||||
|
`live` root마다 backend/state를 분리하고, provider credential은 파일에 저장하지
|
||||||
|
않습니다.
|
||||||
|
|
||||||
|
## 5. Desired state 조립
|
||||||
|
|
||||||
|
필요한 catalog 템플릿을 복사합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -R gitops/platform/_template gitops/platform/core
|
||||||
|
cp -R gitops/apps/_template gitops/apps/example-api
|
||||||
|
mkdir -p gitops/clusters/dev
|
||||||
|
cp -R gitops/clusters/_template gitops/clusters/dev/main
|
||||||
|
```
|
||||||
|
|
||||||
|
component의 `base`에 공통값을 두고, 환경 차이가 있을 때만 overlay를 추가합니다.
|
||||||
|
마지막으로 cluster `kustomization.yaml`이 사용할 component를 참조하게 합니다.
|
||||||
|
복사된 README의 `__REPLACE_ME_*__` 값을 모두 실제 메타데이터로 바꿉니다.
|
||||||
|
controller에 연결하기 전에 실제 cluster root를 로컬에서 렌더해 확인합니다.
|
||||||
|
|
||||||
|
## 6. GitOps bootstrap
|
||||||
|
|
||||||
|
desired-state root가 준비되고 클러스터가 생성되면 `bootstrap/gitops`에서 GitOps
|
||||||
|
컨트롤러 하나를 선택해 설치합니다. 이 단계에는 다음만 포함합니다.
|
||||||
|
|
||||||
|
- controller 설치 또는 설치 선언
|
||||||
|
- repository/OCI source 연결
|
||||||
|
- 검증된 `gitops/clusters/<...>` root reconcile 연결
|
||||||
|
- controller가 secret manager에 접근하는 최소 identity
|
||||||
|
|
||||||
|
일반 platform addon과 application은 이 단계에 넣지 않습니다.
|
||||||
|
|
||||||
|
## 7. 검증
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make doctor
|
||||||
|
make check
|
||||||
|
kubectl kustomize examples/minimal/gitops/clusters/dev/main
|
||||||
|
kubectl kustomize gitops/clusters/dev/main
|
||||||
|
```
|
||||||
|
|
||||||
|
프로젝트에서 실제 IaC, Helm, policy 파일을 추가하면 필요한 validator를
|
||||||
|
`scripts/validate.sh`에 명시적으로 추가하고 CI에서도 같은 `make check`를
|
||||||
|
호출합니다. 도구가 없을 때 조용히 성공하도록 만들지 않습니다.
|
||||||
|
|
||||||
|
첫 환경은 다음 조건을 모두 만족하면 완료된 것으로 봅니다.
|
||||||
|
|
||||||
|
- 실제 `live` root의 대상, state, owner와 실행 절차가 작성되어 있다.
|
||||||
|
- 실제 cluster root가 필요한 catalog base/overlay를 참조하고 비어 있지 않다.
|
||||||
|
- cluster root 렌더 결과와 IaC plan이 리뷰 가능하다.
|
||||||
|
- GitOps bootstrap root가 `_template`이 아닌 실제 cluster root를 가리킨다.
|
||||||
|
- 비밀 관리, rollback과 담당자 연락 경로가 문서화되어 있다.
|
||||||
|
|
||||||
|
## 8. 운영 준비
|
||||||
|
|
||||||
|
- production apply 승인 및 concurrency lock
|
||||||
|
- backup/restore와 disaster recovery runbook
|
||||||
|
- cluster와 addon upgrade 정책
|
||||||
|
- secret rotation과 접근 감사
|
||||||
|
- alert routing과 담당자
|
||||||
|
- 비용, 용량, SLO 기준
|
||||||
|
|
||||||
|
운영 준비가 끝나기 전에는 예제 값을 production에 재사용하지 않습니다.
|
||||||
@@ -19,11 +19,12 @@ CD가 Terraform을 실행하지 않으며 CI가 routine deployment를 위해
|
|||||||
|
|
||||||
## 디렉터리를 고르는 법
|
## 디렉터리를 고르는 법
|
||||||
|
|
||||||
- 여러 system이 공유하는 cluster capability: `platform`
|
- 여러 system이 공유하는 cluster capability: `gitops/platform`
|
||||||
- Project Auth bounded context 전용 backing service: `systems/auth-system`
|
- Project Auth bounded context 전용 backing service:
|
||||||
- 별도 source repository에서 빌드하는 서버: `workloads`
|
`gitops/apps/systems/auth-system`
|
||||||
- Dev namespace, digest, host, Vault annotation: `clusters/dev-k3s/overlays`
|
- 별도 source repository에서 빌드하는 서버: `gitops/apps/workloads`
|
||||||
- Vault API 객체: `iac/terraform`
|
- Dev namespace, digest, host, Vault annotation: `gitops/clusters/dev-k3s/overlays`
|
||||||
|
- Vault API 객체: `infrastructure/components`와 `infrastructure/live`
|
||||||
|
|
||||||
현재 Vault는 platform shared service, PostgreSQL과 Keycloak은 auth-system,
|
현재 Vault는 platform shared service, PostgreSQL과 Keycloak은 auth-system,
|
||||||
`auth-server`와 `api-server`는 workload입니다. 설치 순서나 중요도로
|
`auth-server`와 `api-server`는 workload입니다. 설치 순서나 중요도로
|
||||||
@@ -61,9 +62,9 @@ gate를 엽니다. Gate가 닫혀도 수동 Sync는 가능하므로 임의로
|
|||||||
최종 dev manifest 렌더링:
|
최종 dev manifest 렌더링:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl kustomize clusters/dev-k3s/overlays/workloads/auth-server
|
kubectl kustomize gitops/clusters/dev-k3s/overlays/workloads/auth-server
|
||||||
kubectl kustomize clusters/dev-k3s/overlays/systems/auth-system
|
kubectl kustomize gitops/clusters/dev-k3s/overlays/systems/auth-system
|
||||||
kubectl kustomize clusters/dev-k3s/overlays/platform/vault
|
kubectl kustomize gitops/clusters/dev-k3s/overlays/platform/vault
|
||||||
```
|
```
|
||||||
|
|
||||||
전체 정적 검증:
|
전체 정적 검증:
|
||||||
@@ -78,10 +79,10 @@ Backend 없이 Terraform configuration 검증:
|
|||||||
for terraform_root in vault-foundation vault-workloads vault-database; do
|
for terraform_root in vault-foundation vault-workloads vault-database; do
|
||||||
terraform_data_dir="$(mktemp -d)"
|
terraform_data_dir="$(mktemp -d)"
|
||||||
TF_DATA_DIR="$terraform_data_dir" \
|
TF_DATA_DIR="$terraform_data_dir" \
|
||||||
terraform -chdir="iac/terraform/live/dev-k3s/${terraform_root}" \
|
terraform -chdir="infrastructure/live/dev-k3s/${terraform_root}" \
|
||||||
init -backend=false -input=false -lockfile=readonly
|
init -backend=false -input=false -lockfile=readonly
|
||||||
TF_DATA_DIR="$terraform_data_dir" \
|
TF_DATA_DIR="$terraform_data_dir" \
|
||||||
terraform -chdir="iac/terraform/live/dev-k3s/${terraform_root}" validate
|
terraform -chdir="infrastructure/live/dev-k3s/${terraform_root}" validate
|
||||||
rm -rf "$terraform_data_dir"
|
rm -rf "$terraform_data_dir"
|
||||||
done
|
done
|
||||||
```
|
```
|
||||||
@@ -109,7 +110,7 @@ Image 승격은 Gitea `Promote Dev Image by Pull Request` workflow에 정확한
|
|||||||
4. `docs/architecture/argocd.md`
|
4. `docs/architecture/argocd.md`
|
||||||
5. `docs/architecture/secret-trust.md`
|
5. `docs/architecture/secret-trust.md`
|
||||||
6. `docs/architecture/terraform.md`
|
6. `docs/architecture/terraform.md`
|
||||||
7. `docs/adr/`
|
7. `docs/decisions/`
|
||||||
8. 수행하려는 작업의 runbook
|
8. 수행하려는 작업의 runbook
|
||||||
|
|
||||||
2026-07-26 리팩터링은 repository에서만 구현·검증했으며 실제 cluster에
|
2026-07-26 리팩터링은 repository에서만 구현·검증했으며 실제 cluster에
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Runbooks
|
||||||
|
|
||||||
|
운영자가 긴급 상황에서도 그대로 실행할 수 있는 절차를 둡니다. 프로젝트를
|
||||||
|
운영하기 전에 최소한 다음 runbook을 준비합니다.
|
||||||
|
|
||||||
|
- foundation/state 접근 복구
|
||||||
|
- 실패한 plan/apply 복구와 state lock 처리
|
||||||
|
- GitOps controller 복구와 reconciliation 중지/재개
|
||||||
|
- cluster 및 핵심 addon upgrade/rollback
|
||||||
|
- secret rotation과 credential 노출 대응
|
||||||
|
- backup restore와 disaster recovery
|
||||||
|
- 인증서, DNS, ingress 장애 대응
|
||||||
|
- 관측성 또는 alert pipeline 장애 대응
|
||||||
|
|
||||||
|
각 문서는 `목적`, `사전 조건`, `영향`, `절차`, `검증`, `롤백`,
|
||||||
|
`에스컬레이션` 섹션을 포함해야 합니다.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Runbook 제목
|
||||||
|
|
||||||
|
## 목적
|
||||||
|
|
||||||
|
## 사전 조건
|
||||||
|
|
||||||
|
## 영향
|
||||||
|
|
||||||
|
## 절차
|
||||||
|
|
||||||
|
## 검증
|
||||||
|
|
||||||
|
## 롤백
|
||||||
|
|
||||||
|
## 에스컬레이션
|
||||||
@@ -24,11 +24,11 @@ commit하지 않습니다.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p .local/terraform-backend/dev-k3s
|
mkdir -p .local/terraform-backend/dev-k3s
|
||||||
cp iac/terraform/backend/dev-k3s/vault-foundation.s3.hcl.example \
|
cp infrastructure/live/dev-k3s/vault-foundation/backend.s3.hcl.example \
|
||||||
.local/terraform-backend/dev-k3s/vault-foundation.s3.hcl
|
.local/terraform-backend/dev-k3s/vault-foundation.s3.hcl
|
||||||
cp iac/terraform/backend/dev-k3s/vault-workloads.s3.hcl.example \
|
cp infrastructure/live/dev-k3s/vault-workloads/backend.s3.hcl.example \
|
||||||
.local/terraform-backend/dev-k3s/vault-workloads.s3.hcl
|
.local/terraform-backend/dev-k3s/vault-workloads.s3.hcl
|
||||||
cp iac/terraform/backend/dev-k3s/vault-database.s3.hcl.example \
|
cp infrastructure/live/dev-k3s/vault-database/backend.s3.hcl.example \
|
||||||
.local/terraform-backend/dev-k3s/vault-database.s3.hcl
|
.local/terraform-backend/dev-k3s/vault-database.s3.hcl
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ kubectl -n vault port-forward deployment/vault 8200:8200
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
export VAULT_ADDR=http://127.0.0.1:8200
|
export VAULT_ADDR=http://127.0.0.1:8200
|
||||||
./hack/vault-init.sh init
|
./scripts/vault-init.sh init
|
||||||
```
|
```
|
||||||
|
|
||||||
`.local/vault/dev-k3s-init.json`을 즉시 encrypted custody에 복사합니다.
|
`.local/vault/dev-k3s-init.json`을 즉시 encrypted custody에 복사합니다.
|
||||||
@@ -297,7 +297,7 @@ unseal custody의 담당자와 승인된 Vault generated-root recovery 절차를
|
|||||||
확인할 수 없으면 root를 폐기하지 않습니다.
|
확인할 수 없으면 root를 폐기하지 않습니다.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./hack/vault-init.sh revoke-root
|
./scripts/vault-init.sh revoke-root
|
||||||
|
|
||||||
VAULT_TOKEN="$VAULT_WORKLOADS_TOKEN" vault token revoke -self
|
VAULT_TOKEN="$VAULT_WORKLOADS_TOKEN" vault token revoke -self
|
||||||
VAULT_TOKEN="$VAULT_DATABASE_TOKEN" vault token revoke -self
|
VAULT_TOKEN="$VAULT_DATABASE_TOKEN" vault token revoke -self
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Examples
|
||||||
|
|
||||||
|
예제는 구조와 조립 방식을 설명하기 위한 설계 참고 자료이며 실제 reconcile
|
||||||
|
대상이 아닙니다.
|
||||||
|
|
||||||
|
- [`minimal`](minimal/README.md): `kubectl kustomize`로 렌더 가능한 단일
|
||||||
|
환경·단일 클러스터의 canonical 구조
|
||||||
|
- [`scaled`](scaled/README.md): 여러 계정·환경·리전·클러스터로 확장할 때의
|
||||||
|
경로와 state 분리 기준
|
||||||
|
|
||||||
|
## 활용 순서
|
||||||
|
|
||||||
|
1. `minimal`에서 `infrastructure/live`, catalog `base`,
|
||||||
|
`gitops/clusters`의 관계를 확인합니다.
|
||||||
|
2. 규모가 커질 가능성이 있으면 `scaled`에서 account/region/environment
|
||||||
|
segment와 state 분리 기준을 선택합니다.
|
||||||
|
3. 실제 구현은 예제가 아니라 다음 `_template`을 복사해 시작합니다.
|
||||||
|
|
||||||
|
| 영역 | 복사 원본 |
|
||||||
|
|---|---|
|
||||||
|
| Infrastructure | `../infrastructure/components/_template`, `../infrastructure/stacks/_template`, `../infrastructure/live/_template` |
|
||||||
|
| GitOps | `../gitops/clusters/_template`, `../gitops/platform/_template`, `../gitops/apps/_template`, `../gitops/policies/_template`, `../gitops/tenants/_template` |
|
||||||
|
|
||||||
|
4. 실제 `live`와 cluster root가 예제와 같은 소유권·조립 경계를 유지하는지
|
||||||
|
비교하고 `make check`로 검증합니다.
|
||||||
|
|
||||||
|
예제 디렉터리를 GitOps controller root로 연결하거나 예제의 이름, namespace,
|
||||||
|
값을 production 기본값으로 재사용하지 않습니다.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Minimal Example
|
||||||
|
|
||||||
|
단일 환경·단일 클러스터가 같은 경계를 어떻게 사용하는지 보여 주는 예입니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
minimal/
|
||||||
|
├── infrastructure/
|
||||||
|
│ └── live/dev/cluster/README.md
|
||||||
|
└── gitops/
|
||||||
|
├── platform/core/base/
|
||||||
|
├── apps/hello-config/base/
|
||||||
|
└── clusters/dev/main/
|
||||||
|
```
|
||||||
|
|
||||||
|
실제 cloud 리소스를 만들지 않으며, GitOps 예제는 Namespace와 ConfigMap만
|
||||||
|
렌더합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl kustomize examples/minimal/gitops/clusters/dev/main
|
||||||
|
```
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: hello-config
|
||||||
|
namespace: skeleton-demo
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: hello-config
|
||||||
|
app.kubernetes.io/part-of: skeleton-demo
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
data:
|
||||||
|
message: "replace this example with a real application definition"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- config-map.yaml
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ../../../platform/core/base
|
||||||
|
- ../../../apps/hello-config/base
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: skeleton-demo
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: skeleton-demo
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Example Live Root
|
||||||
|
|
||||||
|
실제 프로젝트에서는 이 위치가 독립 state를 갖는 실행 가능한 IaC root가 됩니다.
|
||||||
|
|
||||||
|
- Scope: local example
|
||||||
|
- Environment: dev
|
||||||
|
- Stack: cluster
|
||||||
|
- State: example에는 없음
|
||||||
|
|
||||||
|
이 예제에는 provider 또는 IaC 엔진을 선택하지 않았기 때문에 실행 코드를
|
||||||
|
포함하지 않습니다.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Scaled Layout Example
|
||||||
|
|
||||||
|
계정·리전·환경·클러스터가 늘어나도 lifecycle과 entrypoint 계약은 바뀌지
|
||||||
|
않습니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
infrastructure/
|
||||||
|
├── components/
|
||||||
|
│ └── aws/
|
||||||
|
│ ├── network/
|
||||||
|
│ ├── identity/
|
||||||
|
│ └── eks/
|
||||||
|
├── stacks/
|
||||||
|
│ ├── regional-foundation/
|
||||||
|
│ └── kubernetes-cluster/
|
||||||
|
└── live/
|
||||||
|
└── aws/
|
||||||
|
├── platform-nonprod/
|
||||||
|
│ └── ap-northeast-2/
|
||||||
|
│ ├── dev/{network,cluster-a}/
|
||||||
|
│ └── staging/{network,cluster-a}/
|
||||||
|
└── platform-prod/
|
||||||
|
├── ap-northeast-2/prod/{network,cluster-a}/
|
||||||
|
└── ap-southeast-1/prod/{network,cluster-b}/
|
||||||
|
|
||||||
|
gitops/
|
||||||
|
├── platform/{core,networking,security,observability}/
|
||||||
|
├── policies/{baseline,production}/
|
||||||
|
├── tenants/{team-a,team-b}/
|
||||||
|
├── apps/{api,worker}/
|
||||||
|
└── clusters/
|
||||||
|
├── dev/ap-northeast-2/cluster-a/
|
||||||
|
├── staging/ap-northeast-2/cluster-a/
|
||||||
|
└── prod/
|
||||||
|
├── ap-northeast-2/cluster-a/
|
||||||
|
└── ap-southeast-1/cluster-b/
|
||||||
|
```
|
||||||
|
|
||||||
|
중괄호 표기는 설명을 줄이기 위한 것이며 실제 폴더명으로 사용하지 않습니다.
|
||||||
|
|
||||||
|
## 분리 기준
|
||||||
|
|
||||||
|
- `regional-foundation` network stack과 cluster는 파괴 영향이 달라 state를
|
||||||
|
분리합니다.
|
||||||
|
- production과 non-production은 account, credential과 state를 분리합니다.
|
||||||
|
- 공통 구현은 catalog에 한 번만 두고 cluster root는 선택과 patch만 가집니다.
|
||||||
|
- tenant/team별 권한이 다르면 CODEOWNERS와 repository 분리를 검토합니다.
|
||||||
|
- repository 분리는 폴더 수가 아니라 소유권과 권한 경계가 달라질 때 수행합니다.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# GitOps Desired State
|
||||||
|
|
||||||
|
Kubernetes API 안에서 지속적으로 reconcile할 desired state를 관리합니다.
|
||||||
|
GitOps controller를 사용하지 않는 초기 단계에도 `kubectl kustomize`로 같은
|
||||||
|
entrypoint를 렌더할 수 있습니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
platform ─┐
|
||||||
|
policies ─┼──▶ clusters/<...> ◀── GitOps controller root
|
||||||
|
tenants ─┤
|
||||||
|
apps ─┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- `clusters`: 클러스터별 최종 조립점
|
||||||
|
- `platform`: cluster-wide addon과 controller
|
||||||
|
- `policies`: cluster-wide admission과 거버넌스 규칙
|
||||||
|
- `tenants`: 구체적인 namespace/RBAC/quota/NetworkPolicy
|
||||||
|
- `apps`: application 배포 정의
|
||||||
|
|
||||||
|
Catalog 디렉터리를 controller root로 직접 지정하지 않습니다. cluster entrypoint가
|
||||||
|
필요한 base/overlay를 선택하고 의존 순서를 명시합니다.
|
||||||
|
|
||||||
|
## 기본 규칙
|
||||||
|
|
||||||
|
- `base`는 환경을 모르며 재사용 가능한 기본값만 가집니다.
|
||||||
|
- `overlays`는 차이만 patch하고 전체 manifest를 복사하지 않습니다.
|
||||||
|
- CRD/controller가 필요한 리소스는 controller 이후에 reconcile합니다.
|
||||||
|
- resource namespace, ownership label과 버전을 명시합니다.
|
||||||
|
- raw `Secret` 또는 실제 비밀값을 커밋하지 않습니다.
|
||||||
|
- 원격 base/chart를 참조할 때 immutable version 또는 digest를 사용합니다.
|
||||||
|
|
||||||
|
Flux/Argo CD 고유 리소스와 sync ordering은 선택한 controller를 기록한 ADR에
|
||||||
|
문서화합니다.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Application Deployment Catalog
|
||||||
|
|
||||||
|
애플리케이션의 source code가 아니라 Kubernetes 배포 정의를 둡니다. app 팀이
|
||||||
|
별도 source/deploy 저장소를 소유하면 이곳에는 immutable artifact를 참조하는
|
||||||
|
GitOps 리소스만 둘 수 있습니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps/
|
||||||
|
└── example-api/
|
||||||
|
├── base/
|
||||||
|
└── overlays/
|
||||||
|
├── dev/
|
||||||
|
└── prod/
|
||||||
|
```
|
||||||
|
|
||||||
|
base는 환경을 모르고, overlay에는 replica/resource/config처럼 필요한 차이만
|
||||||
|
둡니다. image는 mutable tag 대신 조직 정책에 따른 고정 tag 또는 digest를
|
||||||
|
사용합니다.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# __REPLACE_ME_APPLICATION_NAME__
|
||||||
|
|
||||||
|
## 소유자
|
||||||
|
|
||||||
|
Team: __REPLACE_ME_OWNER__
|
||||||
|
|
||||||
|
repository와 on-call 정보를 적습니다.
|
||||||
|
|
||||||
|
## 배포 계약
|
||||||
|
|
||||||
|
- Namespace:
|
||||||
|
- Image/artifact source:
|
||||||
|
- Ports/protocol:
|
||||||
|
- Dependency:
|
||||||
|
- SLO/alerts:
|
||||||
|
|
||||||
|
## 구성
|
||||||
|
|
||||||
|
- `base`: 공통 Kubernetes 배포 정의
|
||||||
|
- `overlays`: 환경별 replica, resource, config 차이
|
||||||
|
|
||||||
|
비밀은 ExternalSecret 같은 참조 또는 승인된 암호화 형식으로만 추가합니다.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Base
|
||||||
|
|
||||||
|
환경을 모르는 application의 공통 manifest를 둡니다. namespace 자체의 소유권이
|
||||||
|
tenant catalog에 있다면 이곳에서 중복 생성하지 않습니다.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources: []
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Overlays
|
||||||
|
|
||||||
|
필요한 환경에만 overlay를 추가합니다. 각 overlay는 `../../base`를 참조하고
|
||||||
|
환경별 patch만 포함합니다.
|
||||||
|
|
||||||
|
비밀값, 임시 debug 설정과 수동 hotfix 결과를 overlay에 커밋하지 않습니다.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Project Auth system
|
||||||
|
|
||||||
|
Project Auth bounded context가 소유하는 PostgreSQL, Keycloak과 client sync의
|
||||||
|
환경 중립 base입니다. `dev-k3s` namespace, host, Vault annotation과
|
||||||
|
NetworkPolicy는
|
||||||
|
`gitops/clusters/dev-k3s/overlays/systems/auth-system`에서 결합합니다.
|
||||||
|
|
||||||
|
Owner: Project Auth system
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# API server
|
||||||
|
|
||||||
|
별도 source repository에서 빌드되는 API server의 환경 중립 Kubernetes
|
||||||
|
base입니다. Image digest, dev configuration, ingress와 pull credential
|
||||||
|
reference는 `gitops/clusters/dev-k3s/overlays/workloads/api-server`가
|
||||||
|
소유합니다.
|
||||||
|
|
||||||
|
Owner: Project API workload
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Auth server
|
||||||
|
|
||||||
|
별도 source repository에서 빌드되는 Auth server의 환경 중립 Kubernetes
|
||||||
|
base입니다. Image digest, dev configuration, ingress와 Vault annotation은
|
||||||
|
`gitops/clusters/dev-k3s/overlays/workloads/auth-server`가 소유합니다.
|
||||||
|
|
||||||
|
Owner: Project Auth workload
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Cluster Entrypoints
|
||||||
|
|
||||||
|
클러스터별 최종 desired state 진입점입니다. GitOps controller의 root는 이
|
||||||
|
디렉터리 아래 **하나의 실제 cluster leaf**만 가리킵니다.
|
||||||
|
|
||||||
|
소규모:
|
||||||
|
|
||||||
|
```text
|
||||||
|
clusters/
|
||||||
|
└── dev/
|
||||||
|
└── main/
|
||||||
|
└── kustomization.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
다중 환경·리전:
|
||||||
|
|
||||||
|
```text
|
||||||
|
clusters/
|
||||||
|
├── dev/ap-northeast-2/dev-a/
|
||||||
|
├── staging/ap-northeast-2/staging-a/
|
||||||
|
└── prod/
|
||||||
|
├── ap-northeast-2/prod-a/
|
||||||
|
└── ap-southeast-1/prod-b/
|
||||||
|
```
|
||||||
|
|
||||||
|
cluster leaf에는 catalog 구현을 복사하지 않고 선택 목록과 cluster 고유 patch만
|
||||||
|
둡니다. 계정 또는 조직 경계가 필요하면 경로 segment를 추가할 수 있지만 자동화가
|
||||||
|
고정 depth에 의존하지 않도록 합니다.
|
||||||
|
|
||||||
|
`_template`을 실제 경로로 복사해 시작합니다.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# __REPLACE_ME_CLUSTER_NAME__
|
||||||
|
|
||||||
|
## 대상
|
||||||
|
|
||||||
|
- Environment: __REPLACE_ME_ENVIRONMENT__
|
||||||
|
- Region: __REPLACE_ME_REGION__
|
||||||
|
- Cluster: __REPLACE_ME_CLUSTER_NAME__
|
||||||
|
- Owner: __REPLACE_ME_OWNER__
|
||||||
|
|
||||||
|
## 구성
|
||||||
|
|
||||||
|
`kustomization.yaml`의 `resources`에 필요한 platform, policy, tenant와 app의
|
||||||
|
base 또는 overlay를 추가합니다. 예:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resources:
|
||||||
|
- ../../../platform/core/base
|
||||||
|
- ../../../policies/baseline/base
|
||||||
|
- ../../../apps/example-api/overlays/prod
|
||||||
|
```
|
||||||
|
|
||||||
|
위 예시는 `clusters/dev/main` 경로를 기준으로 합니다. 실제 상대 경로는 cluster
|
||||||
|
leaf 깊이에 맞게 조정합니다.
|
||||||
|
|
||||||
|
## 규칙
|
||||||
|
|
||||||
|
- 이 디렉터리가 해당 클러스터의 유일한 root입니다.
|
||||||
|
- 공통 manifest를 복사하지 않습니다.
|
||||||
|
- 클러스터 고유 차이만 local patch로 둡니다.
|
||||||
|
- dependency/sync 순서와 장애 시 reconcile 중지 절차를 문서화합니다.
|
||||||
|
- `_template` 자체를 GitOps controller에 연결하지 않습니다.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
# Add reusable platform, policy, tenant and app paths after copying this template.
|
||||||
|
resources: []
|
||||||
@@ -4,13 +4,15 @@
|
|||||||
ApplicationSet의 `server`는 in-cluster API
|
ApplicationSet의 `server`는 in-cluster API
|
||||||
`https://kubernetes.default.svc`를 사용합니다.
|
`https://kubernetes.default.svc`를 사용합니다.
|
||||||
|
|
||||||
이 디렉터리는 base 복사본이 아니라 다음 cluster-specific composition만
|
`kustomization.yaml`은 bootstrap root Application이 읽는 유일한 cluster
|
||||||
소유합니다.
|
entrypoint이며 permission-scoped Argo CD control plane을 조립합니다.
|
||||||
|
ApplicationSet inventory는 아래 cluster-specific overlay를 child
|
||||||
|
Application source로 선택합니다.
|
||||||
|
|
||||||
- `platform/vault`: dev Vault namespace, NetworkPolicy와 single-node profile
|
- `overlays/platform/vault`: dev Vault namespace, NetworkPolicy와 single-node profile
|
||||||
- `systems/auth-system`: `auth-system-dev` namespace, internal/public host,
|
- `overlays/systems/auth-system`: `auth-system-dev` namespace, internal/public host,
|
||||||
Vault injection path와 system NetworkPolicy
|
Vault injection path와 system NetworkPolicy
|
||||||
- `workloads/*`: dev namespace, image reference, ingress, pull
|
- `overlays/workloads/*`: dev namespace, image reference, ingress, pull
|
||||||
SealedSecret과 workload NetworkPolicy
|
SealedSecret과 workload NetworkPolicy
|
||||||
|
|
||||||
현재 Vault NetworkPolicy의 Kubernetes API CIDR와 node address는
|
현재 Vault NetworkPolicy의 Kubernetes API CIDR와 node address는
|
||||||
@@ -19,7 +21,8 @@ ApplicationSet의 `server`는 in-cluster API
|
|||||||
|
|
||||||
두 번째 클러스터를 추가할 때는 다음 순서를 사용합니다.
|
두 번째 클러스터를 추가할 때는 다음 순서를 사용합니다.
|
||||||
|
|
||||||
1. 실제 차이가 있는 overlay만 `clusters/<cluster>/overlays`에 추가합니다.
|
1. 실제 차이가 있는 overlay만 `gitops/clusters/<cluster>/overlays`에
|
||||||
|
추가합니다.
|
||||||
2. Argo CD cluster credential을 Git 밖에서 등록합니다.
|
2. Argo CD cluster credential을 Git 밖에서 등록합니다.
|
||||||
3. 각 AppProject destination에 정확한 API server/namespace를 추가합니다.
|
3. 각 AppProject destination에 정확한 API server/namespace를 추가합니다.
|
||||||
4. 권한별 ApplicationSet inventory에 `autoSync: "false"` element를
|
4. 권한별 ApplicationSet inventory에 `autoSync: "false"` element를
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ../../platform/control-plane/argocd
|
||||||
+1
-1
@@ -4,7 +4,7 @@ kind: Kustomization
|
|||||||
namespace: auth-system-dev
|
namespace: auth-system-dev
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
- ../../../../../systems/auth-system/base
|
- ../../../../../apps/systems/auth-system/base
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
- keycloak-ingress.yaml
|
- keycloak-ingress.yaml
|
||||||
- public-access.yaml
|
- public-access.yaml
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user