AEGLOSLAB ROS 2 Jazzy 대전

제4부 빌드·패키징·배포

4.9 릴리스 — bloom·rosdistro·빌드팜

4.9.1 이 장에서 배우는 것 / 선수 지식

sudo apt install ros-jazzy-nav2-bringup 한 줄이 동작하기까지, 누군가는 그 패키지를 릴리스했다. 이 장은 그 파이프라인을 연다.

두 부류의 독자를 위한 장이다. ① 공개 패키지를 릴리스하려는 사람 — 오픈소스 패키지를 ROS 생태계에 등록하는 절차. ② 사내 배포 체계를 세우려는 사람 — 공개 빌드팜을 쓰지 않고 자체 apt 저장소를 운영하는 방법. 후자가 실무에서 더 흔하다.

배우는 것:

  • 릴리스 파이프라인 전체 — 소스에서 apt까지의 경로.
  • 버전과 CHANGELOG — catkin_prepare_release 워크플로.
  • bloom — 릴리스 저장소와 debian 패키징 생성.
  • rosdistro — 배포판 인덱스에 등록하기.
  • 빌드팜 — 어떤 작업들이 실행되는가.
  • 사내 릴리스 — 자체 빌드팜·apt 저장소 구축 선택지.
  • 릴리스 정책 — 버전 규칙·지원 기간.

선수 지식: 4.4(package.xml·버전), 4.6(rosdep 키), 4.7(소스·재현성), 4.5(colcon).

정직: bloom·빌드팜 절차는 도구 버전과 rosdistro 정책에 따라 변한다. 아래 명령·워크플로는 일반적으로 통용되는 형태이며, 공식 릴리스를 실제로 수행할 때는 ROS 2 문서와 rosdistro 기여 가이드의 현재 내용을 따라야 한다(확인 필요). 이 환경에서 실행 검증하지 않았다(목차 3).

검증 상태(추가): 130번째 회차(151차 갭 점검)까지 이 장은 실행 검증이 전혀 없었다. 130번째 회차가 GitHub 인증·rosdistro PR이 필요 없는 부분 — bloom-generate rosdebian으로 debian 패키징을 생성하고 실제로 .deb를 빌드·설치·실행까지 전 과정을 실제로 실행해 본문에 (실행 확인) 표기를 처음 추가했다 — 4.9.4·4.9.7을 보라. rosdistro PR·빌드팜(4.9.5·4.9.6, 실제 GitHub 권한과 공개 인프라가 필요)은 이번 회차도 다루지 못해 여전히 미검증이다.

4.9.2 릴리스 파이프라인 전체

개발 저장소 (소스) 버전 갱신 + CHANGELOG catkin_prepare_release bloom-release 릴리스 저장소 생성·갱신 rosdistro PR distribution.yaml 갱신 빌드팜 sourcedeb → binarydeb apt 저장소 packages.ros.org 사용자 apt install
단계주체산출물
버전·CHANGELOG개발자태그·CHANGELOG.rst
bloom개발자릴리스 저장소의 debian 브랜치
rosdistro PR개발자 → 검토자distribution.yaml 항목
빌드팜자동.deb 패키지
apt 저장소자동공개 배포

두 개의 저장소가 등장한다는 점이 혼동을 낳는다:

저장소내용누가 편집
개발 저장소 (my_pkg)소스 코드개발자
릴리스 저장소 (my_pkg-release)debian 패키징 메타데이터bloom이 자동 생성

릴리스 저장소는 수동으로 편집하지 않는다. bloom이 관리하며, 개발자는 개발 저장소만 다룬다.

4.9.3 버전과 CHANGELOG

