2P by GN⁺ | ★ favorite | 댓글 1개
  • 개인용 서버와 소형 VPS에서는 Kubernetes의 선언형 자동화가 매력적이지만, CPU·메모리 부담과 운영 복잡도가 실제 이득을 앞지를 수 있음
  • Kubernetes는 원하는 상태를 계속 맞추는 방식으로 Pod 조정과 TLS 인증서 갱신 같은 자동화를 해주지만, 이를 위해 꽤 큰 런타임을 상시 유지함
  • Azure Kubernetes Service, Microk8s, K3S, Raspberry Pi 실험에서 유휴 리소스 사용량과 발열·팬 소음이 반복적으로 문제가 됨
  • Podman은 컨테이너를 systemd 서비스로 만들고 io.containers.autoupdatepodman auto-update로 새 이미지를 감지해 교체할 수 있음
  • Podman, systemd, user lingering 조합은 Kubernetes에서 원했던 자동화 대부분을 더 단순하게 제공하지만, systemd 통합은 Quadlet 방향으로 이동 중임

Kubernetes 자동화가 개인 서버에는 무거웠던 이유

  • Kubernetes는 여러 구성요소, 웹 서비스, 사이드카, 웹훅으로 이뤄져 있지만 핵심 동작은 현재 상태원하는 상태를 계속 비교해 차이를 적용하는 루프에 가까움
    • Pod가 있어야 하는데 없으면 생성함
    • replica가 3개여야 하는데 4개면 하나를 제거함
  • 이 모델은 cert-manager 같은 확장에서 특히 유용했음
    • 특정 도메인에 유효한 TLS 인증서가 있어야 한다고 선언함
    • 인증서 요청 방법을 알려두면, 인증서가 없거나 만료가 가까울 때 새 인증서를 받아 웹 서버에 설치함
  • 개인 실험 용도에서는 재미있고 학습 가치도 있었지만, 실제 운영 목적에는 과도한 도구에 가까웠음
  • 리소스 부담은 여러 환경에서 반복됨
    • NUC에서는 컴퓨터가 계속 돌며 뜨거워지고 팬 소음이 생겨 잠자기 어려웠음
    • Azure Kubernetes Service에서는 Kubernetes 구현이 RAM을 크게 차지했고, worker node에서 유휴 CPU를 약 7~10% 사용함
    • 2 vCPU x86_64 VPS의 단일 인스턴스 Microk8s는 유휴 CPU가 약 12% 수준이었음
    • 2 vCPU Ampere A1 머신의 K3S는 더 가벼운 구현으로 알려졌지만 약 6% 의 상시 CPU를 사용함
    • Raspberry Pi에서도 발열·팬 문제 없이 워크로드에 충분한 CPU를 남기는 구현을 찾지 못함

Podman과 systemd로 바꾼 자동화 방식

  • Kubernetes로 계속 돌아가게 만든 가장 큰 이유는 배포 자동화였음
    • GitOps와 Flux를 쓰면 변경 작업이 쉬웠음
    • 컨테이너 이미지 자동화와 Flux v2의 웹훅으로 새 이미지를 푸시하면 몇 초 안에 서버가 새 이미지를 받아 프로덕션 애플리케이션을 실행했음
  • Kubernetes 밖에서 찾은 기존 대안들은 만족스럽지 않았음
    • 원래 명령행 인자를 모두 기억해 컨테이너를 다시 만드는 방식은 관리 부담이 컸음
    • docker.sock 전체 제어권을 요구하는 도구도 선호하지 않았음
  • Podman auto-updating이 필요한 기능에 가까웠음
    • Podman은 Docker CLI 대안으로 볼 수 있음
    • 컨테이너를 만든 뒤 systemd 서비스 파일을 생성할 수 있음
    • 서비스를 시작하면 컨테이너를 생성하거나 교체하고, 서비스를 중지하면 컨테이너를 제거함
  • 자동 업데이트는 io.containers.autoupdate 태그로 동작함
    • 하루 한 번 타이머로 실행하거나 podman auto-update를 직접 실행함
    • 새 이미지가 있으면 해당 이미지로 컨테이너를 재생성함
  • Fedora Magazine의 Auto-updating Podman containers with systemd가 대부분의 구현 방법을 제공했고, 추가로 두 가지 설정이 필요했음
    • systemctl --user enable mycontainer.service로 로그인할 때 컨테이너가 자동 시작되게 함
    • loginctl enable-linger로 서버 시작 시 사용자 세션이 동작하게 함
  • Podman, systemd, user lingering 조합으로 Kubernetes에서 얻던 이점의 약 99% 를 훨씬 낮은 복잡도와 CPU·메모리 부담으로 얻음
  • 전체 서비스를 기존 VPS에서 vCPU와 RAM이 절반인 새 VPS로 옮겼고, 몇 시간 실행 기준으로 더 가볍고 빠르며 컴퓨트 비용도 낮았음
  • 다만 Podman의 systemd 통합은 이미 지원 중단된 것으로 보이며, 컨테이너 정의는 Quadlet 파일 방향으로 논의되고 있음

