# Nitro: 작고 유연한 init 시스템 및 프로세스 슈퍼바이저

> Clean Markdown view of GeekNews topic #22691. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=22691](https://news.hada.io/topic?id=22691)
- GeekNews Markdown: [https://news.hada.io/topic/22691.md](https://news.hada.io/topic/22691.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-08-24T10:01:45+09:00
- Updated: 2025-08-24T10:01:45+09:00
- Original source: [git.vuxu.org](https://git.vuxu.org/nitro/about/)
- Points: 2
- Comments: 1

## Topic Body

- **Nitro**는 임베디드, 서버, 데스크톱, 컨테이너에 모두 적용 가능한 **초소형 프로세스 슈퍼바이저 및 init 시스템**임
- **시스템 상태를 RAM에만 저장**하여 읽기 전용 파일 시스템에서도 무리 없이 동작하며, 빠르고 효율적인 **이벤트 기반 설계**를 제공함
- **구성 방식은 단순한 스크립트 디렉터리 구조**로, 복잡한 설정 파일이나 부가적인 빌드 과정 없이 서비스 관리가 가능함
- **Parmetrized 서비스, 견고한 재시작**, 개별 서비스별 **신뢰성 높은 로깅** 기능 등 **컨테이너, 임베디드 환경에 최적화된 기능**을 지원함
- **nitroctl 툴을 통한 원격 제어, 신호 기반 동작 제어** 등 높은 **유연성과 통제력**을 보장함

---

### 개요

**Nitro**는 Linux에서 pid 1로도 사용할 수 있는 **초소형 프로세스 슈퍼바이저**임

주요 적용 분야는 아래와 같음
- 임베디드, 데스크톱, 서버 등 다양한 용도의 Linux 머신용 init
- Linux **initramfs**의 init
- Docker/Podman/LXC/Kubernetes 등 **컨테이너 환경의 init**
- POSIX 시스템에서 권한 없이 동작하는 슈퍼비전 데몬

구성은 디렉터리 기반 스크립트 구조를 사용하며, 기본 위치는 `/etc/nitro`임

### 요구사항

- 커널의 **Unix 소켓** 지원 필요
- `tmpfs` 또는 **쓰기 가능한 `/run` 디렉터리** 필요

### 다른 시스템 대비 장점

- 모든 **상태 정보는 RAM**에만 유지되어 읽기 전용 루트 파일 시스템에서도 별도 트릭 없이 동작함
- **이벤트 기반, 폴링 없는 동작 방식**으로 효율성 제공
- 런타임 중 **메모리 동적 할당이 없음**
- 파일 디스크립터가 무한정 소모되지 않음
- 하나의 **self-contained 바이너리(옵션으로 제어 바이너리 추가)** 만 필요함
- 설정 파일 변환 및 컴파일 필요 없음, 서비스는 **스크립트가 들어 있는 단순 디렉터리**임
- **서비스 재시작 및 로깅 체인** 지원
- 시스템 시계가 정확하지 않아도 정상 동작
- FreeBSD에서 `/etc/ttys`를 통해 실행 가능
- **musl libc** 사용 시 초소형 static 바이너리 제작 가능

### 서비스 관리

- 각 서비스 디렉터리(기본 `/etc/nitro` 내부)는 아래 파일을 포함할 수 있음
  - `setup`: 서비스 시작 전 실행되는 (옵션) 스크립트, 정상 종료(0) 시에만 서비스 시작 가능
  - `run`: 서비스 동작 스크립트, 종료되지 않는 한 서비스가 살아있는 상태로 인식됨, 미구현 시 one-shot 서비스로 처리됨
  - `finish`: `run` 종료 후 실행되는 (옵션) 스크립트, 종료 상태 및 시그널 값을 인자로 전달
  - `log`: 다른 서비스 디렉터리를 가리키는 심볼릭 링크, run 출력 내용을 해당 서비스의 입력으로 파이프 연결(로깅 체인 활용 가능)
  - `down`: 이 파일이 존재하면 nitro가 기본적으로 이 서비스를 올리지 않음
  - 디렉터리명이 '@'로 끝나면 무시되어 파라미터 서비스로 활용 가능
  - 서비스명은 64글자 미만, `/`, `,`, 줄바꿈 문자를 포함할 수 없음

- runit의 `chpst` 유틸리티가 `run` 스크립트 작성 시 유용함

### 특수 서비스

- `LOG`: log 링크가 없는 모든 서비스의 로그 기록용 디폴트 서비스
- `SYS`: `SYS/setup`은 모든 서비스 구동 전 실행, 순서 있는 서비스 구동 구현 가능
  - `SYS/finish`: 전체 종료 단계 진입 전 실행
  - `SYS/final`: 모든 프로세스 종료 후 실행
  - `SYS/fatal`: 치명적 에러 발생 시 종료 대신 실행(있을 경우)
  - `SYS/reincarnate`: shutdown 대신 실행되어 예컨대 initramfs 재구현 등에 활용 가능

### 파라미터라이즈드 서비스

- '@'로 끝나는 서비스 디렉터리는 nitro가 무시하지만, 심볼릭 링크 또는 `nitroctl` 명령을 통해 직접 지정 가능
- '@' 뒤 파라미터가 첫 번째 인자로 각 스크립트에 전달됨
  - 예: `agetty@/run`와 `agetty@tty1` 심볼릭 링크가 있으면 `agetty@/run tty1` 실행
  - `nitroctl up agetty@tty2` 입력 시 `agetty@/run tty2` 실행 가능(디렉터리 존재 여부 무관)

### 동작 모드

- 전체 라이프사이클은 **부팅, 서비스 실행(슈퍼비전), 종료** 세 단계로 구성
  - 부팅: 특수 서비스 `SYS`가 존재하면 `setup`부터 실행, 이후 모든 non-down 서비스 실행
  - 서비스가 종료되면 재시작, 단 최근 재시작이 빠르면 2초 대기
  - `nitroctl Reboot` 또는 `Shutdown`으로 종료 신호 전달 가능
    - 이때 `SYS/finish` → 모든 서비스 SIGTERM(최대 7초 대기) → SIGKILL → `SYS/final` → 종료 시퀀스
  - 컨테이너나 권한 없는 슈퍼바이저용일 경우 프로세스만 종료

### nitroctl을 이용한 제어

- **nitroctl** CLI 도구로 멀리서 nitro를 제어할 수 있음

명령어 예시:
  - list: 서비스 목록, 상태, PID, uptime, 마지막 종료 상태 출력
  - up/down/start/stop/restart: 서비스 시작·중지·재시작 등 제어
  - 신호 전송: p(SIGSTOP), c(SIGCONT), h(SIGHUP), a(SIGALRM), i(SIGINT), q(SIGQUIT), 1(SIGUSR1), 2(SIGUSR2), t(SIGTERM), k(SIGKILL)
  - pidof: 지정 서비스의 PID 출력
  - rescan: 서비스 디렉터리 재읽기, 추가·제거 서비스 반영
  - Shutdown/Reboot: 전체 시스템 종료·재부팅

### 신호를 통한 제어

- nitro 프로세스에 시그널 직접 전송으로 컨트롤 가능
  - SIGHUP: 서비스 재스캔(rescan)
  - SIGINT: 재부팅
  - SIGTERM: 종료(nitro가 pid 1이 아니면)

### Linux에서 init으로서의 nitro

- Nitro는 자체 포함형 바이너리로 Linux pid 1로 직접 부팅 가능
- `/dev`, `/run`을 필요 시 마운트하며, 기타 동작은 `SYS/setup`에서 처리
- Ctrl-Alt-Del 이벤트에 질서 정연한 재부팅 트리거

### Docker 컨테이너에서 init으로서 Nitro 사용

- Nitro는 정적으로 빌드되어 컨테이너에 간단히 포함 가능
- `/run`이 컨테이너에 존재해야 기본 소켓 경로 사용 가능
- 컨트롤 소켓을 바인드 마운트 처리하면 외부에서 nitroctl로 원격 제어 가능

### FreeBSD에서의 Nitro

- `/etc/ttys`에 다음 줄 추가로 FreeBSD init에서 nitro를 슈퍼바이즈 가능
  ```
  /etc/nitro "/usr/local/sbin/nitro" "" on
  ```

### 저자

- Leah Neukirchen <leah@vuxu.org>

### 감사

- daemontools, freedt, runit, perp, s6 등 **기존 프로세스 슈퍼비전 시스템**들의 상세 분석 위에서 개발됨

### 라이선스

- 0BSD 라이선스(자세한 내용은 LICENSE 파일 참조)

## Comments



### Comment 42837

- Author: neo
- Created: 2025-08-24T10:01:45+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=44988530) 
- runit와의 비교를 보고 싶음. runit는 극도로 미니멀하면서도 거의 완전한 init 시스템임. 컨트롤 디렉터리, 선언적(declarative)이 아닌 의존성, 비슷한 스크립트 구성, 로깅 접근 방식 등 비슷한 점이 많음. 설명 페이지에도 runit 이야기가 잠깐 나오며 chpst 유틸을 함께 쓰는 것을 추천함. 차별점으로는 하나의 서비스 디렉터리로 여러 유사 프로세스(예: agetty)를 파라미터화하여 관리하는 구조가 좋다고 생각함. reboot나 shutdown을 단일 바이너리(nitroctl)로 바로 실행할 수 있음. 반면 runit는 여러 개의 바이너리 구조임

  - 지난 해 runit로 프로세스를 관리하던 마지막 서버들을 은퇴시키면서 아쉬움이 컸음. 약 15년 전에 처음 runit 서비스를 직접 짜면서 이게 리눅스에서 서비스 관리하는 표준 방식이라 믿었음. 이후 5년간 리눅스를 떠나 있다 돌아오니 systemd가 기본이 되어 있었고, 나쁜 평을 여러 번 들었지만 점차 왜곡된 반감이 많다는 걸 알게 되었음. 현재는 파충류 vivarium에서 Pi Zero로 카메라와 온도 데이터 스트리밍 서비스를 돌리고 있는데 systemd로 세팅하는 것이 굉장히 쉬웠음. OpenSuse 데스크톱이나 업무용 노트북에서도 systemd로 다양한 서비스를 간단하게 운용할 수 있었음. ‘표준이 있다는 건 오히려 좋은 일’이란 생각이 듦

  - runit와 nitro의 적절한 미니멀 비교가 2024년에 발표된 Leah Neukirchen의 발표 슬라이드(PDF)에 있음  
    [https://leahneukirchen.org/talks/#nitroyetanotherinitsy](https://leahneukirchen.org/talks/#nitroyetanotherinitsy)

  - Leah Neukirchen은 Void Linux 커뮤니티에서 활발히 활동하는 분임. 이 프로젝트가 Void와 밀접히 연관될 것으로 예상함. 좀 더 공식적으로 Void에서 nitro를 사용하는 방법에 대한 글을 써줬으면 좋겠음

  - “선언적(declarative) 의존성이 없다”는 점이 장점이라는 것인지 궁금함. systemd를 init로 비판하는 의견은 많이 들어봤지만 선언적 설계 자체를 비판하는 경우는 드물었음. 이유가 있는지 자세히 듣고 싶음

  - Void Linux에서 runit를 접하게 되어 init 시스템으로 잘 쓰고 있지만, UI와 문서화가 부족한 점이 아쉬웠음. 특히 로깅 설정이 정말 어려웠음. 비슷하게 단순하지만 더 합리적 기본값, 더 직관적인 UI, 더 나은 문서를 가진 대안을 써보고 싶음

- 컨테이너에서 init 시스템을 돌리자는 이야기를 볼 때마다 항상 고민임. 실제로 필요에 의해 설계하는 경우도 있지만, 오히려 너무 복잡하게 만드는 경우가 자주 보였음 (특히 Kubernetes, 클라우드 환경에서 실제로 분리 설계를 더 제대로 했어야 함). ‘어차피 다들 이렇게 쓰니까’라는 게 현상인 것 같기도 한데, 굳이 ‘더 잘 만들겠다’면서 문제가 퍼지는 게 나은지, 아니면 기존 솔루션으로 격하게 실패하도록 내버려두는 게 나은지 항상 애매함

  - 어플리케이션 컨테이너는 유닉스 철학 ‘한 가지 일만 잘하라’를 따라야 한다고 생각함. 그런데 컨테이너에서 어떤 이유로든 fork를 한다면, PID 1에 진짜 init가 있어야 한다고 봄

  - 로보틱스 분야에서 겪은 바로는, 많은 컨테이너가 본래 베어메탈에서 돌던 복잡한 시스템이 컨테이너로 옮겨온 경우임. 프로세스간에 비구조화된 RPC가 많아 굳이 여러 개의 별도 컨테이너로 잘게 쪼갤 메리트가 없음. monolithic 앱 컨테이너 내부에서 여러 프로세스를 띄우기엔 supervisor, runit, systemd, tmux까지 각양각색 옵션들이 통용됨

  - Fly.io, Render, Google Cloud Run처럼 컨테이너 단위로 과금하는 호스팅을 사용한 적 있음. 가격 때문에 한 컨테이너에 여러 프로세스를 띄워야 할 때가 종종 있음

- NixOS의 새로운 기능인 [modular-services](https://nixos.org/manual/nixos/unstable/#modular-services)가 Nixpkgs에 포함되었음. 새로운 init 시스템 혹은 새 커널로 NixOS 포팅이 훨씬 쉬워질 예정이라, 지금이 nitro 같은 실험을 해보기 좋은 시기라고 생각함

- Chimera Linux에서 쓰고 있는 dinit과 nitro를 비교해보고 싶음. readme를 빠르게 훑어보니 서비스 의존성 관리가 아직 안되는 것 같아 보임  
  [dinit: https://github.com/davmac314/dinit](https://github.com/davmac314/dinit)

  - Nitro는 선언적으로 서비스 의존성을 다루지 않음. 명령 하나로 서비스 간의 의존 그래프를 예쁘게 보는 게 불가능함. 하지만 setup 스크립트에서 필요한 서비스를 명시해두면 해당 서비스가 떠있는지 확인하고 자동으로 기다렸다 리트라이 함. 의존성 그래프를 보려면 grep 같은 걸로 스크립트를 직접 짜는 수밖에 없음. 반면 서비스가 죽을 때 연쇄적으로 dependent 서비스도 제대로 내리는 걸 깜빡하기 쉬운데, nitro 자체로는 이런 걸 탐지할 편리한 방법이 없음

  - Artix Linux에서 dinit을 써봤는데 정말 가볍고 인상적이었음  
    [Artix FAQ: https://artixlinux.org/faq.php](https://artixlinux.org/faq.php)

- 이런 저수준 프로젝트들을 보면 정말 흥미로움. systemd가 전통적인 SysV·POSIX 틀을 넘어서 리눅스 커널 특화 기능을 잘 활용한 점이 좋았음. 하지만 그게 끝이 아니길 바라고, 계속해서 새로운 아이디어와 혁신이 나와주었으면 함. 최근 직접 제조용 자동화에서 UEFI 펌웨어로부터 바로 netboot되는 Linux 커널에 Go로 직접 짠 단일 init 바이너리만 내장한 셋업을 구현해봄. 직접 가져온 코드와 고수준 언어만으로 OS 환경을 다 제어하니 각종 서브프로세스와 수많은 텍스트 설정파일을 관리할 필요 없다는 점이 정말 자유로웠음

- 약 13년 전에 C로 직접 init 시스템을 구축한 경험이 있음. 예정보다 훨씬 많은 노력이 필요했고, GUI와 백엔드를 성능 낮은 하드웨어에서 빠르게 부팅시키는 데 사용함. 재미있는 프로그래밍 연습이었으나 이미 비슷한 솔루션이 존재했을지도 모르겠다는 자각이 나중에 들었음. 동료가 같은 회사에서 또 다른 init을 만드는 바람에 내 첫 버전은 거의 libc 외에 의존성 없이 가벼웠지만, 동료의 버전은 libevent 기반으로 더 고급 기능이 많았음

- AWS Nitro와 이름과 기능이 겹친다는 점이 신경 쓰임  
  [https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-nitro-system-journey.html](https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-nitro-system-journey.html)

  - 이름만 겹칠 뿐, init 시스템과 하이퍼바이저는 근본적으로 완전히 다름

  - 문제 생길 일은 거의 없다고 봄. 하나는 누구나 쓸 수 있는 init 시스템이고, AWS Nitro는 기업 내부에서만 쓰는 KVM 포크임

- s6와 비교해 nitro가 어떤지 궁금함. 최근 도커 컨테이너에 s6로 init 시스템을 구성해봤는데, s6-overlay로 많은 파일을 직접 만들어야 했고 생각보다 직관적이지 않았음

  - s6는 훨씬 더 복잡하고 풍부함. nitro나 runit가 훨씬 더 단순한 대안임.  
    [tini도 체크해볼 만함: https://github.com/krallin/tini](https://github.com/krallin/tini)

- Distrust에서 rust로 500라인 이하의 초간단 init 시스템을 직접 작성해서, 보안 필수 enclave 환경에서 몇몇 클라이언트가 실서비스로 사용 중임. rust 표준 라이브러리만 써서 감사를 매우 쉽게 했음  
  [https://git.distrust.co/public/nit](https://git.distrust.co/public/nit)

  - 깔끔해 보이지만(nit보다 33% 더 큼), readme에는 빌드 방법만 나와 있고, 실제 인터페이스나 작동 방식은 설명이 없음

- 의존성 지정 불가, 유저/그룹 설정 없음, 순서 수동 지정 필요, 병렬 서비스 실행 없음, 리소스 관리 없음. 이런 게 빠진 시스템을 init 시스템이라고 부르지 않았으면 함. 그냥 베어본 process supervisor임

  - 실제로 이 모든 기능을 잘 해냄(심지어 systemd보다 더 나았다는 경험임). 나는 nitro 대신 오랜 기간 daemontools(그리고 nitro는 그 계승)만을 써왔음. 사용법이 믿을 수 없이 쉽고 안정적이고, 이해하기 쉬움. 의존성 문제에 대해서도 ‘요건 각자 알아서, 대신 간단·저렴·신뢰성 좋은 툴을 제공합니다’라는 djb/daemontools 스타일이 훨씬 실무적임
