Containerimages vorbereiten

Erstellen, erstellen und übertragen Sie ein Agent-Containerimage für gehostete Deployments.

Verwenden Sie die Richtlinien in diesem Thema, um Docker-Images vorzubereiten.

Unterstützte Containerimagearchitektur

Bei Images unterstützt der Generative AI-Service die 64-Bit-Architektur x86, den Codenamen amd64. Beim Erstellen von Containerimages verwenden Sie linux/amd64 als Plattformtyp.

Beispiel:

docker buildx build --platform linux/amd64 -t myimage:latest

Codevorbereitung

Der Docker-Container muss die folgenden Anforderungen erfüllen, um in der gehosteten Deployment-Umgebung ausgeführt werden zu können.

Host und Anschluss
  • Der Container muss auf Host horchen 0.0.0.0.
  • Der Container muss auf Port horchen 8080.
Inhaltstyp für HTTP-Antwort

Der Container muss einen HTTP-basierten Service bereitstellen, der Anforderungs- und Antwortendpunkte im REST-Stil mit Methoden wie GET, PUT, POST, DELETE und PATCH mit benutzerdefinierten Pfaden implementiert.

Die Plattform entscheidet, ob eine Anforderung eine Streamingantwort erwartet, indem sie den Accept-Header prüft.

  • Wenn der Accept-Header Text/Ereignisstrom enthält, muss der Endpunkt eine Server-Sent Events-(SSE-)Antwort mit Inhaltstyptext/Ereignisstrom zurückgeben.
  • Andernfalls muss der Endpunkt eine JSON-Standardantwort mit Inhaltstyp "application/json" zurückgeben.

Dieses Setup unterstützt einen Endpunkt für Streaming- und Nicht-Streaming-Interaktionen auf konsistente und abwärtskompatible Weise.

Bereitschaftsendpunkt

Der Docker-Container muss einen Bereitschaftsendpunkt angeben, um zu prüfen, ob die Anwendung vollständig initialisiert und bereit ist, Anforderungen zu verarbeiten.

  • Pfad: /ready
  • Zweck: Gibt an, ob der Container zum Empfang von Traffic bereit ist
  • Antwortformat: Nur HTTP-Statuscode
  • Inhaltstyp: application/json
  • Erfolgsstatuscode: 200 OK (Anwendung ist bereit)

Wenn der Container nicht bereit ist, muss der Endpunkt einen Nicht-200-Statuscode zurückgeben, um Trafficrouting zu verhindern.

Liveness-Endpunkt

Der Docker-Container muss einen Liveness-Endpunkt bereitstellen, um zu prüfen, ob die Anwendung korrekt ausgeführt wird und keinen Neustart erfordert.

  • Pfad: /health
  • Zweck: Ermittelt, ob der Container aktiv ist und funktioniert
  • Antwortformat: Nur HTTP-Statuscode
  • Inhaltstyp: application/json
  • Erfolgsstatuscode: 200 OK (Anwendung ist fehlerfrei)

Wenn die Anwendung in einen Deadlock- oder nicht behebbaren Status übergeht, muss der Endpunkt einen Nicht-200-Statuscode zurückgeben, damit die Plattform den Container automatisch neu starten kann.

Bildarchitektur

Der Service unterstützt amd64.

Hinweis

Es wird empfohlen, die von Oracle Container Registry bereitgestellten Basisimages zu verwenden. Die Bilder auf dieser Website passieren Schwachstellenscans.
Reservierte Umgebungsvariablen

Die folgenden Umgebungsvariablen sind für die Systemverwendung reserviert. Legen Sie sie nicht im Containercode fest:

PORT
K_SERVICE
K_CONFIGURATION
K_REVISION
OCI_RESOURCE_PRINCIPAL_VERSION
OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM
OCI_RESOURCE_PRINCIPAL_RPST
KUBERNETES_*

Bildarchitektur

Das Image muss für die linux/amd64-Plattform erstellt werden, wie im folgenden Beispiel dargestellt.

Dateizugriff

Das Container-Dateisystem ist schreibgeschützt, mit Ausnahme des /tmp-Verzeichnisses, das schreibgeschützt ist. Wenn Ihre Anwendung Dateien lokal schreiben muss, schreiben Sie sie in /tmp.

Sonstige Einschränkungen

  • Benutzerdefinierte Einstiegspunktbefehle werden nicht unterstützt. Definieren Sie den Eingabebefehl in der Docker-Datei mit CMD oder ENTRYPOINT.
  • Volume-Zuordnung wird nicht unterstützt. Container müssen zustandslos sein, da lokale Dateidaten beim erneuten Deployment oder Knotenersetzen nicht beibehalten werden.

