Ubuntu ROS 실습(5)

zeusqoi·2026년 9월 21일

개인공부

목록 보기
24/42

지난 실습에서는 ROS 2 Talker/Listener 예제를 Snap으로 패키징하는 과정에서 LXD 빌드 환경의 네트워크 문제를 확인했었다.

이번에는 해당 문제를 이어서 확인하고, 최종적으로 ROS 2 Talker/Listener 애플리케이션을 Snap으로 패키징하고 설치 및 실행까지 진행했다.


1. LXD 네트워크 상태 확인

지난 실습에서 Snapcraft의 LXD 빌드 환경이 외부 네트워크에 접근하지 못하는 문제가 있었다.

먼저 FORWARD 정책을 확인했다.

sudo iptables -L FORWARD -n -v --line-numbers

확인 결과:

Chain FORWARD (policy ACCEPT ...)

FORWARD 정책은 ACCEPT 상태였다.

이후 Snapcraft에서 사용하는 LXD 컨테이너의 네트워크를 확인했다.

lxc exec snap-test -- ip route

결과:

default via 10.66.137.1 dev eth0
10.66.137.0/24 dev eth0 ...

컨테이너의 기본 게이트웨이는 10.66.137.1이었다.

게이트웨이와의 통신도 확인했다.

lxc exec snap-test -- ping -c 3 10.66.137.1

결과:

3 packets transmitted, 3 received, 0% packet loss

따라서 컨테이너와 LXD 게이트웨이 사이의 통신은 정상이었다.


2. LXD NAT 설정 확인

LXD의 네트워크 설정을 확인했다.

lxc network show lxdbr0

확인 결과:

ipv4.address: 10.66.137.1/24
ipv4.nat: "true"

즉 lxdbr0에는 IPv4 NAT가 활성화되어 있었다.

호스트의 IPv4 forwarding도 확인했다.

cat /proc/sys/net/ipv4/ip_forward

결과:

1

따라서 IPv4 forwarding도 활성화된 상태였다.


3. nftables에서 실제 NAT 규칙 확인

Ubuntu 환경에서는 iptables뿐만 아니라 nftables를 함께 확인할 필요가 있었다.

sudo nft list ruleset | grep -i -C 3 "10.66.137"

확인 결과 LXD가 다음과 같은 MASQUERADE 규칙을 사용하고 있었다.

ip saddr 10.66.137.0/24
ip daddr != 10.66.137.0/24
oifname != "lxdbr0"
masquerade

또한 forwarding 규칙도 확인했다.

sudo nft list table inet lxd

다음과 같이 lxdbr0에서 들어오고 나가는 IPv4 패킷을 허용하고 있었다.

ip version 4 oifname "lxdbr0" accept
ip version 4 iifname "lxdbr0" accept

따라서 LXD의 NAT 및 forwarding 설정 자체는 정상적으로 구성되어 있는 것을 확인했다.


4. 실제 외부 네트워크 연결 확인

호스트의 외부 인터페이스를 확인했다.

ip route get 8.8.8.8

결과:

8.8.8.8 via 203.237.142.1 dev enp7s0 src 203.237.142.127

따라서 외부 네트워크 인터페이스는 enp7s0였다.

tcpdump를 이용해서 실제 패킷이 외부 인터페이스로 나가는지도 확인했다.

sudo tcpdump -ni enp7s0 host 8.8.8.8

LXD 컨테이너에서 ping을 실행했을 때 다음과 같은 패킷이 확인되었다.

203.237.142.127 > 8.8.8.8: ICMP echo request

컨테이너의 주소는 10.66.137.49였기 때문에, 외부 인터페이스로 나갈 때 NAT가 적용되어 호스트의 IP인 203.237.142.127로 변환된 것을 확인할 수 있었다.

다만 8.8.8.8의 ping 응답은 확인되지 않았다.


5. ICMP 대신 HTTPS 연결 확인

ping은 ICMP를 사용하기 때문에 실제 인터넷 연결 상태를 판단하기 위해 HTTPS 연결도 확인했다.

호스트에서:

curl -I https://github.com

결과:

HTTP/2 200

호스트에서는 GitHub HTTPS 연결이 정상적으로 이루어졌다.

이어서 LXD 컨테이너에서도 확인했다.

lxc exec snap-test -- curl -I https://github.com

결과 역시:

HTTP/2 200

이었다.

따라서 LXD 컨테이너에서도 GitHub HTTPS 통신이 정상적으로 가능한 것을 확인했다.

결국 처음에 확인했던 8.8.8.8 ping 실패는 Snapcraft 패키징을 진행하는 데 필요한 HTTPS 통신 자체가 막힌 문제는 아니었다.


6. ROS 2 Talker/Listener Snap 프로젝트로 이동

이제 실제 Snap 패키징을 진행했다.

프로젝트 디렉터리로 이동했다.

