Deploying ClearML as an Azure ML Alternative ClearML, an open-source MLOps platform, can be deployed as a self-hosted alternative to Azure Machine Learning, offering experiment tracking, pipelines, and model serving on any infrastructure. A developer's guide details setting up ClearML Server with Docker Compose and Traefik, configuring agents for remote execution, and integrating Triton for model serving, providing a cost-effective and portable solution for MLOps workflows. Azure Machine Learning ties experiment tracking, pipelines, and model serving to Azure-specific APIs and managed-compute pricing. ClearML https://clear.ml/ is an open-source MLOps platform that provides the same capabilities — self-hosted, on any infrastructure. This guide deploys ClearML Server with Docker Compose and Traefik, configures agents for remote execution, tracks an experiment, builds a pipeline, runs hyperparameter optimization, and serves a model with Triton. Prerequisites:a Linux server, non-root sudo user, Docker + Docker Compose, DNS A records for app.clearml.example.com , api.clearml.example.com , files.clearml.example.com . GPU workloads optional need the NVIDIA Container Toolkit on the agent host. | Azure ML | ClearML equivalent | |---|---| | Azure ML Studio | ClearML Web UI | | Azure ML Experiments | Experiment Manager auto-tracking | | Azure ML Jobs | Agent + Tasks | | Azure ML Pipelines | ClearML Pipelines Python DAG | | Azure ML Model Registry | Model Repository | | Azure ML Endpoints | ClearML Serving Triton | Server components: API server, web UI, file server — backed by MongoDB + Elasticsearch. Agents are worker daemons that pull tasks from queues and run them on any machine with Python. bash $ echo "vm.max map count=524288" | sudo tee /etc/sysctl.d/99-clearml.conf $ sudo sysctl --system $ sudo systemctl restart docker $ sudo mkdir -p /opt/clearml/{data/elastic 7,data/mongo 4/db,data/mongo 4/configdb,data/redis,data/fileserver,logs,config} $ sudo chown -R 1000:1000 /opt/clearml $ mkdir -p ~/clearml && cd ~/clearml $ curl -fsSL https://raw.githubusercontent.com/clearml/clearml-server/master/docker/docker-compose.yml -o docker-compose.yml Edit docker-compose.yml : comment out every ports: block under apiserver , webserver , fileserver Traefik handles routing , and set named bridge networks: networks: backend: name: clearml backend driver: bridge frontend: name: clearml frontend driver: bridge Create .env replace clearml.example.com with your domain : CLEARML WEB HOST=https://app.clearml.example.com CLEARML API HOST=https://api.clearml.example.com CLEARML FILES HOST=https://files.clearml.example.com bash $ docker compose up -d $ docker compose ps $ docker compose logs --tail 50 bash $ mkdir -p ~/clearml/traefik && cd ~/clearml/traefik $ mkdir -p letsencrypt && touch letsencrypt/acme.json $ chmod 600 letsencrypt/acme.json .env replace with your email : LETSENCRYPT EMAIL=admin@example.com docker-compose.yml : services: traefik: image: traefik:v3.6 container name: traefik command: - "--log.level=INFO" - "--providers.file.filename=/etc/traefik/dynamic conf.yml" - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.web.http.redirections.entrypoint.to=websecure" - "--certificatesResolvers.le.acme.httpChallenge.entryPoint=web" - "--certificatesResolvers.le.acme.email=${LETSENCRYPT EMAIL}" - "--certificatesResolvers.le.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "./letsencrypt:/letsencrypt" - "./dynamic conf.yml:/etc/traefik/dynamic conf.yml:ro" networks: - clearml-frontend restart: unless-stopped networks: clearml-frontend: name: clearml frontend external: true dynamic conf.yml routes each subdomain to its container clearml-webserver:80 , clearml-apiserver:8008 , clearml-fileserver:8081 with certResolver: le . Full rules in the source repo https://github.com/clearml/clearml-server . bash $ docker compose up -d $ docker logs traefik 2 &1 | grep -i certificate https://app.clearml.example.com , create the admin account username + company name . api { web server: https://app.clearml.example.com api server: https://api.clearml.example.com files server: https://files.clearml.example.com credentials { "access key" = "YOUR ACCESS KEY" "secret key" = "YOUR SECRET KEY" } } Agents can run on the server itself or a dedicated ideally GPU-enabled machine. bash $ mkdir -p ~/clearml-agent && cd ~/clearml-agent $ sudo apt install python3.12-venv -y $ python3 -m venv clearml venv $ source clearml venv/bin/activate $ pip install clearml-agent $ clearml-agent init Paste the credentials block when prompted, accept defaults for the rest. Then start it: bash $ clearml-agent daemon --queue default --detached GPU workloads: bash $ clearml-agent daemon --gpus 0,1 --queue default --detached Confirm it registered under Workers & Queues → Workers in the web UI. bash $ source ~/clearml-agent/clearml venv/bin/activate $ pip install clearml scikit-learn joblib pandas $ clearml-init Paste the credentials block again when prompted — saves to ~/clearml.conf . bash $ mkdir -p ~/clearml/experiments && cd ~/clearml/experiments $ nano 01 first experiment.py python import joblib from clearml import Task from sklearn.datasets import load iris from sklearn.model selection import train test split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy score task = Task.init project name='ClearML Tutorial', task name='01 First Experiment', tags= 'tutorial' hyperparams = {'n estimators': 100, 'max depth': 5, 'random state': 42} task.connect hyperparams iris = load iris X train, X test, y train, y test = train test split iris.data, iris.target, test size=0.2, random state=42 clf = RandomForestClassifier hyperparams clf.fit X train, y train accuracy = accuracy score y test, clf.predict X test task.get logger .report scalar title='Performance', series='Accuracy', value=accuracy, iteration=1 joblib.dump clf, 'iris rf model.pkl' task.upload artifact name='trained model', artifact object='iris rf model.pkl' task.close bash $ python3 01 first experiment.py Task.init auto-captures code, environment, and hyperparameters — no manual logging needed beyond report scalar . Open the printed task URL to see it in the web UI: Execution , Configuration , Artifacts , Console , Scalars , Plots tabs. clearml.PipelineController chains functions into a DAG; step outputs feed downstream steps automatically: python from clearml import PipelineController def step one pickle data url : import pickle, pandas as pd from clearml import StorageManager local pkl = StorageManager.get local copy remote url=pickle data url with open local pkl, 'rb' as f: iris = pickle.load f df = pd.DataFrame iris 'data' , columns=iris 'feature names' df 'target' = iris 'target' return df def step two data frame, test size=0.2, random state=42 : from sklearn.model selection import train test split y = data frame 'target' X = data frame.drop columns= 'target' return train test split X, y, test size=test size, random state=random state def step three data : from sklearn.linear model import LogisticRegression X train, X test, y train, y test = data model = LogisticRegression solver='lbfgs', max iter=1000 model.fit X train, y train return model if name == ' main ': pipe = PipelineController project='ClearML Tutorial', name='02 Pipeline Experiment', version='1.0', add pipeline tags=True pipe.add parameter name='url', default='https://github.com/allegroai/events/raw/master/odsc20-east/generic/iris dataset.pkl' pipe.add function step name='step one', function=step one, function kwargs=dict pickle data url='${pipeline.url}' , function return= 'data frame' , cache executed step=True pipe.add function step name='step two', function=step two, function kwargs=dict data frame='${step one.data frame}' , function return= 'processed data' , cache executed step=True pipe.add function step name='step three', function=step three, function kwargs=dict data='${step two.processed data}' , function return= 'model' , cache executed step=True pipe.start locally run pipeline steps locally=True bash $ python3 02 pipeline.py View the execution graph under the project in the web UI. ClearML clones a completed base task and spawns trials across a defined search space: python from clearml import Task from clearml.automation import HyperParameterOptimizer, DiscreteParameterRange, UniformIntegerParameterRange, RandomSearch tasks = Task.get tasks project name='ClearML Tutorial', task filter={'status': 'completed', 'published' }, task name='01 First Experiment' base task id = tasks -1 .id Task.init project name='ClearML Tutorial', task name='03 Hyperparameter Optimization', task type=Task.TaskTypes.optimizer optimizer = HyperParameterOptimizer base task id=base task id, hyper parameters= UniformIntegerParameterRange 'General/n estimators', min value=10, max value=200, step size=20 , DiscreteParameterRange 'General/max depth', values= 3, 5, 7, 10 , objective metric title='Performance', objective metric series='Accuracy', objective metric sign='max', optimizer class=RandomSearch, max number of concurrent tasks=2, total max jobs=6 optimizer.start optimizer.wait top exp = optimizer.get top experiments 1 bash $ python3 03 hpo.py Run the base experiment first — HPO needs a completed task to clone. bash $ cd ~/clearml $ git clone https://github.com/clearml/clearml-serving.git $ pip install clearml-serving $ clearml-serving create --name "serving-example" Copy the printed Serving Service ID, then edit clearml-serving/docker/.env : CLEARML WEB HOST="https://app.clearml.example.com" CLEARML API HOST="https://api.clearml.example.com" CLEARML FILES HOST="https://files.clearml.example.com" CLEARML API ACCESS KEY="YOUR ACCESS KEY" CLEARML API SECRET KEY="YOUR SECRET KEY" CLEARML SERVING TASK ID="SERVING SERVICE ID" bash $ cd ~/clearml/clearml-serving/docker $ docker compose --env-file .env -f docker-compose-triton.yml up -d $ pip install -r ~/clearml/clearml-serving/examples/pytorch/requirements.txt $ python3 ~/clearml/clearml-serving/examples/pytorch/train pytorch mnist.py Grab the Model ID from the task's Artifacts tab, then register the endpoint: bash $ clearml-serving --id SERVING SERVICE ID model add \ --engine triton \ --endpoint "test model pytorch" \ --preprocess "clearml-serving/examples/pytorch/preprocess.py" \ --model-id MODEL ID \ --input-size 1 28 28 \ --input-name "INPUT 0" \ --input-type float32 \ --output-size 10 \ --output-name "OUTPUT 0" \ --output-type float32 $ docker compose --env-file .env -f docker-compose-triton.yml restart Test it replace SERVER-IP : bash $ curl -X POST "http://SERVER-IP:8080/serve/test model pytorch" \ -H "Content-Type: application/json" \ -d '{"url": "https://raw.githubusercontent.com/clearml/clearml-serving/main/examples/pytorch/5.jpg"}' bash $ curl -s https://api.clearml.example.com/debug.ping | head -c 100 $ curl -s -o /dev/null -w "%{http code}" https://files.clearml.example.com/ Confirm the agent shows under Workers & Queues , the first experiment has metrics/artifacts, and cloning + enqueuing a modified experiment gets picked up by the agent. azure.ai.ml job definitions → clearml.Task auto-captures Git state, env, uncommitted changes . task.execute remotely or enqueue via UI. azure.ai.ml → PipelineController or @pipeline decorator. HyperParameterOptimizer , running on your own agents. azure.ai.ml registration → OutputModel , with full lineage. clearml.conf or CLEARML API ACCESS KEY / CLEARML API SECRET KEY . mlflow.log calls route through ClearML's MLflow-compatible backend without a rewrite.ClearML Server is running behind Traefik with an agent, tracked experiments, a pipeline, HPO, and a served model. From here: For the full guide, visit the original article on Vultr Docs .