4.2 Zenoh 라우터(Router) 기본 실행 및 관리
앞선 4.1절에서 Zenoh(제노) 네트워크를 떠받치는 세 기둥(피어, 클라이언트, 라우터)의 생태학적 지위를 확인했다. 이제 추상적인 개념에서 벗어나, 데이터 고속도로의 핵심 교차로인 **Zenoh 라우터(zenohd)**를 우리의 서버 인프라 위에 굳건하게 띄워 올리고 완벽하게 통제하는 실전 운영 기법을 다룬다.
라우터는 개발자가 노트북에서 잠시 테스트용으로 켤 때와, 클라우드의 쿠버네티스(Kubernetes) 팟(Pod) 위에서 365일 무정지로 동작해야 할 때 준비해야 할 세팅이 완전히 다르다. 본 절은 개발, 스테이징, 운영(Production) 환경에 모두 대응할 수 있도록 라우터를 다루는 네 가지 필수 관리 기법을 순차적으로 전개한다.
- 즉각적인 전개 (4.2.1): 복잡한 설정 없이 CLI 터미널에서 명령어 한 줄로 라우터를 띄우고 디버깅하는 가장 원초적인 방법을 확인한다.
- 런타임 파라미터 조율 (4.2.2): 실행 시점에 포트 번호를 비틀거나 로깅 레벨을 조절하는 CLI 인자(Arguments)의 심화 활용법을 배운다.
- 무정지 인프라 구축 (4.2.3): 서버가 재부팅되어도 라우터가 좀비처럼 다시 살아나도록 Linux
systemd데몬(Daemon)으로 승격시키는 엔터프라이즈급 관리법을 짚어본다. - 컨테이너 가상화 (4.2.4): 현대 인프라의 표준인 Docker 환경에서 라우터를 격리 배포하고, 외부 트래픽을 컨테이너 내부로 부드럽게 매핑(Port Mapping)하는 네트워크 설정의 정수를 익힌다.
이 절을 완독하면, 당신은 단순히 라우터를 켤 줄 아는 개발자를 넘어, 서버 인프라 위에 라우터를 견고하게 뿌리내리게 하는 시스템 엔지니어의 시야를 갖추게 될 것이다.
1. CLI(Command Line Interface)를 통한 라우터 단일 실행
**Zenoh(제노)**의 가장 큰 매력 중 하나는 거대한 몸집의 Java 기반 브로커들과 달리, 초기 구동을 위해 수천 줄의 XML이나 복잡한 환경 변수 트리를 요구하지 않는다는 점이다. 개발 과정에서 빠르게 네트워크 중심점(Hub)이 필요하다면, 터미널(CLI) 창 하나만으로도 모든 것이 즉시 해결된다.
1.1 제로 컨피겨레이션(Zero-Configuration) 기동
3.2절에서 설치한 zenohd (Zenoh Daemon) 바이너리가 시스템 PATH에 정상적으로 등록되어 있다면, 터미널에 다음 명령어 다섯 글자를 입력하는 것만으로 라우터가 즉각 기동된다.
$ zenohd
이 짧은 명령어가 실행되는 1초 남짓한 시간 동안, 라우터 내부에서는 다음과 같은 강력한 자동화 로직이 톱니바퀴처럼 맞물려 돌아간다.
- 로컬 호스트 바인딩: 기본적으로 TCP 7447 포트와 UDP 7447 포트를 열고 클라이언트/피어 노드들의 접속(Locator)을 기다린다.
- 멀티캐스트 탐색(Discovery) 시작: 주변 서브넷(Subnet)에 자신이 라우터로 강림했음을 알리는 멀티캐스트 비콘(Beacon)을 일정한 주기로 쏘아 보내, 근처의 피어(Peer) 노드들이 스스로 찾아오게 만든다.
- Admin Space 활성화: 라우터 내부의 상태를 모니터링하고 제어할 수 있는 특수 데이터 공간(
/@/router/*)을 즉시 개방한다.
1.2 초기 기동 로그 분석
zenohd가 올라오면 콘솔에 다음과 같은 일련의 부팅 로그가 쏟아진다. 이 로그 창은 개발자에게 최고의 나침반이다.
[INFO] [zenohd] Zenoh router (version 0.10.x)
[INFO] [zenohd] Local locator: tcp/0.0.0.0:7447
[INFO] [zenohd] Multicast locator: udp/224.0.0.225:7447
...
- Local locator: 현재 라우터가 물고 있는 IP와 포트를 명시한다.
0.0.0.0은 서버의 모든 네트워크 인터페이스(NIC) 로 들어오는 요청을 다 받겠다는 열린 문장이다. - Multicast locator: 라우터가 자신의 존재를 외치고 있는 멀티캐스트의 그룹 IP 채널이다.
가장 단순한 이 CLI 단일 실행 방식은, 복잡한 로봇 코드를 짜기 전 “과연 내 PC 방화벽이 TCP 7447 포트를 열어두었는가?“를 디버깅하는 가장 신속하고 확실한 시금석이 된다. 터미널의 Ctrl + C를 누르는 즉시 라우터는 우아하게(Graceful) 종료되며 메모리에서 깨끗이 증발한다.
2. 라우터 실행 시 주요 파라미터 및 인자 활용법
zenohd를 그저 맨눈으로 켜는 것만으로는 부족하다. 백엔드 시스템에 7447 포트를 이미 다른 미들웨어(예: 다른 브로커나 레거시 서비스)가 점유하고 있거나, 화면이 시커먼 서버에서 디버깅을 위해 더 촘촘한 로그가 필요할 때가 반드시 온다. 무거운 JSON 설정 파일을 건드리지 않고도(이 부분은 4.3절로 미룬다), CLI 커맨드의 꼬리에 인자(Argument)를 붙이는 것만으로 라우터의 성질을 즉각적으로 비틀 수 있다.
2.1 리슨(Listen) 엔드포인트 수동 지정 (-l 또는 --listen)
기본 포트(7447)가 충돌 날 때 가장 자주 꺼내 쓰는 칼이다. 라우터가 클라이언트의 접속을 받아줄 특정 IP나 포트를 강제로 바인딩한다.
## 8000번 포트로 TCP 접속 대기
$ zenohd -l tcp/0.0.0.0:8000
복수의 네트워크 인터페이스(NIC)가 있는 서버라면 유용하다. 보안을 위해 오직 내부망 카드의 IP 리스닝만 열람하거나, 혹은 QUIC 프로토콜 등 다른 트랜스포트를 명시할 때도 요긴하게 쓰인다. (단, 포트를 바꾸면 주변 클라이언트들도 바뀐 포트로 연결되도록 코드를 수정해야 함을 명심하라.)
2.2 타 라우터 노드와 능동적 연결 맺기 (-m 또는 --connect)
지금 내 라우터가 혼자 노는 것이 아니라, 옆 건물 서버실에 떠 있는 다른 라우터의 수하(혹은 동료)로 편입되어 거대한 메쉬(Mesh)를 이뤄야 할 때 쓰는 옵션이다.
## 192.168.1.10 서버에 떠 있는 기둥 라우터(7447)에 TCP로 빨대 꽂기
$ zenohd -m tcp/192.168.1.10:7447
멀티캐스트 패킷이 차단된 아마존 AWS나 구글 클라우드 인프라 내부에서 라우터끼리 수동으로 네트워크 패브릭(Fabric)을 짜 맞출 때 가장 빈번하게 사용되는 생명줄과도 같은 옵션이다.
2.3 디버깅과 로깅 출력 제어 (환경 변수 RUST_LOG)
zenohd는 Rust 기반으로 작성되었으므로 RUST_LOG 환경 변수의 절대적인 지배를 받는다. 네트워크 패킷 하나하나의 유실이 의심될 때, 눈먼 장님처럼 있지 말고 로깅 레벨을 극한으로 올려 파편을 추적하라.
## 최고 수준의 추적(Trace) 모드로 라우터 기동
$ RUST_LOG=zenoh=trace zenohd
보통 error, warn, info, debug, trace 순으로 장황해진다. 치명적인 버그를 잡을 때는 debug나 trace가 필수적이나, 로그 라이팅 자체의 I/O 병목이 라우터 지연 시간(Latency)을 미세하게 늘릴 수 있으므로 운영(Production) 환경에서는 반드시 info나 warn 레벨로 내려두는 관례를 지켜야 한다.
3. 백그라운드 데몬(Daemon) 및 시스템 서비스(Systemd) 등록
터미널에서 띄운 zenohd는 개발자의 로그인 세션이 끊기거나 (SSH 접속 해제 등) 실수로 Ctrl+C를 누르는 즉시 사멸하게 된다. 산업 현장에 배치된 엣지 서버나 클라우드 VM에 라우터를 심어둘 때는, 서버 컴퓨터가 재부팅되더라도 즉각 혼자서 부활하는 좀비 프로세스, 즉 데몬(Daemon) 형태로 라우터를 승격시켜야 한다.
리눅스(Linux) 환경에서 시스템 프로세스의 생사여탈권을 쥐고 있는 핵심 지배자, systemd를 활용하여 zenohd를 무정지 불사조로 만드는 방법을 마스터한다. (참고: apt나 rpm 패키지로 설치했다면, 이 과정을 패키지 매니저가 상당 부분 자동화해주기도 한다.)
3.1 Systemd 서비스 유닛 파일(Unit File) 작성
루트 권한(/etc/systemd/system/)에 zenohd.service라는 명세서를 하나 직접 작성해 준다. 이것은 라우터가 부팅될 때 어떤 설정으로, 누구의 권한으로 띄워야 할지를 적어둔 율법서다.
[Unit]
Description=Zenoh Router Daemon
After=network.target
[Service]
## 보안을 위해 별도의 zenoh_user 등을 권장하나, 여기선 root(또는 일반 구동 유저) 포지션 명시
User=root
## 실행 바이너리의 절대 경로 삽입
ExecStart=/usr/bin/zenohd -c /etc/zenoh/zenoh.json
## 라우터가 예상치 못하게 뻗으면 5초 뒤 무조건 재기동
Restart=always
RestartSec=5
## 프로세스가 뱉어내는 로그는 systemd의 제어를 받음
StandardOutput=journal
StandardError=journal
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
핵심은 Restart=always 옵션이다. OOM(Out of Memory)이나 알 수 없는 치명적 커널 오류로 zenohd가 죽더라도, systemd가 멱살을 잡고 5초 안에 무조건 다시 깨워 네트워크 전면 마비를 방어한다.
3.2 데몬 활성화 및 상태 추적
파일 작성이 끝났다면, 시스템 데몬에게 새 문서가 들어왔음을 알리고, 부팅 시 자동 시작 플래그를 꽂은 뒤, 심장을 뛰게 만든다.
## 새 파일을 systemd 도메인에 인식시킴
$ sudo systemctl daemon-reload
## 부팅하자마자 무조건 켜지게 예약
$ sudo systemctl enable zenohd
## 지금 당장 라우터의 심장을 구동시킴
$ sudo systemctl start zenohd
명령어가 에러 없이 떨어졌다면 네트워크 백본 하나가 성공적으로 서버 내부 깊숙이 용접된 것이다. 동작 여부가 불안하다면 언제든 아래 명령어로 라우터의 맥박(Status)을 정확하게 짚어볼 수 있다.
$ sudo systemctl status zenohd
이제 SSH 연결을 끊고 불을 끄고 퇴근해도 좋다. systemd가 당신 대신 밤새워 트래픽 신호등을 부여잡고 있을 것이다.
4. Docker 컨테이너 환경에서의 라우터 배포와 포트 매핑
최근의 IoT 및 로보틱스 백엔드 인프라는 사실상 컨테이너(Container) 환경으로 대동단결했다. 개발자의 로컬 PC에서 정상 동작하던 라우터 설정이 클라우드 위 쿠버네티스(Kubernetes)나 Docker Swarm에 올라가는 순간 데이터가 거짓말처럼 막히는 현상은, 십중팔구 **네트워크 포트 매핑(Port Mapping)**과 **격리된 멀티캐스트(Multicast)**의 특성을 오해한 데서 비롯된다.
이 절에서는 Eclipse 재단이 제공하는 공식 eclipse/zenoh 도커 이미지를 활용하여, 가장 견고하고 이식성 높은 라우터 컨테이너를 빌드하고 네트워크 병목을 뚫어내는 방법을 해부한다.
4.1 공식 Docker 이미지 기동 파이프라인
호스트 머신에 아무런 의존성을 깔지 않고 깔끔하게 라우터만 띄우는 가장 완벽한 명령어는 다음과 같다.
$ docker run -d \
--name zenoh-router \
-p 7447:7447/tcp \
-p 7447:7447/udp \
eclipse/zenoh
-d: 백그라운드 데몬(Detached) 모드로 실행하여 터미널을 탈취당하지 않는다.-p 7447:7447/tcp -p 7447:7447/udp: 호스트 OS의 7447 포트로 들어오는 TCP/UDP 트래픽을 컨테이너 내부의zenohd로 매핑한다. UDP 포트를 까먹으면 Peer 간의 동적 탐색이 불가능해진다.
4.2 Docker 네트워크 모드의 함정: 호스트 모드의 남용
위의 기본 포트 매핑(-p)은 Docker의 기본 브릿지(Bridge) 네트워크를 탄다. 하지만 멀티캐스트 비콘을 쏘아 주변 센서 기기들을 자동으로 찾아야 하는 에지 게이트웨이(Edge Gateway) 환경에서는 브릿지 네트워크가 멀티캐스트 트래픽을 철저히 차단(Drop)해 버리는 치명적 문제가 발생한다.
이럴 때 고민 없이 사용할 수 있는 비기가 바로 --network host 모드다.
$ docker run -d \
--name zenoh-router-host \
--network host \
eclipse/zenoh
컨테이너가 격리된 네트워크 스택을 버리고 물리적 커널 네트워크 인터페이스를 그대로 차용한다. 라우터가 멀티캐스트를 발송하면 호스트 OS의 랜카드를 통해 외부 공장 망으로 패킷이 직행하므로 탐색(Discovery) 문제가 단번에 해결된다. (단, 로컬 포트를 독점하므로 포트 충돌에 주의해야 한다.)
4.3 커스텀 설정 파일 융합 볼륨 마운트(Volume Mount)
운영 환경에서는 라우터가 기본 세팅만으로 돌 리가 없다. 엄청난 길이의 zenoh.json 파일을 컨테이너 내부에 주입해야 한다면 호스트의 설정 파일을 도커 컨테이너로 매핑(Mount)하여 넘겨주는 방식이 정석이다.
$ docker run -d \
--name zenoh-router-custom \
-v /opt/zenoh_config:/etc/zenoh \
-p 7447:7447 \
eclipse/zenoh -c /etc/zenoh/my_router.json
-v 옵션을 통해 호스트의 /opt/zenoh_config 디렉터리가 컨테이너 내부의 /etc/zenoh로 거울처럼 복제된다. 마지막 인자로 -c 플래그를 넘겨 이미지 부팅 시 내가 주입한 커스텀 JSON 명세서를 읽고 기동 하도록 지시한다. 여기까지 마스터했다면 클라우드 위 데이터 신경망의 핵심 퍼즐을 모두 장악한 것이다.