Preparación de imágenes de contenedor

Preparar, crear y transferir una imagen de contenedor de agente para despliegues alojados.

Utilice las directrices de este tema para preparar imágenes de Docker.

Arquitectura de imagen de contenedor soportada

Para las imágenes, el servicio de IA generativa admite la arquitectura x86 de 64 bits, nombre de código amd64. Al crear imágenes de contenedor, utilice linux/amd64 como tipo de plataforma.

Por ejemplo,

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

Preparación de código

El contenedor de Docker debe cumplir los siguientes requisitos para ejecutarse en el entorno de despliegue alojado.

Host y puerto
  • El contenedor debe recibir en el host 0.0.0.0.
  • El contenedor debe recibir en el puerto 8080.
Tipo contenido respuesta HTTP

El contenedor debe exponer un servicio basado en HTTP que implante puntos finales de solicitud y respuesta de estilo REST mediante métodos como GET, PUT, POST, DELETE y PATCH con rutas definidas por el usuario.

La plataforma determina si una solicitud espera una respuesta de transmisión inspeccionando la cabecera Accept.

  • Si la cabecera Accept incluye texto/flujo de eventos, el punto final debe devolver una respuesta de eventos enviados por el servidor (SSE) con el tipo de contenido texto/flujo de eventos.
  • De lo contrario, el punto final debe devolver una respuesta JSON estándar con el tipo de contenido application/json.

Esta configuración admite un punto final para interacciones de flujo y no de flujo de forma coherente y compatible con versiones anteriores.

Punto final de preparación

El contenedor de Docker debe exponer un punto final de preparación para verificar que la aplicación esté completamente inicializada y lista para manejar solicitudes.

  • Ruta de acceso: /ready
  • Propósito: indica si el contenedor está listo para recibir tráfico
  • Formato de respuesta: solo código de estado HTTP
  • Tipo de contenido: application/json
  • Código de estado correcto: 200 OK (la aplicación está lista)

Si el contenedor no está listo, el punto final debe devolver un código de estado que no sea 200 para evitar el enrutamiento del tráfico.

Punto final de vida

El contenedor de Docker debe exponer un punto final activo para verificar que la aplicación se está ejecutando correctamente y no necesita reiniciar.

  • Ruta de acceso: /health
  • Propósito: detecta si el contenedor está activo y en funcionamiento
  • Formato de respuesta: solo código de estado HTTP
  • Tipo de contenido: application/json
  • Código de estado correcto: 200 OK (la aplicación está en buen estado)

Si la aplicación entra en un estado de interbloqueo o irrecuperable, el punto final debe devolver un código de estado que no sea 200 para que la plataforma pueda reiniciar el contenedor automáticamente.

Arquitectura de imagen

El servicio admite amd64.

Nota

Le recomendamos que utilice imágenes base proporcionadas por Oracle Container Registry. Las imágenes de ese sitio pasan el análisis de vulnerabilidades.
Variables de entorno reservadas

Las siguientes variables de entorno están reservadas para uso del sistema. No los defina en el código de contenedor:

PORT
K_SERVICE
K_CONFIGURATION
K_REVISION
OCI_RESOURCE_PRINCIPAL_VERSION
OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM
OCI_RESOURCE_PRINCIPAL_RPST
KUBERNETES_*

Arquitectura de imagen

La imagen se debe crear para la plataforma linux/amd64, como se muestra en el siguiente ejemplo.

Acceso a archivos

El sistema de archivos de contenedor es de solo lectura, excepto para el directorio /tmp, en el que se puede escribir. Si la aplicación necesita escribir archivos localmente, escríbalos a /tmp.

Análisis de vulnerabilidades

Antes del despliegue, la imagen se explora mediante el servicio de análisis de vulnerabilidades de OCI. El despliegue falla si se detectan vulnerabilidades críticas.

Oracle recomienda utilizar imágenes base de OCI Container Registry:

https://container-registry.oracle.com/, donde las imágenes ya han pasado el análisis de vulnerabilidades.

Otras restricciones

  • Los comandos de punto de entrada personalizados no están soportados. Defina el comando de entrada en Dockerfile mediante CMD o ENTRYPOINT.
  • No se admite la asignación de volumen. Los contenedores no deben tener estado porque los datos del archivo local no se conservan durante el nuevo despliegue o la sustitución de nodos.

Código de ejemplo

En el siguiente ejemplo se muestra un agente simple desarrollado en LangGraph y envuelto con FastAPI.

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"}


Estructura de Proyecto

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

Crear imagen de contenedor

A continuación, se muestra un ejemplo de archivo de Docker en un directorio de proyecto.

Archivo 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"]

Crear la imagen de docker en la arquitectura amd64

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

Insertar imagen en registro

Cree un registro de contenedor. Consulte Visión general de Container Registry.

Utilice la CLI de docker para transferir imágenes de docker al registro de contenedores.

Paso 1: Iniciar sesión en el registro de contenedores Código de ejemplo:

docker login kix.ocir.io

Paso 2: Etiquete la imagen con la URL y el espacio de nombres del registro de contenedor. Código de ejemplo:

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

Paso 3: Insertar imagen Código de ejemplo:

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

Escanear imágenes para vulnerabilidades (recomendado y opcional)

No es raro que los paquetes del sistema operativo incluidos en las imágenes tengan vulnerabilidades. La gestión de estas vulnerabilidades le permite reforzar la estrategia de seguridad de su sistema y responder rápidamente cuando se descubran nuevas vulnerabilidades.

Consulte Exploración de imágenes para vulnerabilidades para crear una receta de exploración y un destino de exploración.