Bring Your Own Container

Erstellen und verwenden Sie einen benutzerdefinierten Container (Bring Your Own Container oder BYOC) als Laufzeitabhängigkeit, wenn Sie ein Modell-Deployment erstellen.

Mit benutzerdefinierten Containern können Sie System- und Sprachabhängigkeiten verpacken, Inferenzserver installieren und konfigurieren und unterschiedliche Sprachlaufzeiten einrichten. Alle innerhalb der definierten Grenzen einer Schnittstelle mit einer Modell-Deployment-Ressource zur Ausführung der Container.

BYOC ermöglicht die Übertragung von Containern zwischen verschiedenen Umgebungen, sodass Sie Anwendungen in die OCI Cloud migrieren und bereitstellen können.

Um den Job auszuführen, müssen Sie eine Dockerfile erstellen und dann ein Image erstellen. Sie beginnen mit einer Dockerfile, die ein Python-Image verwendet. Die Dockerfile ist so konzipiert, dass Sie lokale und Remote-Builds durchführen können. Verwenden Sie den lokalen Build für lokale Tests mit Ihrem Code. Bei der lokalen Entwicklung müssen Sie kein neues Image für jede Codeänderung erstellen.

Zeigt Modelle, Container, Clientanwendung, Inferenzserver, Logging-Service und die OCI Container Registry-Interaktion an.

BYOC Erforderliche Schnittstellen

Erstellen Sie diese erforderlichen Schnittstellen, oder geben Sie sie an, um ein Modell-Deployment zu verwenden.

Modellartefakt

Oberfläche Beschreibung
Laden Sie Modellartefakte in den Data Science-Modellkatalog hoch. Modellartefakte, wie Scoringlogik, ML-Modell und abhängige Dateien, müssen in den Data Science-Modellkatalog hochgeladen werden, bevor sie von einer Modell-Deployment-Ressource verwendet werden.
Keine obligatorischen Dateien.

Für die Erstellung eines BYOC-Modell-Deployments sind keine Dateien erforderlich.

Hinweis: Wenn BYOC nicht für ein Modell-Deployment verwendet wird, sind die Dateien score.py und runtime.yaml weiterhin erforderlich.

Speicherort der gemounteten Modellartefakte.

Während Bootstrap-Modell-Deployments das Modellartefakt entpacken und die Dateien im schreibgeschützten Modus in das Verzeichnis /opt/ds/model/deployed_model im ausgeführten Container mounten. Alle aus diesem Pfad komprimierten Dateien werden in der Bewertungslogik verwendet.

Das Zippen einer Gruppe von Dateien (einschließlich ML-Modell und Scoringlogik) oder eines Ordners, der eine Gruppe von Dateien enthält, hat einen anderen Speicherortpfad zum ML-Modell innerhalb des Containers. Stellen Sie sicher, dass beim Laden des Modells in die Bewertungslogik der richtige Pfad verwendet wird.

Containerimage

Oberfläche Beschreibung
Laufzeitabhängigkeiten in Packages integrieren Verpacken Sie das Containerimage mit den erforderlichen Laufzeitabhängigkeiten, um die ML-Modellbinärdatei zu laden und auszuführen.
Packen Sie einen Webserver, um Endpunkte bereitzustellen.

Verpacken Sie das Containerimage mit einem zustandslosen HTTP-basierten Webserver (FastAPI, Flask, Triton, TensorFlow Serving, PyTorch Serving usw.). Geben Sie einen /health-Endpunkt an, um den Zustand des Webservers und den /predict-Endpunkt für die Inferenzierung zurückzugeben.

  • Vorhersagen: Der Server muss einen /predict-Endpunkt mit der POST-Methode unterstützen.
  • Zustand: Der Server muss einen /health-Endpunkt mit der Methode GET unterstützen. Dieser Endpunkt muss 200 OK zurückgeben, damit der Service den Container als fehlerfrei betrachtet.

Hinweis: Die Endpunkte /predict und /predict/ (mit einem Schrägstrich am Ende) sind nicht identisch. Sie haben jeweils eine andere Semantik aus API-Sicht.

