Files
jarca-ledger-mcp/deploy/k8s

k3s 배포

base/는 jarca-ledger namespace에 다음 리소스를 배포하는 Kustomize base다.

  • 단일 Deployment와 Recreate 전략
  • 동일 ARM64 이미지의 MCP·Dashboard 컨테이너
  • SQLite 초기화를 담당하는 init container
  • 공유 ReadWriteOnce PVC
  • Dashboard용 내부 ClusterIP Service
  • Dashboard port 8501 ingress만 허용하는 NetworkPolicy
  • UID/GID 1000:1000, fsGroup: 1000, read-only root filesystem

사전 준비

Base는 실제 Secret 값을 포함하지 않는다. 먼저 namespace를 생성한다.

kubectl apply -f deploy/k8s/base/namespace.yaml

그 다음 승인된 secret manager나 Git에 기록되지 않는 운영 절차로 다음 Secret을 jarca-ledger namespace에 생성한다.

  • jarca-ledger-registry
    • type: kubernetes.io/dockerconfigjson
    • gitea.jsfamily.quest에서 image를 pull할 수 있는 credential
  • jarca-ledger-dashboard-auth
    • key admin-id
    • key admin-password

Registry credential을 application container에 환경변수나 volume으로 전달하지 않는다. imagePullSecrets로만 사용한다.

Immutable image 지정

base/deployment.yaml의 release version tag는 템플릿 기본값일 뿐이며 운영 배포에 안전한 immutable 참조가 아니다. Release commit 자체에는 최종 image digest를 넣을 수 없다. Image의 revision label이 release commit을 가리키므로, 그 commit에 digest를 기록하면 commit과 image digest가 다시 바뀌는 자기참조가 발생한다.

Release가 완료된 뒤 검증된 digest를 사용하는 환경/인프라 저장소의 overlay를 생성한다. 예를 들어 environments/production/jarca-ledger/kustomization.yaml은 다음과 같다.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../../../jarca-ledger-mcp/deploy/k8s/base
images:
  - name: gitea.jsfamily.quest/jsfamily/jarca-ledger-mcp
    newName: gitea.jsfamily.quest/jsfamily/jarca-ledger-mcp
    digest: sha256:<verified-release-digest>

두 application container와 init container는 반드시 같은 digest를 사용해야 한다.

배포

Namespace와 Secret 준비가 끝난 뒤, base가 아니라 위의 외부 digest-pinned overlay를 적용한다.

kubectl apply -k environments/production/jarca-ledger
kubectl -n jarca-ledger rollout status deployment/jarca-ledger
kubectl -n jarca-ledger get pods,svc,pvc

Dashboard를 외부에 공개하는 Ingress나 NodePort는 environment overlay에서 추가한다. Base에는 MCP Service가 없고, NetworkPolicy는 workload ingress를 dashboard port 8501로 제한하여 인증 계층이 없는 MCP port 8000 ingress를 차단한다. Cluster의 network plugin이 NetworkPolicy를 enforce하는지 운영 환경에서 확인한다.

SQLite와 PVC

  • PVC 전체를 /data에 mount한다. SQLite journal, WAL, SHM 파일이 DB 옆에 생성되므로 DB 파일 하나만 subPath로 mount하지 않는다.
  • replicas는 1, update 전략은 Recreate로 유지한다. RollingUpdate는 일시적으로 두 Pod가 같은 SQLite DB를 열 수 있다.
  • k3s local-path volume에서는 fsGroup: 1000 적용 여부를 기존 PVC에서도 확인한다. 권한이 맞지 않으면 rollout 전에 운영 절차로 소유권을 수정하고, 상시 privileged chown init container는 두지 않는다.
  • 같은 PVC 안의 backup은 node 또는 disk 손실에 대한 재해 복구가 아니다. 별도 저장소로 backup을 내보낸다.