Preparando Imagens de Contêiner

Prepare, crie e envie uma imagem de contêiner de agente para implantações hospedadas.

Use as diretrizes deste tópico para preparar imagens do Docker.

Arquitetura de Imagem de Contêiner Suportada

Para imagens, o serviço Generative AI suporta a arquitetura x86 de 64 bits, nome do código amd64. Ao criar imagens de contêiner, use linux/amd64 como o tipo de plataforma.

Por exemplo,

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

Preparação do Código

O contêiner do Docker deve atender aos requisitos a seguir para ser executado no ambiente de Implantação Hospedada.

Host e porta
  • O contêiner deve fazer listening no host 0.0.0.0.
  • O contêiner deve fazer listening na porta 8080.
Tipo da resposta HTTP

O contêiner deve expor um serviço baseado em HTTP que implementa pontos finais de solicitação e resposta no estilo REST usando métodos como GET, PUT, POST, DELETE e PATCH com caminhos definidos pelo usuário.

A plataforma determina se uma solicitação espera uma resposta de streaming inspecionando o cabeçalho Aceitar.

  • Se o cabeçalho Accept incluir text/event-stream, o ponto final deverá retornar uma resposta SSE (Server-Sent Events) com o tipo de conteúdo text/event-stream.
  • Caso contrário, o ponto final deverá retornar uma resposta JSON padrão com o aplicativo/json do tipo de conteúdo.

Essa configuração suporta um ponto final para interações de streaming e não streaming de maneira consistente e compatível com versões anteriores.

Ponto Final de Prontidão

O contêiner do Docker deve expor um ponto final de preparação para verificar se o aplicativo está totalmente inicializado e pronto para tratar solicitações.

  • Caminho: /ready
  • Finalidade: Indica se o contêiner está pronto para receber tráfego
  • Formato de Resposta: Código de status HTTP somente
  • Tipo de Conteúdo: application/json
  • Código de Status de Sucesso: 200 OK (a aplicação está pronta)

Se o contêiner não estiver pronto, o ponto final deverá retornar um código de status que não seja 200 para evitar o roteamento do tráfego.

Ponto Final do Liveness

O contêiner do Docker deve expor um ponto final ativo para verificar se o aplicativo está sendo executado corretamente e não requer reinicialização.

  • Caminho: /health
  • Finalidade: Detecta se o contêiner está ativo e funcionando
  • Formato de Resposta: Código de status HTTP somente
  • Tipo de Conteúdo: application/json
  • Código de Status de Sucesso: 200 OK (o aplicativo está íntegro)

Se o aplicativo entrar em um deadlock ou estado irrecuperável, o ponto final deverá retornar um código de status não-200 para que a plataforma possa reiniciar o contêiner automaticamente.

Arquitetura da Imagem

O serviço suporta amd64.

Observação

Recomendamos que você use imagens base fornecidas pelo Oracle Container Registry. As imagens nesse site passam pela verificação de vulnerabilidade.
Variáveis de ambiente reservadas

As variáveis de ambiente a seguir são reservadas para uso do sistema. Não os defina no código do contêiner:

PORT
K_SERVICE
K_CONFIGURATION
K_REVISION
OCI_RESOURCE_PRINCIPAL_VERSION
OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM
OCI_RESOURCE_PRINCIPAL_RPST
KUBERNETES_*

Arquitetura da Imagem

A imagem deve ser criada para a plataforma linux/amd64, conforme mostrado no exemplo a seguir.

Acesso ao arquivo

O sistema de arquivos contêiner é somente leitura, exceto para o diretório /tmp, que é gravável. Se o seu aplicativo precisar gravar arquivos localmente, grave-os no /tmp.

Verificação de vulnerabilidades

Antes da implantação, a imagem é verificada usando o OCI Vulnerability Scanning Service. A implantação falhará se forem detectadas vulnerabilidades críticas.

A Oracle recomenda o uso de imagens base do OCI Container Registry:

https://container-registry.oracle.com/, em que as imagens já passaram pela verificação de vulnerabilidade.

Outras restrições

  • Comandos de ponto de entrada personalizados não são suportados. Defina o comando de entrada no Dockerfile usando CMD ou ENTRYPOINT.
  • O mapeamento de volumes não é suportado. Os contêineres devem ser sem monitoramento de estado porque os dados do arquivo local não são preservados durante a reimplantação ou a substituição do nó.

Exemplo de código

O exemplo a seguir mostra um agente simples desenvolvido no LangGraph e encapsulado com 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"}


Estrutura do Projeto

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

Criar Imagem do Contêiner

Veja a seguir um exemplo de arquivo do Docker em um diretório de projeto.

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

Criar a imagem do docker na arquitetura amd64

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

Enviar Imagem ao Registro

Crie um registro de contêiner. Consulte Visão Geral do Container Registry.

Use a CLI do docker para enviar imagens do docker para o registro do contêiner.

Etapa 1: Acessar o registro do contêiner Código de exemplo:

docker login kix.ocir.io

Etapa 2: Marcar a imagem usando o URL e o namespace do registro do contêiner. Exemplo de código:

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

Etapa 3: Enviar imagem Exemplo de código:

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

Verificar Vulnerabilidades em Imagens (Recomendado e Opcional)

Não é incomum que os pacotes do sistema operacional incluídos nas imagens tenham vulnerabilidades. Gerenciar essas vulnerabilidades permite que você fortaleça a postura de segurança do seu sistema e responda rapidamente quando novas vulnerabilidades forem descobertas.

Consulte Verificando Imagens de Vulnerabilidades para criar uma receita de verificação e um destino de verificação.