---
title: "쿠버네티스를 브라우저로 포팅한 개발자가 말하는 LLM 코딩의 진짜 비용"
published: 2026-06-30T20:48:36.000Z
canonical: https://jeff.news/article/4480
---
# 쿠버네티스를 브라우저로 포팅한 개발자가 말하는 LLM 코딩의 진짜 비용

ngrok의 Simon Rose가 쿠버네티스 일부를 타입스크립트로 포팅해 브라우저 안에서 돌아가는 ‘webernetes’를 만들었다. 단순 장난감이 아니라 파드 생명주기, 클러스터 DNS, 네트워킹, IP 할당, 디플로이먼트와 레플리카셋 추적까지 구현했고, 거의 10만 줄을 2개월 동안 552개 커밋으로 밀어붙였다. 핵심은 ‘LLM이 코드를 많이 썼다’가 아니라, 그 결과물을 어떻게 검증했느냐다.

## 브라우저 안에서 돌아가는 쿠버네티스라니, 일단 컨셉이 세다

- ngrok의 Simon Rose가 ‘webernetes’라는 프로젝트를 공개함. 쿠버네티스 일부를 타입스크립트로 포팅해서 브라우저 안에서 클러스터가 돌아가게 만든 것임.
  - 작업 규모가 꽤 미쳤다. 2개월 동안 552개 커밋, 629개 파일, 거의 10만 줄의 코드를 만들었다고 함.
  - 데모에서는 파드가 서로 HTTP 요청을 주고받고, 파란 점으로 그 요청 흐름을 시각화함.

- 이건 단순 UI 시뮬레이터가 아니라, 쿠버네티스가 실제로 하는 일의 꽤 많은 부분을 브라우저에서 흉내 냄.
  - 파드 생명주기, 클러스터 DNS와 네트워킹, 컨테이너 가비지 컬렉션, IP 할당, 디플로이먼트와 레플리카셋 추적 등을 구현함.
  - 다만 운영용 쿠버네티스 배포판은 절대 아님. 목적은 ‘인터랙티브 쿠버네티스 교육 콘텐츠’를 만들기 쉽게 하는 것임.

> [!IMPORTANT]
> webernetes는 Kubernetes를 WebAssembly로 컴파일한 프로젝트가 아님. 브라우저에서 필요한 Kubernetes 동작을 타입스크립트로 다시 구현한 쪽에 가깝다.

## 왜 WebAssembly가 아니었나

- 많은 사람이 “쿠버네티스를 WebAssembly로 컴파일했냐”고 물었는데, 답은 명확히 ‘아니오’였음.
  - 단순한 Go 헬로월드 프로그램도 WebAssembly로 컴파일하면 gzip 기준 약 540KiB임.
  - webernetes 전체가 gzip 기준 약 140KiB라서, Kubernetes 전체를 WebAssembly로 보내면 메가바이트 단위가 될 가능성이 컸음.
  - 실제로 시도도 해봤지만, Kubernetes가 브라우저에 없는 시스템 레벨 API를 호출해서 컴파일 타임 에러가 났다고 함.

- 그래서 webernetes는 자체 브라우저 기반 레지스트리를 둠.
  - Docker Hub 같은 실제 레지스트리에서 이미지를 가져오지 않음.
  - 대신 타입스크립트 API로 이미지를 정의함. 예를 들어 `BaseImage`를 상속하고 `exec` 안에서 `ctx.listenHttp(8080, ...)`로 HTTP 서버를 띄우는 식임.
  - 디플로이먼트도 Kubernetes 리소스처럼 `apiVersion`, `kind`, `metadata`, `spec`, `containers`를 써서 적용함.

- API도 Kubernetes 자바스크립트 클라이언트와 비슷하게 맞췄음.
  - `listNamespacedPod`로 파드를 조회하고, `informer`로 파드 변경을 감시하고, `cluster.fetch`로 파드 IP에 요청을 보낼 수 있음.
  - 브라우저 데모의 움직이는 점도 내부적으로 request/response 이벤트를 받아 시각화한 것임.

## LLM이 거의 다 썼지만, 작성자는 그걸 곧이곧대로 믿지 않았다