CHANGELOG.rst가 릴리스의 기록이다.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package my_robot_driver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1.2.0 (2026-08-13)
------------------
* 시리얼 재연결 로직 추가
* CAN 드라이버의 타임아웃 처리 수정 (#42)
* Contributors: Alice, Bob

1.1.0 (2026-06-01)
------------------
* 초기 릴리스
* Contributors: Alice

도구가 커밋 로그에서 자동 생성한다:

# ① 커밋 로그에서 CHANGELOG 초안 생성
catkin_generate_changelog

# ② 초안을 사람이 다듬는다 (중요)
$EDITOR CHANGELOG.rst

# ③ 버전 갱신하고 태그 생성
catkin_prepare_release

# ④ 푸시
git push --follow-tags

catkin_prepare_release가 하는 일:

작업설명
package.xml의 <version> 증가대화형으로 major/minor/patch 선택
CHANGELOG.rst의 forthcoming을 버전·날짜로 확정
커밋 생성
git 태그 생성1.2.0 형태

함정: setup.py의 version은 자동으로 갱신되지 않는다(4.3.6). Python 패키지에서는 수동으로 맞춰야 한다. 릴리스 체크리스트에 반드시 넣는다.

함정: 워크스페이스에 여러 패키지가 있으면 버전이 함께 갱신된다. catkin_prepare_release는 저장소 안의 모든 패키지를 같은 버전으로 맞추는 것이 기본이다(확인 필요: 옵션으로 조정 가능). 패키지마다 독립적인 버전을 원하면 저장소를 나누거나 옵션을 확인해야 한다.

CHANGELOG를 다듬는 것이 중요하다. 자동 생성된 것은 커밋 메시지 나열이라 사용자에게 유용하지 않다. "무엇이 바뀌었고 사용자가 무엇을 해야 하는가" 를 적어야 한다 — 특히 호환을 깨는 변경(1.2.8).

2.0.0 (2026-09-01)
------------------
* **호환성 깨짐**: ``MotorState`` 메시지에 ``temperature`` 필드 추가.
  이 패키지를 쓰는 모든 노드를 재빌드해야 한다 (1.3.5 type hash 변경).
* 마이그레이션: ...

4.9.4 bloom

sudo apt install python3-bloom

# 릴리스 실행
bloom-release --rosdistro jazzy --track jazzy my_robot_driver

bloom이 하는 일:

bloom-release 개발 저장소에서 태그된 소스 가져오기 릴리스 저장소에 upstream 브랜치 갱신 debian/ 디렉터리 생성 control · rules · changelog 패치 적용 (있으면) 릴리스 태그 생성 release/jazzy/my_pkg/1.2.0-1 rosdistro PR 자동 생성 제안

최초 실행 시 대화형으로 설정을 묻는다:

항목내용
릴리스 저장소 URLgithub.com/ros2-gbp/my_pkg-release 형태
upstream 저장소 URL개발 저장소
upstream 브랜치·태그대개 태그에서
버전:{version}(package.xml에서 자동)

이 설정은 릴리스 저장소의 tracks.yaml에 저장되어 다음 릴리스부터 재사용된다.

생성되는 debian 메타데이터:

  • debian/control — 패키지 이름(ros-jazzy-my-robot-driver), 의존(rosdep으로 변환된 것 — 4.6).
  • debian/rules — 빌드 절차.
  • debian/changelog — CHANGELOG.rst에서 변환.

함정: 패키지 이름 변환 규칙에 주의하라. my_robot_driver → ros-jazzy-my-robot-driver. 밑줄이 하이픈이 된다. rosdep 키나 문서에서 이름을 쓸 때 혼동하기 쉽다.

정직: bloom은 GitHub 인증·릴리스 저장소 권한을 요구하며, 최초 설정이 까다롭다. 공개 릴리스는 대개 ros2-gbp 조직에 릴리스 저장소를 만드는 절차를 거친다(확인 필요: 현재 정책). 상세는 ROS 2 문서의 릴리스 가이드를 따라야 한다.

실행 확인(151차, Jazzy) — bloom-generate rosdebian이 생성하는 debian 메타데이터를 실제 패키지로 직접 대조했다. 이 절의 예시 이름 그대로(my_robot_driver, rclcpp·std_msgs 의존, ament_cmake) 최소 패키지를 만들고 bloom-generate rosdebian --ros-distro jazzy를 실행했다(GitHub 인증·릴리스 저장소 없이, rosdistro 인덱스 읽기만 필요 — 4.9.7이 말하는 "bloom-generate만 쓰는 방법"이 바로 이 경로다). 생성된 debian/control을 그대로 옮기면:

Source: ros-jazzy-my-robot-driver
Build-Depends: debhelper (>= 9.0.0), ros-jazzy-ament-cmake, ros-jazzy-rclcpp, ros-jazzy-std-msgs
Package: ros-jazzy-my-robot-driver
Depends: ${shlibs:Depends}, ${misc:Depends}, ros-jazzy-rclcpp, ros-jazzy-std-msgs

패키지 이름 변환(my_robot_driver → ros-jazzy-my-robot-driver)과 rosdep 의존 변환(rclcpp→ros-jazzy-rclcpp, std_msgs→ros-jazzy-std-msgs, 빌드 의존 ament_cmake→ros-jazzy-ament-cmake) 모두 위 함정·본문 서술과 정확히 일치했다. debian/changelog도 CHANGELOG.rst의 항목("Test release for gap151...")을 그대로 옮겨 실었다. 원시 데이터는 tools/gap_harness/gap151/data/debian_control·debian_changelog·debian_rules. 4.9.7을 이어 실제 빌드까지 확인했다 — 그쪽을 보라. 목차 3.

4.9.5 rosdistro

distribution.yaml이 배포판의 패키지 인덱스다.

# rosdistro/jazzy/distribution.yaml 의 한 항목
my_robot_driver:
  doc:
    type: git
    url: https://github.com/myorg/my_robot_driver.git
    version: jazzy
  release:
    tags:
      release: release/jazzy/{package}/{version}
    url: https://github.com/ros2-gbp/my_robot_driver-release.git
    version: 1.2.0-1
  source:
    type: git
    url: https://github.com/myorg/my_robot_driver.git
    version: jazzy
  status: developed

bloom이 이 항목을 갱신하는 PR을 자동으로 만들어 준다. 검토자가 병합하면 빌드팜이 인식한다.

필드의미
release.version릴리스된 버전(-1은 debian 리비전)
source.version개발 브랜치
statusdeveloped·maintained·end-of-life

rosdistro는 다른 것도 담는다:

파일내용
distribution.yaml패키지 인덱스
rosdep/base.yaml·python.yamlrosdep 규칙(4.6.2)
index-v4.yaml배포판 목록

rosdep 규칙 기여도 여기로 한다 — 공개 라이브러리의 rosdep 키가 없다면 여기에 PR을 보낸다(4.6.7·15.5).

4.9.6 빌드팜

rosdistro 병합 후 자동으로 실행되는 작업들이다.

작업하는 일산출물
sourcedeb릴리스 저장소에서 소스 deb 생성.dsc·.tar.gz
binarydeb아키텍처별 컴파일.deb
devel개발 브랜치를 빌드·테스트(회귀 감시)테스트 결과
pull requestPR을 빌드·테스트검증 결과
docAPI 문서 생성문서 사이트

빌드팜이 실패하는 흔한 원인:

원인설명
의존 선언 누락개발 머신엔 있는데 클린 환경엔 없음(4.4.3)
rosdep 키 없음새 시스템 의존을 등록 안 함(4.6.7)
테스트 실패로컬과 다른 환경
아키텍처 의존 버그arm64 빌드만 실패(4.8.7)
빌드 시간 초과규모가 큰 패키지
의존 패키지가 아직 릴리스 안 됨순서 문제

견해: 빌드팜 실패의 대부분은 로컬에서 예방할 수 있다. 클린 컨테이너에서 rosdep install + colcon build + colcon test를 실행하면(4.4.9) 의존 누락과 테스트 실패를 미리 검출한다. 릴리스 전에 이것을 CI로 자동화하라(4.10).

상태 확인:

# 빌드 상태 페이지(build.ros.org)에서 확인
# 패키지별 빌드 결과·로그를 볼 수 있다

릴리스 후 반영까지 시간이 걸린다 — 빌드·동기화 주기에 따라 수 시간~며칠(확인 필요: 현재 동기화 정책). apt install이 바로 안 되는 것이 정상이다.

4.9.7 사내 릴리스 — 자체 배포 체계

실무에서 더 흔한 경우다. 사내 패키지를 공개 빌드팜에 등록할 수는 없다.

선택지 셋:

① 컨테이너 이미지만 (가장 단순)

docker buildx build --platform linux/arm64 -t registry.internal/my_robot:1.2.0 --push .
  • 장점: 별도 인프라 최소. 4.8.6의 배포와 통합.
  • 단점: 패키지 단위 업데이트 불가(전체 이미지 교체).
  • 적합: 팀이 작고 로봇 구성이 단일할 때.

② 자체 apt 저장소

# deb 생성 (bloom 없이 직접)
cd my_robot_driver
bloom-generate rosdebian --ros-distro jazzy
fakeroot debian/rules binary
# → ../ros-jazzy-my-robot-driver_1.2.0-1_arm64.deb

# 저장소 구축 (aptly · reprepro 등)
aptly repo create -distribution=noble internal-ros
aptly repo add internal-ros ../*.deb
aptly publish repo internal-ros
# 로봇에서
echo "deb [trusted=yes] http://apt.internal/ noble main" | \
  sudo tee /etc/apt/sources.list.d/internal-ros.list
sudo apt update && sudo apt install ros-jazzy-my-robot-driver
  • 장점: 패키지 단위 업데이트·롤백. 기존 OS 관리와 일관.
  • 단점: 저장소 운영·서명·의존 관리 부담.
  • 적합: 로봇 종류가 여럿이고 구성이 다양할 때.

③ 자체 빌드팜

ROS 빌드팜 소프트웨어를 사내에 구축한다.

  • 장점: 공개 빌드팜과 동일한 워크플로.
  • 단점: 구축·운영 비용이 매우 크다.
  • 적합: 패키지 수십~수백 개, 전담 인력이 있는 조직.

견해: 대부분의 팀에게 ①로 시작하고, 필요해지면 ②로 가는 것이 맞다. ③은 규모가 확실히 커진 뒤에 검토할 일이며, 그 전에는 투자 대비 효과가 낮다. 로봇이 여러 종류이거나 부분 업데이트가 필요해지는 시점이 ①→② 전환의 신호다.

bloom-generate만 쓰는 방법이 유용하다 — 릴리스 저장소·rosdistro 없이 deb만 만든다.

bloom-generate rosdebian --ros-distro jazzy
fakeroot debian/rules binary

이것만으로 사내 배포에 필요한 deb를 얻을 수 있고, bloom의 전체 워크플로를 감당할 필요가 없다.

실행 확인(151차, Jazzy) — bloom-generate + fakeroot debian/rules binary + apt install까지 전 과정을 실제로 실행해 실제 설치·실행 가능한 패키지가 나오는지 확인했다. 4.9.4에서 생성한 debian/으로 fakeroot debian/rules binary를 실행하니 ros-jazzy-my-robot-driver_1.2.0-0noble_amd64.deb(10.6KB)가 정상적으로 만들어졌다(dh_shlibdeps가 ROS 공유 라이브러리 이름을 못 알아보는 경고 몇 줄을 빼면 별다른 문제 없이 완료). dpkg -I로 확인한 실제 Depends: 줄은 libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), libstdc++6 (>= 13.1), ros-jazzy-rclcpp, ros-jazzy-std-msgs로 — 시스템 공유 라이브러리 의존과 ROS 의존이 자동으로 함께 채워졌다. dpkg -c로 본 설치 경로는 /opt/ros/jazzy/lib/my_robot_driver/driver_node·/opt/ros/jazzy/share/my_robot_driver/... 등 — apt install ros-jazzy-*로 설치한 여느 공식 패키지와 완전히 동일한 레이아웃이었다.

apt-get install ./ros-jazzy-my-robot-driver_1.2.0-0noble_amd64.deb로 실제 설치했고, ros2 pkg list에 my_robot_driver가 나타났으며, ros2 run my_robot_driver driver_node가 실제로 기동해 [INFO] [driver_node]: driver_node up 로그를 냈다. GitHub 인증도 릴리스 저장소도 rosdistro PR도 전혀 필요 없었다 — 4.9.7의 "사내 배포에 필요한 deb를 얻을 수 있고, bloom의 전체 워크플로를 감당할 필요가 없다"는 서술이 시작부터 끝까지(패키징 생성 → 빌드 → 설치 → 실행) 실측으로 확인됐다. 원시 로그는 tools/gap_harness/gap151/logs/fakeroot_debian_rules_binary.log·apt_install_deb.log, 원시 데이터는 tools/gap_harness/gap151/data/deb_inspect.txt. 목차 3.

4.9.8 릴리스 정책

팀이 정해 두어야 할 것들이다.

버전 규칙:

변경버전
호환 깨짐(메시지 변경·API 제거)major
기능 추가(호환 유지)minor
버그 수정patch

메시지 변경은 거의 항상 major다(1.2.8·1.3.5) — type hash가 바뀌어 통신이 끊기므로.

릴리스 체크리스트:

  • [ ] 클린 환경에서 빌드·테스트 통과(4.4.9)
  • [ ] 대상 아키텍처에서 빌드 확인(4.8.7)
  • [ ] CHANGELOG.rst 사람이 읽을 수 있게 다듬음
  • [ ] 호환 깨짐이 있으면 명시 + 마이그레이션 안내
  • [ ] package.xml·setup.py 버전 일치(4.3.6)
  • [ ] 라이선스·유지보수자 정보 최신(4.4.8)
  • [ ] 의존 선언 정확(rosdep check)
  • [ ] 소스 잠금 파일 보관(vcs export --exact — 4.7.8)
  • [ ] 태그 푸시

지원 정책:

항목결정할 것
지원 배포판Jazzy만? Humble도?
지원 기간배포판 EOL까지?
브랜치 전략배포판별 브랜치? 단일 브랜치 + condition(4.4.4)?
백포트 정책버그 수정을 이전 배포판에도?

견해: 배포판별 브랜치가 명확하다. 단일 브랜치로 여러 배포판을 지원하려면 condition과 조건부 코드가 늘어나고, 어느 배포판에서 무엇이 되는지 추적이 어려워진다. 브랜치를 나누면 백포트 비용이 들지만 각 브랜치가 단순해진다. 패키지가 작고 배포판 간 차이가 적으면 단일 브랜치도 가능하다(15.1).

4.9.9 함정 카탈로그

#함정증상대처
1클린 환경 검증 생략빌드팜에서 실패컨테이너 검증(4.4.9)
2setup.py 버전 미갱신버전 불일치체크리스트
3CHANGELOG를 자동 생성 그대로사용자에게 무용사람이 다듬기
4호환 깨짐을 minor로 릴리스사용자 시스템 파손major + 명시
5새 rosdep 키 미등록빌드팜 의존 해석 실패rosdistro PR(4.6.7)
6릴리스 저장소를 수동으로 편집bloom과 충돌bloom에 맡김
7arm64 검증 없이 릴리스아키텍처별 실패크로스 검증(4.8)
8패키지 이름 변환 혼동문서·스크립트 오류밑줄→하이픈 인지
9사내에서 성급히 빌드팜 구축운영 부담이미지·apt부터
10소스 잠금 미보관과거 릴리스 재현 불가vcs export --exact
11릴리스 후 즉시 apt 기대아직 반영 안 됨동기화 주기 인지
12지원 정책 미정의백포트 요청에 혼란명문화

4.9.10 체크포인트

  • 릴리스 파이프라인 다섯 단계와 각 단계의 산출물을 말할 수 있는가.
  • 개발 저장소와 릴리스 저장소의 차이는 무엇이며, 개발자가 편집하는 것은 어느 쪽인가.
  • catkin_prepare_release가 하는 네 가지 작업과, 자동으로 되지 않는 것 하나는 무엇인가.
  • CHANGELOG를 사람이 다듬어야 하는 이유는? 호환 깨짐이 있을 때 무엇을 적어야 하는가.
  • bloom이 생성하는 debian 메타데이터 세 가지는? 패키지 이름 변환 규칙은?
  • distribution.yaml의 주요 필드 세 가지를 말할 수 있는가. rosdistro가 담는 다른 것은?
  • 빌드팜의 작업 종류 다섯 가지와, 실패의 흔한 원인 여섯 가지를 들 수 있는가. 대부분을 로컬에서 예방하는 방법은?
  • 사내 배포 선택지 세 가지의 장단을 비교하고, 전환 신호가 무엇인지 말할 수 있는가.
  • bloom-generate만 쓰는 방식의 이점은?
  • 메시지 정의 변경이 왜 거의 항상 major 버전인가.
  • 배포판별 브랜치와 단일 브랜치의 트레이드오프를 설명할 수 있는가.

다음 장 4.10은 제4부의 마지막 — CI와 품질 게이트다. 지금까지 다룬 빌드·의존·릴리스 검증을 자동화하고, 어떤 게이트를 세울 것인가.