Build a Gyoza Op#
A Gyoza Op is a self-contained, containerised operation that the Gyoza ecosystem can schedule and execute on any worker. This guide walks you through the project structure, the required configuration files, and the steps to build your op into a usable container image.
Prerequisites#
gyoza installed (see Installation).
Docker daemon running locally.
Basic familiarity with Pydantic models.
Project structure#
A minimal op project looks like this:
my-op/
├── main.py # Op logic with the @gyoza_op decorator
├── gyoza.yml # Gyoza manifest (image name, build config, …)
├── Dockerfile # Container recipe, installs deps and calls gyoza run
└── pyproject.toml # (or requirements.txt) Python dependencies
Each file has a clear responsibility:
main.py— defines the input model, the output model and the decorated function that performs the actual operation.gyoza.yml— tells gyoza how to build the Docker image and, later, how to deploy and run it.Dockerfile— standard Docker build recipe. It installs your dependencies and setsgyoza runas the container entrypoint.
The main.py file#
By default, the op’s entry point is main.py (configurable via the
gyoza_op_file key in gyoza.yml). This file contains the input model, the output model and the decorated function that performs the operation.
Inputs and outputs are defined as Pydantic models. Each model is a simple class that inherits from BaseModel and declares typed fields:
from pydantic import BaseModel
class Input(BaseModel):
image_path: str
top_k: int = 3
class Output(BaseModel):
label: str
confidence: float
Gyoza uses these models to validate the data that flows in and out of your op at runtime. Fields with default values become optional inputs.
The @gyoza_op decorator#
The @gyoza_op decorator ties everything together. It receives the input
and output models and wraps your function so gyoza can call it with
validated data:
from pydantic import BaseModel
from gyoza import gyoza_op
class Input(BaseModel):
image_path: str
top_k: int = 3
class Output(BaseModel):
label: str
confidence: float
@gyoza_op(input_model=Input, output_model=Output)
def classify_image(image_path: str, top_k: int = 3):
# ... load model, run inference ...
return "cat", 0.97
The function parameters must match the fields of input_model. The
return value is a tuple whose values are mapped positionally to the fields
of output_model. In the example above, "cat" maps to label and 0.97 maps to confidence.
When the container starts, gyoza run finds this decorated function,
feeds it the validated inputs, and serialises the output automatically.
The gyoza.yml file#
The gyoza.yml file is the project manifest. It contains everything gyoza
needs to build, deploy, and run your op. For building, the two required keys are image and build.
name: classify-image
version: "1.0.0"
image: myregistry/classify-image:1.0.0
build:
context: .
dockerfile: Dockerfile
args:
GITHUB_TOKEN: "${GITHUB_TOKEN}"
USER_UID: "${DOCKER_USER_ID:-1000}"
GROUP_ID: "${GROUP_ID:-1000}"
imageThe full Docker image tag that will be produced by the build. Use your registry prefix so images are easy to identify and push later.
buildUnder the hood, gyoza generates a temporary
docker-compose.ymland copies this section directly into it, so it supports the same keys as a Compose build block. In general, the most common keys are:contextPath to the build context (usually
., the project root).dockerfilePath to the Dockerfile, relative to the context.
argsBuild-time variables injected as Docker
ARGvalues. Values support${ENV_VAR}and${ENV_VAR:-default}substitution, so secrets like tokens do not need to be committed to the manifest.
All the other keys supported by the Docker Compose build block are supported by gyoza.
See also
The remaining fields in gyoza.yml (e.g constraints, retry_policy,
deploy, event_delivery, etc.) are covered in
Deploy a Gyoza Op.
The Dockerfile#
The Dockerfile is a regular Docker build recipe. The only gyoza-specific
requirement is that the container’s default command must call
gyoza run, pointing it at your op file:
FROM python:3.12-slim
ARG GITHUB_TOKEN
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN git config --global url."https://${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
WORKDIR /app
COPY ./ /app/
# Install your project (and gyoza as a dependency)
RUN pip install --no-cache-dir .
CMD ["gyoza", "run", "--file", "main.py"]
In the above Dockerfile, we ensure that the gyoza run command is available inside the container by installing gyoza as a dependency and setting it as the container entrypoint, which calls the main.py file containing the op logic and IO models.
Build the image#
Once the three files are in place, build the gyoza op image with:
gyoza build ./my-op
On success, you will see:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Build completed successfully!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
After that you can check if the image was built successfully by running:
docker images
You should see the image you built in the list.
REPOSITORY ID
myregistry/sample-op 1.0.0 31f3e0f1cfec
See also
gyoza build is also the first step of gyoza deploy. Use it
standalone when you want to iterate on the image locally before doing a
full deploy cycle. For testing the image locally, you can check the Test a Gyoza Op guide.
Full example#
Below is a complete, minimal op project for reference.
main.py#
from pydantic import BaseModel
from gyoza import gyoza_op
class Input(BaseModel):
image_path: str
top_k: int = 3
class Output(BaseModel):
label: str
confidence: float
@gyoza_op(input_model=Input, output_model=Output)
def classify_image(image_path: str, top_k: int = 3):
# ... load model, run inference ...
return "cat", 0.97
gyoza.yml#
name: sample-op
version: "1.0.0"
image: myregistry/sample-op:1.0.0
build:
context: .
dockerfile: Dockerfile
args:
GITHUB_TOKEN: "${GITHUB_TOKEN}"
Dockerfile#
FROM python:3.12-slim
ARG GITHUB_TOKEN
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
RUN git config --global url."https://${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
WORKDIR /app
COPY ./ /app/
RUN pip install --no-cache-dir .
CMD ["gyoza", "run", "--file", "main.py"]
pyproject.toml#
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "sample-op"
version = "1.0.0"
requires-python = ">=3.12"
dependencies = [
"gyoza @ git+https://github.com/g-e-o-i-a/gyoza.git",
]
[tool.setuptools]
py-modules = ["main"]
Build and verify:
gyoza build ./sample-op
Next steps#
Deploy a Gyoza Op, push the image, register the OpDefinition on the server, and start running your op in the cluster.