사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
일반▾
인터페이스▾
관측성▾
성능▾
네이티브▾
개발▾

Kubernetes

Akan 앱은 모두 같은 Helm chart인 infra/app으로 배포합니다. chart는 <appName>-<branch> 네임스페이스에 리소스 네 개를 만듭니다.
리소스이름하는 일
Deploymentapp-deployment앱 이미지를 pod 하나로 실행합니다.
Serviceapp-svc클러스터 안에서 8282 포트로 앱을 노출합니다.
Ingressapp-ingress도메인을 Service에 연결하고 TLS 인증서를 발급받습니다.
PersistentVolumeClaimsqlite-datapod가 재시작돼도 /workspace/sqlite의 sqlite 데이터를 유지합니다.
브랜치는 네임스페이스가 정합니다
branch는 값으로 적지 않습니다. chart가 release 네임스페이스에서 읽어 옵니다.
  1. <appName>-<branch> 네임스페이스에 배포합니다. 예를 들면 myapp-main입니다.
  2. chart가 이름을 -로 나눠 두 번째 조각인 main을 branch로 씁니다.
  3. values의 main: 블록을 읽고, pod에 AKAN_PUBLIC_ENV=main을 넘깁니다.

구조

요청은 Ingress로 들어와 Service를 거쳐 pod에 닿고, pod는 데이터를 PVC에 저장합니다. 그 옆에서 kubelet이 pod의 상태를 확인합니다.
요청 경로
도메인<appName>-<branch>.<serveDomain>
IngressTLS, subRoute·도메인마다 호스트 하나
Service :8282
Podreplicas: 1
PVC/workspace/sqlite
kubelet
  • pod는 언제나 하나입니다. replicas: 1은 template에 고정돼 있습니다. 확장하려면 pod를 늘리지 말고 pod 안의 AKAN_REPLICA를 올립니다.
  • 하나인 이유. sqlite PVC가 ReadWriteOnce라서 한 번에 노드 하나에만 붙습니다. 그래서 pod를 여러 노드에 나눠 띄울 수 없습니다.
  • 인증서는 하나입니다. 기본 호스트, subRoute 호스트, 운영 도메인이 모두 TLS secret cert-<appName>-<branch> 하나를 함께 씁니다.

Values

values.yaml 하나로 끝나지 않습니다. Helm이 파일 네 개를 순서대로 읽고, 뒤의 파일이 앞의 값을 덮어씁니다. 그래서 앱 자신의 파일에는 보통 이름과 운영 도메인만 적습니다.
#파일담는 값
1_common-values.yamldebug, develop, main 브랜치별 replica, 리소스, 스토리지 기본값입니다.
2_common-secret.yaml모든 앱이 함께 쓰는 repoName, serveDomain, image.registry 값입니다.
3<appName>-values.yaml앱 자신의 appName, subRoutes, 도메인, 덮어쓸 값입니다.
4<appName>-secret.yaml앱 전용 비밀값이며 비어 있어도 됩니다.
두 *-secret.yaml 파일은 git에 올리지 않습니다. bun run downloadSecret은 infra/master/jenkins/getSecrets.sh에 적힌 파일을 받아 오므로, 새 앱의 파일도 거기에 추가합니다.
배포 명령
Jenkins 배포 단계는 앱마다 infra/에서 아래 두 명령을 실행합니다.
Terminal
  • -f 순서가 곧 우선순위입니다. 뒤에 오는 파일이 같은 키를 덮어씁니다.
  • -n이 branch를 정합니다. myapp-main이면 main: 블록을 씁니다.
  • rollout restart가 새 빌드를 반영합니다. 재시작한 pod가 이미지를 다시 받아 오므로, 방금 올린 빌드로 뜹니다.
앱 values 파일
기본값보다 용량이 더 필요한 운영 앱이라면 파일이 이 정도가 됩니다.
infra/app/values/myapp-values.yaml
  • 최상위 키는 모든 브랜치에 적용됩니다. appName과 subRoutes는 맨 위에 적습니다.
  • main: 블록은 main에만 적용됩니다. 적지 않은 키는 _common-values.yaml의 기본값을 따르고, domains 같은 목록은 통째로 바뀝니다.
최상위 키
_common-secret.yaml 표시가 붙은 키는 그 파일에 한 번만 적고 모든 앱이 함께 씁니다.
appNamestring
네임스페이스 <appName>-<branch>, 이미지 경로, 기본 호스트 이름에 쓰입니다.
repoNamestring_common-secret.yaml
이미지 경로 <registry>/<repoName>/<appName>의 workspace 부분입니다.
serveDomainstring_common-secret.yaml
기준 도메인이며, 기본 호스트는 <appName>-<branch>.<serveDomain>입니다.
subRoutesstring[]기본값 []
basePath마다 <subRoute>-<branch>.<serveDomain> 호스트와 TLS 이름을 하나씩 더합니다.
image.registrystring_common-secret.yaml
이미지 레지스트리 호스트입니다.
image.tagstring기본값 <branch>-live
특정 빌드에 고정할 때만 적습니다.
브랜치별 키
main: 같은 브랜치 블록 아래에 적습니다. 기본값은 _common-values.yaml에서 옵니다.
<branch>.domainsstring[]기본값 []
운영 도메인처럼 그 브랜치에 더할 호스트와 TLS 이름입니다.
<branch>.app.replicastring기본값 "0,0,1"
pod 안에서 AKAN_REPLICA, 즉 federation, batch, all 순서의 프로세스 수가 됩니다.
<branch>.app.solostring기본값 없음
AKAN_SOLO가 되며, replica가 하나여도 gateway를 두려면 false를 적습니다.
<branch>.app.resources.requests{ memory, cpu }기본값 250M / 0.05 (main: 1G / 1)
pod가 요청하는 메모리와 CPU입니다.
<branch>.app.resources.limits{ memory, cpu }기본값 1G / 0.5 (main: 4G / 4)
pod의 limit이며, CPU limit은 이미지 최적화가 한 번에 인코딩하는 수도 정합니다.
<branch>.app.resources.storagestring기본값 2Gi (main: 5Gi)
/workspace/sqlite에 마운트되는 ReadWriteOnce PVC의 크기입니다.

