server 2 CPU·2 GiB 이상의 최소 조건과 workload 여유, SSD 기반 data disk
LIGHTWEIGHT KUBERNETES
K3s 단일 서버·확장 준비 구성
K3s 요구 자원·포트·CIDR을 확인하고 원격 설치 script를 파일로 검토한 뒤 고정 버전, 0600 kubeconfig·token file, embedded etcd snapshot과 안전한 복구 기준으로 구성합니다.BEFORE YOU START
시작 전에 준비하세요
고유 hostname과 충돌 없는 Pod 10.42.0.0/16·Service 10.43.0.0/16 또는 승인 대체 CIDR
agent→server 6443/TCP, node 간 8472/UDP·10250/TCP를 출발지 제한한 방화벽
설치 script SHA-256·고정 K3s version을 검토한 change record와 console 복구 경로
etcd snapshot과 server token을 별도 암호화 위치에 복구 시험한 backup
권장 대상 개발·사내 edge 환경에 단일 K3s server를 설치하고 향후 node 추가와 datastore 복구를 책임질 인프라 담당자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
자원·아키텍처·고유 node 확인
K3s 공식 최소 조건은 workload를 포함하지 않으므로 실제 여유와 SSD, hostname·주소를 확인합니다. SD/eMMC는 etcd write 부하에 적합하지 않습니다.
cat /etc/os-release
uname -m
uname -rhostnamectl --static
ip -brief addressnproc
free -h
lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,MODEL
df -hT / /var/libstat -fc %T /sys/fs/cgroup
systemd --version | head -1- hostname과 node 주소가 고유하고 재부팅 뒤 유지됩니다.
- server 자원은 최소 2 CPU·2 GiB를 넘고 workload 여유가 있습니다.
- K3s data path는 신뢰 가능한 SSD와 충분한 IOPS·용량을 가집니다.
중복 hostname, 휘발 주소, 부족한 memory·disk면 설치 전에 기반 환경을 수정합니다.
CIDR·port·기존 Kubernetes·firewall을 점검합니다.
CIDR·port·기존 cluster 사전 점검
기본 K3s network가 사내망·VPN·Docker와 겹치지 않는지, 필수 port와 기존 data·service가 없는지 확인합니다. 8472/UDP는 인터넷에 노출하면 안 됩니다.
ip route show
ip -brief addresssudo ss -lntup | grep -E ':(6443|6444|8472|10250|2379|2380)\b'systemctl status k3s.service k3s-agent.service --no-pager -l
sudo test -e /var/lib/rancher/k3s && sudo du -sh /var/lib/rancher/k3s || truesudo ufw status verbose- Pod·Service CIDR이 모든 route·VPN·Docker network와 겹치지 않습니다.
- 기존 K3s·kubeadm·container runtime의 data owner를 확인했습니다.
- agent·node CIDR로 제한할 방화벽 정책과 관리 SSH 경로가 있습니다.
기존 datastore가 있거나 CIDR이 겹치면 installer를 실행하지 않습니다.
공식 install script를 별도 파일로 내려받아 hash·내용을 검토합니다.
공식 install script 검토 후 고정 버전 설치
get.k3s.io script를 shell pipe로 실행하지 않습니다. 파일로 다운로드해 SHA-256·내용·공식 URL을 검토하고 조직이 승인한 hash와 일치할 때만 start를 건너뛴 채 설치합니다.
umask 077
mktemp -d -p /var/tmp haru-k3s.XXXXXXXX출력된 절대 경로를 <K3S_WORK_DIR>에 그대로 대입합니다.stat -Lc '%a %U:%G %n' <K3S_WORK_DIR>
curl -fL -o <K3S_WORK_DIR>/install.sh https://get.k3s.io
sha256sum <K3S_WORK_DIR>/install.sh
less <K3S_WORK_DIR>/install.sh출력 hash가 change record의 <APPROVED_INSTALL_SCRIPT_SHA256>와 정확히 일치하고 script review가 끝나야 합니다.sh -n <K3S_WORK_DIR>/install.shsudo env INSTALL_K3S_VERSION=<APPROVED_K3S_VERSION> INSTALL_K3S_SKIP_ENABLE=true INSTALL_K3S_SKIP_START=true sh <K3S_WORK_DIR>/install.sh server공식 release와 승인 script hash를 확인한 뒤 실행합니다. channel·latest를 사용하지 않습니다./usr/local/bin/k3s --version
systemctl cat k3s.service- script SHA-256과 내용이 승인 기록과 일치합니다.
- K3s version은 정확한 release로 고정됐습니다.
- 서비스는 아직 시작하지 않았고 unit의 argument·environment를 검토했습니다.
hash·version·unit이 다르면 start하지 말고 설치 결과와 script를 격리해 검토합니다.
config·token·방화벽을 백업하고 구성합니다.
config·token·firewall 백업과 편집
config 파일과 token을 0600으로 유지하고 embedded etcd·고정 node identity·TLS SAN을 설정합니다. token을 명령 인자나 화면에 출력하지 않습니다.
sudo install -d -o root -g root -m 0700 /etc/rancher/k3s
if sudo test -f /etc/rancher/k3s/config.yaml; then sudo cp --archive --no-clobber /etc/rancher/k3s/config.yaml /etc/rancher/k3s/config.yaml.<BACKUP_SUFFIX>; fi
sudoedit /etc/rancher/k3s/config.yamlsudo sh -c 'umask 077; openssl rand -base64 48 > /etc/rancher/k3s/server-token'
sudo chmod 0600 /etc/rancher/k3s/server-token
sudo stat -Lc '%a %U:%G %n' /etc/rancher/k3s/server-token신규 cluster에서만 생성합니다. 기존 token을 교체하면 기존 snapshot과 node join에 영향을 줍니다.sudo ufw allow from <AGENT_IPV4_CIDR> to any port 6443 proto tcp
sudo ufw allow from <K3S_NODE_IPV4_CIDR> to any port 8472 proto udp
sudo ufw allow from <K3S_NODE_IPV4_CIDR> to any port 10250 proto tcp실제 node·agent 사설 CIDR로 제한합니다. 8472를 0.0.0.0/0에 열지 않습니다.sudo chown root:root /etc/rancher/k3s/config.yaml /etc/rancher/k3s/server-token
sudo chmod 0600 /etc/rancher/k3s/config.yaml /etc/rancher/k3s/server-token
sudo stat -Lc '%a %U:%G %n' /etc/rancher/k3s/config.yaml /etc/rancher/k3s/server-tokencluster-init: true
write-kubeconfig-mode: "0600"
token-file: /etc/rancher/k3s/server-token
tls-san:
- "<STABLE_API_HOST>"
node-name: "<UNIQUE_NODE_NAME>"
cluster-cidr: "<POD_CIDR>"
service-cidr: "<SERVICE_CIDR>"
etcd-snapshot-schedule-cron: "0 */12 * * *"
etcd-snapshot-retention: 5HA server를 추가할 때 critical flag·CIDR이 모두 같아야 합니다. token 값을 config에 직접 넣지 않습니다.- 기존 config는 고유한 suffix로 백업했고, 원본이 없었다면 신규 생성으로 변경 기록에 남겼습니다.
- token은 0600 파일이고 shell history·journal에 값이 없습니다.
- cluster·service CIDR과 TLS SAN이 실제 설계와 일치합니다.
- 6443·8472·10250은 승인된 사설 source만 허용합니다.
기존 token·cluster data가 있다면 신규 token 생성이나 cluster-init을 진행하지 않습니다.
config를 검토하고 service를 시작합니다.
service 시작과 kubeconfig 검증
config·unit·firewall을 다시 확인한 뒤 K3s를 시작합니다. kubeconfig는 root 0600 상태를 유지하고 공유용 0644로 완화하지 않습니다.
sudo systemd-analyze verify /etc/systemd/system/k3s.service
sudo sed -n '1,160p' /etc/rancher/k3s/config.yamltoken 값이 config에 없음을 확인하고 내부 SAN·CIDR은 외부 공유 전 마스킹합니다.sudo systemctl enable --now k3s.servicesudo k3s kubectl get nodes -o wide
sudo k3s kubectl get pods -Asudo stat -Lc '%a %U:%G %n' /etc/rancher/k3s/k3s.yaml- k3s service가 active이고 node가 Ready입니다.
- system Pod가 Running·Completed이며 반복 restart가 없습니다.
- kubeconfig와 token은 0600입니다.
node NotReady·system Pod 오류면 workload를 배포하지 말고 journal·event·CIDR·module을 확인합니다.
snapshot·DNS·storage·재부팅 후 상태를 검증합니다.
cluster·network·snapshot·재부팅 검증
API·DNS·storage class·snapshot을 확인하고 작은 smoke workload는 승인된 namespace에서만 사용합니다. snapshot과 token이 함께 복구 가능해야 합니다.
sudo k3s kubectl cluster-info
sudo k3s kubectl get nodes
sudo k3s kubectl get pods -A
sudo k3s kubectl get storageclasssudo k3s kubectl get events -A --sort-by=.lastTimestampsudo k3s etcd-snapshot save --name pre-workload-<CHANGE_ID>
sudo k3s etcd-snapshot listsudo find /var/lib/rancher/k3s/server/db/snapshots -maxdepth 1 -type f -printf '%m %u:%g %s %p\n'
sudo stat -Lc '%a %U:%G %n' /etc/rancher/k3s/server-token- node·CoreDNS·metrics-server·local-path provisioner 상태를 확인했습니다.
- snapshot save와 list가 성공하고 별도 암호화 backup으로 복제했습니다.
- 동일 server token도 별도 암호화 위치에 함께 보관했습니다.
- 승인된 재부팅 뒤 node·system Pod가 회복됩니다.
snapshot만 있고 token이 없으면 confidential data를 복호화할 수 없어 복구가 불가능할 수 있습니다.
API·VXLAN·kubelet port, Pod security, kubeconfig·token·snapshot 접근을 점검합니다.
network·Pod·credential·backup 보안
8472/UDP를 인터넷에 열지 않고 비신뢰 Pod에는 restricted Pod Security 기준으로 NET_RAW 등을 제한합니다. kubeconfig·token·snapshot은 cluster 관리자 비밀입니다.
sudo ss -lntup | grep -E ':(6443|8472|10250|2379|2380)\b'
sudo ufw status numberedsudo stat -Lc '%a %U:%G %n' /etc/rancher/k3s/k3s.yaml /etc/rancher/k3s/server-token /var/lib/rancher/k3s/server/tokensudo k3s kubectl get nodes -o wide
sudo k3s kubectl get namespace --show-labelssudo k3s certificate check --output table- 6443은 승인 agent source, 8472·10250은 node 사설망에서만 접근합니다.
- kubeconfig·server token·snapshot은 0600과 암호화 backup·접근 감사를 적용합니다.
- 비신뢰 namespace에 restricted Pod Security와 최소 RBAC를 적용합니다.
- workload image digest·registry TLS·secret encryption·network policy를 별도 운영 기준으로 둡니다.
- K3s release·Kubernetes skew·certificate·backup restore를 정기 검증합니다.
- <...> 자리표시자는 승인된 리터럴 값으로 직접 치환하고 외부 입력으로 shell 명령을 조립하거나 eval하지 않습니다.
public VXLAN, world-readable kubeconfig, 검증되지 않은 image 또는 backup 없는 cluster면 workload 투입을 중단합니다.
config rollback과 datastore restore·fresh uninstall의 데이터 경계를 확인합니다.
config 복원 또는 datastore 복구 분기
단순 config 실패와 datastore 손상을 구분합니다. installer가 만든 uninstall script는 local datastore·local-storage PV까지 삭제하므로 fresh·무데이터 호스트가 아니면 실행하지 않습니다.
systemctl status k3s.service --no-pager -l
journalctl -u k3s.service --since '-30 min' --no-pager
sudo k3s etcd-snapshot listsudo systemctl stop k3s.service
if sudo test -f /etc/rancher/k3s/config.yaml.<BACKUP_SUFFIX>; then sudo cp --archive /etc/rancher/k3s/config.yaml.<BACKUP_SUFFIX> /etc/rancher/k3s/config.yaml; sudo chmod 0600 /etc/rancher/k3s/config.yaml; sudo systemctl start k3s.service; fisudo systemctl disable --now k3s.service
sudo install -d -o root -g root -m 0700 <APPROVED_QUARANTINE_DIR>
if sudo test -f /etc/rancher/k3s/config.yaml; then sudo mv --no-clobber /etc/rancher/k3s/config.yaml <APPROVED_QUARANTINE_DIR>/config.yaml.new; fi
if sudo test -f /etc/systemd/system/k3s.service; then sudo mv --no-clobber /etc/systemd/system/k3s.service <APPROVED_QUARANTINE_DIR>/k3s.service.new; fi
if sudo test -f /etc/systemd/system/k3s.service.env; then sudo mv --no-clobber /etc/systemd/system/k3s.service.env <APPROVED_QUARANTINE_DIR>/k3s.service.env.new; fi
if sudo test -L /etc/systemd/system/multi-user.target.wants/k3s.service; then sudo mv --no-clobber /etc/systemd/system/multi-user.target.wants/k3s.service <APPROVED_QUARANTINE_DIR>/k3s.service.link; fi
sudo systemctl daemon-reloadbackup이 없고 변경 기록으로 이 레시피가 신규 생성한 정확한 파일·link임이 확인될 때만 A 대신 실행합니다. binary·package·datastore·PV는 purge하지 않습니다.if systemctl is-active --quiet k3s.service; then sudo k3s kubectl get nodes; sudo k3s kubectl get pods -A; sudo k3s etcd-snapshot list; fi
systemctl is-enabled k3s.service || true
systemctl is-active k3s.service || truesudo sha256sum <APPROVED_ETCD_SNAPSHOT>
sudo stat -Lc '%a %U:%G %n' <APPROVED_ENCRYPTED_TOKEN_BACKUP>실제 datastore restore는 node topology·같은 token·snapshot·version을 검토한 별도 장애 변경으로 K3s 공식 절차를 따릅니다.- config 문제만이면 datastore를 건드리지 않고 이전 config로 회복했습니다.
- datastore restore에는 snapshot과 동일 server token이 준비됐습니다.
- uninstall script를 편의상 실행하지 않았습니다.
- node·system Pod·PVC·업무 데이터가 복구 뒤 정상입니다.
K3s uninstall은 running Pod, local datastore, local-storage PV와 설정을 삭제할 수 있어 일반 rollback이 아닙니다. snapshot restore도 cluster membership을 재구성하므로 별도 승인과 복구 연습이 필요합니다.
원인·K3s version·config diff·snapshot checksum·복구 시간을 기록하고 정기 restore drill을 예약합니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- get.k3s.io script를 pipe 실행하지 않고 파일·SHA-256·내용·고정 version을 검토합니다.
- kubeconfig·token·snapshot을 0600과 암호화 backup으로 보호하고 token 값을 출력하지 않습니다.
- 6443·8472·10250은 필요한 사설 source만 허용하고 8472를 인터넷에 노출하지 않습니다.
- 비신뢰 workload에 restricted Pod Security·최소 RBAC·network policy·image digest를 적용합니다.
- embedded etcd snapshot과 같은 server token을 함께 백업하고 실제 restore를 시험합니다.
- uninstall script가 local data를 삭제한다는 경계를 알고 일반 rollback으로 사용하지 않습니다.
- <...> 자리표시자는 승인된 리터럴 값으로 직접 치환하고 외부 입력으로 shell 명령을 조립하거나 eval하지 않습니다.
COMMON ERRORS
자주 막히는 지점
Node NotReady·system Pod Pending
- 증상
- 설치 직후 node가 NotReady이거나 CoreDNS가 Pending입니다.
- 가능한 원인
- CIDR 충돌, cgroup·kernel module, disk·memory 압박 또는 CNI port 차단일 수 있습니다.
- 확인 순서
- event·journal·route·firewall을 확인하고 taint 제거·방화벽 비활성으로 우회하지 않습니다.
agent join 실패
- 증상
- token·x509·critical configuration mismatch 오류로 agent가 붙지 않습니다.
- 가능한 원인
- server URL·TLS SAN·token file 또는 server 간 critical flag·CIDR이 일치하지 않을 수 있습니다.
- 확인 순서
- token 값을 출력하지 말고 file 권한·SAN·config checksum을 양쪽에서 비교합니다.
Pod 통신·DNS 실패
- 증상
- Pod는 Running이나 service·DNS·node 간 통신이 안 됩니다.
- 가능한 원인
- VXLAN 8472, kubelet 10250, route·CIDR 중복 또는 NetworkPolicy가 원인일 수 있습니다.
- 확인 순서
- node source로 제한한 firewall과 route를 확인하고 VXLAN을 인터넷에 열지 않습니다.
PRIMARY REFERENCES
공식 문서
- K3s · Requirements와 네트워크 포트
- K3s · Configuration Options
- K3s · Backup and Restore
- K3s · etcd-snapshot 명령
- K3s · Uninstall의 데이터 삭제 경고
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.