cd ~/ros2-humble-talker-listener-snap

프로젝트 구조를 확인했다.

ls

결과:

LICENSE
README.md
renovate.json
SECURITY.md
snap

그리고 snap 디렉터리 안에 snapcraft.yaml이 존재하는 것을 확인했다.

ls snap

7. Snap 패키징

프로젝트 디렉터리에서 다음 명령을 실행했다.

snapcraft pack

처음에는 LXD 빌드 환경에서 Snapcraft를 설치하는 과정이 600초 동안 timeout되면서 실패했다.

하지만 생성된 LXD 빌드 컨테이너를 직접 확인해 보니 컨테이너 자체는 정상적으로 실행되고 있었다.

lxc --project snapcraft list

빌드용 컨테이너가 RUNNING 상태인 것을 확인했다.

컨테이너 내부의 Snap 버전도 확인했다.

lxc --project snapcraft exec \
base-instance-snapcraft-buildd-base-v71--d799df4d4588b4abe861 \
-- snap version

결과:

snap          2.76.3+ubuntu22.04
snapd         2.76.3+ubuntu22.04
series        16
ubuntu        22.04
architecture  amd64

또한 /tmp/snapcraft.snap 파일도 정상적으로 존재했다.

lxc --project snapcraft exec \
base-instance-snapcraft-buildd-base-v71--d799df4d4588b4abe861 \
-- ls -lh /tmp/snapcraft.snap

결과:

-rw-rw-r-- 1 root root 69M ... /tmp/snapcraft.snap

직접 설치를 테스트한 결과:

lxc --project snapcraft exec \
base-instance-snapcraft-buildd-base-v71--d799df4d4588b4abe861 \
-- snap install /tmp/snapcraft.snap --classic

정상적으로:

snapcraft 9.0.1 from Canonical✓ installed

가 출력되었다.

이후 다시 snapcraft pack을 실행했고, 최종적으로 Snap 패키징에 성공했다.

생성된 파일을 확인했다.

ls -lh *.snap

결과:

-rw-r--r-- 1 namseungjoo namseungjoo 64M Sep 21 15:38 \
ros2-talker-listener_0.1_amd64.snap

드디어 ROS 2 Talker/Listener 애플리케이션의 Snap 패키지가 정상적으로 생성되었다.


8. 생성된 Snap 패키지 설치

생성된 .snap 파일을 로컬에서 설치했다.

처음에는:

sudo snap install ./ros2-talker-listener_0.1_amd64.snap --dangerous

를 실행했지만 다음과 같은 메시지가 나왔다.

error: snap "./ros2-talker-listener_0.1_amd64.snap" requires devmode or
confinement override

snapcraft.yaml에서 다음과 같이 devmode를 사용하도록 설정되어 있기 때문이다.

confinement: devmode

따라서 --devmode 옵션을 추가해서 다시 설치했다.

sudo snap install ./ros2-talker-listener_0.1_amd64.snap --dangerous --devmode

결과:

ros2-talker-listener 0.1 installed

정상적으로 설치되었다.


9. 설치된 Snap 확인

설치된 Snap을 확인했다.

snap list ros2-talker-listener

결과:

Name                  Version  Rev  Tracking  Publisher  Notes
ros2-talker-listener  0.1      x1   -         -          devmode

따라서 Snap이 정상적으로 설치되어 있는 것을 확인할 수 있었다.


10. Snap 서비스 확인

처음에는 서비스 형태로 실행되는지 확인하기 위해:

snap services ros2-talker-listener

를 실행했다.

하지만:

error: snap "ros2-talker-listener" has no services

라는 결과가 나왔다.

services로 실행하는 daemon 형태가 아니라 apps로 정의된 애플리케이션이기 때문에 snap run을 사용해야 했다.


11. snapcraft.yaml 확인

현재 프로젝트의 snap/snapcraft.yaml을 확인했다.

name: ros2-talker-listener
version: '0.1'
summary: ROS 2 Talker/Listener Example
description: |
  This example launches a ROS 2 talker and listener.
confinement: devmode
base: core22

parts:
  ros-demos:
    plugin: colcon
    source: https://github.com/ros2/demos.git
    source-branch: humble
    source-subdir: demo_nodes_cpp
    build-packages: [build-essential]
    stage-packages: [ros-humble-ros2launch]

apps:
  ros2-talker-listener:
    command: opt/ros/humble/bin/ros2 launch demo_nodes_cpp talker_listener.launch.py
    extensions: [ros2-humble]

여기서 apps에 다음과 같이 ros2-talker-listener가 정의되어 있었다.

apps:
  ros2-talker-listener:

따라서 Snap 서비스가 아니라 다음과 같이 실행할 수 있다.


12. Snap으로 ROS 2 Talker/Listener 실행

다음 명령을 실행했다.

snap run ros2-talker-listener