확장

<branch>.app.replica는 pod 안에서 AKAN_REPLICA가 됩니다. 역할별 프로세스 수 세 개이며, CPU·메모리 limit과 함께 올립니다.
federation
요청을 처리하고, serverMode: "batch"로 고정한 서비스와 internal은 건너뜁니다.
batch
요청은 받지 않고, batch로 고정한 것을 포함해 예약·큐 internal을 돌립니다.
all
요청을 처리하고 모든 internal도 돌립니다.
자주 쓰는 값
AKAN_REPLICA
요청 처리
batch internal
Gateway
프로세스 하나, gateway 없음
0,0,1
✓
✓
chart 기본값으로, 무엇이든 하는 프로세스 하나입니다.
1,0,0
✓
요청 프로세스 하나라서 batch로 고정한 internal은 돌지 않습니다.
gateway 뒤의 여러 프로세스
2,1,0
✓
✓
✓
요청 프로세스 두 개와 batch worker 하나입니다.
✓함안 함
상태 확인 probe
프로세스가 하나면 재시작해 줄 gateway가 없어서 kubelet이 그 일을 맡습니다. chart는 probe 세 개를 /_akan/app/health로 보내고, solo 프로세스가 이 경로에 직접 응답합니다.
Probe주기타임아웃실패 한도
↳ 하는 일
startupProbe5s1s24
SSR은 라우트 산출물을 불러온 뒤에야 요청을 받으므로 부팅을 최대 2분까지 기다립니다.
livenessProbe15s3s3
세 번 연속 실패하면 멈춘 서버를 재시작합니다.
readinessProbe10s3s2
두 번 연속 실패하면 pod를 Service에서 뺍니다.
  • 종료 유예는 40초입니다. 서버는 종료할 때 최대 30초 동안 하던 일을 마무리합니다(AKAN_SHUTDOWN_TIMEOUT_MS). 10초의 여유 덕분에 마무리가 끝나는 순간 SIGKILL이 떨어지지 않습니다.
  • gateway가 있으면 자식 프로세스는 gateway가 재시작합니다. 2,1,0처럼 프로세스가 여럿이면 죽은 프로세스를 gateway가 다시 띄우고, probe는 그대로 pod를 지켜봅니다.

콘솔 열기

빌드한 이미지에는 console.js가 이미 들어 있습니다. 실행 중인 pod 안에서 kubectl exec로 엽니다.
Terminal
  • 네임스페이스와 컨테이너. -n에는 <appName>-<branch>를 적고, 컨테이너 이름은 언제나 app입니다.
  • AKAN_CONSOLE=1은 이 명령에만 붙입니다. 이미지는 브랜치와 상관없이 운영 모드로 돌기 때문에, 이 값이 없으면 console이 열리지 않습니다.
  • 별도 프로세스입니다. console은 pod 안에서 요청을 받지 않고 internal 작업과 큐 worker도 돌리지 않는 서버 프로세스를 따로 띄웁니다. 실행 중인 main.js의 메모리에 붙는 것이 아닙니다.
  • 실행 중인 서버의 로그는 볼 수 있습니다. .tail과 .trace가 runtime 디렉터리의 제어 소켓을 통해 가져옵니다.

꿀팁

  • request는 작게 시작합니다. 메트릭을 확인한 뒤에 limit을 올립니다.
  • 스토리지는 미리 늘립니다. sqlite PVC는 급해지기 전에 여유 있게 키웁니다.
  • 호스트는 빠짐없이 적습니다. subRoutes와 domains를 명시하고 akan.config.ts의 routes와 맞춰 두면 Ingress 규칙을 예측할 수 있습니다. chart는 호스트를 열어 줄 뿐이고, 어느 basePath가 응답할지는 앱이 정합니다.
  • helm upgrade를 직접 돌렸다면 rollout을 재시작합니다. 기본 태그 <branch>-live는 빌드가 바뀌어도 이름이 같아서 Deployment가 바뀌지 않습니다. kubectl rollout restart 전까지 pod는 이전 빌드로 돕니다.
함께 보기

MIT 라이선스 하에 배포되었습니다.

내 AI에 이 문서 연결하기

MCPhttps://akanjs.com/mcp
Copyright © 2026 Akan.js 모든 권리 보유.시스템 관리자bassman