Linux (서버)
매니저는 Docker 이미지 (ongrid:<version>) 로 출하되며 docker compose 를 통해 운영됩니다. 둘 다 make package 가 생산하는 릴리스 tarball 에서 옵니다 — apt install ongrid 없음, 호스트 측 데몬 없음.
지원 배포판
다음 호스트에서 매니저를 일상적으로 실행합니다. Docker Engine 24+ 를 실행하는 모든 것이 동작해야 합니다; 아래 리스트는 릴리스별로 명시적 테스트되는 것.
| Distribution | Tested on |
|---|---|
| Ubuntu | 22.04 LTS, 24.04 LTS |
| Debian | 12 (bookworm) |
| RHEL | 9 |
| Rocky Linux | 9 |
| AlmaLinux | 9 |
CentOS 7 은 지원되지 않음 — 번들 Compose 스택에 glibc 와 systemd 가 너무 오래되었고 업스트림 EOL 에 도달.
필수 소프트웨어
- Docker Engine 24.0 이상. 이전 릴리스는
make docker-build가 의존하는--platform배관이 없고extra_hosts: host-gateway를 깨뜨림. - Docker Compose v2 (
docker composeCLI 플러그인, 레거시docker-compose바이너리가 아님).deploy/docker-compose.yml의 compose 파일은 의도적으로 최상위version:키를 생략, v1 이 거부. - 호스트용 systemd. 매니저 자체는 systemd unit 을 등록하지 않음 — 설치 스크립트
deploy/install/server-install.sh는 Docker 시작에만 systemd 의존 — 하지만 재부팅 시 자동 재시작은docker.service활성화 필요. - iptables / nftables 어느 쪽도 좋음; 두 백엔드 모두 동작.
Docker 자체가 필요한 것 (overlayfs, namespaces, cgroups v1 또는 v2) 외에 필수 커널 모듈 없음.
자원 하한
| Resource | Floor | 권장 | Why |
|---|---|---|---|
| CPU | 2 vCPU | 4 vCPU | 매니저 Go 프로세스, Prometheus, Loki, Tempo, Grafana, MySQL 모두 같은 호스트에 거주. |
| Memory | 4 GB | 8 GB | Prometheus + Loki 합쳐 idle 에 1.5 GB 도달 가능. 여유 공간이 OOM killer 가 MySQL 에 닿지 않게 함. |
| Disk | 20 GB | 100 GB | Prometheus 보존은 기본 90 일 / 20 GB (compose 파일의 --storage.tsdb.retention.* 참고). Loki + Tempo 가 나머지 공유. |
| Network | 10 Mbps | 100 Mbps | 텔레메트리는 데이터 플레인 — 많은 edge 의 로그 전송이 매니저 자체보다 먼저 얇은 파이프를 포화시킬 수 있음. |
20 GB 하한은 소수의 edge 로만 테스트할 때 가정. 메트릭 + 로그 + 트레이스를 보내는 ~25 호스트를 넘으면 Loki 30 일 유지만 위해 200 GB 계획.
포트
| Port | 방향 | Protocol | 무엇 |
|---|---|---|---|
| 443 | inbound | HTTPS | nginx — SPA, REST API, 로그/트레이스 인제스트 |
| 80 | inbound | HTTP | nginx 가 443 으로 리다이렉트 |
| 40012 | inbound | TCP (geminio) | Frontier 브로커 — 모든 edge 가 이걸 다이얼 |
| 3306 | 로컬 노출 | TCP | MySQL — 프로덕션에서 127.0.0.1 에 바인드 |
| 9090 | 로컬 노출 | HTTP | Prometheus — 프로덕션에서 127.0.0.1 에 바인드 |
| 9100 | inbound (선택) | HTTP | 매니저 /metrics — 외부 Prometheus 가 scrape 용 |
443, 80, 40012 만 공인 인터넷 (또는 edge 함대의 네트워크) 에서 도달 가능해야 함. 그 외 모든 것은 프로덕션에서 localhost 에 바인드된 채로 유지 — nginx 가 API 를 front 하고, Grafana / Prometheus / Loki / Tempo 는 docker 네트워크로 도달.
Compose 스택이 실행하는 것
deploy/docker-compose.yml 에서:
| Service | Image | Role |
|---|---|---|
mysql | mysql:8.0 | 매니저의 주 저장소 (users, edges, devices, alert rules, sessions). |
ongrid | ongrid:<version> | 매니저 — cmd/ongrid 에서 빌드된 Go 바이너리. |
nginx | ongrid-web:<version> | TLS 종단, SPA, /api/* 리버스 프록시, 설치 번들용 /edge/* 정적. |
frontier | singchia/frontier:1.2.5 | Geminio 브로커; edge 터널 엔드포인트 (ADR-007). |
prometheus | prom/prometheus:v2.54.0 | 메트릭 저장소 + remote_write 수신기 (ADR-009). |
loki | grafana/loki:3.4.0 | 로그 저장소 (ADR-012). |
tempo | grafana/tempo:2.5.0 | 트레이스 저장소 (ADR-013). |
searxng | searxng/searxng:latest | web_search 기능용 셀프 호스트 검색 백엔드. |
grafana | grafana/grafana-oss:11.1.4 | Monitor 페이지용 대시보드 임베드. |
Compose 파일이 프로덕션 형태 — 두 번째 "prod" 파일 없음. YAML 을 포크하는 대신 env 블록 (ONGRID_* — 환경 변수 참고) 으로 노브 오버라이드.
TLS
nginx 가 deploy/certs/ 에서 bind-mount 된 인증서 (cert.pem, key.pem) 로 TLS 종단. 첫 부팅에 설치 스크립트가 self-signed 인증서 생성; 언제든 실제 인증서로 교체하고 docker compose restart nginx. Let's Encrypt 는 deploy/README.md 에 문서화된 사이드카 패턴으로 지원.
SELinux + AppArmor
박스 그대로 동작. compose 파일은 민감한 호스트 경로를 read-write 로 마운트하지 않음; bind mount (./edge, ./nginx, ./certs, ./grafana/provisioning) 모두 :ro. SELinux 정책이 bind mount 에 엄격한 레이블을 강제한다면 docker-compose.override.yml 의 마운트 문자열에 :Z append.
업그레이드
make package # produces dist/out/ongrid-vX.Y.Z-linux-amd64.tar.xz
scp dist/out/ongrid-vX.Y.Z-linux-amd64.tar.xz host:/tmp/
ssh host /tmp/upgrade.shupgrade.sh 는 tarball 옆에 살며 멱등 동작 수행: 새 이미지 로드, 새 태그를 고정하는 임시 docker-compose.override.yml 작성, docker compose up -d, 1 분 healthy 후 이전 이미지 prune. 업그레이드 참고.
동작하지 않는 것
- Podman + podman-compose: compose 파일은 podman 이 호환되지 않게 파싱하거나 무시하는 Docker 특화 단축 표기 (
extra_hosts: host-gateway,:ZSELinux 의미) 사용. 테스트하지 않음. - K3s 호스트 모드 네트워킹: 매니저에는 동작하지만 edge installer 가 bare systemd 중심으로 빌드 — daemonset 패턴은 Kubernetes 참고.
- OpenRC / runit / s6: 매니저 컨테이너는 신경 쓰지 않지만 호스트의 Docker daemon 이 부팅 시 올라와야 함. init 시스템이 그것을 할 수 있다면 괜찮음.