Separate Python and Rust into python/ and rust/ with per-stack Dockerfiles
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -27,11 +27,11 @@ dist/
|
|||||||
.eggs/
|
.eggs/
|
||||||
|
|
||||||
# Rust / maturin build artifacts
|
# Rust / maturin build artifacts
|
||||||
myfsio_core/target/
|
python/myfsio_core/target/
|
||||||
myfsio_core/Cargo.lock
|
python/myfsio_core/Cargo.lock
|
||||||
|
|
||||||
# Rust engine build artifacts
|
# Rust engine build artifacts
|
||||||
myfsio-engine/target/
|
rust/myfsio-engine/target/
|
||||||
|
|
||||||
# Local runtime artifacts
|
# Local runtime artifacts
|
||||||
logs/
|
logs/
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
ENGINE="${ENGINE:-rust}"
|
|
||||||
|
|
||||||
exec python run.py --prod --engine "$ENGINE"
|
|
||||||
@@ -11,5 +11,7 @@ htmlcov
|
|||||||
logs
|
logs
|
||||||
data
|
data
|
||||||
tmp
|
tmp
|
||||||
|
tests
|
||||||
myfsio_core/target
|
myfsio_core/target
|
||||||
myfsio-engine/target
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM python:3.14.3-slim
|
FROM python:3.14.3-slim AS builder
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
PYTHONUNBUFFERED=1
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /build
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends build-essential curl \
|
&& apt-get install -y --no-install-recommends build-essential curl \
|
||||||
@@ -12,27 +12,34 @@ RUN apt-get update \
|
|||||||
|
|
||||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
COPY requirements.txt ./
|
RUN pip install --no-cache-dir maturin
|
||||||
|
|
||||||
|
COPY myfsio_core ./myfsio_core
|
||||||
|
RUN cd myfsio_core \
|
||||||
|
&& maturin build --release --out /wheels
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.14.3-slim
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt ./
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
COPY . .
|
COPY --from=builder /wheels/*.whl /tmp/
|
||||||
|
RUN pip install --no-cache-dir /tmp/*.whl && rm /tmp/*.whl
|
||||||
|
|
||||||
RUN pip install --no-cache-dir maturin \
|
COPY app ./app
|
||||||
&& cd myfsio_core \
|
COPY templates ./templates
|
||||||
&& maturin build --release \
|
COPY static ./static
|
||||||
&& pip install target/wheels/*.whl \
|
COPY run.py ./
|
||||||
&& cd ../myfsio-engine \
|
COPY docker-entrypoint.sh ./
|
||||||
&& cargo build --release \
|
|
||||||
&& cp target/release/myfsio-server /usr/local/bin/myfsio-server \
|
|
||||||
&& cd .. \
|
|
||||||
&& rm -rf myfsio_core/target myfsio-engine/target \
|
|
||||||
&& pip uninstall -y maturin \
|
|
||||||
&& rustup self uninstall -y
|
|
||||||
|
|
||||||
RUN chmod +x docker-entrypoint.sh
|
RUN chmod +x docker-entrypoint.sh \
|
||||||
|
&& mkdir -p /app/data \
|
||||||
RUN mkdir -p /app/data \
|
|
||||||
&& useradd -m -u 1000 myfsio \
|
&& useradd -m -u 1000 myfsio \
|
||||||
&& chown -R myfsio:myfsio /app
|
&& chown -R myfsio:myfsio /app
|
||||||
|
|
||||||
@@ -41,8 +48,7 @@ USER myfsio
|
|||||||
EXPOSE 5000 5100
|
EXPOSE 5000 5100
|
||||||
ENV APP_HOST=0.0.0.0 \
|
ENV APP_HOST=0.0.0.0 \
|
||||||
FLASK_ENV=production \
|
FLASK_ENV=production \
|
||||||
FLASK_DEBUG=0 \
|
FLASK_DEBUG=0
|
||||||
ENGINE=rust
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
CMD python -c "import requests; requests.get('http://localhost:5000/myfsio/health', timeout=2)"
|
CMD python -c "import requests; requests.get('http://localhost:5000/myfsio/health', timeout=2)"
|
||||||
4
python/docker-entrypoint.sh
Normal file
4
python/docker-entrypoint.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
exec python run.py --prod
|
||||||
@@ -5,7 +5,6 @@ import argparse
|
|||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
@@ -75,49 +74,6 @@ def _serve_granian(target: str, port: int, config: Optional[AppConfig] = None) -
|
|||||||
server.serve()
|
server.serve()
|
||||||
|
|
||||||
|
|
||||||
def _find_rust_binary() -> Optional[Path]:
|
|
||||||
candidates = [
|
|
||||||
Path("/usr/local/bin/myfsio-server"),
|
|
||||||
Path(__file__).parent / "myfsio-engine" / "target" / "release" / "myfsio-server.exe",
|
|
||||||
Path(__file__).parent / "myfsio-engine" / "target" / "release" / "myfsio-server",
|
|
||||||
Path(__file__).parent / "myfsio-engine" / "target" / "debug" / "myfsio-server.exe",
|
|
||||||
Path(__file__).parent / "myfsio-engine" / "target" / "debug" / "myfsio-server",
|
|
||||||
]
|
|
||||||
for p in candidates:
|
|
||||||
if p.exists():
|
|
||||||
return p
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def serve_rust_api(port: int, config: Optional[AppConfig] = None) -> None:
|
|
||||||
binary = _find_rust_binary()
|
|
||||||
if binary is None:
|
|
||||||
print("ERROR: Rust engine binary not found. Build it first:")
|
|
||||||
print(" cd myfsio-engine && cargo build --release")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
env = os.environ.copy()
|
|
||||||
env["PORT"] = str(port)
|
|
||||||
env["HOST"] = _server_host()
|
|
||||||
if config:
|
|
||||||
env["STORAGE_ROOT"] = str(config.storage_root)
|
|
||||||
env["AWS_REGION"] = config.aws_region
|
|
||||||
if config.secret_key:
|
|
||||||
env["SECRET_KEY"] = config.secret_key
|
|
||||||
env.setdefault("ENCRYPTION_ENABLED", str(config.encryption_enabled).lower())
|
|
||||||
env.setdefault("KMS_ENABLED", str(config.kms_enabled).lower())
|
|
||||||
env.setdefault("LIFECYCLE_ENABLED", str(config.lifecycle_enabled).lower())
|
|
||||||
env.setdefault("RUST_LOG", "info")
|
|
||||||
|
|
||||||
print(f"Starting Rust S3 engine: {binary}")
|
|
||||||
proc = subprocess.Popen([str(binary)], env=env)
|
|
||||||
try:
|
|
||||||
proc.wait()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
proc.terminate()
|
|
||||||
proc.wait(timeout=5)
|
|
||||||
|
|
||||||
|
|
||||||
def serve_api(port: int, prod: bool = False, config: Optional[AppConfig] = None) -> None:
|
def serve_api(port: int, prod: bool = False, config: Optional[AppConfig] = None) -> None:
|
||||||
if prod:
|
if prod:
|
||||||
_serve_granian("app:create_api_app", port, config)
|
_serve_granian("app:create_api_app", port, config)
|
||||||
@@ -271,7 +227,6 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument("--ui-port", type=int, default=5100)
|
parser.add_argument("--ui-port", type=int, default=5100)
|
||||||
parser.add_argument("--prod", action="store_true", help="Run in production mode using Granian")
|
parser.add_argument("--prod", action="store_true", help="Run in production mode using Granian")
|
||||||
parser.add_argument("--dev", action="store_true", help="Force development mode (Flask dev server)")
|
parser.add_argument("--dev", action="store_true", help="Force development mode (Flask dev server)")
|
||||||
parser.add_argument("--engine", choices=["python", "rust"], default=os.getenv("ENGINE", "python"), help="API engine: python (Flask) or rust (myfsio-engine)")
|
|
||||||
parser.add_argument("--check-config", action="store_true", help="Validate configuration and exit")
|
parser.add_argument("--check-config", action="store_true", help="Validate configuration and exit")
|
||||||
parser.add_argument("--show-config", action="store_true", help="Show configuration summary and exit")
|
parser.add_argument("--show-config", action="store_true", help="Show configuration summary and exit")
|
||||||
parser.add_argument("--reset-cred", action="store_true", help="Reset admin credentials and exit")
|
parser.add_argument("--reset-cred", action="store_true", help="Reset admin credentials and exit")
|
||||||
@@ -325,17 +280,9 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
print("Running in development mode (Flask dev server)")
|
print("Running in development mode (Flask dev server)")
|
||||||
|
|
||||||
use_rust = args.engine == "rust"
|
|
||||||
|
|
||||||
if args.mode in {"api", "both"}:
|
if args.mode in {"api", "both"}:
|
||||||
if use_rust:
|
print(f"Starting API server on port {args.api_port}...")
|
||||||
print(f"Starting Rust API engine on port {args.api_port}...")
|
api_proc = Process(target=serve_api, args=(args.api_port, prod_mode, config))
|
||||||
else:
|
|
||||||
print(f"Starting API server on port {args.api_port}...")
|
|
||||||
if use_rust:
|
|
||||||
api_proc = Process(target=serve_rust_api, args=(args.api_port, config))
|
|
||||||
else:
|
|
||||||
api_proc = Process(target=serve_api, args=(args.api_port, prod_mode, config))
|
|
||||||
api_proc.start()
|
api_proc.start()
|
||||||
else:
|
else:
|
||||||
api_proc = None
|
api_proc = None
|
||||||
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 872 KiB After Width: | Height: | Size: 872 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user