mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-08 23:46:38 +00:00
build: multi-stage Docker image with uv and BuildKit caching (#1261)
* build: multi-stage Docker image with uv and BuildKit caching Builder/runtime split keeps the toolchain out of the runtime image (standalone ~1.8GB -> ~1.2GB). Dependencies install with uv from uv.lock in a cache-mounted, source-independent layer. Runtime keeps the editable install because akkudoktoreos.core.version needs the src/ layout. Also fixes the io.hass.version label and adds a HEALTHCHECK. * build: address Docker image review feedback - Healthcheck honours EOS_SERVER__PORT instead of hardcoding 8503. - BUILD_VERSION defaults to "dev" rather than the literal "VERSION"; docker-compose passes the real version, and the redundant org.opencontainers.image.version label is dropped (CI sets it via docker/metadata-action). * fix: use resolved server port for container healthcheck --------- Co-authored-by: Normann <github@koldrack.com> Co-authored-by: Normann Koldrack <normann.koldrack@desy.de>
This commit is contained in:
co-authored by
Normann
Normann Koldrack
parent
e9bd55caac
commit
2d18547aaa
@@ -0,0 +1,52 @@
|
||||
"""Lightweight container healthcheck using the port selected by the running server."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from urllib.request import ProxyHandler, build_opener
|
||||
|
||||
PORT_FILE_ENV = "EOS_HEALTHCHECK_PORT_FILE"
|
||||
|
||||
|
||||
def publish_port(port: int) -> None:
|
||||
"""Atomically publish the startup port when container healthchecks are enabled.
|
||||
|
||||
Called after configuration resolution and privilege dropping. This preserves
|
||||
CLI, environment and config-file precedence without loading EOS in the probe.
|
||||
"""
|
||||
filename = os.environ.get(PORT_FILE_ENV)
|
||||
if not filename:
|
||||
return
|
||||
path = Path(filename)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary_path = None
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", encoding="utf-8", dir=path.parent, delete=False
|
||||
) as output:
|
||||
temporary_path = Path(output.name)
|
||||
output.write(str(port))
|
||||
temporary_path.replace(path)
|
||||
finally:
|
||||
if temporary_path is not None:
|
||||
temporary_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Return success only when the selected EOS port serves a healthy response."""
|
||||
try:
|
||||
port = int(Path(os.environ[PORT_FILE_ENV]).read_text(encoding="utf-8"))
|
||||
if not 1 <= port <= 65535:
|
||||
raise ValueError(f"Invalid server port: {port}")
|
||||
# The probe is always local and must not use HTTP_PROXY from the container.
|
||||
opener = build_opener(ProxyHandler({}))
|
||||
with opener.open(f"http://127.0.0.1:{port}/v1/health", timeout=3) as response:
|
||||
return 0 if response.status == 200 else 1
|
||||
except (KeyError, OSError, ValueError) as error:
|
||||
print(f"EOS healthcheck failed: {error}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -73,6 +73,7 @@ from akkudoktoreos.prediction.load import LoadCommonSettings
|
||||
from akkudoktoreos.prediction.loadakkudoktor import LoadAkkudoktorCommonSettings
|
||||
from akkudoktoreos.prediction.pvforecast import PVForecastCommonSettings
|
||||
from akkudoktoreos.prediction.pvforecastpvlib import _cec_inverters, _cec_modules
|
||||
from akkudoktoreos.server.container_healthcheck import publish_port
|
||||
from akkudoktoreos.server.rest.error import (
|
||||
EOSProblem,
|
||||
create_error_page,
|
||||
@@ -2360,6 +2361,9 @@ def run_eos() -> None:
|
||||
# Switch privileges to run_as_user
|
||||
drop_root_privileges(run_as_user=config_eos.server.run_as_user)
|
||||
|
||||
# Publish the effective startup port for the lightweight container probe.
|
||||
publish_port(config_eos.server.port)
|
||||
|
||||
# Init the other singletons (besides config_eos)
|
||||
singletons_init()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user