배포
에이전트를 systemd 서비스나 Docker 컨테이너로 상시 실행하고, 디바이스 토큰을 교체한다
운영 장비에서는 에이전트를 감시자(supervisor, 프로세스가 끝나면 다시 띄워 주는 프로그램) 아래에서 돌립니다. 에이전트는 스스로 다시 실행하지 않습니다. 그래서 서버의 재시작 명령(종료 코드 3)이나 충돌, 정전 뒤에는 누군가 다시 띄워 줘야 합니다. systemd 나 Docker 중 하나를 고릅니다.
어느 쪽이든 파일은 둘입니다.
| 파일 | 내용 | 권한 |
|---|---|---|
/etc/geo-mlops/edge.yaml | 현장 구성(장비 이름, 수집기, 보존 한도) | 읽기 가능 |
/etc/geo-mlops/edge.env | 비밀. GEO_EDGE_*=값 을 한 줄에 하나씩. 최소 GEO_EDGE_CENTRAL__TOKEN | 600, 소유자만 |
systemd
-
전용 계정과 가상환경을 만들고 설치합니다.
sudo useradd --system --home /var/lib/geo-mlops-edge --shell /usr/sbin/nologin geo-mlops sudo python3 -m venv /opt/geo-mlops/venv sudo /opt/geo-mlops/venv/bin/pip install 'geo-mlops-sdk[edge,gpu,modbus]>=0.2,<0.3' -
설정 파일 두 개를 둡니다.
sudo mkdir -p /etc/geo-mlops sudo cp edge.yaml /etc/geo-mlops/edge.yaml echo 'GEO_EDGE_CENTRAL__TOKEN=<device-token>' | sudo tee /etc/geo-mlops/edge.env >/dev/null sudo chmod 600 /etc/geo-mlops/edge.env -
아래 유닛을
/etc/systemd/system/geo-mlops-edge.service로 저장하고 켭니다.sudo systemctl daemon-reload sudo systemctl enable --now geo-mlops-edge journalctl -u geo-mlops-edge -f
# /etc/systemd/system/geo-mlops-edge.service
[Unit]
Description=Geo-MLOps edge agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=geo-mlops
Group=geo-mlops
# 비밀은 여기서. 토큰을 바꿀 때 고치는 곳도 이 파일이다
EnvironmentFile=-/etc/geo-mlops/edge.env
Environment=GEO_EDGE_CONFIG=/etc/geo-mlops/edge.yaml
ExecStart=/opt/geo-mlops/venv/bin/geo-mlops-edge run
WorkingDirectory=/var/lib/geo-mlops-edge
# 0(정지 요청)·3(재시작 요청)·충돌 모두 다시 띄운다
Restart=always
RestartSec=2
# SIGTERM 이면 보내던 청크를 끝내고 큐를 정리한 뒤 끝난다(에이전트 자체 유예 20초)
KillSignal=SIGTERM
TimeoutStopSec=45
# 에이전트가 쓰는 곳은 한 군데뿐
StateDirectory=geo-mlops-edge
ReadWritePaths=/var/lib/geo-mlops-edge
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target
ProtectSystem=strict이므로 에이전트는/var/lib/geo-mlops-edge에만 씁니다. watchdir 수집기가 다른 폴더(예:/data/incoming)의 파일을 옮겨야 한다면ReadWritePaths=에 그 폴더를 더합니다./opt/geo-mlops/venv가 아닌 곳에 설치했다면ExecStart를 바꿉니다.
Docker
이미지는 필요한 엑스트라만 넣어 만듭니다. 모델 엑스트라는 PyTorch 까지 설치해 1 GB 가까이 되므로, 데이터만 보내는 장비는 edge,modbus 로 충분합니다.
# Dockerfile
FROM python:3.12-slim
ARG EXTRAS=edge
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
GEO_EDGE_DATA_DIR=/var/lib/geo-mlops-edge
RUN pip install --upgrade pip \
&& pip install "geo-mlops-sdk[${EXTRAS}]>=0.2,<0.3"
# 큐와 모델 캐시는 컨테이너보다 오래 살아야 한다
VOLUME ["/var/lib/geo-mlops-edge"]
RUN useradd --system --create-home --home-dir /var/lib/geo-mlops-edge geo-mlops \
&& chown -R geo-mlops:geo-mlops /var/lib/geo-mlops-edge
USER geo-mlops
EXPOSE 8600
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import httpx,sys; sys.exit(0 if httpx.get('http://127.0.0.1:8600/health', timeout=3).status_code==200 else 1)"
ENTRYPOINT ["geo-mlops-edge"]
CMD ["run"]
docker build --build-arg EXTRAS='edge,modbus' -t geo-mlops-edge .
docker build --build-arg EXTRAS='edge,gpu,yolo' -t geo-mlops-edge:yolo .
docker compose
# docker-compose.yml
name: geo-mlops-edge
services:
edge:
build:
context: .
args:
EXTRAS: ${EDGE_EXTRAS:-edge,modbus}
image: geo-mlops-edge:latest
container_name: geo-mlops-edge
restart: unless-stopped
env_file:
- path: /etc/geo-mlops/edge.env
required: false
volumes:
- edge-state:/var/lib/geo-mlops-edge # 큐·모델 캐시
- /etc/geo-mlops:/etc/geo-mlops:ro # edge.yaml 을 기본 경로에서 읽는다
- ${EDGE_INCOMING:-/data/incoming}:/data/incoming # watchdir 수집기용
ports:
- "${EDGE_API_PORT:-8600}:8600"
volumes:
edge-state:
name: geo-mlops-edge-state
docker compose up -d --build # 빌드 + (재)시작
docker compose logs -f edge
docker compose down # 정지 (큐와 모델 캐시는 남는다)
docker compose down -v # 정지 + 상태 볼륨까지 삭제. 보내지 못한 데이터도 사라진다
- 컨테이너 안에서는
/etc/geo-mlops/edge.yaml이 기본 탐색 경로이므로 따로 넘길 것이 없습니다. edge.yaml의api.host는0.0.0.0이어야 포트 매핑으로 접근됩니다.edge.env에 있는GEO_EDGE_*키를 compose 의environment:에 다시 적지 마세요. compose 는environment:를env_file보다 우선하므로, 토큰을 교체해도 옛 값이 조용히 쓰입니다.- 두 파일 모두 없어도 컨테이너는 기본값으로 뜹니다. 그때는
status가 보낼 곳이 없다는 것을 알려 줍니다.
디바이스 토큰 교체
토큰은 1년 동안 유효하고, 교체는 현장에서 해야 하는 작업입니다. 장비에 새 토큰을 원격으로 넣을 방법은 없습니다.
-
중앙에서 디바이스 상세 토큰 관리 카드의 ① 회전 을 누릅니다. 새 토큰이 한 번만 표시되니 복사합니다. (② 회수 는 모든 토큰을 무효로 만들 뿐 새로 발급하지 않습니다.)
토큰 관리 카드: ① 회전(새 토큰 발급) ② 회수(모든 토큰 무효화) -
그 순간부터 장비의 다음 호출은
401로 거절되고, 에이전트는 링크를auth_failed로 두고 스스로 멈춥니다. 어차피 거절될 요청을 계속 보내 서버에 부담을 주지 않으려는 것입니다. 명령 폴링도 함께 멈추므로 재시작 명령도 닿지 않습니다. -
장비에서
/etc/geo-mlops/edge.env의GEO_EDGE_CENTRAL__TOKEN을 새 값으로 바꾸고 서비스를 다시 시작합니다.sudo systemctl restart geo-mlops-edge # 또는: docker compose up -d
그동안에도 수집은 계속됩니다. 데이터는 로컬 큐에 쌓였다가, 새 토큰으로 연결되면 올라갑니다.
플릿 API 는 토큰 남은 날수(token_expires_in_days)를 알려 줍니다. 갑자기 만료되지 않도록, 만료 전 현장 방문 일정에 토큰 교체를 넣어 두세요.