<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yhary Arias</title>
    <description>The latest articles on DEV Community by Yhary Arias (@yhary_arias).</description>
    <link>https://dev.to/yhary_arias</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2762480%2F5d914b6a-fa1a-4e00-bf36-fc6e3b1e9a9d.png</url>
      <title>DEV Community: Yhary Arias</title>
      <link>https://dev.to/yhary_arias</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yhary_arias"/>
    <language>en</language>
    <item>
      <title>I set up my first Docker SBX kit, and here's how I did it</title>
      <dc:creator>Yhary Arias</dc:creator>
      <pubDate>Thu, 03 Sep 2026 20:22:23 +0000</pubDate>
      <link>https://dev.to/yhary_arias/i-set-up-my-first-docker-sbx-kit-and-heres-how-i-did-it-b9a</link>
      <guid>https://dev.to/yhary_arias/i-set-up-my-first-docker-sbx-kit-and-heres-how-i-did-it-b9a</guid>
      <description>&lt;p&gt;A practical guide to building a real MLflow mixin kit from scratch, errors included.&lt;/p&gt;

&lt;p&gt;Hey! Let me tell you something. When I first heard about &lt;strong&gt;Docker Sandbox Kits&lt;/strong&gt;, my first reaction was: "Okay, another YAML thing. How hard can it be?"&lt;/p&gt;

&lt;p&gt;Spoiler: it was harder than expected. But also way more interesting.&lt;/p&gt;

&lt;p&gt;I'm Yhary, a Docker Captain and AI Engineer from Colombia. I recently built my first SBX kit as part of a Docker Captains community activity, and I want to walk you through the whole journey: what it is, why it matters, how I built it, and most importantly, every single thing that broke along the way.&lt;/p&gt;

&lt;p&gt;Let's go.&lt;/p&gt;

&lt;p&gt;First Things First: &lt;strong&gt;What Even Is a Docker Sandbox Kit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you're an AI engineer. You spin up a new sandbox to run some experiments with Claude Code. But before you can actually do anything, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install your ML libraries&lt;/li&gt;
&lt;li&gt;Set up your environment variables&lt;/li&gt;
&lt;li&gt;Start your tracking server&lt;/li&gt;
&lt;li&gt;Configure your network rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every. Single. Time.&lt;/p&gt;

&lt;p&gt;That's configuration drift. And it's been a problem since the 90s.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Docker Sandbox Kit (SBX Kit)&lt;/strong&gt; solves this. It's a declarative YAML file (&lt;code&gt;spec.yaml&lt;/code&gt;) that configures your sandbox environment automatically at creation time. One file. Reproducible. Shareable. No more "works on my machine."&lt;/p&gt;

&lt;p&gt;Think of it like &lt;strong&gt;dotfiles&lt;/strong&gt; + &lt;strong&gt;Infrastructure as Code&lt;/strong&gt;, but specifically designed for AI agent sandboxes.&lt;/p&gt;

&lt;p&gt;What a kit actually does&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Installs tools&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pip install mlflow&lt;/code&gt;, CLIs, binaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injects environment variables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MLFLOW_TRACKING_URI=http://localhost:5000&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manages secrets securely&lt;/td&gt;
&lt;td&gt;Tokens never enter the sandbox VM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controls network access&lt;/td&gt;
&lt;td&gt;Only allows &lt;code&gt;pypi.org&lt;/code&gt;, blocks everything else&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runs startup scripts&lt;/td&gt;
&lt;td&gt;Launches MLflow server automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two types of kits&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kind: agent&lt;/code&gt;: Defines a completely new agent from scratch. Has its own base image and entrypoint.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kind: mixin&lt;/code&gt;: Extends an existing agent (like Claude Code) by layering new capabilities on top. Think of it as a plugin.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;The golden rule:&lt;/u&gt;&lt;/strong&gt; Put heavy, stable dependencies in the Docker image. Put everything that changes (credentials, network rules, startup commands) in the kit YAML.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Okay, Now Let's Build One&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enough theory&lt;/strong&gt;. Let me show you what I built and how.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal:&lt;/strong&gt; A mixin kit that automatically starts an MLflow tracking server when the sandbox is created, so Claude Code can log ML experiments, track metrics, and version models right out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Plan the architecture&lt;/p&gt;

