update the gitea_modal_build.py
This commit is contained in:
@@ -22,36 +22,40 @@ import json
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import modal
|
import modal
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Configuration
|
# Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
APP_NAME = "msk-lumina-backend-builder"
|
|
||||||
|
|
||||||
# Default registry/image settings
|
|
||||||
DEFAULT_REGISTRY = "public.ecr.aws/i9a4e3f6/msk-cv-inference-server"
|
DEFAULT_REGISTRY = "public.ecr.aws/i9a4e3f6/msk-cv-inference-server"
|
||||||
DEFAULT_IMAGE_NAME = "msk-lumina-backend"
|
DEFAULT_IMAGE_NAME = "msk-lumina-backend"
|
||||||
DEFAULT_TAG = "latest"
|
DEFAULT_TAG = "latest"
|
||||||
|
APP_NAME = "msk-lumina-backend-builder"
|
||||||
# Modal secret for ECR credentials
|
|
||||||
ECR_SECRET_NAME = "ecr-credentials"
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 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
|
# 2. Build your final builder image on a clean Debian system that HAS apt-get
|
||||||
# the build context and Dockerfile at runtime.
|
|
||||||
# The Dockerfile path is resolved at runtime, not at image build time.
|
|
||||||
builder_image = (
|
builder_image = (
|
||||||
modal.Image.debian_slim()
|
modal.Image.debian_slim()
|
||||||
.apt_install("curl", "ca-certificates")
|
.apt_install("curl", "ca-certificates")
|
||||||
.run_commands(
|
.pip_install("boto3")
|
||||||
"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",
|
# 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)
|
# Build and Push Function (Kaniko)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
@app.function(
|
@app.function(
|
||||||
timeout=900, # 15 min for heavy ML deps (torch, transformers, etc.)
|
timeout=900,
|
||||||
cpu=4,
|
cpu=4,
|
||||||
memory=8192, # 8GB RAM - plenty for wheel building
|
memory=8192,
|
||||||
secrets=[
|
secrets=[modal.Secret.from_name("aws-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
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
def build_and_push(
|
def build_and_push(
|
||||||
registry: str = DEFAULT_REGISTRY,
|
registry: str = DEFAULT_REGISTRY,
|
||||||
@@ -77,73 +77,71 @@ def build_and_push(
|
|||||||
push: bool = True,
|
push: bool = True,
|
||||||
platform: str = "linux/amd64",
|
platform: str = "linux/amd64",
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""
|
import boto3
|
||||||
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"----------------------------------------")
|
|
||||||
|
|
||||||
full_image = f"{registry}/{image_name}:{tag}"
|
full_image = f"{registry}/{image_name}:{tag}"
|
||||||
print(f"Building {full_image} for {platform}")
|
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
|
# Prepare docker config for Kaniko if pushing to ECR
|
||||||
docker_config_dir = None
|
docker_config_dir = None
|
||||||
if push and ("ecr.aws" in registry or "ecr." in registry):
|
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 = boto3.client("ecr", region_name=region)
|
||||||
ecr_password = os.getenv("ECR_PASSWORD")
|
auth = ecr.get_authorization_token()
|
||||||
|
token = auth["authorizationData"][0]["authorizationToken"]
|
||||||
if not ecr_username or not ecr_password:
|
username, password = base64.b64decode(token).decode().split(":")
|
||||||
raise RuntimeError(
|
|
||||||
f"ECR_USERNAME and ECR_PASSWORD must be set in Modal secret '{ECR_SECRET_NAME}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"auths": {
|
"auths": {
|
||||||
registry: {
|
registry: {
|
||||||
"username": ecr_username,
|
"username": username,
|
||||||
"password": ecr_password,
|
"password": password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
docker_config_dir = project_root / ".kaniko"
|
docker_config_dir = workspace_root / ".kaniko"
|
||||||
docker_config_dir.mkdir(parents=True, exist_ok=True)
|
docker_config_dir.mkdir(exist_ok=True)
|
||||||
(docker_config_dir / "config.json").write_text(json.dumps(config))
|
(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
|
# Build with Kaniko
|
||||||
kaniko_cmd = [
|
kaniko_cmd = [
|
||||||
"/usr/local/bin/kaniko",
|
"/usr/local/bin/kaniko", # Update this line to match where it was copied
|
||||||
"--context", str(project_root),
|
"--context", str(workspace_root),
|
||||||
"--dockerfile", str(dockerfile_path),
|
"--dockerfile", str(dockerfile_path),
|
||||||
"--destination", full_image,
|
"--destination", full_image,
|
||||||
"--platform", platform,
|
"--custom-platform", platform,
|
||||||
"--verbosity", "info",
|
"--verbosity", "info",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Configure the environment variables to include DOCKER_CONFIG if auth exists
|
||||||
|
current_env = os.environ.copy()
|
||||||
if docker_config_dir:
|
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)}")
|
print(f"Running Kaniko: {' '.join(kaniko_cmd)}")
|
||||||
result = subprocess.run(kaniko_cmd, capture_output=True, text=True)
|
result = subprocess.run(kaniko_cmd, capture_output=True, text=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user