- 흥미로운 대목은 webernetes 코드 대부분을 LLM이 작성했다는 점임.
  - 작성자도 사람들이 “조회수용으로 Kubernetes를 대충 slop-porting 한 거 아니냐”고 의심할 걸 예상한다고 함.
  - 그래서 본인이 강조한 건 두 가지임. 원본 Kubernetes Go 코드와 줄 단위로 최대한 비슷하게 포팅했는지 리뷰했고, 실제 동작이 같은지 테스트로 확인했다는 것.

- 작성자는 LLM이 포팅을 잘한다고 보지 않음. 오히려 “LLM은 코드 포팅을 못한다”고 꽤 세게 말함.
  - 원본 구조를 미묘하게 바꾸거나, 언어 차이 때문에 동작이 달라지거나, Go의 관용구를 JavaScript에 잘못 옮기는 문제가 반복됐다고 함.
  - 그래서 프롬프트만 잘 쓰면 한 번에 정확히 포팅된다는 식의 낙관론에는 선을 그음.
  - 결론은 단순함. LLM 포팅 결과를 믿으려면 사람이 리뷰해야 하고, 자동화된 검증도 있어야 함.

```mermaid
sequenceDiagram
    participant 개발자
    participant LLM
    participant Webernetes
    participant k3s
    participant 테스트
    개발자->>LLM: Kubernetes Go 코드를 TypeScript로 포팅 요청
    LLM-->>개발자: 포팅된 코드 생성
    개발자->>테스트: 같은 시나리오를 양쪽에 실행
    테스트->>k3s: 기준 Kubernetes 동작 확인
    테스트->>Webernetes: 브라우저 구현 동작 확인
    Webernetes-->>테스트: 결과 반환
    k3s-->>테스트: 결과 반환
    테스트-->>개발자: 차이가 나면 버그로 피드백
```

## 검증 방식이 이 글의 진짜 핵심

- 작성자는 같은 테스트를 실제 k3s 클러스터와 webernetes에 모두 돌리는 구조를 만들었음.
  - `pnpm test:node`는 Node 환경에서 k3s를 대상으로 테스트함.
  - `pnpm test:browser`는 헤드리스 브라우저에서 webernetes를 대상으로 테스트함.
  - 같은 `createNamespacedPod`, `deleteNamespacedPod`, `listNamespacedPod` API를 써서 두 구현체의 동작을 비교함.

- 예시 테스트는 파드를 만들고, 존재하는지 확인하고, 삭제한 뒤 정말 사라졌는지 기다리는 흐름임.
  - 각 테스트는 고유 네임스페이스를 만들어 서로 격리함.
  - `waitFor`로 비동기 상태 변화를 기다리기 때문에 Kubernetes 특유의 eventually consistent한 동작도 반영함.
  - 이게 단순 단위 테스트보다 중요한 이유는 브라우저 기반 컨테이너 런타임과 클러스터 네트워크가 실제 클러스터처럼 맞물려야 하기 때문임.

> [!TIP]
> 작성자가 버그를 만나면 먼저 “k3s에서는 통과하고 webernetes에서는 실패하는 테스트”를 만든다고 함. LLM에게 바로 고치라고 던지기 전에, 실패 조건을 먼저 고정하는 게 포인트임.

- 현재 테스트 규모도 작지 않음.
  - 통합 테스트는 204개.
  - 단위 테스트는 1,855개이고, 대부분 Kubernetes Go 코드베이스에서 직접 포팅한 테스트라고 함.
  - LLM이 빠르게 만든 코드라도 이 정도 검증망 없이는 믿기 어렵다는 메시지가 선명함.

## 토큰을 때려 넣으면 되긴 되는데, 효율은 별개 문제

- 프로젝트 후반에는 디플로이먼트 지원을 넣으려다 예상보다 일이 커졌다고 함.
  - 처음에는 오래 걸리지 않을 줄 알았지만, LLM의 첫 시도는 필요한 기능을 크게 빼먹었음.
  - 결국 여러 에이전트를 띄워 의존성 체인을 찾고, 컴포넌트를 나눠 포팅하고, 또 다른 서브에이전트로 리뷰까지 돌렸다고 함.