&lt;p&gt;Before writing any YAML, I sketched the architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SANDBOX (sbx)

Claude Code Agent
(orchestrates experiments via prompts)

MLflow Tracking Server 
http://localhost:5000

SQLite backend + artifact store
~/.mlflow/mlflow.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code talks to MLflow. MLflow persists everything to SQLite. Simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Set up the folder structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mlops-experiment-agent/
├── spec.yaml - The heart of the kit
├── Dockerfile - Base image with heavy dependencies
├── CLAUDE.md - Instructions for the Claude Code agent
├── scripts/
│   └── start-mlflow.sh
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Write the Dockerfile&lt;/p&gt;

&lt;p&gt;Heavy dependencies go in the image not in the install hook. This way, creating a sandbox just pulls a layer instead of downloading gigabytes every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; --platform=linux/amd64 docker/sandbox-templates:shell-docker&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    software-properties-common &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    pkg-config &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; add-apt-repository ppa:deadsnakes/ppa &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    python3.11 &lt;span class="se"&gt;\
&lt;/span&gt;    python3.11-venv &lt;span class="se"&gt;\
&lt;/span&gt;    python3.11-dev &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 1000&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/home/agent/.venv/bin:/home/agent/.local/bin:${PATH}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;python3.11 &lt;span class="nt"&gt;-m&lt;/span&gt; venv /home/agent/.venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    /home/agent/.venv/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    /home/agent/.venv/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="s2"&gt;"numpy==1.26.4"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="s2"&gt;"pandas==2.2.2"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="s2"&gt;"scikit-learn==1.4.2"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="s2"&gt;"mlflow==2.13.0"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="s2"&gt;"boto3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Write CLAUDE.md&lt;/p&gt;

&lt;p&gt;This file tells Claude Code what tools are available inside the sandbox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# MLOps Experiment Agent&lt;/span&gt;

You are an ML experiment orchestrator. MLflow is running at http://localhost:5000.

&lt;span class="gu"&gt;## Your capabilities&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Log experiments: &lt;span class="sb"&gt;`mlflow.start_run()`&lt;/span&gt;, &lt;span class="sb"&gt;`mlflow.log_param()`&lt;/span&gt;, &lt;span class="sb"&gt;`mlflow.log_metric()`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Register models: &lt;span class="sb"&gt;`mlflow.sklearn.log_model()`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Compare runs via the MLflow UI or Python client
&lt;span class="p"&gt;-&lt;/span&gt; Version datasets using MLflow's dataset tracking

&lt;span class="gu"&gt;## Common tasks you can do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; "Run a baseline experiment with this dataset"
&lt;span class="p"&gt;-&lt;/span&gt; "Compare the last 3 runs by accuracy"
&lt;span class="p"&gt;-&lt;/span&gt; "Register the best model to the Model Registry"
&lt;span class="p"&gt;-&lt;/span&gt; "Show me all experiments logged today"

&lt;span class="gu"&gt;## MLflow UI&lt;/span&gt;
Available at: http://localhost:5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Write the spec.yaml&lt;/p&gt;