댓글과 토론

Hacker News 의견들
  • 원문 작성자의 감정에 완전히 공감함. 직장에서는 수십 개 마이크로서비스가 도는 여러 Kubernetes 클러스터를 비교적 쉽게 관리하지만, 수익이 없는 취미 프로젝트에서는 예산이 작아서 Kubernetes를 쓰고 싶어도 못 씀
    1 공유 vCPU와 2GB RAM짜리 월 $10 VPS에서 Kubernetes는 너무 무거움. Deployment 대신 SSH로 docker compose up/down을 수동 실행하고, Ingress 대신 Traefik의 컨테이너 탐색 기능에 기대며, CronJobs를 못 써서 crontab을 멱등적으로 관리하는 작은 스크립트까지 직접 만들었음
    정말 원하는 건 저렴한 VPS에서도 잘 도는 Kubernetes 호환 API를 제공하는 가벼운 대안임. 엔터프라이즈급 컨테이너 오케스트레이션과 취미용 저가 호스팅 사이의 간극이 여전히 너무 큼

    • 필요한 Kube API 범위에 따라 Podman이 그 역할을 할 수 있음. Kubernetes 매니페스트에서 컨테이너와 파드를 생성할 수 있어서, Kubernetes 매니페스트를 쓰는 docker compose처럼 동작함
      글에서 설명한 방식처럼 systemd 유닛과도 같이 쓸 수 있음. Podman은 Docker API도 대부분 또는 전부 지원하므로 docker compose도 동작하고, SSH를 통해 원격 소켓에 연결해 작업할 수도 있음
      https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
      https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
    • k0sk3s를 봤는지 궁금함. 작은 규모에서 이걸 잘 쓰는 사례가 꽤 많음: https://news.ycombinator.com/item?id=43593269
    • Oracle 홍보처럼 들리긴 싫지만, Oracle Cloud Free Tier가 압도적으로 관대함. 작은 k8s 클러스터를 포함해 꽤 많은 걸 돌릴 수 있고, k8s 제어부 서비스도 무료임
      무료로 ARM64 코어 4개와 RAM 24GB를 주며, 원하는 방식에 따라 1~4개 노드로 나눌 수 있음
      https://www.oracle.com/cloud/free/
    • 옛날 방식대로 Ansible 같은 걸 쓰면 됨. 전용 서버 몇 대를 Ansible로 완전히 관리하는데, 일종의 강화판 docker compose처럼 쓸 수 있음
      Traefik과 라벨을 써서 리버스 프록시와 TLS 인증서를 일반화하고, Authelia를 간단한 인증 제공자로 붙이면 됨. GitHub에 예제 프로젝트도 많고, 주말 정도 설정하면 꽤 관리하기 쉬운 시스템이 됨
    • Kubernetes를 쓰는 비용이 너무 높다고 이미 말했으니, 어떤 축으로 효율을 재느냐에 따라 직접 만든 해법이 오히려 더 효율적일 수도 있음
  • systemd는 욕을 많이 먹지만 정말 많은 문제를 해결해 주므로 쉽게 무시하면 안 됨. 배포판에 기본으로 들어오기 시작했을 때 사람들이 바뀌어야 해서 싫어했던 면이 큼
    컨테이너, machinectl, 더 강력한 chroot인 nspawn, 완전 가상화가 필요할 때 쓰는 vmspawn, 머신을 내려받고 가져오고 내보내는 importctl, 홈 디렉터리 암호화와 권한 제어를 쉽게 해주는 homed/homectl 등이 있음
    fstab 대신 마운트를 유닛으로 다루고, 부팅 순서와 서비스 시작·중지를 제어하며, cron보다 강력한 타이머도 제공함. 예를 들어 머신이 꺼져 있어 실행 못 한 작업을 알거나, 부팅 후 특정 조건에서 지연 실행하는 식이 가능함
    서비스 유닛은 작업을 세밀하게 통제하고 권한을 제한할 수 있으며, systemctl edit으로 원본 설정을 건드리지 않고 override 설정을 만들 수 있음. 처음 배우기는 조금 귀찮지만, 복잡한 일을 하려면 문서를 전혀 안 봐도 되는 도구는 어차피 없음

    • systemd가 초기에 몇 년, 어쩌면 10년 가까이 욕을 먹은 건 프로젝트 자체가 나빠서가 아니었음. 오히려 여러 문제에도 불구하고 성공할 만큼 뛰어났음
      문제는 관리자의 태도였음. 잘 동작하던 것들을 아무렇지 않게 깨뜨리면서 적절한 수정책을 제공하지 않는 식이었음. systemd 때문에 고통을 못 느꼈다면 늦게 합류했거나, 본인의 필요가 핵심 관리자 필요와 우연히 겹쳤던 것일 수 있음
    • systemd에서 마음에 안 드는 유일한 점은 셀 수 없을 만큼 큰 코드베이스에서 나온 바이너리가 PID 1 역할을 맡고, 업그레이드 때 자기 자신을 제자리에서 exec하려고 더 복잡한 동작을 한다는 것임
      PID 1이 해야 할 일을 100% 정확히 하고 그 외에는 아무것도 안 하는 프로그램은 훨씬 작게 가능함. 여기서 systemd를 띄우면, systemd에 뭔가 문제가 생겨도 즉시 커널 패닉으로 이어지지 않음
      출처: https://ewontfix.com/14/
    • cron을 잊으라는 건 납득하기 어려움. 50년 동안 잘 동작했는데, 갑자기 아주 잘못된 것이 되어 당연히 systemd로 대체되어야 한다는 식임
    • fstab을 잊고 systemd 마운트를 쓰면, 자동 마운트 규칙이 복잡하고 문서와 1:1로 맞춰도 가끔 그냥 동작하지 않아서 파일시스템이 제때 마운트되지 않을 수 있음
    • systemd는 현대적인 데스크톱이나 서버 Linux, 또는 그와 비슷한 용도라면 훌륭함. 하지만 프로젝트가 상정한 방식에서 벗어난 걸 하려 하면 조롱과 저항을 만나게 됨. musl 팀에 물어보면 됨
      배포판이나 업스트림 입장에서는 삶을 아주 쉽게 만들어 주지만, 그 대가로 시스템 최하위 계층에 점점 커지는 복잡성을 추가함. 관점에 따라 journalctl, timedatectl, dbus 의존 또는 대체 같은 것들이 유닉스 철학에 맞지 않는다고 볼 수 있음
      단지 프로세스들을 조율하고 올바른 순서로 실행하며 자동 활성화를 보장하려는 목적이라면, k8s나 Docker보다 적절한 수준의 도구라고 봄
  • 홈랩을 한동안 podman-systemd, 즉 Quadlet으로 운영해 왔고, 새로운 k8s 변종을 살펴볼 때마다 추가 번거로움을 감수할 가치가 없었음. 오래된 Ansible 플레이북에서 이미지를 미리 받아 두고 유닛 파일을 제 위치에 넣는 식으로 충분함
    Voron 3D 프린터 스택 전체도 podman-systemd로 돌려서 모든 구성요소를 한 번에 업데이트하고 롤백할 수 있게 했음. 다만 이제는 mkosisystemd-sysupdate로 전체 디스크 이미지를 한 번에 업데이트·롤백하는 방식도 검토 중임
    주요 문제는 사람들이 대체로 docker-compose 파일만 배포해서 systemd 유닛으로 변환해야 한다는 점, 그리고 일부 Docker 이미지가 사용자·권한 설정에서 Podman에는 불필요한 복잡성을 갖고 있다는 점임. 특히 컨테이너가 root 실행을 거부하거나 다른 사용자로 전환하면 귀찮은 userns ID 매핑이 필요할 때가 있음
    그래도 전체적으로 어떤 k8s 또는 k8s 변종 설정보다 훨씬 덜 복잡함. systemd와 journald에 모두 통합되어 두 군데로 나뉘지 않는 점도 좋음

    • 비슷한 접근을 몇 년째 쓰고 있음: https://github.com/Mati365/hetzner-podman-bunjs-deploy. Podman과 systemd 기반이고, 그동안 아무것도 깨지지 않았음
      유닛만 넣으면 되는 방식이라 매우 안정적이고 단순함
    • compose 파일을 Quadlet 파일로 변환할 때 podlet을 쓸 수 있음: https://github.com/containers/podlet
    • 결국 단일 노드, 또는 독립적인 노드 묶음인 것 아닌가 싶음. Podman/systemd/Quadlet은 k8s 노드가 컨테이너를 실행하는 구현 세부사항, 말하자면 CRI 비슷한 것일 수는 있음
      하지만 k8s가 제공하는 여러 노드 위의 오케스트레이션·스케줄링 추상화를 대체하지는 않음. “Podman-systemd 파일을 실행할 수 있는 머신들이 여기 있고, 실행하고 싶은 명세가 여기 있으니 알아서 배치해 달라”는 부분이 빠져 있음
    • 비슷한 경험임. 작업 흐름은 podman run 명령으로 컨테이너를 띄워 보고, 제대로 도는지 확인한 뒤, podlet으로 기본 컨테이너 파일을 만들고, 볼륨과 네트워크를 다른 Quadlet 파일로 분리하는 식으로 컨테이너 파일을 수정하면 끝임
      podman-compose 프로젝트도 여전히 활발히 유지되는 듯하고 docker-compose의 좋은 대안이 될 수 있음. 하지만 Podman과 systemd의 연동이 워낙 만족스러움
  • 이걸 더 단순화하는 다음 단계는 systemd 안에서 Quadlet으로 컨테이너를 관리하는 것임. 자세한 내용은 https://www.redhat.com/en/blog/quadlet-podman에 있음

    • Quadlet이 바로 그 길임. 컨테이너를 실행하는 방식으로 정말 좋고, 설정해 두면 잊어도 되는 느낌임. Fedora나 Rocky Linux에서는 적어도 추가 패키지를 설치할 필요도 없음
    • 글 끝부분에서 다뤄졌지만, 작성자는 아직 살펴보지 않은 상태였음. Podman의 systemd 통합이 이미 deprecated처럼 보이고 이제 “Quadlet” 파일로 컨테이너를 정의하자는 얘기가 나온다니, 나중에 배워야 할 거리로 남겨 둔 셈임
    • 댓글을 보러 온 이유가 누군가 Quadlet을 언급했는지 확인하려는 것이었음. 지난주 홈 서버를 docker compose에서 rootless Podman Quadlet으로 옮겼고, 전환은 힘들었지만 결과에는 매우 만족함
    • 홈랩을 Quadlet으로 매끄럽게 전환하는 데 이 글도 큰 도움이 됨: https://news.ycombinator.com/item?id=43456934
  • skate를 만들었음: https://github.com/skateco/skate. 기본적으로 이런 목적이지만 여러 호스트를 지원하고 k8s 매니페스트도 지원함. 내부적으로는 Podman과 systemd를 씀

    • 이 접근이 아주 마음에 듦. 여러 호스트에 걸친 Docker/Podman을 단순하게 실행하는 방법이 없다는 게 정말 답답함. Docker Swarm은 안타깝게도 2019년 이후 사실상 방치된 상태임
      다만 k8s는 API와 사용자 경험이 최악이라고 봄. Docker Compose 명세가 훨씬 사용자 친화적이라, 현재 여러 호스트용 docker-compose를 실험 중임: https://github.com/psviderski/uncloud
  • 다시 deb 패키지로 묶어 EC2 인스턴스에서 systemd로 직접 실행하는 방식으로 돌아갔고, 컨테이너는 더 이상 쓰지 않음. 인스턴스는 ALB가 붙은 Auto Scaling Group에 넣고, 부팅 시 간단한 ansible-pull이 deb를 설치함
    꽤 날것 그대로의 방식이지만, 끝없는 JSON 안의 YAML 안의 HCL에 지쳤음. 이제는 Ansible YAML 정도만 다루고 싶음

    • 이 접근에서 좋은 점은 공통 라이브러리에 버그가 있을 때 apt full-upgrade를 실행하고 실행 중인 프로세스만 재시작하면 보호된다는 것임
      뭔가를 다시 빌드하거나, 직접 만들었을 수도 있고 아닐 수도 있는 컨테이너 깊숙한 곳에 묻힌 라이브러리를 어떻게 업데이트할지 찾아볼 필요가 없음
    • 아주 단순한 애플리케이션에서 같은 길을 택했음. systemd가 의외로 즐거웠고, 시스템이 할당한 사용자 계정으로 서비스를 최소 권한으로 실행하는 점이 꽤 좋았음
      cgroup 지원 덕분에 하나의 VPS에서 여러 서비스를 돌리기도 좋음
    • “대규모 YAML 관리”라는 문제 영역에 낭비된 인간 수명을 생각하면 아찔함
  • 글이 1년 넘은 것이라, 지금은 systemd에 불변 워크플로를 위한 공식 지원 OS 배포판인 ParticleOS까지 있음
    https://github.com/systemd/particleos
    https://news.ycombinator.com/item?id=43649088

    • 다음 논리적 단계는 Linux 커널을 systemd-kernel로 대체하는 것일 테고, 그러면 완성임
  • 읽어 보니 이 모든 걸 docker compose 명령과 인증서를 자동으로 받아 주는 Caddy 같은 것으로 대체할 수 있어 보임
    compose.yaml만 있으면 기본적으로 docker compose up -d --pull always 한 줄이면 됨. CI 설정도 scp compose.yaml user@remote-host:~/ 뒤에 ssh user@remote-host 'docker compose up -d --pull always'면 충분함
    장점은 단순하고 개발 머신에서도 동작한다는 점임. 물론 부가 목표가 재미있는 걸 해 보고 배우는 것이라면 Quadlet, k8s, systemd도 좋은 선택임

    • 한 번만 docker context create --docker 'host=ssh://user@remote-host' remote-host를 실행하면 됨
      그다음에는 docker -c remote-host compose -f compose.yaml up -d --pull always를 쓰면 파일을 복사할 필요가 없음. 또 ~/.ssh/config에 사용자 정보를 설정해 두면 SSH 호출에서 user@를 안 써도 되어 팀에서 문서나 명령을 복사해 쓰기 편함
    • 형제 댓글 방식대로 하거나 DOCKER_HOST 환경 변수를 설정하면 됨. 다만 compose 파일 보간에는 로컬 환경 변수가 사용되니 주의해야 함
  • 단일 서버에 배포하는 일이 이렇게 복잡하면 안 된다고 생각해서 원하는 방식대로 배포하는 도구를 만들었음: https://harbormaster.readthedocs.io/
    Harbormaster는 YAML 파일로 저장소를 찾고, 주기적으로 클론·업데이트한 뒤, 그 안의 Docker Compose 파일을 실행함. 모든 상태도 단일 디렉터리에 보관하므로 백업이 쉬움
    단일 서버만 필요하다면 지금까지 본 컨테이너 오케스트레이션 도구 중 가장 쉽고 좋음. 전체 설정이 저장소에 선언되고, 모든 상태가 한 디렉터리에 있고, 모든 것이 그냥 Compose 파일이라는 점이 마음에 듦

  • 여기 댓글들을 읽다 보니 나이가 든 느낌임. 이제 아무도 ssh와 nginx만 쓰지 않는 건가 싶음
    한 박스에 전부 욱여넣고, 그 박스를 공격적으로 백업하면 끝임. 집에서 쓰는 용도에 마이크로서비스 관리까지는 정말 필요 없음

    • nginx와 커스텀 서비스 몇 개만 쓰고 있지만, 요구사항이 아주 작아서 가능함. 조금만 복잡해지거나 여러 노드를 띄워 중복성이 필요해지면 컨테이너가 엄청나게 말이 되기 시작함