,

[인프라 자동화] Provider 계층만 교체한다 — 인프라에 적용한 Hexagonal과 ‘무료가 기본값’인 스킬 설계

이 글의 위치: 기술 블로그 → Infra/DevOps · OKE 인프라 학습 시리즈의 마무리 편. 앞에서 무료 클러스터 구축인그레스·HTTPS채팅 배포까지 손으로 했다. 이번엔 그 반복 절차를 재사용 가능한 스킬로 묶은 이야기 — 자동화 자체를 아키텍처로 다룬다.

이 프로비저닝은 Claude Code 플러그인 스킬(oke-init)로 코드화돼 있다. 그리고 그 스킬은 하나의 원칙 위에 서 있다 — 클라우드 provider 계층만 교체하고, 그 위 쿠버네티스 계층은 건드리지 않는다.

1. 인프라에 적용한 Hexagonal — provider가 어댑터다

가장 마음에 드는 부분. 인프라를 provider 계층쿠버네티스 계층으로 분리해 두면, GCP→OCI 전환은 provider 계층만 갈아끼우면 된다. 그 위(ArgoCD·Traefik·서비스 배포)는 provider와 무관하게 그대로 재사용된다.

GCP:  gke-init  ─┐
                 ├─→ k8s-init → argocd-init → traefik-init → service-deploy
OCI:  oke-init  ─┘        (이 계층은 provider 무관, 재사용)

실제로 GKE에서 OKE로 옮기면서 Traefik·cert-manager 설정은 거의 그대로 재사용했다. 스킬을 Hexagonal 용어로 매핑하면 이렇게 읽힌다.

Hexagonal 요소 oke-init에서
Primary Adapter (Handler) /oke-init 커맨드
Inbound Port 스킬의 argument-hint(입력 계약)
UseCase setup-oke.sh의 7단계 절차
Outbound Port 리소스별 oci 서브커맨드
Secondary Adapter oci CLI
Domain 네이밍 파생 규칙 + Always Free 불변식

즉 코드가 아니라 인프라 자동화에 Clean/Hexagonal을 문자 그대로 적용했다. provider(gke ↔ oke)는 서로 교체 가능한 Secondary Adapter인 셈이다.

2. GCP와 OCI는 같은 개념을 다르게 부른다

provider 계층을 분리하려면 두 클라우드의 개념 대응을 먼저 정확히 알아야 한다. 이 매핑 표가 스킬 문서의 뼈대다.

개념 GCP (gke-init) OCI (oke-init)
CLI gcloud oci
프로젝트 경계 Project Compartment + Tenancy
레지스트리 Artifact Registry OCIR (<region-key>.ocir.io)
네트워크 기본 VPC VCN + public/private 서브넷 + IGW/NAT (클러스터보다 먼저)
CI 자격증명 Workload Identity Federation (GitHub OIDC) 배포 IAM 유저 + Auth Token

특히 두 가지가 체감이 다르다. ① OCI는 클러스터 전에 네트워크(VCN)가 존재해야 한다. ② OCI엔 GitHub OIDC(WIF) 같은 1급 연동이 없어서, 배포 전용 유저 + Auth Token을 만들어 GitHub Secrets에 넣는 방식으로 CI를 붙인다. GCP의 WIF를 OCI에서 어떻게 대체하는가 — 이 우회 설계 자체가 스킬의 핵심 지식이다.

3. 무료가 기본값이다 — 실수로 과금되지 않는 설계

스킬의 기본값 자체를 Always Free로 승격했다. 플래그 없이 실행하면 관리비 $0 구성이 뜨고, 유료로 가려면 명시적으로 opt-in 해야 한다.

CLUSTER_TYPE="basic"              # → BASIC_CLUSTER : 관리비 $0 (Enhanced=$0.10/hr)
NODE_SHAPE="VM.Standard.A1.Flex"  # Ampere(arm64) : Always Free 대상
# 노드 총합 ≤ 4 OCPU / 24GB  (2 OCPU × 2노드 = 4, 12GB × 2 = 24)

거기에 런타임 가드가 붙는다. BASIC_CLUSTER && A1.Flex인데 총 OCPU>4 또는 MEM>24면 "⚠️ Always Free 한도 초과" 경고를 띄우고, oci limits resource-availability get으로 A1 무료 여유를 사전 조회한다. "기본값을 어디에 두느냐"가 곧 정책이다 — 무료를 기본값으로 두면, 아무 생각 없이 실행해도 돈이 안 나간다.

4. 며칠치 삽질을 코드 주석으로 박제한다

스킬의 진짜 가치는 절차가 아니라 함정의 코드화다. 스크립트 한 줄에 며칠치 삽질이 압축돼 있다.

이런 암묵지(tribal knowledge)를 사람 기억이 아니라 스크립트 가드·주석으로 옮기면, 다음 사람(그리고 6개월 뒤의 나)이 같은 함정에 다시 빠지지 않는다.

5. 버전 로그로 읽는 스킬의 성장사

재사용 스킬은 semver로 진화를 기록한다. plugin.json 버전 하나로 스킬의 역사가 읽힌다.

커밋 변경 버전
gcp-init→gke-init 리네임 + oke-init 신규 스킬 추가 1.3.0 → 1.4.0
OKE cloud-provider 패턴 + 무료 티어(Basic/A1) 패턴/기능 추가 1.4.0 → 1.5.0
Always Free 기본값 정합화 + OCID/arch 버그 수정 수정 1.5.0 → 1.6.0

규칙은 단순하다 — Patch=문구, Minor=패턴/스킬 추가, Major=리네임/삭제. 여기서 배운 것 하나: 마켓플레이스 매니페스트 동기화를 잊으면 상위 카탈로그가 stale 버전을 가리킨다(실제로 marketplace가 1.3.0을 가리키는 동안 플러그인은 이미 1.6.0이었다). 버저닝은 코드가 아니라 규율의 문제다.

정리 — 시리즈를 닫으며

  • 인프라를 provider 계층 / K8s 계층으로 나누면 클라우드 전환이 계층 교체로 끝난다.
  • 그 경계를 Hexagonal 포트/어댑터로 설계하면 자동화가 아키텍처가 된다.
  • 무료를 기본값으로 두면 실수로 과금되지 않는다.
  • 함정은 사람이 아니라 코드 주석·가드가 기억한다.
  • semver는 재사용 스킬의 성장 로그다.

왜 다시 상시 가동 쿠버네티스로 옮겼는가에서 시작해, 무료 클러스터를 띄우고, 채팅 백엔드를 설계·배포하고, Flutter 클라이언트까지 붙였다. 인프라 한 겹, 백엔드 한 겹, 클라이언트 한 겹 — 그리고 그 전부를 다시 자동화 스킬 한 겹으로 감싼 셈이다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다