- 결과적으로 일은 빨리 끝났지만, 토큰 효율은 “매우 나빴다”고 평가함.
  - 특히 긴 컨텍스트 창을 자주 채우면 캐시된 입력 토큰 소비가 엄청나게 커진다고 함.
  - 그래도 마지막까지 가장 비싼 비용 항목은 토큰이 아니라 본인의 시간이었음.

- 작성자의 LLM 코딩관은 꽤 실무적임.
  - 예전에는 사람 PR에서 좋은 테스트와 좋은 코드를 기대했다면, 2026년에는 LLM 출력에도 똑같이 그걸 요구해야 한다는 것.
  - 차이는 사람 동료는 어느 정도 신뢰했지만, LLM은 기본적으로 신뢰하지 않는 편이 안전하다는 점임.
  - 테스트만 있고 리뷰가 없으면 테스트 자체가 맞는지 알 수 없고, 리뷰만 있고 테스트가 없으면 사람 머리로 모든 케이스를 놓치지 않는다고 착각하게 됨.

---

## 기술 맥락

- 이 프로젝트의 선택은 “Kubernetes를 그대로 브라우저에 올리자”가 아니라 “교육용으로 필요한 Kubernetes 동작을 작고 통제 가능한 런타임으로 다시 만들자”에 가까워요. WebAssembly로 통째로 가져오면 크기와 시스템 API 문제가 생기니까, 브라우저에서 설명 가능한 범위만 타입스크립트로 구현한 거예요.

- 검증 전략이 중요한 이유는 포팅 작업이 겉보기 유사성만으로는 절대 안전하지 않기 때문이에요. Go와 JavaScript는 런타임 모델이 다르고, 채널, 뮤텍스, select 같은 Go식 동시성 표현을 JavaScript로 옮기면 같은 코드처럼 보여도 행동이 달라질 수 있거든요.

- 그래서 작성자는 k3s를 기준선으로 두고, 같은 테스트를 실제 Kubernetes와 webernetes에 모두 실행했어요. 이 방식은 “내 구현이 맞는 것 같다”가 아니라 “기준 구현과 같은 입력에서 같은 결과를 낸다”로 검증 기준을 바꿔줘요.

- LLM을 쓴 방식도 무작정 생성형 코딩이 아니라, 실패하는 테스트를 먼저 만들고 그 피드백 루프 안에서 수정하게 하는 쪽이에요. LLM은 지치지 않고 빠르게 코드를 뽑아내지만, 성공 조건을 사람이 정확히 고정하지 않으면 그 속도가 그대로 리스크가 되기 때문이에요.

## 핵심 포인트

- webernetes는 쿠버네티스를 웹어셈블리로 컴파일한 게 아니라, 쿠버네티스 동작 일부를 타입스크립트로 다시 구현한 브라우저용 클러스터다.
- 프로젝트는 약 10만 줄, 629개 파일, 552개 커밋 규모로 진행됐고, gzip 기준 번들 크기는 약 140KiB다.
- LLM이 대부분의 코드를 작성했지만, 작성자는 실제 k3s 클러스터와 같은 테스트를 돌려 동작을 비교하는 방식으로 검증했다.
- 현재 204개 통합 테스트와 1,855개 단위 테스트가 있으며, 버그를 발견하면 먼저 k3s에서는 통과하고 webernetes에서는 실패하는 테스트를 만든다.
- LLM은 빠르게 많이 쓰게 해주지만, 포팅에서는 실수도 많이 하므로 리뷰와 테스트가 둘 다 필요하다는 게 글의 핵심 주장이다.

## 인사이트

이 글은 ‘LLM으로 대충 쿠버네티스 베꼈다’가 아니라, 대규모 코드 포팅에서 신뢰를 어떻게 만들어야 하는지 꽤 현실적으로 보여준다. 특히 실제 구현체와 API 호환 테스트를 나란히 돌리는 방식은 LLM 코딩을 업무에 붙이려는 팀이 그대로 참고할 만함.