Wenn der Endpunkt des Inferenzservers nicht an die Data Science-Endpunktschnittstelle angepasst werden kann, verwenden Sie einen Proxy (z.B. NGINX), um die vom Service erforderlichen Endpunkte den von Ihrem Framework bereitgestellten Endpunkten zuzuordnen.

Angegebene Ports.

Die Ports, die für die Endpunkte /predict und /health verwendet werden sollen, können angepasst werden, indem der benutzerdefinierte Port über die API übergeben wird.

Die Ports sind auf 1024 bis 65535 begrenzt. Die Ports 24224, 8446 und 8447 sind ausgeschlossen. Die bereitgestellten Ports werden vom Service im Container verfügbar gemacht, sodass sie nicht erneut in der Docker-Datei verfügbar gemacht werden müssen.

Größe des Images. Die Größe des Containerimages ist in unkomprimierter Form auf 16 GB begrenzt.
Zugriff auf das Bild. Der Operator, der das Modell-Deployment erstellt, muss Zugriff auf das zu verwendende Containerimage haben.
Curl-Package. Das curl-Package muss im Containerimage installiert sein, damit die Docker-Policy HEALTHCHECK erfolgreich ist. Installieren Sie den neuesten stabilen curl-Befehl, der keine offenen Sicherheitslücken aufweist.
CMD, Entrypoint Der Docker CMD oder Entrypoint muss entweder über die API oder die Docker-Datei bereitgestellt werden, die den Webserver bootstrapiert.
CMD, Größe Entrypoint. Die kombinierte Größe von CMD und Entrypoint darf die 2048 Byte nicht überschreiten. Wenn die Größe mehr als 2048 Byte beträgt, geben Sie die Anwendungsargumente mit dem Modellartefakt an, oder rufen Sie die Daten mit Object Storage ab.

Allgemeine Empfehlungen

Empfehlung Beschreibung
Packen Sie das ML-Modell in Modellartefakten.

Packen Sie das ML-Modell als Artefakt, und laden Sie es in den Data Science-Modellkatalog hoch, um die Modell-Governance- und Modellversionierungsfeatures zu verwenden. Eine Option zum Packen des ML-Modells im Containerimage ist vorhanden. Speichern Sie das Modell im Modellkatalog.

Nachdem das Modell in den Modellkatalog hochgeladen und bei der Erstellung des Modell-Deployments referenziert wurde, lädt Data Science eine Kopie des Artefakts herunter und entpackt es im Verzeichnis /opt/ds/model/deployed_model , damit die Scoringlogik konsumiert werden kann.

Image- und Image-Digest für alle Vorgänge bereitstellen Es wird empfohlen, den Image- und Imagedigest anzugeben, um Modell-Deployment-Vorgänge zu erstellen, zu aktualisieren und zu aktivieren, um die Konsistenz bei der Verwendung des Images zu gewährleisten. Während eines Aktualisierungsvorgangs auf ein anderes Image sind sowohl Image als auch Imagedigest unerlässlich, um das erwartete Image zu aktualisieren.
Vulnerability Scanning Wir empfehlen, den OCI-Service Vulnerability Scanning zu verwenden, um nach Sicherheitslücken im Image zu suchen.
API-Feld ist null Wenn ein API-Feld leer ist, übergeben Sie keine leere Zeichenfolge, kein leeres Objekt oder keine leere Liste. Übergeben Sie das Feld als Null oder nicht übergeben, es sei denn, Sie möchten explizit als leeres Objekt übergeben.