Beispielcode

Das folgende Beispiel zeigt einen einfachen Agent, der in LangGraph entwickelt und mit FastAPI gewrappt wurde.

from contextlib import asynccontextmanager
import os
import sys
from typing import Any, Dict

from dotenv import load_dotenv
from fastapi import FastAPI
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent

load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
TEMPERATURE = float(os.getenv("OPENAI_TEMPERATURE", "0.7"))
OPENAI_MOCK_MODE_ENV = os.getenv("OPENAI_MOCK_MODE")
if OPENAI_MOCK_MODE_ENV is None:
    OPENAI_MOCK_MODE = not bool(OPENAI_API_KEY)
else:
    OPENAI_MOCK_MODE = OPENAI_MOCK_MODE_ENV.strip().lower() in (
        "1",
        "true",
        "yes",
        "on",
    )

app_graph = None


@asynccontextmanager
async def lifespan(app: FastAPI):
    global app_graph

    if OPENAI_MOCK_MODE and not OPENAI_API_KEY:
        print(
            "OPENAI_API_KEY is not set; running in OPENAI_MOCK_MODE.",
            file=sys.stderr,
        )
        yield
        return

    if not OPENAI_API_KEY:
        raise RuntimeError("OPENAI_API_KEY is not set in environment.")

    model = ChatOpenAI(
        model=OPENAI_MODEL,
        temperature=TEMPERATURE,
        api_key=OPENAI_API_KEY,
        streaming=True,
    )
    app_graph = create_react_agent(
        model=model,
        tools=[],
        checkpointer=MemorySaver(),
    )
    yield


app = FastAPI(lifespan=lifespan)


@app.post("/chat")
async def chat(body: Dict[str, Any]):
    thread_id = body["thread_id"]
    msg = body["message"]

    if OPENAI_MOCK_MODE and not OPENAI_API_KEY:
        return {
            "reply": f"[MOCK] OPENAI_API_KEY missing. Echo: {msg}",
            "thread_id": thread_id,
        }

    response = await app_graph.ainvoke(
        {"messages": [HumanMessage(content=msg)]},
        config={"configurable": {"thread_id": thread_id}},
    )

    if "messages" in response and response["messages"]:
        last_message = response["messages"][-1]
        ai_content = getattr(last_message, "content", str(last_message))
    else:
        ai_content = "I'm not sure how to respond to that."

    return {"reply": ai_content}


@app.get("/health")
async def health():
    return {
        "status": "Healthy",
        "mode": "mock" if (OPENAI_MOCK_MODE and not OPENAI_API_KEY) else "normal",
    }


@app.get("/ready")
async def ready():
    if OPENAI_MOCK_MODE and not OPENAI_API_KEY:
        return {"status": "Ready", "mode": "mock"}
    return {"status": "Ready"}


Projektstruktur

project_directory/
├── agent_example.py # Your main agent code
├── pyproject.toml # Dependencies for your agent
├── Dockerfile # docker file for building image
├── uv.lock # auto generated by uv
└── __init__.py # Makes the directory a Python package

Container-Image erstellen

Im Folgenden finden Sie ein Beispiel für eine Docker-Datei in einem Projektverzeichnis.

Dockerfile
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

# Copy project files
COPY pyproject.toml uv.lock ./
COPY *.py ./


# Install dependencies using uv
RUN uv sync --frozen

# Expose port
EXPOSE 8080

# Run the application using uv
CMD ["uv", "run", "python", "agent_example.py"]

Docker-Image in amd64-Architektur erstellen

docker buildx build --platform linux/amd64 -t my_agent:v1 .

Image in Registry übertragen

Erstellen Sie eine Containerregistrierung. Siehe Überblick über Container Registry.

Mit der Docking-CLI können Sie Docking-Images an die Container-Registry übertragen.

Schritt 1: Bei Container-Registry anmelden Beispielcode:

docker login kix.ocir.io

Schritt 2: Image mit Container-Registry-URL und -Namespace taggen. Beispielcode:

docker tag my_agent:v1 ap-osaka-1.ocir.io/{your_tenancy_namespace}/my_agent:v1

Schritt 3: Bild pushen Beispielcode:

docker push ap-osaka-1.ocir.io/<your_tenancy_namespace>/my_agent:v1