Self-hosted service
aws/sagemaker-training-toolkit avatar
aws/sagemaker-training-toolkit

sagemaker-training-toolkit: making a custom Docker image speak the SageMaker contract

Train machine learning models within a 🐳 Docker container using 🧠 Amazon SageMaker.

530 stars140 forksPythonApache-2.0

At a glance

What is it?
The SageMaker Training Toolkit is the adapter layer that turns an ordinary training container into one SageMaker can schedule. It is small, Apache-2.0, and mostly invisible until the contract between your entry point and the service breaks.
Who is it for?
Adopt sagemaker-training-toolkit if you already build your own training image and want SageMaker to schedule it without rewriting the service integration, and if you are prepared to keep the entry point under /opt/ml/code and read configuration from SM_* environment variables. Do not adopt it if you are happy with a prebuilt SageMaker framework image, since the README states this library may already be included there, or if you need a scheduler that is not SageMaker.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The contract problem the toolkit exists to absorb

SageMaker does not run your training script directly. It starts a container and expects that container to behave in a particular way: to know which file is the entry point, to find input data at known filesystem locations, and to receive job configuration through a defined set of variables and arguments. A plain Docker image that runs python train.py has none of that wiring. The toolkit is the piece that supplies it, and its scope is deliberately narrow. It does not train anything, does not manage instances, and does not talk to S3 on your behalf. It translates the job description SageMaker hands to the container into the conventions a normal Python or shell script can consume. That narrowness is the point. If you are building a custom training container because no prebuilt image carries your dependencies, you want the SageMaker-specific glue to be a pip install rather than code you maintain. The README frames the audience directly: it is for people who include a training script and its dependencies in a Docker container and want that container to be compatible with SageMaker training.

Entry point, channels and hyperparameters: the three wiring paths

The first path is the entry point. The training script must sit in /opt/ml/code, and the environment variable SAGEMAKER_PROGRAM names which file inside that directory to execute. The README states that when training starts, the interpreter executes the entry point defined by SAGEMAKER_PROGRAM, and that both Python and shell scripts are supported. This is why the documented Dockerfile both copies train.py into /opt/ml/code and sets ENV SAGEMAKER_PROGRAM train.py. Get either half wrong and the container starts with nothing to run.

The second path is hyperparameters. Anything the training job supplies as hyperparameters arrives at the entry point as script arguments, which is why the README's example script uses argparse and declares flags such as --learning-rate, --batch-size and --communicator. The same channel carries SageMaker's own control values: the README notes that the SageMaker Python SDK passes special hyperparameters including sagemaker_program and sagemaker_submit_directory, and points to params.py for the complete list. That detail matters when you debug. A flag you did not set can still appear in your argument parser, because the SDK put it there.

The third path is environment variables. Input channels declared at fit time, such as training and testing, surface inside the container as SM_CHANNEL_TRAINING and SM_CHANNEL_TESTING. The README's example reads them with os.environ and uses them as argparse defaults, which is a neat pattern: the script works standalone if you pass paths manually, and works under SageMaker if you do not. The toolkit also prints all available environment variables when training starts, and ENVIRONMENT_VARIABLES.md is referenced as the full list. The README also describes an Environment object that exposes hyperparameters, system characteristics, filesystem locations, environment variables and configuration settings, described as a read-only snapshot of the container environment during training. The supplied README text is truncated mid-sentence at that point, so the exact surface of Environment beyond that description cannot be confirmed here.

Getting a container running: the documented sequence

The installation step is a single line in the Dockerfile: RUN pip3 install sagemaker-training. The documented container then copies the training script into /opt/ml/code and sets SAGEMAKER_PROGRAM. The README's example uses yourbaseimage:tag as the FROM line, which is the honest framing: the toolkit assumes you already have a base image with your framework and dependencies, and it adds compatibility rather than a runtime.

Build and tag follow the ordinary Docker path: docker build -t custom-training-container . To start a job, the README uses the SageMaker Python SDK, constructing an Estimator with image_name set to that tag, a role, train_instance_count=1 and train_instance_type="local". Note that "local" is what the README shows for a local run; training on SageMaker means pushing the image to ECR and starting the job with the image URI, which the README states but does not spell out as commands. The hyperparameter example is given as a raw job-style dict, {"HyperParameters": {"batch-size": 256, "learning-rate": 0.0001, "communicator": "pure_nccl"}}, which is useful because it shows the wire format rather than the SDK wrapper.

