Configuration
⚠️ Research Use Only — Models trained and deployed through this platform are for research and development purposes. Clinical deployment requires regulatory review, validation against clinical standards, and human oversight. AI predictions must not be used as the sole basis for medical decisions.
This document covers all configuration options for the MedML Training Dashboard — environment files, AWS credentials, Docker setup, IAM permissions, and ECR image management.
1. Environment Files
The application uses a two-layer environment variable system loaded by python-dotenv in main.py:
File |
Purpose |
Committed to git? |
|---|---|---|
|
General application config (region, MLflow URI, log settings) |
Yes ( |
|
Account-specific secrets and identifiers (account ID, role ARN, ECR URIs) |
No (gitignored) |
|
Template for |
Yes |
Load order: .env is loaded first, then .env.local overrides any overlapping keys:
load_dotenv() # loads .env
load_dotenv(".env.local", override=True) # loads .env.local, overriding duplicates
Initial setup
cp .env.example .env
cp .env.local.example .env.local
# Edit .env.local with your real AWS account ID, role ARN, and ECR URIs
2. General Config (.env)
These variables control application behavior and third-party service endpoints.
Variable |
Description |
Default |
Example |
|---|---|---|---|
|
AWS access key (optional if using |
— |
|
|
AWS secret key |
— |
|
|
AWS region for all boto3 clients |
|
|
|
MLflow server endpoint for experiment tracking |
|
|
|
Default MLflow experiment name |
|
|
|
Directory for TensorBoard event files |
|
|
|
Enable debug mode (verbose logging, auto-reload) |
|
|
|
Python logging level |
|
|
Example .env
# AWS Configuration (optional — can be configured via UI)
AWS_ACCESS_KEY_ID=your_access_key_here
AWS_SECRET_ACCESS_KEY=your_secret_key_here
AWS_DEFAULT_REGION=us-east-1
# MLflow Configuration
MLFLOW_TRACKING_URI=http://localhost:5000
MLFLOW_EXPERIMENT_NAME=medical_imaging_experiments
# TensorBoard Configuration
TENSORBOARD_LOG_DIR=./logs/tensorboard
# Application Configuration
DEBUG=True
LOG_LEVEL=INFO
3. Account-Specific Config (.env.local)
These variables are unique to your AWS account and should never be committed.
Variable |
Description |
Example |
|---|---|---|
|
Your 12-digit AWS account ID |
|
|
SageMaker execution role ARN |
|
|
ECR URI for the classification training container |
|
|
ECR URI for the segmentation training container |
|
|
ECR URI for the classification inference container |
|
|
ECR URI for the segmentation inference container |
|
|
Default training data S3 URI (pre-populates the UI form) |
|
|
S3 URI of a test DICOM image for integration tests |
|
|
S3 URI of a test NIfTI volume for segmentation tests |
|
Example .env.local
# Your AWS account ID (used for ECR image URIs)
AWS_ACCOUNT_ID=123456789012
# SageMaker execution role (created by ./create-sagemaker-role.sh)
SAGEMAKER_ROLE_ARN=arn:aws:iam::123456789012:role/AmazonSageMaker-ExecutionRole-sgm
# ECR image URIs (built via build_and_push.sh)
TRAINING_IMAGE_CLASSIFICATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-classification:latest
TRAINING_IMAGE_SEGMENTATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-segmentation:latest
INFERENCE_IMAGE_CLASSIFICATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-classification:latest
INFERENCE_IMAGE_SEGMENTATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-segmentation:latest
# Default data locations
DEFAULT_DATA_S3_URI=s3://<your-bucket-name>/training/spine-xr/
# Test data locations
TEST_IMAGE_S3_URI=s3://<your-bucket-name>/test/sample.dcm
TEST_SEGMENTATION_S3_URI=s3://<your-bucket-name>/test/volume.nii.gz
4. AWS Credentials
The application supports three methods for providing AWS credentials, checked in this order:
Method 1: Environment variables (.env or .env.local)
Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in your .env file:
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION=us-east-1
Best for: local development when you don’t have AWS CLI configured.
Method 2: AWS credentials file (~/.aws/credentials)
Configure the AWS CLI and the app picks up the default profile automatically:
aws configure
# Enter: Access Key ID, Secret Access Key, Region, Output format
Or use a named profile by setting AWS_PROFILE:
export AWS_PROFILE=medml-dev
python main.py
Best for: developers who use multiple AWS accounts.
Method 3: Dashboard UI
Navigate to the AWS tab in the dashboard and enter credentials interactively. The dashboard calls AWSService.configure_credentials() which creates boto3 clients in memory — credentials are not persisted to disk.
Best for: quick testing or demos without touching local config files.
Credential priority
If environment variables are set at startup, the AWSService automatically initializes boto3 clients. If they’re absent, the service remains unconfigured until credentials are provided via the UI.
5. Runtime Config API
The GET /api/config endpoint serves non-secret configuration values to the frontend, allowing the UI to pre-populate forms with ECR URIs, role ARNs, and default data paths.
Response
{
"aws_account_id": "123456789012",
"aws_region": "us-east-1",
"sagemaker_role_arn": "arn:aws:iam::123456789012:role/AmazonSageMaker-ExecutionRole-sgm",
"training_image_classification": "123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-classification:latest",
"training_image_segmentation": "123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-segmentation:latest",
"inference_image_classification": "123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-classification:latest",
"inference_image_segmentation": "123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-segmentation:latest",
"default_data_s3_uri": "s3://<your-bucket-name>/training/spine-xr/"
}
How it works
Values come from environment variables (loaded from
.env.local)If
AWS_ACCOUNT_IDis set but specific image URIs are not, the endpoint auto-generates ECR URIs using the conventional naming schemeNo secrets (access keys, secret keys) are ever exposed through this endpoint
Frontend usage
The dashboard JavaScript fetches /api/config on page load to pre-fill the SageMaker training form:
const config = await fetch('/api/config').then(r => r.json());
document.getElementById('image-uri').value = config.training_image_classification;
document.getElementById('role-arn').value = config.sagemaker_role_arn;
6. Docker Configuration
docker-compose.yml
The single-container setup runs FastAPI, MLflow, and TensorBoard together:
version: '3.8'
services:
medml-platform:
build: .
ports:
- "8000:8000" # FastAPI application
- "5000:5000" # MLflow
- "6006:6006" # TensorBoard
environment:
- DEBUG=True
- LOG_LEVEL=INFO
- MLFLOW_TRACKING_URI=http://localhost:5000
- TENSORBOARD_LOG_DIR=./logs/tensorboard
volumes:
- ./data:/app/data
- ./logs:/app/logs
- ./models:/app/models
restart: unless-stopped
Environment variables in Docker
Pass AWS credentials and account config at run time (never bake them into the image):
docker-compose run -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_DEFAULT_REGION=us-east-1 \
medml-platform
Or use an env file:
# docker-compose.override.yml
services:
medml-platform:
env_file:
- .env
- .env.local
Volume mounts
Host path |
Container path |
Purpose |
|---|---|---|
|
|
Persisted job records, training reports, imported models |
|
|
TensorBoard event files |
|
|
Downloaded model artifacts |
Exposed ports
Port |
Service |
|---|---|
8000 |
FastAPI dashboard |
5000 |
MLflow tracking server |
6006 |
TensorBoard |
7. SageMaker IAM Role
The SAGEMAKER_ROLE_ARN must have permissions to run training jobs, deploy endpoints, access S3 data, pull ECR images, write logs, and track experiments with MLflow.
Role creation script
The create-sagemaker-role.sh script is the bash equivalent of the shared Python get_or_create_role() utility (found in utils.py). It creates a role with managed AWS policies and an inline MLflow policy.
# Create with the default role name (AmazonSageMaker-ExecutionRole-sgm)
./create-sagemaker-role.sh
# Or specify a custom role name
./create-sagemaker-role.sh MyCustomRoleName
The script also runs via the setup helper:
./setup.sh --role
If the role already exists, the script updates the trust policy and re-attaches all policies (idempotent).
Default role name
AmazonSageMaker-ExecutionRole-sgm
This matches the Python get_or_create_role() default, so both the bash script and Python notebooks produce the same role.
Trust policy
The role trusts the SageMaker service to assume it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sagemaker.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Managed policies attached
The script attaches the following AWS managed policies:
Policy |
Purpose |
|---|---|
|
Training jobs, endpoints, processing, monitoring |
|
Read/write training data, model artifacts, capture logs |
|
Image analysis capabilities |
|
NLP text analysis |
|
Medical text extraction |
|
Pull/push container images |
|
SageMaker Canvas no-code ML |
|
Canvas AI services integration |
|
Canvas data science assistant |
|
Canvas data preparation |
Production note: For production deployments, replace
FullAccesspolicies with scoped policies restricted to specific bucket ARNs, repository ARNs, and resource prefixes. The broad policies above are suitable for development and experimentation.
Inline MLflow policy
An inline policy named mlflow-policy is added for SageMaker MLflow experiment tracking. The resource is scoped to your specific tracking server:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "MLflowTrackingAccess",
"Effect": "Allow",
"Action": ["sagemaker-mlflow:*"],
"Resource": "arn:aws:sagemaker:<region>:<account-id>:mlflow-tracking-server/<server-name>"
}
]
}
The script determines the resource ARN based on your .env.local configuration:
|
|
Resource scope |
|---|---|---|
Yes |
Yes |
|
No |
Yes |
|
No |
No |
|
Security note: Always set
MLFLOW_TRACKING_SERVER_NAMEin.env.localto scope permissions to your specific tracking server. UsingResource: "*"grants MLflow permissions across all tracking servers in the account.
When to use which approach
Context |
Method |
|---|---|
Running outside SageMaker (EC2, local, CI/CD) |
|
Running inside SageMaker (Studio, notebook instances) |
|
Creating the role manually
If you prefer not to use the script:
# 1. Create the role with trust policy
aws iam create-role \
--role-name AmazonSageMaker-ExecutionRole-sgm \
--assume-role-policy-document file://trust-policy.json \
--description "SageMaker execution role for medical imaging training"
# 2. Attach managed policies
aws iam attach-role-policy --role-name AmazonSageMaker-ExecutionRole-sgm \
--policy-arn arn:aws:iam::aws:policy/AmazonSageMakerFullAccess
aws iam attach-role-policy --role-name AmazonSageMaker-ExecutionRole-sgm \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# ... (attach remaining policies as listed above)
# 3. Add inline MLflow policy
aws iam put-role-policy \
--role-name AmazonSageMaker-ExecutionRole-sgm \
--policy-name mlflow-policy \
--policy-document file://mlflow-policy.json
After role creation
The script automatically updates SAGEMAKER_ROLE_ARN in .env.local. If you created the role manually, update it yourself:
# In .env.local
SAGEMAKER_ROLE_ARN=arn:aws:iam::<your-account-id>:role/AmazonSageMaker-ExecutionRole-sgm
8. ECR Repositories
Four ECR repositories are required — two for training (classification + segmentation) and two for inference.
Repository names
Repository |
Purpose |
Build script |
|---|---|---|
|
Classification training container |
|
|
Segmentation training container |
|
|
Classification inference container |
|
|
Segmentation inference container |
|
Prerequisites
Docker installed and running
AWS CLI configured with ECR push permissions
Login to the AWS Deep Learning Containers registry (base image source):
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin \
763104351884.dkr.ecr.us-east-1.amazonaws.com
This is required on every new machine. Without it, Docker cannot pull the PyTorch base image and the build fails with
403 Forbidden.
Build and push commands
# All images at once (recommended)
./setup.sh --images
# Or individually:
# Classification training image
./build_and_push.sh classification
# Segmentation training image
./build_and_push.sh segmentation
# Classification inference image
./build_and_push_inference.sh classification
# Segmentation inference image
./build_and_push_inference.sh segmentation
# Force full rebuild (no Docker layer cache)
./build_and_push.sh classification --no-cache
./build_and_push_inference.sh segmentation --no-cache
All scripts read AWS_ACCOUNT_ID and AWS_DEFAULT_REGION from .env.local. Builds use Docker’s layer cache by default for speed; pass --no-cache when base images or dependencies have changed.
Each script automatically:
Logs in to the AWS DLC ECR registry (for pulling the base image)
Builds the Docker image from the appropriate Dockerfile
Logs into your ECR registry
Creates the repository if it doesn’t exist
Pushes the image
The inference build script (build_and_push_inference.sh) additionally deletes the existing ECR image before pushing and verifies that the pushed manifest is in Docker V2 format (required by SageMaker’s CreateModel API).
Important: Docker manifest format — SageMaker only supports Docker V2 manifests (
application/vnd.docker.distribution.manifest.v2+json). Newer versions of Docker with BuildKit enabled produce OCI format images by default, which SageMaker rejects withUnsupported manifest media type application/vnd.oci.image.index.v1+json. The build scripts handle this automatically by usingDOCKER_BUILDKIT=0, which forces Docker V2 output. If you build images manually, always includeDOCKER_BUILDKIT=0in your build command.Note: SageMaker’s
CreateModeloperation (used for inference/deployment) is stricter about manifest formats thanCreateTrainingJob. You may find that training images built with OCI manifests work fine, but the same format fails at deployment time. Always use Docker V2 manifests for both training and inference images to avoid surprises.
Debugging: OCI Manifest Errors
If you encounter Unsupported manifest media type application/vnd.oci.image.manifest.v1+json when deploying, follow these steps:
1. Verify the manifest type in ECR:
aws ecr batch-get-image \
--repository-name sm-inference-byoc-classification \
--region us-east-1 \
--image-ids imageTag=latest \
--query 'images[0].imageManifestMediaType' \
--output text
Expected: application/vnd.docker.distribution.manifest.v2+json
Problem: application/vnd.oci.image.manifest.v1+json
2. Why this happens:
Docker 23+ uses BuildKit by default, which outputs OCI format images
SageMaker’s
CreateModelAPI (inference/deployment) validates the manifest type and rejects OCISageMaker’s
CreateTrainingJobAPI does not perform this check — training images with OCI manifests work fine because the container runtime (containerd) on training instances supports both formatsThis inconsistency means the same build process can produce images that work for training but fail at deployment
3. Fix — delete from ECR, rebuild, and push:
The working solution requires three things: clearing the Docker cache, deleting the old image from ECR, and rebuilding with BuildKit disabled.
# Clear all cached images (removes OCI-format base image layers)
docker system prune -a --force
# Login to DLC registry (for pulling the base image)
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin 763104351884.dkr.ecr.us-east-1.amazonaws.com
# Delete the existing OCI image from ECR
aws ecr batch-delete-image \
--repository-name sm-inference-byoc-classification \
--region us-east-1 \
--image-ids imageTag=latest
# Rebuild with BuildKit disabled and no cache
DOCKER_BUILDKIT=0 docker build --no-cache --platform linux/amd64 \
-f Dockerfile.inference --build-arg TASK=classification \
-t 811260109607.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-classification:latest .
# Login to your ECR
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin 811260109607.dkr.ecr.us-east-1.amazonaws.com
# Push fresh
docker push 811260109607.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-classification:latest
# Verify — must return application/vnd.docker.distribution.manifest.v2+json
aws ecr batch-get-image \
--repository-name sm-inference-byoc-classification \
--region us-east-1 \
--image-ids imageTag=latest \
--query 'images[0].imageManifest' --output text \
| python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('mediaType','unknown'))"
All three steps are critical:
docker system prune -a— Without this, Docker reuses cached OCI-format base image layers even with--no-cacheDelete from ECR — Pushing with the same tag doesn’t always overwrite the manifest
DOCKER_BUILDKIT=0— Forces the legacy builder which outputs Docker V2 format
4. If the above still produces OCI manifests:
Configure the Docker daemon to disable OCI output entirely:
sudo tee /etc/docker/daemon.json <<'EOF'
{
"features": {
"containerd-snapshotter": false
}
}
EOF
sudo systemctl restart docker
Then repeat step 3. This ensures Docker never converts back to OCI on push.
5. References:
What the training image contains
The Dockerfile.sagemaker builds on the AWS PyTorch DLC base image and installs task-specific dependencies:
ARG TASK=classification
FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:2.9.0-gpu-py312-cu130-ubuntu22.04-sagemaker
ARG TASK
COPY src/${TASK}/requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt
COPY src/${TASK}/ /opt/program/
COPY src/inference/${TASK}/ /opt/program/inference/
ENV SAGEMAKER_PROGRAM train.py
Key packages bundled: monai, torch, torchvision, nibabel, SimpleITK, pydicom, mlflow, tensorboard.
The src/inference/${TASK}/ directory is included so training scripts can copy inference artifacts (e.g., inference.py) into model_dir/code/ during training, producing a model.tar.gz ready for SageMaker PyTorch serving.
After building
Update .env.local with the resulting image URIs:
TRAINING_IMAGE_CLASSIFICATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-classification:latest
TRAINING_IMAGE_SEGMENTATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-segmentation:latest
INFERENCE_IMAGE_CLASSIFICATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-classification:latest
INFERENCE_IMAGE_SEGMENTATION=123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-inference-byoc-segmentation:latest
Verifying images
# List images in a repository
aws ecr describe-images \
--repository-name sm-training-byoc-classification \
--region us-east-1 \
--query 'imageDetails[*].{Tags:imageTags,Pushed:imagePushedAt,Size:imageSizeInBytes}'
# Pull and test locally
docker pull 123456789012.dkr.ecr.us-east-1.amazonaws.com/sm-training-byoc-classification:latest
docker run --rm -it <image-uri> python -c "import torch; import monai; print(f'PyTorch {torch.__version__}, MONAI {monai.__version__}')"
Quick Reference
Minimal setup (local development)
cp .env.example .env
cp .env.local.example .env.local
# Edit .env.local:
# AWS_ACCOUNT_ID=123456789012
# Then create the role:
./create-sagemaker-role.sh
# Start the dashboard:
python main.py
Full setup (training + deployment)
# 1. Configure environment
cp .env.example .env
cp .env.local.example .env.local
vim .env.local # fill in all values
# 2. Build and push Docker images
./setup.sh --images
# Or individually:
# ./build_and_push.sh classification
# ./build_and_push.sh segmentation
# ./build_and_push_inference.sh classification
# ./build_and_push_inference.sh segmentation
# 3. Start the dashboard
python main.py
# 4. Open http://localhost:8000 and sync from AWS