Best Practices für BYOC

  • Das Modell-Deployment unterstützt nur Containerimages, die sich in der OCI-Registry befinden.
  • Stellen Sie sicher, dass das Containerimage während des gesamten Lebenszyklus des Modell-Deployments in der OCI Registry vorhanden ist. Das Image muss vorhanden sein, um die Verfügbarkeit sicherzustellen, falls eine Instanz automatisch neu gestartet wird oder das Serviceteam Patching ausführt.
  • Nur Docker-Container werden mit BYOC unterstützt.
  • Data Science verwendet das gezippte Modellartefakt, um die ML-Modellbewertungslogik zu verwenden, und erwartet, dass es im Data Science-Modellkatalog verfügbar ist.
  • Die Größe des Containerimages ist in unkomprimierter Form auf 16 GB begrenzt.
  • Data Science fügt vor dem Starten des Containers eine HEALTHCHECK-Aufgabe hinzu, sodass die HEALTHCHECK-Policy nicht explizit in der Docker-Datei hinzugefügt werden muss, weil sie überschrieben wird. Der Health Check wird 10 Minuten nach dem Start des Containers ausgeführt. Anschließend wird /health alle 30 Sekunden mit einem Timeout von drei Sekunden und drei Wiederholungen pro Prüfung geprüft.
  • Ein Curlpackage muss im Containerimage installiert werden, damit die Docker-Policy HEALTHCHECK erfolgreich ist.
  • Der Benutzer, der die Modell-Deployment-Ressource erstellt, muss Zugriff auf das Containerimage in OCI Registry haben, um es zu verwenden. Falls nicht, erstellen Sie eine IAM-Policy für den Benutzerzugriff, bevor Sie ein Modell-Deployment erstellen.
  • Der Docker CMD oder Entrypoint muss entweder über die API oder Dockerfile bereitgestellt werden, die den Webserver per Bootstrapping festlegt.
  • Der vom Service definierte Timeout für die Ausführung des Containers beträgt 10 Minuten. Stellen Sie daher sicher, dass der Inferenz-Servingcontainer innerhalb dieses Zeitrahmens startet (ist fehlerfrei).
  • Testen Sie den Container immer lokal, bevor Sie ihn mit einem Modell-Deployment in der Cloud bereitstellen.

Docker-Imagedigests

Images in einer Docker-Registry werden durch Repository, Name und Tag identifiziert. Außerdem gibt Docker jeder Version eines Images einen eindeutigen alphanumerischen Digest. Beim Übertragen eines aktualisierten Docker-Images wird empfohlen, dem aktualisierten Image ein neues Tag zu geben, um es zu identifizieren, anstatt ein vorhandenes Tag wieder zu verwenden. Selbst wenn Sie ein aktualisiertes Image übertragen und diesem den Namen und das Tag einer früheren Version geben, hat die neu übertragene Version einen anderen Digest als die frühere Version.

Wenn Sie eine Modell-Deployment-Ressource erstellen, geben Sie den Namen und das Tag einer bestimmten Version eines Images an, auf der das Modell-Deployment basiert. Um Inkonsistenzen zu vermeiden, zeichnet das Modell-Deployment den eindeutigen Digest dieser Version des Images auf. Sie können den Digest des Images auch beim Erstellen eines Modell-Deployments angeben.

Wenn Sie eine aktualisierte Version eines Images mit demselben Namen und Tag wie die ursprüngliche Version des Images, auf dem das Modell-Deployment basiert, in die Docker-Registry übertragen, wird standardmäßig weiterhin der ursprüngliche Digest verwendet, um die ursprüngliche Version des Images abzurufen. Wenn das Modell-Deployment die spätere Version des Images abrufen soll, können Sie den Imagenamen explizit mit einem Tag und einem Digest ändern, mit dem das Modell-Deployment identifiziert, welche Version des Images abgerufen werden soll.

Modellartefakt vorbereiten

Erstellen Sie eine Artefakt-ZIP-Datei, und speichern Sie sie mit dem Modell im Modellkatalog. Das Artefakt enthält den Code zum Ausführen des Containers und Ausführen der Inferenzanforderungen.

Der Container muss einen /health-Endpunkt angeben, um den Zustand des Inferenzservers zurückzugeben, und einen /predict-Endpunkt für die Inferenzierung.

Die folgende Python-Datei im Modellartefakt definiert diese Endpunkte mit einem Flask-Server mit Port 5000:

# We now need the json library so we can load and export json data
import json
import os
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.neural_network import MLPClassifier
import pandas as pd
from joblib import load
from sklearn import preprocessing
import logging

from flask import Flask, request

