LabHub
배우기 러닝패스 코스

쿠버네티스 배포판 — 직접 세운다 · k3s 기본 구성요소 · 이론

k3s 는 왜 지운 traefik 을 다시 설치하나

LabHub 에서 이어서 보기

한 줄 요약

k3s 는 서버의 manifests 디렉터리를 기동할 때와 파일이 바뀔 때 적용하고 기본 구성요소 파일은 기동마다 다시 쓰므로, 구성요소를 없애려면 kubectl 이 아니라 --disable 을, 값을 바꾸려면 파일 수정이 아니라 HelmChartConfig 를 써야 합니다.

왜 이게 필요했나

관리형 쿠버네티스에서는 인그레스 컨트롤러나 메트릭 서버를 "설치하는 사람" 이 따로 있습니다. 필요 없으면 kubectl delete 로 지우고, 다시 필요하면 다시 설치합니다.
k3s 는 설치 한 줄로 coredns·traefik·local-storage·metrics-server 까지 갖춘 클러스터를 주려고 만들어졌습니다. 그러려면 k3s 자신이 그 구성요소들의 설치자여야 하고, 누군가 손으로 망가뜨려도 원래 모습으로 돌아가게 해야 합니다.
그래서 k3s 는 기본 구성요소의 매니페스트를 서버 디스크에 두고 기동할 때마다 다시 써서 적용합니다. 공식 문서는 이 파일들이 무결성을 위해 기동 때마다 다시 쓰이므로 고치지 말라고 적고 있습니다.

이 설계가 현장에서 어떤 모습이 되는지는 실측으로 확인했습니다(v1.35.8+k3s1).

kubectl -n kube-system delete helmchart traefik   → helm-delete Job 이 릴리스를 지움, traefik 사라짐(20초 기다려도 그대로)systemctl restart k3s                              → API 5초, HelmChart 가 새 UID 로 생기고 20초 뒤 traefik 복귀

"안 쓰려고 지웠는데 재부팅하니 다시 있다" 는 사고의 정체가 이것입니다.

어떻게 동작하나

층이 두 개입니다.

첫째 층은 배포 컨트롤러와 AddOn 입니다. /var/lib/rancher/k3s/server/manifests 아래의 파일 하나(하위 디렉터리 포함)가 kube-system 네임스페이스의 AddOn 객체 하나가 되고, 이름은 파일 이름에서 확장자를 뗀 것입니다. 컨트롤러는 파일을 kubectl apply 비슷하게 적용하고 AddOn 의 spec.checksum 에 내용 해시를 적어 둡니다.
적용의 계기는 두 가지뿐입니다 — k3s 기동, 그리고 파일 내용의 변경. 실측해 보면 클러스터에서 객체를 지워도, 파일을 touch 만 해도 다시 적용되지 않았고, 값을 바꾸자 몇 초 만에 새 UID 로 다시 생겼습니다. 반대로 파일을 지워도 클러스터의 객체와 AddOn 은 남습니다. 문서도 파일 삭제가 리소스를 지우지 않는다고 분명히 적습니다.

둘째 층은 helm-controller 와 HelmChart 입니다. traefik.yaml 에는 Deployment 가 아니라 HelmChart 객체가 들어 있고, helm-controller 가 그것을 보고 helm-install-traefik Job 을 띄워 차트를 설치합니다. 차트 파일은 API 서버의 static 경로에서 받습니다. 값의 우선순위는 차트 기본값 → HelmChart valuesContent → HelmChartConfig valuesContent → HelmChart spec.set 순으로 뒤가 이깁니다.

apiVersion: helm.cattle.io/v1kind: HelmChartConfigmetadata:  name: traefik          # 대상 HelmChart 와 이름·네임스페이스가 같아야 한다  namespace: kube-systemspec:  valuesContent: |-    logs:      general:        level: DEBUG

HelmChartConfig 는 k3s 가 다시 쓰는 파일이 아니라 따로 둔 객체라서 기동 때 덮이지 않습니다. 적용하면 helm upgrade 가 돌아 릴리스 Secret 이 하나 늘어납니다.

끄는 방법도 두 가지이고 성격이 다릅니다.

--disable=traefik     AddOn 을 실제로 제거하고 원본 파일도 지운다. 구성은 기동할 때 읽힌다traefik.yaml.skip     그 파일을 없는 것처럼 무시한다. 이미 만든 객체는 지우지 않는다

구성은 /etc/rancher/k3s/config.yamlconfig.yaml.d/*.yaml(이름순)에서 읽고, 같은 키는 마지막 값이 이기며, 키 끝에 + 를 붙이면 목록에 덧붙입니다. 파일과 CLI 인자가 같은 키를 가지면 CLI 가 이깁니다. 설치 스크립트에 넘긴 INSTALL_K3S_EXEC 는 systemd 유닛의 인자로 저장되므로 CLI 쪽입니다.

현장에서 만나는 모습

가장 흔한 것은 인그레스를 nginx 로 바꾸려는 팀이 traefik 을 kubectl 로 지우는 경우입니다. 그날은 조용하다가 노드 재부팅이나 k3s 업그레이드 날 traefik 이 되살아나 80·443 을 차지하고, 새 인그레스 컨트롤러의 LoadBalancer 가 Pending 에 걸립니다. 원인을 모르면 "누가 설치했나" 부터 찾게 됩니다.

두 번째는 traefik.yaml 을 직접 고쳐 값을 바꾼 경우입니다. 당장은 반영되지만 다음 기동에 원본으로 되돌아갑니다. 값은 HelmChartConfig 로, 제거는 --disable 로 해야 재부팅과 업그레이드를 견딥니다.

세 번째는 구성 파일을 고쳤는데 반영되지 않는 경우입니다. 실측에서 config.yaml 에 write-kubeconfig-mode: "0600" 을 적고 재시작해도 k3s.yaml 은 644 로 남았습니다. 설치할 때 넘긴 --write-kubeconfig-mode 644 가 유닛 인자로 남아 있었기 때문입니다. drop-in 에서 disable:+ 없이 쓰면 앞 파일의 목록이 통째로 덮여 꺼 두었던 구성요소가 다시 설치되는 것도 같은 계열의 실수입니다.

실무에서 진짜 중요한 것

다음 실습에서 할 것

VM 안의 k3s 에서 AddOn 목록을 기록하고, 사용자 AddOn 을 kubectl 로 지웠을 때와 파일을 고쳤을 때를 비교합니다. HelmChart traefik 을 지운 뒤 재시작해 되살아나는 것을 UID 로 확인하고, .skip·drop-in disable·CLI 우선순위·HelmChartConfig 를 차례로 적용해 무엇이 재시작을 요구하는지 표로 정리합니다.

참고 문서: [Managing Packaged Components](https://docs.k3s.io/installation/packaged-components) · [Helm (HelmChart·HelmChartConfig)](https://docs.k3s.io/add-ons/helm) · [Configuration Options](https://docs.k3s.io/installation/configuration)