One practical caution the README does not address: pip3 install sagemaker-training without a version pin means your image changes when a new release lands. Given the release cadence visible in the repository (v5.0.0 in June 2025, v5.1.0 in August 2025, v5.1.1 in September 2025), pinning is the difference between a reproducible image and one that rebuilds differently next month.

Where the toolkit stops helping

The toolkit is an adapter, so it inherits every constraint of the thing it adapts to. The /opt/ml/code requirement is not a suggestion. If your project layout puts the script elsewhere, or generates it at runtime, you either restructure or add a copy step. The SAGEMAKER_PROGRAM variable names a single file, so multi-entry-point images need a dispatcher script rather than two programs.

The heavier limitation is that nothing here is useful outside SageMaker. The environment variables, the channel paths, the hyperparameter-passing convention and the Environment object are all SageMaker's contract. Running the same image under a different orchestrator means reimplementing the glue, because the toolkit does not abstract over schedulers. If your organisation is multi-cloud or expects to move training off SageMaker, this dependency is a one-way door in your Dockerfile.

There is also a debugging asymmetry worth naming. When the entry point is wrong, the failure appears as a container that starts and does nothing useful, not as a clear error about a missing script. The README's instruction that the toolkit prints all environment variables at training start is the main lever you get, and it is a good one, but it means the first move in a broken job is reading logs rather than reading a validation error. The README does not describe a pre-flight check for the entry point, and the supplied material gives no indication that one exists.

The realistic alternative: a prebuilt framework image

The alternative most teams actually face is not a competing toolkit. It is not building a custom container at all. SageMaker publishes prebuilt training images for frameworks, and the README says plainly that if you use a prebuilt SageMaker Docker image for training, this library may already be included. The difference in approach is where your code lives. With a prebuilt image, you supply the training script through the SDK and it is delivered to the container, which is why the SDK passes sagemaker_program and sagemaker_submit_directory as hyperparameters. You write train.py, call estimator.fit(), and never touch a Dockerfile.

Choosing the toolkit means accepting Docker as your dependency boundary. That buys you control: any base image, any system package, any pinned framework version, and a build artifact you can test locally before it ever reaches SageMaker. It costs you the maintenance of that image, plus the entry point and environment variable conventions above. The trade is not about which is better. It is about whether your dependency set fits inside a framework image. If it does, the prebuilt route has strictly less machinery. If it does not, the toolkit is the smaller of the two custom options, because the alternative is writing the SageMaker integration yourself.

Maintenance, versioning and the licence

The repository is active rather than archived, with a last push in September 2026 and three releases across 2025. That cadence is relevant to anyone pinning a version in a Dockerfile: a library that ships minor releases regularly will drift from your pin, and the drift is invisible until you rebuild. The README's install line carries no version, so the discipline has to come from your side.

The Apache-2.0 licence is permissive and includes an explicit patent grant, which matters for a component that sits inside your training image and ships to your own registry. It does not impose copyleft obligations on your training code. This is a description of the licence text, not legal advice; if your organisation has policies about dependencies embedded in distributed images, run the specifics past whoever owns that policy.

The maintenance cost that the material does support is the contract itself. Every custom container you build repeats the same three conventions: a script under /opt/ml/code, SAGEMAKER_PROGRAM pointing at it, and a training script that reads SM_CHANNEL_* rather than hardcoded paths. Those conventions are the toolkit's interface, and they are the part that breaks when someone reorganises a repository or renames a script without updating the Dockerfile. Centralising the Dockerfile pattern across teams is cheaper than rediscovering it per project.

Editorial conclusion

Adopt sagemaker-training-toolkit if you already build your own training image and want SageMaker to schedule it without rewriting the service integration, and if you are prepared to keep the entry point under /opt/ml/code and read configuration from SM_* environment variables. Do not adopt it if you are happy with a prebuilt SageMaker framework image, since the README states this library may already be included there, or if you need a scheduler that is not SageMaker. Before committing, verify three things against your own image: that SAGEMAKER_PROGRAM names a file you actually COPY into /opt/ml/code, that the toolkit version pinned in your Dockerfile is the one you intend to support, and that your training script reads channel paths from SM_CHANNEL_* rather than from hardcoded paths.

Official sources

  1. aws/sagemaker-training-toolkit on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Community notes

Community notes