From 663999f17371f41ec10bf0cf3af452242b4cd9e4 Mon Sep 17 00:00:00 2001 From: chy ky Date: Wed, 4 Mar 2026 16:04:19 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=94=AF=E6=8C=81=E7=BA=AF?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 1 - README.md | 82 ++++++++++++++++++++++++++++++++++++++++++++-- docker-compose.yml | 5 ++- 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index aea52c4..95027a5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,5 +6,4 @@ RUN pip install --no-cache-dir --prefix=/install -r requirements.txt FROM python:3.13-slim-bookworm WORKDIR /app COPY --from=builder /install /usr/local -COPY app/ ./app/ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7000", "--workers", "4"] diff --git a/README.md b/README.md index f30494a..9213e53 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,80 @@ If you prefer the repository root entrypoint, `uv run main.py` now starts the sa ## Dependency Management - Local Python development uses `uv` via [`pyproject.toml`](/d:/project/sentinel/pyproject.toml). -- Container builds still use [`requirements.txt`](/d:/project/sentinel/requirements.txt) because the Dockerfile is intentionally minimal and matches the delivery requirements. +- The container runtime image uses [`requirements.txt`](/d:/project/sentinel/requirements.txt) and intentionally installs only Python dependencies. +- Application source code is mounted by Compose at runtime, so the offline host does not need to rebuild the image just to load the current backend code. + +## Offline Deployment Model + +If your production machine has no internet access, the current repository should be used in this way: + +1. Build the `key-ip-sentinel:latest` image on a machine with internet access. +2. Export that image as a tar archive. +3. Import the archive on the offline machine. +4. Place the repository files on the offline machine. +5. Start the stack with `docker compose up -d`, not `docker compose up --build -d`. + +This works because: + +- `Dockerfile` installs only Python dependencies into the image. +- `docker-compose.yml` mounts `./app` into the running `sentinel-app` container. +- The offline machine only needs the prebuilt image plus the repository files. + +Important limitation: + +- If you change Python dependencies in `requirements.txt`, you must rebuild and re-export the image on a connected machine. +- If you only change backend application code under `app/`, you do not need to rebuild the image; restarting the container is enough. +- `frontend/dist` must already exist before deployment, because Nginx serves the built frontend directly from the repository. +- The base images used by this stack, such as `nginx:alpine`, `redis:7-alpine`, and `postgres:16`, must also be available on the offline host in advance. + +### Prepare images on a connected machine + +Build and export the Sentinel runtime image: + +```bash +docker build -t key-ip-sentinel:latest . +docker save -o key-ip-sentinel-latest.tar key-ip-sentinel:latest +``` + +Also export the public images used by Compose if the offline machine cannot pull them: + +```bash +docker pull nginx:alpine +docker pull redis:7-alpine +docker pull postgres:16 + +docker save -o sentinel-support-images.tar nginx:alpine redis:7-alpine postgres:16 +``` + +If the admin frontend is not already built, build it on the connected machine too: + +```bash +cd frontend +npm install +npm run build +cd .. +``` + +Then copy these items to the offline machine: + +- the full repository working tree +- `key-ip-sentinel-latest.tar` +- `sentinel-support-images.tar` if needed + +### Import images on the offline machine + +```bash +docker load -i key-ip-sentinel-latest.tar +docker load -i sentinel-support-images.tar +``` + +### Start on the offline machine + +After `.env`, `frontend/dist`, and `shared_network` are ready: + +```bash +docker compose up -d +``` ## Production Deployment @@ -278,17 +351,22 @@ cd .. This produces `frontend/dist`, which Nginx serves at `/admin/ui/`. +If the target host is offline, do this on a connected machine first and copy the resulting `frontend/dist` directory with the repository. + ### 5. Confirm Sentinel compose prerequisites - Build the frontend first. If `frontend/dist` is missing, `/admin/ui/` cannot be served by Nginx. - Ensure the external Docker network `shared_network` already exists before starting Sentinel. +- Ensure `key-ip-sentinel:latest`, `nginx:alpine`, `redis:7-alpine`, and `postgres:16` are already present on the host if the host cannot access the internet. ### 6. Start the Sentinel stack ```bash -docker compose up --build -d +docker compose up -d ``` +Use `docker compose up --build -d` only on a connected machine where rebuilding the Sentinel image is actually intended. + Services: - `http:///` forwards model API traffic through Sentinel. diff --git a/docker-compose.yml b/docker-compose.yml index 79cb3c3..0dcc0ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,14 +14,13 @@ services: - sentinel-net sentinel-app: - build: - context: . - dockerfile: Dockerfile image: key-ip-sentinel:latest container_name: sentinel-app restart: unless-stopped env_file: - .env + volumes: + - ./app:/app/app:ro depends_on: - redis - postgres