이번 실습에서는 Canonical Robotics의 튜토리얼을 따라 ROS 2 Humble Talker/Listener 예제를 Snap 패키지로 빌드해 보았다.
실습 환경은 Ubuntu 22.04.5 LTS + ROS 2 Humble이며, Snapcraft에서 사용하는 LXD 환경까지 구성한 뒤 실제 패키징을 시도했다.
먼저 Snapcraft를 설치했다.
sudo snap install snapcraft --classic
설치가 완료된 후 버전을 확인했다.
snapcraft --version
실습 환경에서는 다음과 같이 확인되었다.
snapcraft 9.0.1
Snapcraft는 빌드 과정에서 LXD 기반의 빌드 환경을 사용할 수 있기 때문에 LXD도 설치했다.
sudo snap install lxd
설치 후 LXD를 자동으로 초기화했다.
lxd init --auto
그리고 LXD 네트워크를 확인했다.
lxc network list
lxdbr0라는 브리지 네트워크가 생성되어 있는 것을 확인할 수 있었다.
lxdbr0
IPv4: 10.66.137.1/24
Canonical Robotics 튜토리얼에서 사용하는 예제 저장소를 Clone했다.
git clone https://github.com/ubuntu-robotics/ros2-humble-talker-listener-snap.git
프로젝트 디렉터리로 이동했다.
cd ~/ros2-humble-talker-listener-snap
프로젝트에는 다음과 같은 구조가 있었다.
ros2-humble-talker-listener-snap/
├── .git/
├── .github/
├── snap/
│ └── snapcraft.yaml
├── README.md
├── LICENSE
└── ...
Snap 패키징에 필요한 설정은 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
이 설정을 통해 ROS 2 Humble의 demo_nodes_cpp를 빌드하고, Talker/Listener를 실행하는 Snap을 생성하도록 구성되어 있다.
기존의 snapcraft 명령 대신 현재 방식에 맞춰 다음 명령으로 패키징을 시도했다.
snapcraft pack
하지만 여기서 문제가 발생했다.
craft-providers error:
A network related operation failed in a context of no network access.
즉, 호스트 Ubuntu에서는 인터넷이 정상적으로 연결되지만 Snapcraft가 생성한 LXD 빌드 환경에서는 외부 네트워크 연결이 되지 않는 문제가 발생했다.
먼저 호스트 자체의 인터넷 연결에는 문제가 없는지 확인했다.
curl -I https://github.com
호스트에서는 정상적으로 GitHub에 접속할 수 있었다.
따라서 단순히 Ubuntu 자체의 인터넷 연결 문제는 아니었다.
문제의 원인을 확인하기 위해 테스트용 LXD 컨테이너를 생성했다.
lxc launch ubuntu:22.04 snap-test
컨테이너 내부에서 GitHub 연결을 테스트했다.
lxc exec snap-test -- curl -I https://github.com
하지만 연결이 되지 않았다.
반면 LXD 브리지 자체와 컨테이너 사이의 통신은 정상적으로 확인되었다.
lxc exec snap-test -- ping -c 3 10.66.137.1
결과:
3 packets transmitted, 3 received, 0% packet loss
즉,
컨테이너
↓
lxdbr0
까지의 통신은 정상적이었다.
컨테이너에서 Google DNS로 직접 통신을 시도했다.
lxc exec snap-test -- ping -c 3 8.8.8.8
결과:
3 packets transmitted, 0 received, 100% packet loss
GitHub에 대한 TCP 연결도 확인했다.
lxc exec snap-test -- curl -4 -v --connect-timeout 5 https://github.com
DNS 주소는 정상적으로 확인되었지만 TCP 연결은 timeout이 발생했다.
* Trying 20.26.156.215:443...
* connect to 20.26.156.215 port 443 failed: Connection timed out
curl: (28) Connection timeout after 5001 ms
LXD 브리지의 NAT 설정도 확인했다.
lxc network show lxdbr0
다음과 같이 NAT가 활성화되어 있었다.
config:
ipv4.address: 10.66.137.1/24
ipv4.nat: "true"
실제로 nftables에도 LXD의 NAT 규칙이 존재하는 것을 확인했다.
sudo nft list chain inet lxd pstrt.lxdbr0
결과에는 다음과 같은 masquerade 규칙이 존재했다.
ip saddr 10.66.137.0/24
ip daddr != 10.66.137.0/24
oifname != "lxdbr0"
masquerade
따라서 LXD에 NAT 설정 자체가 빠져 있는 상황은 아니었다.
호스트의 nftables 설정을 확인하면서 Docker의 FORWARD 체인 정책이 DROP으로 설정되어 있는 것도 확인했다.
sudo iptables -L FORWARD -n -v --line-numbers
결과:
Chain FORWARD (policy DROP ...)
이를 확인하기 위해 테스트 목적으로 lxdbr0에서 들어오는 패킷을 허용하는 규칙을 추가했다.
sudo iptables -I DOCKER-USER 1 -i lxdbr0 -j ACCEPT
그리고 FORWARD에도 임시 허용 규칙을 추가했다.
sudo iptables -I FORWARD 1 -i lxdbr0 -j ACCEPT
규칙이 실제로 패킷을 잡는 것은 확인할 수 있었다.
num pkts bytes target
1 34 2040 ACCEPT all -- lxdbr0 *
하지만 이렇게 해도 컨테이너의 외부 통신은 정상적으로 되지 않았다.
tcpdump를 이용해 실제 패킷이 어느 구간까지 전달되는지 확인했다.
컨테이너에서:
lxc exec snap-test -- ping -c 3 8.8.8.8
를 실행하면서 lxdbr0를 확인했을 때 컨테이너의 패킷은 확인되었다.
10.66.137.49 > 8.8.8.8
하지만 외부 네트워크 인터페이스인 enp7s0에서는 컨테이너의 패킷이 확인되지 않았다.
sudo tcpdump -ni enp7s0 host 8.8.8.8
여기서는 다음과 같이 호스트 자신의 IP에서 나가는 패킷만 확인되었다.
203.237.142.127 > 8.8.8.8
즉, 컨테이너의 패킷이
LXD 컨테이너
↓
lxdbr0
↓
FORWARD
↓
???
↓
enp7s0
과정에서 외부 인터페이스까지 전달되지 않는 상황으로 확인했다.
최종적으로 snapcraft pack을 다시 시도했지만 동일한 문제가 발생했다.
craft-providers error:
A network related operation failed in a context of no network access.
Snapcraft의 로그에서도 빌드 컨테이너가 네트워크가 준비되기를 기다리는 과정이 확인되었다.
Waiting for networking to be ready...
Executing in container:
getent hosts snapcraft.io
즉, Snapcraft 자체의 패키징 설정 문제라기보다 Snapcraft가 사용하는 LXD 빌드 환경에서 외부 네트워크가 정상적으로 연결되지 않는 문제가 남아 있는 상태이다.
이번 실습에서는 다음 과정까지 진행했다.
snapcraft.yaml 확인snapcraft pack 실행FORWARD 정책 확인iptables를 이용한 임시 네트워크 허용 테스트tcpdump를 이용한 패킷 흐름 확인하지만 LXD 컨테이너에서 외부 인터넷으로 나가는 네트워크 연결 문제가 해결되지 않아 최종 Snap 패키지 생성에는 실패했다.
이번 실습에서는 여기까지 진행하고, LXD 네트워크 문제 해결 및 Snap 패키지 생성은 이후에 이어서 진행할 예정이다.