# Set environnment variables
WORK_DIRECTORY = os.environ["WORK_DIRECTORY"]
TEST_DATA = os.path.join(WORK_DIRECTORY, "test.json")
MODEL_DIR = os.environ["MODEL_DIR"]
MODEL_FILE_LDA = os.environ["MODEL_FILE_LDA"]
MODEL_PATH_LDA = os.path.join(MODEL_DIR, MODEL_FILE_LDA)

# Loading LDA model
print("Loading model from: {}".format(MODEL_PATH_LDA))
inference_lda = load(MODEL_PATH_LDA)

# Creation of the Flask app
app = Flask(__name__)


# API 1
# Flask route so that we can serve HTTP traffic on that route
@app.route('/health')
# Get data from json and return the requested row defined by the variable Line
def health():
    # We can then find the data for the requested row and send it back as json
    return {"status": "success"}

# API 2
# Flask route so that we can serve HTTP traffic on that route
@app.route('/predict',methods=['POST'])
# Return prediction for both Neural Network and LDA inference model with the requested row as input
def prediction():
    data = pd.read_json(TEST_DATA)
    request_data = request.get_data()
    print(request_data)
    print(type(request_data))
    if isinstance(request_data, bytes):
        print("Data is of type bytes")
        request_data = request_data.decode("utf-8")
    print(request_data)
    line = json.loads(request_data)['line']
    data_test = data.transpose()
    X = data_test.drop(data_test.loc[:, 'Line':'# Letter'].columns, axis = 1)
    X_test = X.iloc[int(line),:].values.reshape(1, -1)

    clf_lda = load(MODEL_PATH_LDA)
    prediction_lda = clf_lda.predict(X_test)

    return {'prediction LDA': int(prediction_lda)}


if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port = 5000)

Container erstellen

Sie können jedes Image aus OCI Container Registry verwenden. Im Folgenden finden Sie ein Beispiel für eine Dockerfile, die den Flask-Server verwendet:

FROM jupyter/scipy-notebook
  
USER root
RUN \
  apt-get update && \
  apt-get -y install curl
  
ENV WORK_DIRECTORY=/opt/ds/model/deployed_model
ENV MODEL_DIR=$WORK_DIRECTORY/models
RUN mkdir -p $MODEL_DIR
  
ENV MODEL_FILE_LDA=clf_lda.joblib
  
COPY requirements.txt /opt/requirements.txt
RUN pip install -r /opt/requirements.txt
Wichtig

Das Curl-Package muss im Containerimage installiert sein, damit die Docker-Policy HEALTHCHECK funktioniert.

Erstellen Sie eine requirements.txt-Datei mit den folgenden Packages in demselben Verzeichnis wie Dockerfile:

flask
flask-restful
joblib

Führen Sie den Befehl docker build aus:

docker build -t ml_flask_app_demo:1.0.0 -f Dockerfile .
Hinweis

Die maximale Größe eines dekomprimierten Containerimages, das Sie mit Modell-Deployments verwenden können, beträgt 16 GB. Beachten Sie, dass die Größe des Containerimages die Provisioning-Zeit für das Modell-Deployment verlangsamt, weil es aus der Container Registry abgerufen wird. Wir empfehlen Ihnen, möglichst kleinste Containerbilder zu verwenden.

Container testen

Stellen Sie sicher, dass sich das Modellartefakt und der Inferenzcode im selben Verzeichnis wie die Dockerfile befinden. Führen Sie den Container auf dem lokalen Rechner aus. Sie müssen die auf dem lokalen Rechner gespeicherten Dateien referenzieren, indem Sie das lokale Modellverzeichnis in /opt/ds/model/deployed_model mounten:

docker run -p 5000:5000 \
  --health-cmd='curl -f http://localhost:5000/health || exit 1' \
  --health-interval=30s \
  --health-retries=3 \
  --health-timeout=3s \
  --health-start-period=1m \
  --mount type=bind,src=$(pwd),dst=/opt/ds/model/deployed_model \
  ml_flask_app_demo:1.0.0 python /opt/ds/model/deployed_model/api.py

Senden Sie eine Zustandsanfrage, um zu überprüfen, ob der Container innerhalb des 10 Minuten definierten Service ausgeführt wird:

curl -vf http://localhost:5000/health