&lt;p&gt;This is the final kit manifest after all the debugging (more on that below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mixin&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mlops-mixin&lt;/span&gt;
&lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MLOps Experiment Agent&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Orchestrates ML experiments inside a Docker Sandbox. Tracks runs,&lt;/span&gt;
  &lt;span class="s"&gt;logs metrics and parameters, versions models using MLflow.&lt;/span&gt;
  &lt;span class="s"&gt;Ideal for classification and CV pipelines.&lt;/span&gt;

&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;MLFLOW_TRACKING_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:5000"&lt;/span&gt;
    &lt;span class="na"&gt;MLFLOW_EXPERIMENT_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sandbox-experiments"&lt;/span&gt;

&lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowedDomains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pypi.org:443"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;files.pythonhosted.org:443"&lt;/span&gt;

&lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pip&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--break-system-packages&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--upgrade&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pip&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pip&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--break-system-packages&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'numpy&amp;gt;=2.0'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'pandas&amp;gt;=2.0'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'scikit-learn&amp;gt;=1.5'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'mlflow&amp;gt;=2.13'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;boto3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-i&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'s/from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;importlib.abc&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;import&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Traversable/from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;importlib.resources.abc&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;import&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Traversable/'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/agent/.local/lib/python3.14/site-packages/mlflow/assistant/skill_installer.py"&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000"&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MLflow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ML&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dependencies&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;patch&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Python&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;3.14&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;compatibility"&lt;/span&gt;
  &lt;span class="na"&gt;startup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mkdir&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-p&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/agent/.mlflow/artifacts&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;setsid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/agent/.local/bin/mlflow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--backend-store-uri&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sqlite:////home/agent/.mlflow/mlflow.db&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--default-artifact-root&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/agent/.mlflow/artifacts&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--port&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5000&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/agent/.mlflow/server.log&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000"&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Start&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MLflow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tracking&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Build and publish the Docker image&lt;/p&gt;

&lt;p&gt;On Apple Silicon (M1/M2/M3) you need to build for multiple architectures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a multi-arch builder&lt;/span&gt;
docker buildx create &lt;span class="nt"&gt;--name&lt;/span&gt; multiarch-builder &lt;span class="nt"&gt;--use&lt;/span&gt;

&lt;span class="c"&gt;# Build and push to Docker Hub for both platforms&lt;/span&gt;
docker buildx build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; yharyarias/mlops-experiment-agent:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 7:&lt;/strong&gt; Stage and publish the kit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage a clean copy, sbx kit push ignores .gitignore!&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /tmp/kit-stage/mlops-experiment-agent
rsync &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'.git'&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'.venv'&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'.sbx'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'*.tar'&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'.DS_Store'&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s1"&gt;'__pycache__'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ./mlops-experiment-agent/ /tmp/kit-stage/mlops-experiment-agent/

&lt;span class="c"&gt;# Publish as an OCI artifact&lt;/span&gt;
sbx kit push /tmp/kit-stage/mlops-experiment-agent &lt;span class="se"&gt;\&lt;/span&gt;
  docker.io/yharyarias/mlops-experiment-agent-kit:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; sbx kit push packages the directory exactly as it is, it does NOT respect .gitignore. Always stage a clean copy first. If you have a .venv or .sbx/.env with real secrets, they will be published.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Step 8: Run it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sbx run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kit&lt;/span&gt; docker.io/yharyarias/mlops-experiment-agent-kit:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; mlops-sandbox &lt;span class="se"&gt;\&lt;/span&gt;
  claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify from a second terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Is MLflow running?&lt;/span&gt;
sbx &lt;span class="nb"&gt;exec &lt;/span&gt;mlops-sandbox &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:5000/health

&lt;span class="c"&gt;# Check the startup log&lt;/span&gt;
sbx &lt;span class="nb"&gt;exec &lt;/span&gt;mlops-sandbox &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /var/log/sbx-kit-startup.log

&lt;span class="c"&gt;# Check the MLflow server log&lt;/span&gt;
sbx &lt;span class="nb"&gt;exec &lt;/span&gt;mlops-sandbox &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /home/agent/.mlflow/server.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Errors (This Is the Good Part)&lt;/p&gt;

&lt;p&gt;Let me be honest with you. Nothing worked on the first try. Here's every error I hit and how I fixed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error 1&lt;/strong&gt;: PEP 668: pip won't install system packages&lt;br&gt;
note: If you believe this is a mistake, please contact your Python installation or OS &lt;br&gt;
distribution provider. You can override this, at the risk of breaking your Python &lt;br&gt;
installation or OS, by passing --break-system-packages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; Modern Ubuntu protects the system Python from pip installs.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install --break-system-packages mlflow scikit-learn pandas numpy boto3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error 2&lt;/strong&gt;: NumPy has no wheel for Python 3.14&lt;br&gt;
Cannot compile &lt;code&gt;Python.h&lt;/code&gt;. Perhaps you need to install python-dev|python-devel&lt;br&gt;
Project name: NumPy&lt;br&gt;
Project version: 1.26.4&lt;br&gt;
Run-time dependency python found: YES 3.14&lt;br&gt;
Has header "Python.h" with dependency python: NO&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; The sandbox base image uses Python 3.14. &lt;code&gt;NumPy 1.26.4&lt;/code&gt; has no prebuilt wheel for &lt;code&gt;Python 3.14&lt;/code&gt;, it tries to compile from source and fails.&lt;/p&gt;

&lt;p&gt;Fix: Use &lt;code&gt;numpy&amp;gt;=2.0&lt;/code&gt; which has prebuilt wheels for Python 3.14:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install --break-system-packages 'numpy&amp;gt;=2.0' 'pandas&amp;gt;=2.0' 'scikit-learn&amp;gt;=1.5' 'mlflow&amp;gt;=2.13'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error 3&lt;/strong&gt;: Apple Silicon platform mismatch&lt;br&gt;
no match for platform in manifest sha256:dd0618b...: not found&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; Building on Mac M1/M2/M3 produces an aarch64 image. The sbx runtime expected a multi-arch manifest.&lt;/p&gt;

&lt;p&gt;Fix: Use docker buildx to build for both platforms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; yharyarias/mlops-experiment-agent:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error 4&lt;/strong&gt;: MLflow ImportError on Python 3.14&lt;br&gt;
&lt;em&gt;ImportError: cannot import name 'Traversable' from 'importlib.abc'&lt;br&gt;
  File ".../mlflow/assistant/skill_installer.py", line 11, in &lt;br&gt;
    from importlib.abc import Traversable&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; importlib.abc.Traversable was removed in Python 3.14 and moved to importlib.resources.abc. MLflow hadn't been updated yet.&lt;/p&gt;

&lt;p&gt;The cool part: Claude Code actually found and fixed this bug by itself inside the sandbox, it patched &lt;code&gt;skill_installer.py&lt;/code&gt; automatically. &lt;/p&gt;

&lt;p&gt;Fix: Apply a &lt;code&gt;sed&lt;/code&gt; patch in the install hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/from importlib.abc import Traversable/from importlib.resources.abc import Traversable/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  /home/agent/.local/lib/python3.14/site-packages/mlflow/assistant/skill_installer.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error 5:&lt;/strong&gt; Background process dies during startup&lt;br&gt;
setsid: failed to execute mlflow: No such file or directory&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; Two issues at once:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PATH&lt;/code&gt; is not set during startup hooks, so &lt;code&gt;mlflow&lt;/code&gt; can't be found by name&lt;br&gt;
Background processes started without &lt;code&gt;setsid&lt;/code&gt; die when the startup session ends&lt;/p&gt;

&lt;p&gt;Fix: Use the absolute path and always prefix with setsid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Wrong&lt;/span&gt;
&lt;span class="nb"&gt;nohup &lt;/span&gt;mlflow server ... &amp;amp;

&lt;span class="c"&gt;# Correct&lt;/span&gt;
setsid /home/agent/.local/bin/mlflow server ... &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /home/agent/.mlflow/server.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error 6:&lt;/strong&gt; MLflow directory doesn't exist at startup&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; MLflow tried to create its database before the artifact directory existed, and failed silently.&lt;/p&gt;

&lt;p&gt;Fix: Create the directory in the same startup command, before MLflow runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/agent/.mlflow/artifacts &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; setsid /home/agent/.local/bin/mlflow server ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pin to versions with prebuilt wheels. If your sandbox runs Python 3.14, don't pin to NumPy 1.26, check which versions have wheels for your target platform first.&lt;/li&gt;
&lt;li&gt;Use setsid + absolute paths for background processes. Every time, no exceptions.&lt;/li&gt;
&lt;li&gt;Stage before pushing. sbx kit push ignores .gitignore. Use rsync with excludes.&lt;/li&gt;
&lt;li&gt;Check the logs when something fails:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   sbx &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;sandbox&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /var/log/sbx-kit-startup.log
   sbx &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;sandbox&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /home/agent/.mlflow/server.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Test your install command locally using the hint Docker gives you on failure:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s1"&gt;'1000'&lt;/span&gt; &lt;span class="s1"&gt;'docker/sandbox-templates:claude-code-docker'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'your install command here'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Try It Yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The kit is live on Docker Hub. Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sbx run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kit&lt;/span&gt; docker.io/yharyarias/mlops-experiment-agent-kit:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; mlops-sandbox &lt;span class="se"&gt;\&lt;/span&gt;
  claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MLflow will start automatically on port 5000. Then you can prompt Claude Code with things like:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Run a baseline logistic regression on the iris dataset and log the results to MLflow&lt;br&gt;
Compare the last 3 MLflow runs by accuracy&lt;br&gt;
Register the best model to the Model Registry&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Links&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Hub: &lt;a href="https://hub.docker.com/r/yharyarias/mlops-experiment-agent-kit" rel="noopener noreferrer"&gt;yharyarias/mlops-experiment-agent-kit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR on sbx-kits-contrib: &lt;a href="https://github.com/docker/sbx-kits-contrib/pull/111" rel="noopener noreferrer"&gt;#111 - Yharyarias mlops mixin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docker SBX Docs: &lt;a href="https://docs.docker.com/ai/sandboxes/get-started/" rel="noopener noreferrer"&gt;docs.docker.com/ai/sandboxes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>Docker Offload and the advantages of using it in IA projects</title>
      <dc:creator>Yhary Arias</dc:creator>
      <pubDate>Wed, 16 Jul 2025 02:43:11 +0000</pubDate>
      <link>https://dev.to/yhary_arias/docker-offload-y-las-ventajas-de-usarlo-en-proyectos-de-ai-5dpa</link>
      <guid>https://dev.to/yhary_arias/docker-offload-y-las-ventajas-de-usarlo-en-proyectos-de-ai-5dpa</guid>
      <description>&lt;p&gt;Docker Offload is the new release of Docker released this July 10, 2025, this new functionality allows us to offload the execution of containers remotely, taking advantage of the cloud without configuring complex environments.&lt;/p&gt;

&lt;p&gt;Docker describes it as a way to run containers “as if it were local, but running on another machine”, all controlled from your own docker run as we have always done.&lt;/p&gt;

&lt;p&gt;How can this be an advantage in an IA project?&lt;br&gt;
In general we know that IA projects usually need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Powerful GPU's to train or run models.&lt;/li&gt;
&lt;li&gt;Lots and lots of RAM (otherwise the machine shuts down 😬)&lt;/li&gt;
&lt;li&gt;Scalability and efficiency in model testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Docker Offload, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use your local machine to develop, but running models on a more powerful infrastructure.&lt;/li&gt;
&lt;li&gt;Accelerate ML pipelines without manually mounting servers&lt;/li&gt;
&lt;li&gt;Test giant models without crashing your machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get to the point! here are the advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplicity: No need to set up complex clusters or remote servers.&lt;/li&gt;
&lt;li&gt;Scalability: You can easily leverage cloud or external servers&lt;/li&gt;
&lt;li&gt;Portability: You keep using the usual Docker ecosystem.&lt;/li&gt;
&lt;li&gt;Ideal for AI testing and development without overloading your team 😎&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get to the good stuff, the practice:&lt;/p&gt;

&lt;p&gt;🚀 Step by step: basic Docker Offload configuration.&lt;/p&gt;

&lt;p&gt;Before you start, you need to have installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Desktop updated (I recommend you to remove the app from your machine and reinstall it, to go fixed).&lt;/li&gt;
&lt;li&gt;Docker Offload enabled (requires Docker account with beta program access).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Enable Docker Offload&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Docker Desktop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Features in development&lt;/li&gt;
&lt;li&gt;Enable the Docker Offload option&lt;/li&gt;
&lt;li&gt;Restart Docker Desktop&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Let's follow the "quickstart" of the official Docker documentation&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;According to the documentation as of today (07/15/2025) we must open Docker Desktop and log in.&lt;/li&gt;
&lt;li&gt;Now open the terminal of your machine (whatever it is) and run the following command:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ docker offload start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It should show you the following message:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk3uaazpjjp505xqs2fr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk3uaazpjjp505xqs2fr.png" alt=" " width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit Enter if the account you are going to use is correct. Then it will ask you if you need GPU support. For this example we will say “yes”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mks35hvhhslaaelalk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mks35hvhhslaaelalk2.png" alt=" " width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are now ready to use Docker Offload! 🚀&lt;/p&gt;

&lt;p&gt;Docker Offload will run on an instance with an NVIDIA L4 &lt;strong&gt;GPU&lt;/strong&gt;, which is useful for machine learning or resource intensive workloads.&lt;/p&gt;

&lt;p&gt;Now if you go to Docker Desktop you are going to see a cloud icon ☁️ in the header of the panel, this tells us that you have successfully enabled Docker Offload.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqzg1b8hah0qi2hfq3ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqzg1b8hah0qi2hfq3ta.png" alt=" " width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To check the status of Docker Offload let's run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker offload status&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgna79tqxbrjtunrhjuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgna79tqxbrjtunrhjuw.png" alt=" " width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally we are going to run a container with Docker Offload.&lt;/p&gt;

&lt;p&gt;The documentation suggests the following example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run --rm --gpus all hello-world&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see the following after running the command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7wr2z0npuqj6czpxct4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7wr2z0npuqj6czpxct4.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are doing quite well 🥳 now the following example is optional, so you can see how it works with another command creating a container in a simple way:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ &lt;br&gt;
docker run --platform linux/amd64 python:3.11-slim python -c "print('Hola desde Docker Offload!')"&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfo9m2n6457wufnxlyla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfo9m2n6457wufnxlyla.png" alt=" " width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait ‼️ don't go away, we must stop the use of Docker Offload to avoid unnecessary consumption of resources in the cloud and return to a local environment by running the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker offload stop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;🛠️ And that's it!&lt;br&gt;
I hope this Docker Offload journey has saved you CPU, RAM... and headaches! 🧠💻&lt;/p&gt;

&lt;p&gt;Love you guys, thanks for making it this far. Bye.&lt;br&gt;
[Yhary Arias / &lt;a class="mentioned-user" href="https://dev.to/ia"&gt;@ia&lt;/a&gt;.fania]&lt;/p&gt;

</description>
      <category>programming</category>
      <category>docker</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Orchestrating Models: Machine Learning with Docker Compose</title>
      <dc:creator>Yhary Arias</dc:creator>
      <pubDate>Tue, 25 Mar 2025 18:19:50 +0000</pubDate>
      <link>https://dev.to/yhary_arias/orchestrating-models-machine-learning-with-docker-compose-5dlo</link>
      <guid>https://dev.to/yhary_arias/orchestrating-models-machine-learning-with-docker-compose-5dlo</guid>
      <description>&lt;p&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt; is a powerful tool for defining and managing multi-container Docker applications in a simple and efficient way. In this article, we will explore the basics of Docker Compose and how you can start using it to orchestrate your applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Docker Compose?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Docker Compose is a tool that allows you to define and run multi-container Docker applications using a YAML file to configure your application's services. Then, with a single command, you can create and run all the defined containers. This makes it easier to create and configure complex development and production environments where multiple services need to interact with each other.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Optional&lt;br&gt;
&lt;strong&gt;Installing Docker Compose&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Before getting started, make sure you have Docker Compose installed on your machine. You can install it by following the &lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;official Docker instructions&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your OS is Mac, you can use the following command to install Docker Compose. Before running it, ensure that Docker Desktop is installed on your machine.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ brew install docker-compose&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, check the installed version:&lt;br&gt;
&lt;code&gt;$ docker-compose --version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Before testing Docker Compose with a Machine Learning project, let's clarify the difference between Docker Compose and Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What it does:&lt;/strong&gt; Docker Compose is a tool that allows you to run multiple containers together. It is mainly designed for development and testing. It is ideal if you want to quickly spin up multiple services on your machine, such as a database, an API, and a web application, all running locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt; You use a file called &lt;code&gt;docker-compose.yml&lt;/code&gt; to define which containers you will use and how they connect to each other. For example, you can say: "I want to launch my application and connect it to a database." Compose will take care of that for you with a single command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; Small or development projects where you don't need a very complex system and just want to test things quickly on your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What it does:&lt;/strong&gt; Kubernetes is much larger and more powerful than Docker Compose. Not only does it help you launch containers, but it also helps manage applications in production, on real servers, efficiently and at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt; Kubernetes ensures that your application is always running, has enough resources, and can handle many users. If one of your containers fails, Kubernetes automatically replaces it. It can also scale (increase or decrease the number of containers) based on what your application needs at any moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; Large-scale production applications that need to be always available and handle heavy traffic. Big companies or projects expecting significant growth often use Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In summary:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Docker Compose is for launching and managing multiple containers quickly on your local machine, ideal for development or testing.&lt;br&gt;&lt;br&gt;
Kubernetes is for managing large-scale applications in production, where you need more control, stability, and scalability.&lt;br&gt;&lt;br&gt;
Compose is like a small engine that helps you work on your project. Kubernetes is like a massive system that keeps your application running smoothly, even with many users and high traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, let's get to the real deal. 😎&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;I'll show you how to apply Docker Compose in an ML project. We will create a simple application that trains a machine learning model and exposes a web service for making predictions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Objective&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Our project will consist of two services:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ML Service:&lt;/strong&gt; A trained machine learning model using &lt;strong&gt;scikit-learn&lt;/strong&gt; that is exposed via a Flask web API.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Database Service:&lt;/strong&gt; A PostgreSQL database to store prediction results.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The basic file structure will be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ml_project/
│
├── docker-compose.yml
├── ml_service/
│   ├── Dockerfile
│   ├── app.py
│   ├── model.py
│   ├── requirements.txt
└── db/
    ├── init.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1. Define &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The first step is to define the services in a &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:
  ml_service:
    build: ./ml_service
    ports:
      - "5000:5000"
    depends_on:
      - db
  db:
    image: postgres
    environment:
      POSTGRES_DB: ml_results
      POSTGRES_USER: ml_user
      POSTGRES_PASSWORD: ml_password
    volumes:
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create the Machine Learning service&lt;/strong&gt;&lt;br&gt;
Inside the &lt;code&gt;ml_service/&lt;/code&gt; folder, we create a &lt;code&gt;Dockerfile&lt;/code&gt; that will install the necessary Python dependencies, train a model, and expose the service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt; (for the ML service)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.8

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;br&gt;
Here we define the dependencies we will use, such as Flask for the web server and scikit-learn for the ML model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flask==2.1.0
scikit-learn==1.0.2
psycopg2-binary==2.9.3  # Para conectar con PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;model.py&lt;/code&gt;&lt;br&gt;
This file contains the code to train the machine learning model. We will use a simple classification model like Logistic Regression.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
import pickle

def train_model():
    # Load sample dataset
    iris = load_iris()
    X, y = iris.data, iris.target

    # Train model
    model = LogisticRegression()
    model.fit(X, y)

    # Save model to file
    with open('model.pkl', 'wb') as f:
        pickle.dump(model, f)

if __name__ == "__main__":
    train_model()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code trains a simple classification model and saves it as a &lt;code&gt;model.pkl&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app.py&lt;/code&gt;&lt;br&gt;
This is the Flask file that creates the API to make predictions using the trained model. Additionally, it stores the predictions in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, request, jsonify
import pickle
import psycopg2

app = Flask(__name__)

# Load trained ML model
with open('model.pkl', 'rb') as f:
    model = pickle.load(f)

# Connect to PostgreSQL database
conn = psycopg2.connect(
    dbname="ml_results", user="ml_user", password="ml_password", host="db"
)
cur = conn.cursor()

@app.route('/predict', methods=['POST'])
def predict():
    data = request.json
    X_new = [data['features']]

    # Make prediction
    prediction = model.predict(X_new)[0]

    # Save prediction to database
    cur.execute("INSERT INTO predictions (input, result) VALUES (%s, %s)", (str(X_new), int(prediction)))
    conn.commit()

    return jsonify({"prediction": int(prediction)})

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Flask service listens on port 5000 and, upon receiving a POST request with the input characteristics, returns a prediction and stores the result in PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure the Database&lt;/strong&gt;&lt;br&gt;
In the &lt;code&gt;db/&lt;/code&gt; directory, we create an &lt;code&gt;init.sql&lt;/code&gt; file to initialize the database with a table to store predictions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;init.sql&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE predictions (
    id SERIAL PRIMARY KEY,
    input TEXT,
    result INTEGER
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script will run automatically when the PostgreSQL container is started, and will create a table called &lt;code&gt;predictions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Run the Project&lt;/strong&gt;&lt;br&gt;
Now that everything is set up, you can run the entire project with Docker Compose. From the root project directory, run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will make Docker Compose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build the machine learning service image.&lt;/li&gt;
&lt;li&gt;Start the ML and database containers.&lt;/li&gt;
&lt;li&gt;Run the Flask model and web server on port 5000.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Test the API&lt;/strong&gt;&lt;br&gt;
To make a prediction, send a POST request to &lt;code&gt;http://localhost:5000/predict&lt;/code&gt; with a JSON body containing dataset features.&lt;/p&gt;

&lt;p&gt;Command example &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;code&gt;$ curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"features": [5.1, 3.5, 1.4, 0.2]}'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything is configured correctly, you will get a response like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "prediction": 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
With Docker Compose, we have created a machine learning project that includes a web service to make predictions with an ML model, as well as a PostgreSQL database to store the results. Docker Compose simplifies the management of these services in development and production environments, allowing you to work with multiple containers in a coordinated manner.&lt;/p&gt;

&lt;p&gt;This example is just a starting point, and you can expand it by adding more services, connecting other machine learning models or integrating tools like Redis for caching or Celery for asynchronous tasks.&lt;/p&gt;

&lt;p&gt;Now you're ready to use Docker Compose in more complex machine learning projects!&lt;/p&gt;

&lt;p&gt;Author: Yhary Arias.&lt;br&gt;
GitHub: &lt;a href="https://github.com/yharyarias" rel="noopener noreferrer"&gt;@yharyarias&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/yharyarias/" rel="noopener noreferrer"&gt;@yharyarias&lt;/a&gt;&lt;br&gt;
Instagram: &lt;a href="https://www.instagram.com/ia.fania/" rel="noopener noreferrer"&gt;@ia.fania&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>api</category>
      <category>flask</category>
      <category>python</category>
    </item>
  </channel>
</rss>
