Air-gapped installation
Installing on a site with no internet — importing image tars, turning off the package proxies, preloading pretrained weights
With the default settings, Geo-MLOps goes out to the internet in a few places. In an air-gapped network, each of those points needs preparation: fetch in advance, redirect to an internal mirror, or turn off. This page starts by listing what uses the internet, and where.
Where the internet is used
| When | What is downloaded | In an air-gapped network |
|---|---|---|
Building the app image (docker compose up --build) | uv, kubectl, Python packages | Build on an internet-connected network and import as a tar |
| Starting the Compose services | Public images such as Postgres, RustFS, Prometheus | Import as a tar |
| Installing k3s, the device plugin | k3s binary and images, nvcr.io/nvidia/k8s-device-plugin | The official k3s air-gap install + image import |
| Publishing shared images (builds inside the cluster) | docker.io/moby/buildkit:v0.18.2-rootless, pip and apt packages, PyTorch wheels | Point at internal mirrors, or import images baked outside |
| Running training | Pretrained weights (checkpoints) | Preload them into the weights mirror and turn off internet download |
1. Import container images
-
On a PC with internet access, build the app image from the same version of the source, and check the image names Compose uses.
docker compose -f /opt/geo-mlops/docker-compose.yml build docker compose -f /opt/geo-mlops/docker-compose.yml pull --ignore-buildable docker compose -f /opt/geo-mlops/docker-compose.yml config --images -
Bundle all the images listed above into one tar and carry it over. Bundle the images for cluster pods (BuildKit rootless, device plugin) separately.
docker save -o geo-mlops-compose.tar $(docker compose -f /opt/geo-mlops/docker-compose.yml config --images) docker pull docker.io/moby/buildkit:v0.18.2-rootless docker pull nvcr.io/nvidia/k8s-device-plugin:v0.19.3 docker save -o geo-mlops-k3s.tar docker.io/moby/buildkit:v0.18.2-rootless nvcr.io/nvidia/k8s-device-plugin:v0.19.3 -
On the air-gapped server, load them and start without building.
docker load -i geo-mlops-compose.tar sudo k3s ctr images import geo-mlops-k3s.tar docker compose -f /opt/geo-mlops/docker-compose.yml up -d --no-build
Images that the platform normally bakes inside the cluster, such as the training runtime, can also be baked outside and brought in. Upload the tar made with docker save through Container Registry (컨테이너 레지스트리) → Import image (이미지 반입) in the web UI, then register that image as an External image (외부 이미지) variant on the training runtime screen. External image variants have no publish (build) step.
2. Build package proxies
The proxpi (pip) and apt-cacher-ng (apt) that come with Compose are only caches, not mirrors. If they cannot reach the internet they cannot be filled, and a build that goes through an empty cache fails. Choose one of the two.
| Choice | Setting (app.env) |
|---|---|
| You have internal mirrors — you run a pip index and an apt mirror internally | GEO_MLOPS_BUILD_PIP_INDEX_URL=http://<internal-pip-mirror>/simple/GEO_MLOPS_BUILD_APT_PROXY=http://<internal-apt-proxy>:3142If needed, also point GEO_MLOPS_TRAINING_RUNTIME_TORCH_INDEX at an internal PyTorch wheel index |
| You have no mirrors — turn off proxy injection | GEO_MLOPS_BUILD_PACKAGE_PROXY_ENABLED=false |
# /etc/geo-mlops/app.env — environment without proxies
GEO_MLOPS_BUILD_PACKAGE_PROXY_ENABLED=false
- This is the only switch that turns them off. Leaving the address settings empty does not mean "off"; it means "use the default addresses (
10.42.0.1:5000,:3142)". - When they are off, builds go directly to PyPI and the Debian repositories. In an air-gapped network those builds fail too, so if you have no mirrors, import images baked outside as in section 1 above.
- After changing the setting, recreate the app (
docker compose … up -d app) and republish the serving builder once — see "Republish images" in Upgrade. - If the Build cache (빌드 캐시) screen shows both proxies as "Off (꺼져 있음)", they are properly off. If they are left on while a proxy is down, it shows "Failure (장애)", and every build in that state fails.
3. Preload pretrained weights
Training uses pretrained checkpoints (for example, YOLO and RF-DETR weights) when it starts. The platform keeps them in the weights mirror in the object store and places them in the pod in advance. With the default settings, if a checkpoint is not in the mirror, the stager downloads it from the internet and fills the mirror. In an air-gapped network, turn off this internet download and fill the mirror by hand.
# /etc/geo-mlops/app.env
GEO_MLOPS_TRAINING_WEIGHTS_UPSTREAM_FETCH=false
-
See which weights are in the catalog and what is in the mirror.
docker exec geo-mlops-app ./run geo-mlops-admin weights list # rf-detr rf-detr-nano 349.3MB -- # yolo yolo11n 5.4MB -- # -> 0/16 mirrored, 3.6GB total -
Copy the checkpoint file you fetched from the internet-connected network into the app container, and push it together with the catalog's model key. If the file's MD5 differs from the catalog, it is rejected, so there is no risk of a wrong file getting in.
docker cp ./rf-detr-nano.pth geo-mlops-app:/tmp/rf-detr-nano.pth docker exec geo-mlops-app ./run geo-mlops-admin weights push rf-detr-nano /tmp/rf-detr-nano.pth # rf-detr/rf-detr-nano: pushed -
On the Weights mirror (가중치 미러) screen in the system console, check that the model's mirror column changed from "Not yet (아직 없음)" to "Present (있음)". With internet download off, "Auto-fetch off (자동 확보 꺼짐)" appears at the top of the screen. If the same model key exists in several frameworks, you get an error asking you to add
--framework.Weights mirror — pretrained checkpoints kept in in-house storage
Submitting training with weights that are not in the mirror does not block the training. But with internet download off, the trainer may try to download them itself and fail, so put the models you will use in the mirror in advance.
4. Web UI
Build the web UI's static files on the internet-connected network too (npm ci && npm run build) and bring over dist/. The method is the same as "Deploy the web UI" in Install with Docker Compose.
The full list of settings is in the Reference.