배포
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=MLOps Central Platform 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 을 받으면 전송을 중단하고, 처리 중인 큐 항목을 대기 상태로 되돌리고, DB 를 닫은 뒤 종료한다(에이전트 자체 유예 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의link.state는 계속offline,GET /api/v1/settings의central.configured는false.
디바이스 토큰 교체
토큰 유효 기간은 1년, 교체는 현장에서 수행해야 하는 작업. 장비에 새 토큰을 원격으로 전달하는 방법은 없음.
-
중앙에서 디바이스 상세 토큰 관리 카드의 ① 회전 클릭. 새 토큰이 한 번만 표시되므로 복사. (② 회수 는 모든 토큰을 무효화할 뿐 새로 발급하지 않음.)
토큰 관리 카드: ① 회전(새 토큰 발급) ② 회수(모든 토큰 무효화) -
그 순간부터 장비의 다음 호출은
401로 거부, 에이전트는 링크를auth_failed로 전환하고 중앙 호출을 스스로 중단. 거부될 요청으로 서버에 부담을 주지 않기 위한 동작. 명령 폴링도 함께 중단되므로 재시작 명령도 전달되지 않음. -
장비에서
/etc/geo-mlops/edge.env의GEO_EDGE_CENTRAL__TOKEN을 새 값으로 변경하고 서비스 재시작.sudo systemctl restart geo-mlops-edge # 또는: docker compose up -d
그동안에도 수집은 계속. 데이터는 로컬 큐에 누적되었다가 새 토큰으로 연결되면 업로드.
토큰 만료까지 남은 일수는 플릿 API(GET /api/v1/edge/fleet, GET /api/v1/edge/devices/{id})의 token_expires_in_days 로 확인. 화면에는 표시되지 않음. 만료 전 현장 방문 일정에 토큰 교체 포함 필요.