Testen Sie durch Senden einer Vorhersageanforderung:

curl -H "Content-type: application/json" -X  POST http://localhost:5000/predict --data '{"line" : "12"}'

Container in OCI Container Registry übertragen

Bevor Sie Images an Oracle Cloud Infrastructure Registry (auch als Container Registry bezeichnet) übergeben und von dort abrufen können, benötigen Sie ein Oracle Cloud Infrastructure-Autorisierungstoken. Die Zeichenfolge des Auth-Token wird nur bei der Erstellung angezeigt. Kopieren Sie das Auth-Token also sofort an einen sicheren Speicherort.

  1. So zeigen Sie die Details in der Konsole an: Wählen Sie in der Navigationsleiste das Menü Profil aus, und wählen Sie je nach der angezeigten Option Benutzereinstellungen oder Mein Profil aus.
  2. Wählen Sie auf der Seite Authentifizierungstoken die Option Token generieren aus.
  3. Geben Sie eine benutzerfreundliche Beschreibung für das Token ein. Geben Sie dabei keine vertraulichen Informationen ein.
  4. Wählen Sie Token generieren aus. Das neue Authentifizierungstoken wird angezeigt.
  5. Kopieren Sie das Authentifizierungstoken sofort in einen sicheren Speicherort, an dem Sie es später abrufen können. Das Authentifizierungstoken wird nicht mehr in der Konsole angezeigt.
  6. Schließen Sie das Dialogfeld "Token generieren".
  7. Öffnen Sie ein Terminalfenster auf dem lokalen Rechner.
  8. Melden Sie sich bei der Container Registry an, damit Sie das Containerimage erstellen, ausführen, testen, taggen und übertragen können.
    docker login -u '<tenant-namespace>/<username>' <region>.ocir.io
  9. Taggen Sie das lokale Containerimage:
    docker tag <local_image_name>:<local_version> <region>.ocir.io/<tenancy_ocir_namespace>/<repository>:<version>
  10. Push des Containerimages:
    docker push <region>.ocir.io/<tenancy>/byoc:1.0
    Hinweis

    Stellen Sie sicher, dass die Modell-Deployment-Ressource über eine Policy für den Resource Principal verfügt, damit sie das Image aus der OCI-Registry aus dem Compartment lesen kann, in dem Sie das Image gespeichert haben. Modell-Deployment-Zugriff auf einen benutzerdefinierten Container mit Resource Principal erteilen

Sie können dieses Containerimage mit der BYOC-Option verwenden, wenn Sie ein Modell-Deployment erstellen.

Wichtig

BYOC-Modell-Deployments unterstützen das regionsübergreifende Abrufen von Containerimages nicht. Beispiel: Wenn Sie ein BYOC-Modell-Deployment in einer IAD-(Ashburn-)Region ausführen, können Sie keine Containerimages aus OCIR (Oracle Cloud Container Registry) in der PHX-(Phoenix-)Region abrufen.

BYOC-Aktualisierungsvorgang - Verhalten

BYOC-Aktualisierungsvorgänge sind unvollständige Aktualisierungen des Zusammenführungstyps.

Ein beschreibbares Feld der obersten Ebene muss vollständig ersetzt werden, wenn es im Anforderungsinhalt definiert und andernfalls unverändert beibehalten wird. Beispiel: Für eine Ressource wie die folgende:

{ 
    "environmentConfigurationDetails": {
        "environmentConfigurationType": "OCIR_CONTAINER",  
        "serverPort": 5454,
        "image": "iad.ocir.io/testtenancy/md_byoc_ref_iris_data:1.0.1",
        "imageDigest": "sha256:a9c8468cb671929aec7ad947b9dccd6fe8e6d77f7bcecfe2e10e1c935a88c2a5",
        "environmentVariables": {
            "a": "b",
            "c": "d",
            "e": "f"
        },
        "entrypoint": [ "python", "-m", "uvicorn", "a/model/server:app", "--port", "5000","--host","0.0.0.0"]
        "cmd": ["param1"]
}

Ein erfolgreiches Update mit Folgendem:

{
    "environmentConfigurationDetails": {
        "serverPort": 2000, 
        "environmentVariables": {"x":"y"},
        "entrypoint": []
    }
}

Führt zu einem Status, in dem serverPort und environmentVariables durch den Aktualisierungsinhalt überschrieben werden (einschließlich der Löschung zuvor vorhandener Daten in Tiefenfeldern, die im Aktualisierungsinhalt fehlen). Die image wird unverändert beibehalten, da sie nicht im Updateinhalt angezeigt wurde, und entrypoint wird durch eine explizite leere Liste gelöscht:

{ 
    "environmentConfigurationDetails": {
        "environmentConfigurationType": "OCIR_CONTAINER",  
        "serverPort": 2000,
        "image": "iad.ocir.io/testtenancy/md_byoc_ref_iris_data:1.0.1",
        "imageDigest": "sha256:a9c8468cb671929aec7ad947b9dccd6fe8e6d77f7bcecfe2e10e1c935a88c2a5",
        "environmentVariables": {"x": "y"},
        "entrypoint": []
        "cmd": ["param1"]
}

Eine erfolgreiche Aktualisierung mit { "environmentConfigurationDetails": null or {} } führt dazu, dass nichts überschrieben wird. Bei einer vollständigen Ersetzung auf oberster Ebene werden alle Werte gelöscht, die nicht im Anforderungsinhalt enthalten sind. Vermeiden Sie dies. Alle Felder sind im Aktualisierungsobjekt optional. Wenn Sie das Image also nicht angeben, sollte das Image im Deployment nicht zurückgesetzt werden. Data Science ersetzt die Felder der zweiten Ebene nur, wenn sie nicht Null sind.

Wenn Sie kein Feld im Anforderungsobjekt festlegen (Null übergeben), wird Data Science dieses Feld nicht berücksichtigen, um die Differenz zu ermitteln und durch den vorhandenen Feldwert zu ersetzen.

Um einen Wert eines beliebigen Feldes zurückzusetzen, übergeben Sie ein leeres Objekt. Bei Listen- und Zuordnungstypfeldern kann Data Science eine leere Liste ([]) oder Zuordnung ({}) als Hinweis zum Löschen der Werte akzeptieren. In jedem Fall bedeutet Null nicht, dass die Werte gelöscht werden. Sie können den Wert jedoch immer in etwas anderes ändern. Um einen Standardport zu verwenden und den Feldwert dafür aufzuheben, legen Sie explizit den Standardport fest.

Die Aktualisierung der Liste und der Zuordnungsfelder ist ein vollständiger Ersatz. Data Science betrachtet die Objekte nicht für einzelne Werte.

Für Image und Digest lässt Data Science den Wert nicht löschen.

Bereitstellung mit einem Triton Inference Server Container

NVIDIA Triton Inference Server optimiert und standardisiert KI-Inferenz, indem Teams trainierte KI-Modelle aus jedem Framework auf einer beliebigen GPU- oder CPU-basierten Infrastruktur bereitstellen, ausführen und skalieren können.

Einige der wichtigsten Merkmale von Triton sind:

  • Gleichzeitige Modellausführung: Die Möglichkeit, mehrere ML-Modelle gleichzeitig zu bedienen. Diese Funktion ist nützlich, wenn mehrere Modelle in einem einzigen System bereitgestellt und verwaltet werden müssen.
  • Dynamisches Batching: Der Server kann Anforderungen basierend auf der Workload dynamisch im Batch zusammenfassen, um die Performance zu verbessern.

Das Modell-Deployment bietet spezielle Unterstützung für NVIDIA Triton Inference Server. Sie können ein vorhandenes Triton-Image aus dem Container-Katalog von NVIDIA bereitstellen. Das Modell-Deployment stellt sicher, dass die Triton-Schnittstellen übereinstimmen, ohne dass beim Erstellen des Modell-Deployments etwas im Container geändert werden muss. Verwenden Sie dazu die folgende Umgebungsvariable:

CONTAINER_TYPE = TRITON

Ein vollständiges dokumentiertes Beispiel zur Bereitstellung von ONNX-Modellen in Triton ist im Data Science-Modell-Deployment-Repository GitHub verfügbar.