diff --git a/workspace/sprint_1_2/CODEBASE/deps/implementation/backend_deploy/gitea_modal_build.py b/workspace/sprint_1_2/CODEBASE/deps/implementation/backend_deploy/gitea_modal_build.py index e0fc232..84d521c 100644 --- a/workspace/sprint_1_2/CODEBASE/deps/implementation/backend_deploy/gitea_modal_build.py +++ b/workspace/sprint_1_2/CODEBASE/deps/implementation/backend_deploy/gitea_modal_build.py @@ -22,36 +22,40 @@ import json import os from pathlib import Path import subprocess - import modal # ============================================================================= # Configuration # ============================================================================= - -APP_NAME = "msk-lumina-backend-builder" - -# Default registry/image settings DEFAULT_REGISTRY = "public.ecr.aws/i9a4e3f6/msk-cv-inference-server" DEFAULT_IMAGE_NAME = "msk-lumina-backend" DEFAULT_TAG = "latest" - -# Modal secret for ECR credentials -ECR_SECRET_NAME = "ecr-credentials" +APP_NAME = "msk-lumina-backend-builder" # ============================================================================= -# Modal Image Definition - Kaniko-based builder (no Docker daemon required) +# Modal Image Definition # ============================================================================= +# 1. Start from Kaniko to extract the binary, and map it to a local folder via an App build +kaniko_image = ( + modal.Image.from_registry("gcr.io/kaniko-project/executor:debug") + .add_local_dir(os.getcwd(), remote_path="/workspace") +) -# We bake the project source into the image at /workspace so Kaniko can access -# the build context and Dockerfile at runtime. -# The Dockerfile path is resolved at runtime, not at image build time. +# 2. Build your final builder image on a clean Debian system that HAS apt-get builder_image = ( modal.Image.debian_slim() .apt_install("curl", "ca-certificates") - .run_commands( - "curl -sSL https://github.com/chainguard-forks/kaniko/releases/latest/download/kaniko-linux-amd64 -o /usr/local/bin/kaniko", - "chmod +x /usr/local/bin/kaniko", + .pip_install("boto3") + + # Use standard dockerfile_commands to copy the binary directly from the Kaniko base image layer + .dockerfile_commands( + [ + "COPY --from=gcr.io/kaniko-project/executor:debug /kaniko/executor /usr/local/bin/kaniko" + ] + ) + .add_local_dir( + os.getcwd(), + remote_path="/workspace", ) ) @@ -60,15 +64,11 @@ app = modal.App(APP_NAME, image=builder_image) # ============================================================================= # Build and Push Function (Kaniko) # ============================================================================= - @app.function( - timeout=900, # 15 min for heavy ML deps (torch, transformers, etc.) + timeout=900, cpu=4, - memory=8192, # 8GB RAM - plenty for wheel building - secrets=[ - modal.Secret.from_name("aws-secrets"), # AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION - modal.Secret.from_name(ECR_SECRET_NAME), # ECR_USERNAME, ECR_PASSWORD - ], + memory=8192, + secrets=[modal.Secret.from_name("aws-secrets")], ) def build_and_push( registry: str = DEFAULT_REGISTRY, @@ -77,73 +77,71 @@ def build_and_push( push: bool = True, platform: str = "linux/amd64", ) -> dict: - """ - Build the backend Docker image with Kaniko and push to registry. - - Args: - registry: Container registry hostname (e.g., public.ecr.aws/vkist-project) - image_name: Image name (e.g., vkist-backend) - tag: Image tag (e.g., v1.2.3, latest, git-sha) - push: Whether to push to registry - platform: Target platform (linux/amd64, linux/arm64) - - Returns: - Dict with image reference and build status - """ - # Resolve paths at runtime inside Modal. - # The project files are baked into /workspace by the Modal image definition. - workspace = Path("/workspace") - project_root = workspace if (workspace / "backend").exists() else workspace - dockerfile_path = workspace / "deps" / "implementation" / "backend_deploy" / "Dockerfile" - - print(f"--- Runtime Path Verification ---") - print(f"Workspace: {workspace} (Exists: {workspace.exists()})") - print(f"PROJECT_ROOT: {project_root} (Exists: {project_root.exists()})") - print(f"DOCKERFILE_PATH: {dockerfile_path} (Exists: {dockerfile_path.exists()})") - print(f"----------------------------------------") - + import boto3 full_image = f"{registry}/{image_name}:{tag}" print(f"Building {full_image} for {platform}") + # Explicitly use the inside-container paths + workspace_root = Path("/workspace") + # Adjust this path if your Dockerfile lives in a specific subdirectory inside your workspace + dockerfile_path = workspace_root / "Dockerfile" + # Prepare docker config for Kaniko if pushing to ECR docker_config_dir = None if push and ("ecr.aws" in registry or "ecr." in registry): - print(f"Configuring ECR authentication from Modal secret '{ECR_SECRET_NAME}'...") + print(f"Configuring ECR authentication...") + region = os.getenv("AWS_REGION", "us-east-1") - ecr_username = os.getenv("ECR_USERNAME") - ecr_password = os.getenv("ECR_PASSWORD") - - if not ecr_username or not ecr_password: - raise RuntimeError( - f"ECR_USERNAME and ECR_PASSWORD must be set in Modal secret '{ECR_SECRET_NAME}'" - ) + ecr = boto3.client("ecr", region_name=region) + auth = ecr.get_authorization_token() + token = auth["authorizationData"][0]["authorizationToken"] + username, password = base64.b64decode(token).decode().split(":") config = { "auths": { registry: { - "username": ecr_username, - "password": ecr_password, + "username": username, + "password": password, } } } - docker_config_dir = project_root / ".kaniko" - docker_config_dir.mkdir(parents=True, exist_ok=True) + docker_config_dir = workspace_root / ".kaniko" + docker_config_dir.mkdir(exist_ok=True) (docker_config_dir / "config.json").write_text(json.dumps(config)) - print(f"ECR auth configured for {registry}") + print(f"ECR auth configured for {registry}") + + # --- INSPECT MODAL WORKSPACE DIRECTORIES HERE --- Success + print("\n=== DEBUG: Inspecting Modal Container Filesystem ===") + try: + # 1. Print the contents of the /workspace root directory + print(f"Contents of {workspace_root}:") + workspace_files = subprocess.run(["ls", "-la", str(workspace_root)], capture_output=True, text=True) + print(workspace_files.stdout) + + # 2. Verify exactly where the copied Kaniko binary lives + # print("Checking for Kaniko binary location:") + # kaniko_check = subprocess.run(["ls", "-la", "/usr/local/bin/kaniko"], capture_output=True, text=True) + # print(kaniko_check.stdout if kaniko_check.returncode == 0 else "❌ Kaniko not found in /usr/local/bin/kaniko\n") + + except Exception as e: + print(f"Failed to run inspection: {e}") + print("==================================================\n") # Build with Kaniko kaniko_cmd = [ - "/usr/local/bin/kaniko", - "--context", str(project_root), + "/usr/local/bin/kaniko", # Update this line to match where it was copied + "--context", str(workspace_root), "--dockerfile", str(dockerfile_path), "--destination", full_image, - "--platform", platform, + "--custom-platform", platform, "--verbosity", "info", ] + # Configure the environment variables to include DOCKER_CONFIG if auth exists + current_env = os.environ.copy() if docker_config_dir: - kaniko_cmd.extend(["--docker-config", str(docker_config_dir)]) + current_env["DOCKER_CONFIG"] = str(docker_config_dir) print(f"Running Kaniko: {' '.join(kaniko_cmd)}") result = subprocess.run(kaniko_cmd, capture_output=True, text=True)