제14부 시스템 설계·품질·운영
14.8 배포 — systemd·Docker·OTA
14.8.1 이 장에서 배우는 것 / 선수 지식
개발 PC에서 ros2 launch로 실행되던 시스템을 로봇 위에서, 사람 없이, 재부팅해도, 몇 달 동안 실행되게 만드는 것이 배포다. 그 사이에는 생각보다 많은 문제가 있다.
전형적인 증상들이 이 문제다. "전원을 켜면 기동되지 않는다", "SSH를 끊으면 종료된다", "로그가 디스크를 채웠다", "업데이트했더니 안 돌아온다", "어느 버전이 실행되고 있는지 모른다".
배우는 것:
- 배포 형태 — 무엇을 어떻게 배포하는가.
- systemd — 서비스로 만들기.
- 환경 문제 — 소싱·변수·권한.
- 컨테이너 — 이점과 대가.
- 이미지·프로비저닝 — 로봇을 준비하는 절차.
- OTA 갱신 — 원격 업데이트와 롤백.
- 버전 관리 — 무엇이 실행되고 있는가.
- 종료 코드와
Restart의 간극(14.8.13) — systemd가 감지하는 실패와 검출하지 못하는 실패.
선수 지식: 4.5(빌드·오버레이), 4.9(릴리스), 14.3(launch), 13.4(운영 보안), 14.2(오케스트레이션), 14.9(플릿 — 다음 장).
정직: systemd·컨테이너·OTA 도구의 설정은 배포판·제품에 따라 다르다. 다만 ROS 2 노드의 시그널 처리는 Jazzy에서 실측했고(실행 확인 — 14.8.12), 그 결과 이 장의 조언 하나를 정정했다. 특정 제품을 권장하지 않으며, 개념과 판단 기준을 다룬다. 안전 관련 시스템의 갱신 정책은 안전 요구·규제·전문가의 영역이다(13.4.6·14.10). 이 환경에서 검증하지 않았다(목차 3).
14.8.2 배포 형태
| 형태 | 장점 | 단점 |
|---|---|---|
| ① 로봇에서 빌드 | 단순·수정 즉시 | 느림·환경 차이·재현성 낮음 |
| ② 데비안 패키지 | 표준·의존성 관리 | 빌드 인프라 필요(4.7) |
| ③ 컨테이너 | 환경 격리·재현성 | 크기·하드웨어 접근 복잡 |
| ④ 시스템 이미지 | 원자적·롤백 쉬움 | 인프라·크기 |
견해: ①(로봇에서 빌드)은 개발에는 편리하지만 운영에는 부적합하다. 빌드가 실패하면 로봇이 기동되지 않고, 로봇마다 미묘하게 다른 상태가 되며, 무엇이 설치됐는지 추적이 어렵다. 개발과 운영의 배포 방식을 분리하는 것이 표준적 방법이다.
견해: ②~④ 중 무엇이 맞는지는 조직 역량과 규모에 달렸다. 로봇 몇 대면 ②로 충분하고, 환경 재현성이 중요하면 ③, 원자적 갱신과 롤백이 필요하면 ④가 유리하다. 롤백 가능성이 핵심 판단 기준이다(13.4.6).
정직: 컨테이너가 항상 정답은 아니다. 실시간 요구(12.1)·하드웨어 직접 접근·GPU 사용에서 추가 설정이 필요하고, 성능 영향도 확인이 필요하다
(확인 필요). 이점(재현성·격리)과 대가(복잡도·성능)를 자신의 요구로 저울질해야 한다.
14.8.3 systemd
"전원을 켜면 기동된다"를 만드는 표준 수단이다.
# /etc/systemd/system/robot.service (개념 — 확인 필요: 배포판별 세부)
[Unit]
Description=Robot ROS 2 stack
After=network-online.target time-sync.target
Wants=network-online.target
[Service]
Type=simple
User=robot
Group=robot
Environment=ROS_DOMAIN_ID=42
Environment=RMW_IMPLEMENTATION=rmw_fastrtps_cpp
ExecStart=/opt/robot/start_robot.sh
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=300
TimeoutStopSec=30
KillSignal=SIGINT
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
#!/bin/bash
# /opt/robot/start_robot.sh
set -e
source /opt/ros/jazzy/setup.bash # ★ 소싱이 핵심
source /opt/robot/ws/install/setup.bash
exec ros2 launch my_bringup robot.launch.py "$@"
| 설정 | 의미 |
|---|---|
After·Wants | 의존 순서(네트워크·시계) |
Restart=on-failure | 실패 시 재시작 |
StartLimit* | 무한 재시작 방지(14.2.6) |
TimeoutStopSec | 정상 종료 시간(14.2.8) |
KillSignal=SIGINT | ROS가 정리할 기회(11.2.7) |
User | 최소 권한(13.4.4) |
Environment | 환경 변수 |
함정: systemd 환경에는 셸 프로파일이 없다.
source /opt/ros/.../setup.bash를 하지 않으면ros2명령조차 없다. 래퍼 스크립트에서 명시적으로 소싱하는 것이 표준 해법이다.
정정(실행 확인, Jazzy): 이 자리에 원래 "
KillSignal이 기본값(SIGTERM)이면 노드가 정리 없이 종료될 수 있으니SIGINT로 바꾸라"고 적혀 있었다. 실측하니 그렇지 않다 —rclcpp는 SIGTERM과 SIGINT를 같은 핸들러로 처리하며, 둘 다signal_handler(SIGINT/SIGTERM)로그를 남기고 정상 종료 경로를 거친다.KillSignal을 바꿀 필요가 없다. 실측 표는 14.8.12에 있다.
함정: 다만
TimeoutStopSec은 여전히 중요하다. 시그널을 받은 뒤 정리(bag 마감·상태 저장)에 시간이 걸리는데, 기본 타임아웃 안에 못 끝내면 systemd가SIGKILL로 강제 종료한다 — 그때는 정말로 bag이 손상된다(11.2.7). 정리에 필요한 시간을 측정해서 넉넉히 설정하라.
함정:
Restart=always에 제한이 없으면 계속 종료되는 노드가 무한 재시작되며 문제를 감춘다(14.2.6).StartLimitBurst로 제한하고, 한계 초과 시 실패 상태로 두어 사람이 알아채게 한다.
견해: 시계 동기를
After에 넣는 것이 중요하다(7.7.6·13.3.3). 시계가 틀린 상태로 기동되면 인증이 실패하고 tf·기록의 시각이 엉킨다.time-sync.target을 기다리게 하는 것이 안전하다 — 이름이 맞다(89차 실행 확인, Ubuntu 24.04:/usr/lib/systemd/system/time-sync.target).time-set.target도 함께 있다 — 둘은 다르다:time-set.target은 시각이 설정된 시점,time-sync.target은 동기가 완료된 시점이다. 로봇에서는 후자를 기다려야 tf·인증의 시각이 믿을 만해진다.
분할할 것인가:
| 방식 | 특성 |
|---|---|
| 단일 서비스 = 전체 launch | 단순·전체 재시작 |
| 서비스 여러 개 | 부분 재시작·의존 관리 |
견해: 처음에는 단일 서비스로 시작하고, 부분 재시작이 필요해지면 나눠라. 서비스를 나누면 systemd 의존 관리가 복잡해지고, launch의 조율(14.2)과 역할이 겹친다. launch가 그래프를, systemd가 프로세스 생명주기를 담당하는 구분이 깔끔하다.
14.8.4 환경 문제
배포에서 가장 흔한 실패 원인이다.
| 문제 | 증상 |
|---|---|
| 소싱 누락 | 명령·패키지를 못 찾음 |
| 오버레이 순서 | 옛 버전 실행(4.5.8) |
| 환경 변수 부재 | 도메인·RMW 기본값 |
LD_LIBRARY_PATH | 라이브러리 못 찾음 |
| 권한 | 장치 접근 실패(6.1.8) |
| 홈 디렉터리 | 로그·설정 경로(1.11.3) |
| 로케일 | 파싱·출력 차이 |
# 진단: 서비스가 보는 환경 확인
systemctl show robot.service -p Environment
sudo systemd-run --uid=robot --pty /bin/bash # 같은 조건의 셸 (확인 필요)
견해: "내가 SSH로 실행하면 되는데 서비스로는 안 된다"의 원인은 거의 항상 환경이다. SSH 셸은 프로파일을 읽고 홈이 설정되지만, systemd는 그렇지 않다. 서비스와 같은 조건의 셸을 만들어 비교하면 원인이 빨리 드러난다.
함정: 장치 권한은 udev 규칙으로 해결한다(6.1.8). 서비스 사용자를
dialout·video같은 그룹에 넣거나, udev 규칙으로 권한을 부여한다. root로 실행해 해결하는 것은 피하라(13.4.4).
견해: 환경 설정을 한 파일에 모으라.
/etc/robot/env같은 파일을 만들고 systemd의EnvironmentFile로 읽으면, 로봇별 차이를 한 곳에서 관리할 수 있고 진단도 쉽다.
14.8.5 컨테이너
| 이점 | 설명 |
|---|---|
| 환경 재현성 | 개발=운영 |
| 의존성 격리 | 호스트 오염 없음 |
| 롤백 용이 | 이미지 교체 |
| 배포 표준화 | 레지스트리 |
| 대가 | 설명 |
|---|---|
| 하드웨어 접근 | 장치·권한 설정 필요 |
| 네트워크 | DDS 멀티캐스트·호스트 모드(3.3.5) |
| 이미지 크기 | 저장·전송 |
| GPU | 추가 런타임(확인 필요) |
| 실시간 | 추가 확인 필요(12.1) |
| 디버깅 | 한 겹 더 |
# ROS 2 컨테이너의 전형적 요구 (개념 — 확인 필요)
docker run --rm -it \
--network host \ # ★ DDS 디스커버리 (3.3·3.9)
--ipc host \ # ★ 공유 메모리 전송 (12.3.5)
--device /dev/ttyUSB0 \
-v /dev:/dev \
robot-image:1.2.3
함정: DDS 디스커버리가 컨테이너 네트워크에서 막히는 것이 최다 문제다(3.3·3.9.4). 다만 "컨테이너면 무조건 막힌다"는 부정확하다 — 실측하면 같은 Docker 네트워크의 컨테이너끼리는 기본 브리지로도 통한다(3.9.12). 끊기는 지점은 다른 네트워크·다른 호스트다. 그러므로
--network host를 반사적으로 켜기 전에 경계를 먼저 좁혀라(11.1.15). 정말 호스트를 넘어야 하면host모드가 가장 단순하지만 격리를 포기하는 것이므로, 격리가 필요하면 Discovery Server(3.10)를 검토한다.
함정: 공유 메모리 전송이 컨테이너 경계에서 안 될 수 있다.
--ipc host없이는 같은 호스트의 다른 컨테이너와 제로 카피가 안 되거나 성능이 떨어진다(확인 필요: 구현별). 성능을 측정해 확인하라(11.7).
견해: 컨테이너는 "환경 재현성" 하나만으로도 값을 하는 경우가 많다. "개발에서는 되는데 로봇에서는 안 된다"의 상당수가 환경 차이인데(14.8.4), 컨테이너가 그것을 없앤다. 다만 하드웨어·네트워크 설정이라는 새 문제를 준다.
견해: 컨테이너 안에서도 systemd 계층은 필요하다 — 컨테이너 자체를 systemd 서비스나 오케스트레이터가 관리한다. 컨테이너는 "무엇을 실행하는가", systemd는 "언제·어떻게 유지하는가" 로 역할이 나뉜다.
14.8.6 이미지와 프로비저닝
로봇 한 대를 처음부터 준비하는 절차다.
| 단계 | 내용 |
|---|---|
| 공통 이미지 | 모든 로봇 동일 |
| 로봇별 데이터 | ID·이름·키(13.4.5)·캘리브레이션(9.6.4) |
| 검증 | 자동 점검(13.4.8) |
| 기록 | 무엇을 언제 |
견해: "공통 이미지 + 로봇별 데이터" 분리가 규모의 핵심이다. 이미지는 하나만 관리하고, 로봇별 차이는 데이터로 주입한다. 캘리브레이션 값·시리얼 번호·인증서가 그 데이터이며, 이것을 이미지에 굽지 않는 것이 중요하다.
견해: 로봇별 데이터를 백업하라. 이미지는 다시 만들 수 있지만 캘리브레이션은 다시 측정해야 한다(9.6.4). 저장장치가 고장 났을 때 복구 시간을 결정하는 것이 이 백업의 유무다.
함정: 프로비저닝을 수작업으로 하면 로봇마다 미묘하게 달라진다. 그 차이가 나중에 "왜 이 로봇만 다르지"를 만든다. 스크립트화하고 결과를 기록하라.
14.8.7 OTA 갱신
원격으로 소프트웨어를 바꾼다.
| 요소 | 설명 |
|---|---|
| 원자성 | 중간 상태가 없어야 |
| 롤백 | 이전 버전으로 복귀 |
| 검증 | 갱신 후 자가 점검 |
| 안전 조건 | 동작 중 갱신 금지 |
| 재개 가능 | 통신 끊김 대비 |
| 단계적 배포 | 위험 분산 |
| 기록 | 무엇이 언제 |
견해: "동작 중에는 갱신하지 않는다"를 강제하라. 로봇이 움직이는 중에 소프트웨어가 바뀌면 예측 불가능한 상태가 된다. 정지·도킹·충전 중 같은 안전 조건에서만 갱신을 허용하는 것이 원칙이다.
견해: A/B 파티션 방식이 롤백을 가장 확실하게 만든다. 새 버전을 비활성 파티션에 쓰고 부팅을 전환하며, 실패하면 자동으로 되돌아간다. 인프라 비용이 있지만 무인 운영에서는 값을 한다.
함정: 갱신 실패로 로봇이 부팅되지 않으면 현장 방문이 필요하다. 원격 로봇에서는 이것이 큰 비용이다. 부팅 실패 시 자동 롤백(워치독 기반)이 그 대비이며, 이것이 없으면 갱신을 두려워하게 된다(13.4.6).
견해: 카나리 배포가 플릿에서 필수다(14.9). 한 대에 먼저 적용해 며칠 관찰하고 확대하면, 문제가 전체로 퍼지지 않는다. "전체 동시 갱신"은 전체 동시 장애의 가능성을 뜻한다.
정직: 안전 관련 소프트웨어의 원격 갱신은 규제·표준의 대상일 수 있다. 무엇을 원격으로 바꿀 수 있고 어떤 검증이 필요한지는 안전 요구와 전문가의 판단을 따라야 한다(14.10).
14.8.8 버전 관리와 관측
"무엇이 실행되고 있는가"를 항상 답할 수 있어야 한다(11.1.9).
| 방법 | 설명 |
|---|---|
| 시작 로그에 버전 | 커밋·빌드 시각(4.7) |
| 진단에 버전 포함 | 원격 조회(6.9) |
| 버전 파일 | /etc/robot/version |
| 이미지 태그 | 컨테이너 |
| 플릿 대시보드 | 전체 현황(14.9) |
// 노드 시작 시 (개념)
RCLCPP_INFO(get_logger(), "my_node 시작 — 버전 %s, 커밋 %s, 빌드 %s",
kVersion, kGitSha, kBuildTime);
견해: 버전을 진단으로 발행하면 플릿 전체의 버전 분포를 볼 수 있다. "어느 로봇이 옛 버전인가"를 즉시 알 수 있고, 문제 발생 시 "그 버전에서만 나는가"를 판정할 수 있다. 비용은 거의 없고 효과가 크다.
함정: 빌드 시 커밋 해시를 넣지 않으면 나중에 알 수 없다. CMake에서 git 정보를 헤더로 생성하는 것이 표준적이며, 더티 상태(커밋되지 않은 변경) 표시도 함께 넣으면 유용하다.
견해: 배포 이력을 기록하라. 언제·어느 로봇에·무슨 버전을 배포했는지 남기면, 문제가 생겼을 때 시간 상관관계를 볼 수 있다(11.1.8). "어제 배포한 것과 관련이 있는가" 는 진단의 첫 질문 중 하나다.
14.8.9 로그와 디스크
배포 후 서서히 나타나는 문제다.
| 문제 | 대처 |
|---|---|
| 로그 무한 증가 | journald 크기 제한·회전 |
| ROS 로그 파일 | ~/.ros/log 정리(1.11.3) |
| bag 축적 | 보존 정책(11.3.7) |
| 디스크 가득 | 감시·경보(11.1.3) |
| 코어 덤프 | 크기 제한 |
# journald 제한 (개념 — 확인 필요)
# /etc/systemd/journald.conf
SystemMaxUse=500M
MaxRetentionSec=1week
함정:
~/.ros/log가 조용히 쌓인다(1.11.3). ROS 2는 실행마다 로그 디렉터리를 만드는데, 자동 정리가 없으면 무한히 는다. 정기 정리를 cron·systemd timer로 두라.
견해: 디스크 여유를 진단 항목으로 만들라(11.1.3의 반복). 디스크가 차면 로그·기록·갱신이 모두 실패하고 증상이 비정상적으로 변한다. 임계에서 경보하고, 자동 정리가 동작하게 한다.
14.8.12 시그널 처리 — 실측
systemd가 서비스를 멈출 때 무엇을 보내고 노드가 그것을 어떻게 받는지는 배포 설정의 핵심 전제다. Jazzy에서 시그널을 직접 보내 확인했다(실행 확인).
| 보낸 시그널 | 결과 | 마지막 로그 |
|---|---|---|
SIGTERM(systemd 기본) | 정상 종료 | [rclcpp]: signal_handler(SIGINT/SIGTERM) |
SIGINT(Ctrl+C) | 정상 종료 | [rclcpp]: signal_handler(SIGINT/SIGTERM) |
SIGHUP | 종료되지만 핸들러 없음 | 발행 로그에서 그대로 끊김 |
rclcpp의 시그널 핸들러가 SIGINT와 SIGTERM을 하나로 묶어 처리한다. 로그 문구 자체가 signal_handler(SIGINT/SIGTERM)으로 둘을 함께 적고 있다 — 구현이 둘을 구별하지 않는다는 뜻이다.
따라서 KillSignal=SIGINT로 바꿔 쓰라는 조언은 Jazzy에서는 불필요하다. systemd 기본값 그대로 두면 된다.
함정:
SIGHUP은 다르다. 터미널이 끊길 때 오는 시그널인데 rclcpp가 포착하지 않아 정리 없이 종료된다.nohup없이 SSH로 노드를 실행해 두고 접속을 끊으면 이 경로를 거친다 — bag을 기록 중이었다면 손상된다. systemd·setsid·tmux어느 것이든 터미널에서 떼어 놓고 실행하는 것이 답이다.
견해: 정리 시간을 실제로 측정해 보라.
TimeoutStopSec을 정하는 근거가 "넉넉해 보이는 값"이면 안 된다. bag 기록·지도 저장·컨트롤러 정지가 걸리는 시간은 시스템마다 다르고, 넘기면SIGKILL이 온다.systemctl stop후journalctl에서 종료까지 걸린 시간을 확인해 약 두 배를 설정하는 것이 실무적이다.
14.8.13 종료 코드와 Restart 정책의 간극 — 실측
14.8.3의 유닛 파일은 Restart=on-failure를 쓴다. 그 정책이 판정하는 것은 종료 코드인데, ROS 2 노드가 어떤 코드를 내는지는 이 장에 없었다. 측정했다(실행 확인, Jazzy).
14.8.13.1 종료 코드
| 종료 방식 | 종료 코드 | Restart=on-failure가 재시작하는가 |
|---|---|---|
정상 종료(shutdown 후 main 반환) | 0 | 아니오 |
SIGTERM(systemd 기본·kill 기본) | 0 | 아니오 |
SIGINT(Ctrl-C) | 0 | 아니오 |
SIGHUP | 129 | 예 |
SIGKILL(OOM killer 등) | 137 | 예 |
| 콜백에서 예외가 나가 종료될 때 | 134(SIGABRT) | 예 |
rclcpp가 SIGTERM·SIGINT를 처리해 정리하고 0으로 종료한다(14.8.12에서 확인한 핸들러의 결과다). systemctl stop이 의도한 정지로 처리되는 것은 맞고 바람직하다.
그런데 대가가 있다 — 밖에서 온
SIGTERM도 똑같이0이다. 감시 스크립트나 다른 도구가kill <pid>를 보내면(기본이SIGTERM이다) 노드는 사라지는데 systemd는 "정상적으로 멈췄다"로 본다.Restart=on-failure는 되살리지 않는다.
Restart=always가 이 경우를 검출한다 — 14.8.3의 표에서 둘을 고르는 기준이 여기서 분명해진다. "의도적 정지를 존중할 것인가, 어떤 이유로든 사라지면 되살릴 것인가"이며,always를 쓸 때는StartLimitBurst가 필수다(같은 절의 함정).
반대로 systemd가 확실히 감지하는 것은 SIGKILL(137 — OOM killer가 보내는 것)과 콜백 예외(134)다. 후자가 유용하다 — 2.8.11.2·2.9에서 본 "콜백 예외가 노드를 세운다"가 SIGABRT로 끝나므로 on-failure로 검출된다.
14.8.13.2 그러나 가장 심각한 실패는 종료조차 하지 않는다
71~72차에서 확인한 두 가지를 여기에 겹쳐 보면 그림이 완성된다.
| 실패 | 프로세스 | 종료 코드 | systemd가 보는 것 |
|---|---|---|---|
| 콜백 예외 | 종료된다 | 134 | 실패 — 재시작 ✅ |
| OOM | 종료된다 | 137 | 실패 — 재시작 ✅ |
외부 SIGTERM | 종료된다 | 0 | 정상 정지 — 가만히 있음 |
라이프사이클 finalized(1.12.10.3) | 실행 중이다 | — | 아무 일 없음 |
| 부분 활성 시스템(1.12.11.2) | 전부 실행 중이다 | — | 아무 일 없음 |
아래 두 줄이 이 장의 요점이다. 노드가 아무 일도 하지 않으면서 프로세스로는 정상인 상태를 systemd는 구조적으로 볼 수 없다 — 감시 대상이 프로세스이기 때문이다.
그러므로
Restart=설정만으로는 로봇의 가용성을 보장하지 못한다. 프로세스 감시(systemd)와 상태 감시(라이프사이클·진단, 6.9·1.12.10.3)는 다른 층을 본다. 둘 다 있어야 한다.실무 구성: systemd가 프로세스를, 진단 집계기가 라이프사이클 상태를 본다 — 실제로 동작함을 확인했다(6.9.14.1). 상태가
finalized·unconfigured로 굳으면 워치독이 프로세스를 강제 종료해 systemd에게 넘긴다 — 그때는SIGKILL(137)이나 예외로 종료돼야on-failure가 동작한다는 점까지 계산에 넣으라.
14.8.13.3 확인하지 못한 것
- 실제 systemd 유닛으로 실행해 보지 않았다 — 종료 코드만 측정했고,
Restart정책의 판정은 systemd 문서의 규칙에 근거한 추론이다(확인 필요). 컨테이너에서 systemd를 기동하는 부담 때문이다. RestartSec·StartLimitBurst의 실제 동작은 시험하지 않았다.rclpy노드의 종료 코드는 측정하지 않았다(확인 필요)— 2.8.11.2에서 본 예외 전파와 다를 수 있다.
14.8.10 함정 카탈로그
| # | 함정 | 증상 | 대처 |
|---|---|---|---|
| 1 | 로봇에서 소스 빌드 운영 | 재현성·실패 위험 | 이미지·패키지 |
| 2 | systemd에서 소싱 누락 | 실행 실패 | 래퍼 스크립트 |
| 3 | TimeoutStopSec 부족 | 정리 중 SIGKILL → bag 손상 | 정리 시간을 측정해서 넉넉히(14.8.12) |
| 4 | 무제한 재시작 | 문제 은폐 | StartLimit* |
| 5 | 시계 동기 전 기동 | 인증·시각 문제 | After 의존 |
| 6 | root로 실행 | 피해 확대 | 사용자·udev |
| 7 | 컨테이너 네트워크로 디스커버리 실패 | 노드 미발견 | 경계부터 확인(3.9.12) → 호스트를 넘으면 --network host·서버 |
| 8 | 공유 메모리 미설정 | 성능 저하 | --ipc host·측정 |
| 9 | 로봇별 데이터를 이미지에 | 이미지 폭증·관리 불가 | 분리 주입 |
| 10 | 캘리브레이션 백업 없음 | 재측정 | 백업 |
| 11 | 수작업 프로비저닝 | 로봇 간 차이 | 스크립트화 |
| 12 | 동작 중 갱신 | 예측 불가 상태 | 안전 조건 강제 |
| 13 | 롤백 없음 | 갱신 기피·현장 방문 | A/B·자동 롤백 |
| 14 | 전체 동시 갱신 | 전체 동시 장애 | 카나리 |
| 15 | 버전 미노출 | 진단 시작 불가 | 로그·진단 |
| 16 | 배포 이력 미기록 | 상관관계 불명 | 기록 |
| 17 | 로그·bag 무제한 | 디스크 가득 | 제한·정리·감시 |
| 18 | Restart=on-failure로 모든 실패를 덮는다고 가정 | SIGTERM 종료는 코드 0 — 검출되지 않는다 | always 검토 또는 상태 감시 병행(14.8.13.1) |
| 19 | 프로세스 감시만으로 가용성 보장 | finalized·부분 활성은 프로세스가 정상 | 상태 감시를 따로 두라(14.8.13.2) |
14.8.11 체크포인트
- 배포 형태 네 가지의 장단점과, 개발·운영을 분리하는 이유는?
- 배포 형태 선택의 핵심 판단 기준은?
- 컨테이너가 항상 정답이 아닌 이유는?
- systemd 유닛의 주요 설정 일곱 가지와 각각의 의미는?
- 소싱 누락이 왜 발생하며 어떻게 해결하는가.
SIGTERM·SIGINT·SIGHUP을 노드가 각각 어떻게 처리하는가.TimeoutStopSec이 중요한 이유는?- 무한 재시작을 막는 설정과 그 근거는?
- 시계 동기를 기다려야 하는 두 가지 이유는?
- 서비스 분할의 판단과, launch·systemd의 역할 구분은?
- 배포 환경 문제 일곱 가지와, "SSH로는 되는데" 진단법은?
- 컨테이너의 이점 네 가지·대가 여섯 가지를 말할 수 있는가.
- 컨테이너에서 DDS 디스커버리가 막히는 이유와 해법은?
- 프로비저닝에서 "공통 이미지 + 로봇별 데이터" 분리의 이점은?
- 로봇별 데이터 백업이 왜 중요한가.
- OTA의 일곱 요소와, "동작 중 갱신 금지"의 근거는?
- A/B 파티션과 자동 롤백이 해결하는 문제는?
- 카나리 배포가 플릿에서 필수인 이유는?
- 버전을 진단으로 발행하는 것의 이점 둘은?
- 배포 후 서서히 나타나는 디스크 문제 다섯 가지와 대처는?
SIGTERM·SIGINT·SIGHUP을 노드가 각각 어떻게 처리하는가(14.8.12).SIGTERM으로 종료된 노드의 종료 코드는 무엇이며, 그것이Restart=on-failure에 뜻하는 바는(14.8.13.1).- systemd가 구조적으로 볼 수 없는 실패 두 가지를 들 수 있는가(14.8.13.2).
다음 장 14.9은 로봇 한 대에서 여러 대로 — 다중 로봇과 플릿 운영을 다룬다.