본문으로 건너뛰기

Raspberry Pi 엣지 배포

이 튜토리얼에서는 Caffeine Bridge.Host를 Raspberry Pi에 배포하여 현장 장비 데이터를 수집하는 엣지 게이트웨이를 구성합니다.

개요​

단계주제소요 시간
1개발 환경 준비5분
2ARM 크로스 컴파일10분
3드라이버 설정10분
4Raspberry Pi 배포5분
5systemd 서비스 등록5분
6Offline Buffer 설정10분

사전 요구 사항:

학습 목표:

  • .NET 애플리케이션을 ARM64로 크로스 컴파일할 수 있다
  • Caffeine Bridge.Host를 Raspberry Pi에서 서비스로 운영할 수 있다
  • 네트워크 단절 시 Offline Buffer로 데이터 무손실을 보장할 수 있다

1단계: 개발 환경 준비​

아키텍처 이해​

Bridge.Host는 현장 장비와 직접 통신하며, 수집된 데이터를 클라우드의 Caffeine Engine으로 전송합니다. 네트워크가 불안정한 환경에서는 SQLite 기반 Offline Buffer가 데이터를 로컬에 보관합니다.

Raspberry Pi 확인​

# SSH로 Raspberry Pi 접속
ssh pi@raspberrypi.local

# OS 아키텍처 확인 (arm64 또는 aarch64)
uname -m

# 사용 가능한 메모리 확인
free -h

# .NET이 이미 설치되어 있는지 확인
dotnet --version 2>/dev/null || echo ".NET 미설치 (self-contained 배포 예정)"

Raspberry Pi에 .NET SDK를 설치할 필요 없습니다. Self-contained 배포를 사용하면 .NET 런타임이 앱과 함께 배포됩니다.


2단계: ARM64 Docker 이미지 배포 (권장)​

Caffeine Bridge.Host는 ARM64 Docker 이미지로 제공됩니다:

# Raspberry Pi에서 직접 실행
docker run -d --name bridge-host \
-p 5100:5100 \
--restart unless-stopped \
nexcode/caffeine-bridge-host:latest-arm64

Docker Compose 사용​

services:
bridge-host:
image: nexcode/caffeine-bridge-host:latest-arm64
ports:
- "5100:5100"
volumes:
- ./driver_settings.json:/app/driver_settings.json
- ./drivers:/app/drivers
restart: unless-stopped

Self-contained 배포 (Docker 없이)​

Docker를 사용할 수 없는 환경에서는 Self-contained 바이너리를 직접 배포할 수 있습니다. ARM64 빌드 패키지는 기술 지원을 통해 제공받을 수 있습니다.

옵션설명효과
ARM64 바이너리Raspberry Pi 호환Pi에 .NET 설치 불필요
Self-contained.NET 런타임 포함단일 실행 파일 (~40MB)

3단계: 드라이버 설정​

driver_settings.json​

Bridge.Host가 어떤 드라이버를 로드하고 장비와 어떻게 통신할지 정의합니다:

{
"Driver": {
"Id": "pi-modbus-01",
"Type": "Modbus",
"Port": 502,
"IpAddress": "192.168.1.100",
"Settings": {
"Protocol": "TCP",
"SlaveId": 1,
"PollIntervalMs": 1000,
"Tags": [
{ "Name": "Temperature", "Address": "40001", "Type": "Float" },
{ "Name": "Pressure", "Address": "40003", "Type": "Float" },
{ "Name": "FlowRate", "Address": "40005", "Type": "Float" },
{ "Name": "MotorStatus", "Address": "00001", "Type": "Boolean" }
]
}
}
}

시뮬레이션 모드로 먼저 테스트​

실 장비 연결 전에 시뮬레이션 드라이버로 테스트합니다:

{
"Driver": {
"Id": "pi-sim-01",
"Type": "Simulation",
"Settings": {
"DeviceCount": 2,
"TagsPerDevice": 5,
"UpdateIntervalMs": 1000,
"Scenario": "Normal"
}
}
}

환경변수로 오버라이드​

배포 환경별로 설정을 변경할 때는 환경변수를 사용합니다:

# 장비 IP를 환경변수로 오버라이드
export Driver__IpAddress=192.168.2.50
export Driver__Port=5020

4단계: Raspberry Pi 배포​

파일 전송​

