쿠버네티스 배포판 — 직접 세운다 · Talos Linux · 이론
들어갈 곳이 없는 OS — Talos 가 셸을 없앤 이유
한 줄 요약
Talos Linux 는 셸·SSH·패키지 없이 쿠버네티스만 돌리는 OS 이고, 노드에 들어가는 대신 노드마다 열린 gRPC API 로 모든 것을 읽고 바꿉니다.
왜 이게 필요했나
노드가 서른 대쯤 되면 반드시 이런 일이 생깁니다. 장애 때 누군가 한 노드에 SSH 로 들어가 sysctl 을 바꾸고 kubelet 인자를 고쳐 급한 불을 끕니다. 기록은 남지 않고, 석 달 뒤 그 노드만 이상하게 동작합니다. 설정 관리 도구를 붙여도 "관리 도구 밖에서 손댄 것" 은 여전히 가능합니다.
Talos 는 이 문제를 규칙이 아니라 구조로 막습니다. [철학 문서](https://docs.siderolabs.com/talos/v1.13/learn-more/philosophy)는 셸도, SSH 도, GNU 유틸리티도, busybox 조차 없다고 적습니다. 커널이 띄우는 첫 프로세스는 systemd 가 아니라 Go 로 쓴 machined 이고, 루트 파일 시스템은 SquashFS 라 쓸 수 없습니다. 들어갈 곳이 없으니 손댈 수도 없습니다. 대신 노드의 모든 상태는 하나의 선언적 머신 설정으로 정해지고, 바꾸는 길은 API 하나입니다.
어떻게 동작하나
구성요소는 적습니다. apid 가 50000번에서 gRPC 요청을 받아 machined 로 넘기고, 컨트롤 플레인이라면 다른 노드의 apid 로 중계도 합니다. machined 는 정해진 서비스(containerd·etcd·kubelet·trustd 등)만 돌리고 임의의 사용자 서비스는 받지 않습니다. talosctl 은 이 API 의 클라이언트이고, -e 는 어느 노드의 apid 로 들어갈지, -n 은 어느 노드가 답할지를 정합니다.
내부 상태는 쿠버네티스처럼 리소스와 컨트롤러로 표현됩니다. 서비스·클러스터 멤버·머신 설정이 모두 리소스라서 같은 명령으로 읽힙니다.
talosctl -n 10.5.0.2 services # machined 가 돌리는 서비스talosctl -n 10.5.0.2 get members # 클러스터 멤버(discovery)talosctl -n 10.5.0.3 get mc v1alpha1 -o yaml # 머신 설정도 버전이 붙은 리소스talosctl -n 10.5.0.3 logs kubelet # 셸 대신 로그도 API 로설정을 바꾸는 명령은 apply-config·edit machineconfig·patch machineconfig 셋이고, 적용 방식은 --mode 로 고릅니다. [설정 편집 문서](https://docs.siderolabs.com/talos/v1.13/configure-your-talos-cluster/system-configuration/editing-machine-configuration)(v1.13)에 따르면 auto 는 필요하면 재부팅, no-reboot 는 즉시 적용하되 재부팅이 필요한 필드면 거절, staged 는 다음 재부팅에, try 는 즉시 적용한 뒤 정해진 시간 안에 다른 변경이 없으면 되돌립니다. nodeLabels·kubelet·network 같은 항목은 재부팅 없이 반영되는 목록에 있습니다. 패치는 설정의 일부만 적은 strategic merge YAML 이고, 목록은 보통 덧붙지만 cluster.network.podSubnets·serviceSubnets 는 덮어씁니다. 특정 키는 $patch: delete 로 지웁니다.
로컬에서는 [Docker 안내](https://docs.siderolabs.com/talos/v1.13/platform-specific-installations/local-platforms/docker)대로 talosctl cluster create docker 로 노드를 컨테이너로 띄울 수 있습니다. 컨테이너 모드에서는 upgrade·reset 같은 API 가 적용되지 않습니다.
현장에서 만나는 모습
이 코스의 VM 에서 실측한 것입니다. 노드 컨테이너에 docker exec ... sh 를 하면 exit 127 로 executable file not found 가 나오고, 노드 IP 의 22번은 거절되며 50000번만 열려 있습니다. 습관대로 "일단 들어가 보자" 가 첫 줄에서 막힙니다.
대역 함정도 그대로 나왔습니다. talosctl 이 만드는 기본 대역은 파드 10.244.0.0/16·서비스 10.96.0.0/12 인데, 이 VM 자신의 주소가 호스트 클러스터의 10.244 대역에 있습니다. 그래서 --config-patch 로 10.200/10.201 을 주고 띄웠습니다.
판 선택도 실측으로 정했습니다. talosctl v1.14.0 의 기본 이미지로 띄우자 노드 로그에 /etc overlay 를 만들다 FSCONFIG_SET_FD failed ... lowerdir+ 가 나오고 API 가 끝내 준비되지 않았습니다(호스트 커널 6.8). 같은 VM 에서 v1.13.10 은 약 2분 만에 두 노드가 Ready 였습니다. 컨테이너 안의 Talos 는 호스트 커널을 그대로 쓰므로, 판을 올릴 때는 호스트 커널이 먼저 조건이 됩니다.
가장 중요한 실측은 검증의 한계입니다. 라벨 이름에 공백을 넣은 패치는 InvalidArgument 로 거절되고 설정 버전이 그대로입니다. 반면 kubelet 의 extraArgs 에 없는 플래그를 넣으면 "Applied configuration without a reboot" 로 받아들여지고, kubelet 이 unknown flag 로 5초마다 재시작합니다. 검증은 문서 형식을 볼 뿐 kubelet 이 그 플래그를 아는지는 모릅니다. 셸이 없으니 원인은 talosctl services 의 LAST EVENT 와 talosctl logs kubelet 에서 찾고, $patch: delete 로 그 키만 지우자 3초 안에 kubelet 이 건강해졌습니다.
실무에서 진짜 중요한 것
머신 설정 파일이 곧 노드입니다. 노드에서 고친 것은 없고, 설정 리소스의 version 이 변경 이력의 뼈대입니다. 패치 파일을 저장소에 두고 같은 파일로 여러 노드에 적용하는 흐름이 자연스러워집니다.
try 모드를 원격 변경의 안전줄로 씁니다. 네트워크처럼 잘못 바꾸면 API 에 다시 닿지 못할 수 있는 설정은 try 로 넣고, 확인되면 같은 변경을 다시 적용해 굳힙니다. 확인하는 동안 다른 변경을 넣으면 되돌리기가 취소된다는 점도 기억해야 합니다.
검증 통과를 성공으로 읽지 않습니다. 적용 뒤에는 서비스 상태와 노드 Ready 를 반드시 다시 봅니다. 그리고 --dry-run 은 합친 결과를 보여 줄 뿐 검증하지 않습니다(실측).
응급처치 수단이 API 뿐이라는 것을 받아들입니다. apid 에 닿을 수 있는 네트워크와 talosconfig 인증서를 잃으면 노드를 고칠 방법이 사실상 없습니다. 인증서 보관과 접근 경로가 SSH 키 관리보다 더 중요해집니다.
다음 실습에서 할 것
VM 안에 도커로 띄운 Talos 노드 두 대에서 셸이 없음을 증거로 남기고, 서비스·멤버·머신 설정을 읽고, kubeconfig 를 API 로 받아 대역을 확인합니다. 그다음 워커에 no-reboot 로 라벨을 붙이고, try 로 붙인 라벨이 30초 뒤 되돌아가는 것을 봅니다. 마지막으로 검증이 거절하는 패치와 받아들여졌지만 kubelet 을 죽이는 패치를 차례로 넣고, 로그로 원인을 찾아 되돌린 뒤 보고서로 정리합니다.