정상적으로 ROS 2 Launch가 실행되었고, Talker와 Listener 프로세스가 함께 시작되었다.

[INFO] [launch]: All log files can be found below ...
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [talker-1]: process started
[INFO] [listener-2]: process started

이후 Talker가 메시지를 발행하고 Listener가 해당 메시지를 수신하는 것을 확인했다.

이처럼 Talker가 발행한 Hello World 메시지를 Listener가 정상적으로 수신하고 있었다.


13. ros2topic 애플리케이션 추가

기존 Snap에는 ROS 2 Talker/Listener 애플리케이션만 포함되어 있었다.

이번에는 Canonical Robotics의 Exercise를 따라 ros2topic을 추가하여 Snap 내부에서 ROS 2 토픽을 확인할 수 있도록 구성했다.

먼저 snapcraft.yaml의 stage-packages에 ros-humble-ros2topic을 추가했다.

ros2topic 실행 과정에서 NumPy가 BLAS 라이브러리를 찾지 못하는 문제가 발생하여 libblas3도 함께 추가했다.

stage-packages: [ros-humble-ros2launch, ros-humble-ros2topic, libblas3]

그리고 apps에 ros2topic 애플리케이션을 추가했다.

ros2topic:
  command: opt/ros/humble/bin/ros2 topic
  environment:
    LD_LIBRARY_PATH: $SNAP/usr/lib/x86_64-linux-gnu/blas:$SNAP/usr/lib/x86_64-linux-gnu/lapack:$LD_LIBRARY_PATH
  extensions: [ros2-humble]

이후 다시 Snap 패키지를 빌드했다.

snapcraft pack

정상적으로 다음과 같은 Snap 패키지가 생성되었다.

Created snap package ros2-talker-listener_0.1_amd64.snap

생성된 Snap을 다시 설치했다.

sudo snap install ./ros2-talker-listener_0.1_amd64.snap --dangerous --devmode

결과:

ros2-talker-listener 0.1 installed

14. ros2topic으로 /chatter 확인

Talker/Listener를 실행한 상태에서 새 터미널을 열고 다음 명령을 실행했다.

snap run ros2-talker-listener.ros2topic hz /chatter

처음 ros2topic을 실행했을 때 NumPy가 사용하는 BLAS/LAPACK 라이브러리를 찾지 못하는 문제가 발생했다.

libblas.so.3: cannot open shared object file

확인 결과 libblas.so.3와 liblapack.so.3는 Snap 내부에 존재했지만 각각 blas, lapack 하위 디렉터리에 위치하고 있었다.

따라서 LD_LIBRARY_PATH에 해당 경로를 추가하여 테스트했다.

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/usr/lib/x86_64-linux-gnu/blas:$SNAP/usr/lib/x86_64-linux-gnu/lapack"

이후 다시 실행하자 정상적으로 /chatter 토픽의 발행 주기를 확인할 수 있었다.

ros2 topic hz /chatter
average rate: 1.000
min: 1.000s max: 1.000s

테스트 결과를 바탕으로 해당 환경변수 설정을 snapcraft.yaml의 ros2topic 앱에 추가했다.

이후 Snap을 다시 빌드하고 설치한 뒤에는 별도의 export 명령 없이도 다음 명령만으로 정상적으로 실행할 수 있었다.

snap run ros2-talker-listener.ros2topic hz /chatter

최종적으로 /chatter 토픽이 약 1Hz의 주기로 정상적으로 발행되고 있는 것을 확인했다.


마무리

이번 실습에서는 ROS 2의 Talker/Listener 애플리케이션을 Snap으로 패키징하고, LXD 빌드 환경의 네트워크 상태를 확인한 뒤 실제 Ubuntu 환경에 설치하여 실행해 보았다.

또한 기존 Snap에 ros2topic 애플리케이션을 추가하고, /chatter 토픽의 발행 주기를 직접 확인했다. 이 과정에서 Snap 내부의 BLAS/LAPACK 라이브러리 경로 문제를 확인하고 LD_LIBRARY_PATH를 설정하여 해결했다.

전체 과정은 다음과 같다.

ROS 2 Talker/Listener
        ↓
snapcraft.yaml 작성
        ↓
LXD 빌드 환경 및 네트워크 확인
        ↓
snapcraft pack
        ↓
ros2-talker-listener_0.1_amd64.snap 생성
        ↓
Snap 설치
        ↓
snap run ros2-talker-listener
        ↓
Talker → "Hello World"
        ↓
Listener → 메시지 수신
        ↓
ros2topic 추가
        ↓
ros2 topic hz /chatter
        ↓
약 1 Hz 확인

최종적으로 ROS 2 Talker/Listener 애플리케이션을 Snap으로 패키징하고 설치 및 실행하는 과정을 완료했으며, ros2topic을 이용하여 /chatter 토픽의 통신 상태까지 확인할 수 있었다.

0개의 댓글