# 개발 PC에서 실행
scp -r ./publish/linux-arm64/* pi@raspberrypi.local:/opt/caffeine/bridge/

디렉토리 구조​

/opt/caffeine/bridge/
├── Caffeine.Bridge.Host ← 실행 파일
├── appsettings.json ← 앱 설정
├── driver_settings.json ← 드라이버 설정
├── drivers/ ← 동적 로드 드라이버 DLL
│ ├── Caffeine.Drivers.Modbus.dll
│ └── Caffeine.Drivers.Simulation.dll
└── data/ ← Offline Buffer DB
└── offline_buffer.db

실행 테스트​

# Raspberry Pi에서 실행
ssh pi@raspberrypi.local

cd /opt/caffeine/bridge
chmod +x Caffeine.Bridge.Host
./Caffeine.Bridge.Host

# 정상 출력 예시:
# [INF] Caffeine Bridge.Host starting...
# [INF] Driver loaded: pi-sim-01 (Simulation)
# [INF] Listening on: http://0.0.0.0:5060
# [INF] Health check: http://0.0.0.0:5060/health

Health Check 확인​

curl http://localhost:5060/health
# {"status":"Healthy","driver":"Connected","uptime":"00:01:23"}

5단계: systemd 서비스 등록​

서비스 파일 생성​

sudo nano /etc/systemd/system/caffeine-bridge.service
[Unit]
Description=Caffeine Bridge.Host Edge Gateway
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/opt/caffeine/bridge/Caffeine.Bridge.Host
WorkingDirectory=/opt/caffeine/bridge
Restart=on-failure
RestartSec=10
User=pi
Environment=DOTNET_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://0.0.0.0:5060

# 리소스 제한 (Raspberry Pi 보호)
MemoryMax=512M
CPUQuota=80%

# 로그
StandardOutput=journal
StandardError=journal
SyslogIdentifier=caffeine-bridge

[Install]
WantedBy=multi-user.target

서비스 활성화 및 시작​

# 서비스 등록
sudo systemctl daemon-reload
sudo systemctl enable caffeine-bridge

# 서비스 시작
sudo systemctl start caffeine-bridge

# 상태 확인
sudo systemctl status caffeine-bridge

# 실시간 로그 확인
journalctl -u caffeine-bridge -f

서비스 관리 명령어​

명령어설명
systemctl start caffeine-bridge서비스 시작
systemctl stop caffeine-bridge서비스 중지
systemctl restart caffeine-bridge서비스 재시작
systemctl status caffeine-bridge상태 확인
journalctl -u caffeine-bridge -f실시간 로그
journalctl -u caffeine-bridge --since "1 hour ago"최근 1시간 로그

6단계: Offline Buffer 설정​

왜 Offline Buffer가 필요한가?​

제조 현장의 네트워크는 불안정할 수 있습니다:

  • 공장 Wi-Fi 간헐적 단절
  • VPN 터널 재연결 지연
  • 네트워크 장비 유지보수

Offline Buffer는 네트워크 단절 시 데이터를 SQLite DB에 로컬 저장하고, 연결 복구 시 **자동으로 전송(FIFO)**합니다.

appsettings.json 설정​

{
"OfflineBuffer": {
"Enabled": true,
"DbPath": "/opt/caffeine/bridge/data/offline_buffer.db",
"MaxSizeMb": 500,
"MessageTtlHours": 72
},
"CloudConnection": {
"Transport": "gRPC",
"EngineUrl": "http://caffeine-engine.local:5050",
"RetryIntervalSeconds": 5
}
}

설정 파라미터​

파라미터기본값설명
EnabledtrueOffline Buffer 활성화
DbPath./offline_buffer.dbSQLite DB 파일 경로
MaxSizeMb500최대 버퍼 크기 (MB)
MessageTtlHours72메시지 보존 기간 (시간)

네트워크 단절 시나리오 실습​

# 1. 정상 동작 확인
curl http://localhost:5060/health
# {"status":"Healthy","cloudConnection":"Connected","bufferedMessages":0}

# 2. 네트워크 단절 시뮬레이션
sudo ip link set eth0 down

# 3. 잠시 후 상태 확인
curl http://localhost:5060/health
# {"status":"Degraded","cloudConnection":"Disconnected","bufferedMessages":42}
# → 데이터가 Offline Buffer에 저장되고 있음

# 4. 네트워크 복구
sudo ip link set eth0 up

# 5. 자동 전송 확인
# 로그에서 "Flushing X buffered messages" 메시지 확인
journalctl -u caffeine-bridge --since "1 minute ago" | grep -i flush
# [INF] Flushing 42 buffered messages to cloud...
# [INF] Flush completed. 42/42 messages sent successfully.

디스크 용량 관리​

Offline Buffer는 두 가지 방식으로 자동 정리됩니다:

  1. TTL 만료: MessageTtlHours 초과 메시지 자동 삭제
  2. 크기 제한: MaxSizeMb 초과 시 가장 오래된 메시지부터 삭제
# 버퍼 DB 크기 확인
du -sh /opt/caffeine/bridge/data/offline_buffer.db
# 12M offline_buffer.db

배운 내용 정리​

항목설명
ARM 크로스 컴파일dotnet publish -r linux-arm64 --self-contained
Self-contained 배포Pi에 .NET 설치 불필요, 단일 바이너리
systemd 서비스자동 시작, 장애 시 자동 재시작, 리소스 제한
Offline BufferSQLite 기반 로컬 버퍼, 재연결 시 FIFO 전송
Health Check/health 엔드포인트로 서비스 상태 모니터링

다음 단계​


문제 해결​

Q: ARM 빌드 시 NETSDK1083 오류가 발생합니다.

linux-arm64 RID가 지원되는 .NET 10 SDK인지 확인하세요. dotnet --list-runtimes로 설치된 런타임을 확인할 수 있습니다.

Q: Raspberry Pi에서 실행 시 Permission denied가 발생합니다.

chmod +x Caffeine.Bridge.Host로 실행 권한을 부여하세요.

Q: systemd 서비스가 시작 직후 종료됩니다.

journalctl -u caffeine-bridge -e로 에러 로그를 확인하세요. 포트 충돌이나 설정 파일 경로 오류일 수 있습니다.

Q: Offline Buffer DB가 계속 커집니다.

MessageTtlHours와 MaxSizeMb 설정을 확인하세요. 클라우드 연결이 장기간 불가능하면 TTL 만료된 메시지가 자동 삭제됩니다.