Host a Pretrained Model on SageMaker

Amazon SageMaker is a service to accelerate the entire machine learning lifecycle. It includes components for building, training and deploying machine learning models. Each SageMaker component is modular, so you’re welcome to only use the features needed for your use case. One of the most popular features of SageMaker is model hosting. Using SageMaker hosting, you can deploy your model as a scalable, highly available, multi-process API endpoint with a few lines of code. Read more at Deploy a Model in Amazon SageMaker. In this notebook, we demonstrate how to host a pretrained BERT model in Amazon SageMaker to extract embeddings from text.

SageMaker provides prebuilt containers that can be used for training, hosting, or data processing. The inference containers include a web serving stack, so you don’t need to install and configure one. We use the SageMaker PyTorch container, but you may use the TensorFlow container, or bring your own container if needed. See all containers at AWS Deep Learning Containers.

This notebook walks you through how to deploy a pretrained Hugging Face model as a scalable, highly available, production-ready API.


This notebook takes approximately 5 minutes to run.


  1. Retrieve Model Artifacts

  2. Write the Inference Script

  3. Package Model

  4. Deploy Model

  5. Get Predictions

  6. Conclusion

  7. Cleanup

Retrieve Model Artifacts

First we download the model artifacts for the pretrained BERT model. BERT is a popular natural language processing (NLP) model that extracts meaning and context from text. You can read the original paper, BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.

!pip install transformers==3.3.1 sagemaker==2.15.0 --quiet
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead:
import os
from transformers import BertTokenizer, BertModel

tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased")

model_path = "model/"
code_path = "code/"

if not os.path.exists(model_path):

('model/vocab.txt', 'model/special_tokens_map.json', 'model/added_tokens.json')

Write the Inference Script

Since we are bringing a model to SageMaker, we must create an inference script. The script runs inside our PyTorch container. Our script should include a function for model loading, and optionally functions generating predictions, and input/output processing. The PyTorch container provides default implementations for generating a prediction and input/output processing. By including these functions in your script you are overriding the default functions. You can find additional details at Serve a PyTorch Model.

The next cell shows our inference script, whcich uses the Transformers library from HuggingFace. This library is not installed in the container by default, so we add it in the next section.

!pygmentize code/
import os
import json
from transformers import BertTokenizer, BertModel

def model_fn(model_dir):
    Load the model for inference

    model_path = os.path.join(model_dir, 'model/')

    # Load BERT tokenizer from disk.
    tokenizer = BertTokenizer.from_pretrained(model_path)

    # Load BERT model from disk.
    model = BertModel.from_pretrained(model_path)

    model_dict = {'model': model, 'tokenizer':tokenizer}

    return model_dict

def predict_fn(input_data, model):
    Apply model to the incoming request

    tokenizer = model['tokenizer']
    bert_model = model['model']

    encoded_input = tokenizer(input_data, return_tensors='pt')

    return bert_model(**encoded_input)

def input_fn(request_body, request_content_type):
    Deserialize and prepare the prediction input

    if request_content_type == "application/json":
        request = json.loads(request_body)
        request = request_body

    return request

def output_fn(prediction, response_content_type):
    Serialize and prepare the prediction output

    if response_content_type == "application/json":
        response = str(prediction)
        response = str(prediction)

    return response

Package Model

For hosting, SageMaker requires that the deployment package be structured in a compatible format. It expects all files to be packaged in a tar archive named “model.tar.gz” with gzip compression. To install additional libraries at container startup, we can add a requirements.txt file that specifies the libraries to be installed using pip. Read more at Using Third-Party Libraries. Within the archive, the PyTorch container expects all inference code and requirements.txt file to be inside the code/ directory. See the Model Directory Structure guide for a thorough explanation of the required directory structure.

import tarfile

zipped_model_path = os.path.join(model_path, "model.tar.gz")

with, "w:gz") as tar:

Deploy Model

Now that we have our deployment package, we can use the SageMaker Python SDK to deploy our API endpoint with two lines of code. We need to specify an IAM role for the SageMaker endpoint to use. Minimally, it needs read access to the default SageMaker bucket (usually named s3://sagemaker-{region}-{your account ID}) so it can read the deployment package. When we call deploy(), the SDK saves our deployment archive to S3 for the SageMaker endpoint to use. We use the helper function get_execution_role() to retrieve our current IAM role so we can pass it to the SageMaker endpoint. Minimally it requires read access to the model artifacts in S3 and the ECR repository where the container image is stored by AWS.

You may notice that we specify our PyTorch version and Python version when creating the PyTorchModel object. The SageMaker SDK uses these parameters to determine which PyTorch container to use.

We use an m5.xlarge instance for our endpoint to ensure we have sufficient memory to serve our model.

from sagemaker.pytorch import PyTorchModel
from sagemaker import get_execution_role
import time

endpoint_name = "bert-base-" + time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime())

model = PyTorchModel(

predictor = model.deploy(
    initial_instance_count=1, instance_type="ml.m5.xlarge", endpoint_name=endpoint_name

Get Predictions

Now that our API endpoint is deployed, we send it text to get predictions from our BERT model. You can use the SageMaker SDK or the InvokeEndpoint method of the SageMaker Runtime API to invoke the endpoint.

import sagemaker

sm = sagemaker.Session().sagemaker_runtime_client

prompt = "The best part of Amazon SageMaker is that it makes machine learning easy."

response = sm.invoke_endpoint(
    EndpointName=endpoint_name, Body=prompt.encode(encoding="UTF-8"), ContentType="text/csv"

b'(tensor([[[-0.2462, -0.0988,  0.1747,  ..., -0.4059,  0.0966,  0.6564],\n         [-0.1352, -0.5824, -0.0728,  ..., -0.1726,  0.5765,  0.1273],\n         [-0.1491, -0.4218,  0.2821,  ...,  0.1332,  0.5053, -0.2813],\n         ...,\n         [-0.8054, -0.3126,  0.6776,  ..., -0.0572,  0.0806, -0.0318],\n         [ 0.7608,  0.1367, -0.2650,  ...,  0.1246, -0.5977, -0.2397],\n         [ 0.4660,  0.2762,  0.0636,  ...,  0.1112, -0.5502, -0.2997]]],\n       grad_fn=<NativeLayerNormBackward>), tensor([[-7.0429e-01, -4.2229e-01, -9.7203e-01,  6.3414e-01,  8.6010e-01,\n         -3.5008e-01,  3.8001e-02,  2.2652e-01, -8.5239e-01, -9.9980e-01,\n         -6.4649e-01,  8.4232e-01,  8.9319e-01,  6.2476e-01,  4.8914e-01,\n         -3.7195e-01,  1.0597e-01, -5.0569e-01,  3.3702e-01,  7.3767e-01,\n          6.0322e-01,  1.0000e+00, -3.2281e-01,  4.7648e-01,  4.4296e-01,\n          9.4813e-01, -6.6813e-01,  7.4915e-01,  8.2229e-01,  6.3062e-01,\n         -1.4025e-01,  2.2783e-01, -9.6329e-01, -2.0670e-01, -9.7215e-01,\n         -9.3046e-01,  5.0601e-01, -4.7677e-01,  1.6829e-01, -2.7723e-02,\n         -7.4092e-01,  3.3085e-01,  9.9991e-01, -6.8587e-01,  7.2314e-01,\n         -1.7280e-01, -1.0000e+00,  2.7953e-01, -6.6518e-01,  9.3125e-01,\n          8.8504e-01,  9.0542e-01,  2.4233e-01,  4.6617e-01,  4.7114e-01,\n         -5.9370e-01, -2.0038e-01,  2.7291e-02, -2.8522e-01, -5.5561e-01,\n         -6.1984e-01,  4.2931e-01, -8.7690e-01, -7.1666e-01,  8.7416e-01,\n          9.3529e-01, -1.6623e-01, -2.3902e-01, -1.9703e-01, -4.2381e-02,\n          6.0962e-01,  1.7582e-01, -3.2225e-01, -7.3443e-01,  7.5766e-01,\n          2.8546e-01, -6.3455e-01,  1.0000e+00, -1.5006e-01, -8.9906e-01,\n          9.4594e-01,  8.2220e-01,  5.8257e-01, -6.1727e-01,  7.2892e-01,\n         -1.0000e+00,  5.9967e-01, -1.9553e-01, -9.5505e-01,  2.8234e-01,\n          6.5812e-01, -3.3026e-01,  9.2597e-01,  7.0949e-01, -6.0489e-01,\n         -6.2557e-01, -2.1836e-01, -9.4475e-01, -3.5476e-01, -6.5299e-01,\n          2.4002e-01, -2.9925e-01, -3.6173e-01, -3.2079e-01,  4.4673e-01,\n         -4.7877e-01,  3.8068e-03,  6.1428e-01,  3.1495e-01,  5.5661e-01,\n          5.4409e-01, -4.0993e-01,  3.5277e-01, -7.7047e-01,  4.9286e-01,\n         -3.3508e-01, -9.6048e-01, -6.4067e-01, -9.5352e-01,  4.8227e-01,\n         -2.5500e-01, -2.7310e-01,  6.2703e-01, -6.0067e-01,  4.3773e-01,\n         -1.3204e-01, -8.9876e-01, -1.0000e+00, -5.7486e-01, -5.8367e-01,\n         -3.7799e-02, -3.1076e-01, -9.2927e-01, -8.9301e-01,  5.7826e-01,\n          8.9921e-01,  3.2762e-01,  9.9950e-01, -2.9299e-01,  7.4470e-01,\n         -2.8432e-01, -6.9845e-01,  6.4370e-01, -4.0474e-01,  8.6064e-01,\n         -4.2865e-01, -8.4202e-02,  1.9170e-01, -4.9307e-01,  2.4258e-01,\n         -7.5579e-01, -1.5230e-01, -8.7137e-01, -7.5294e-01, -3.9612e-01,\n          7.5623e-01, -7.2463e-01, -9.5676e-01, -2.1992e-01, -7.2245e-03,\n         -4.2903e-01,  7.3310e-01,  7.8768e-01,  1.8995e-01, -4.1924e-01,\n          3.3158e-01,  3.7686e-03,  4.9328e-01, -5.4632e-01, -2.5544e-01,\n          4.2792e-01, -3.4765e-01, -9.5505e-01, -9.1659e-01, -2.7968e-01,\n          3.3616e-01,  9.3921e-01,  3.2194e-01,  4.4059e-01,  7.8101e-01,\n         -4.1404e-01,  5.6999e-01, -8.9867e-01,  9.4501e-01, -1.2916e-01,\n          2.3877e-01, -8.0565e-01,  5.4742e-01, -6.9169e-01,  3.2258e-01,\n          4.6589e-01, -8.1670e-01, -5.5204e-01, -1.2755e-01, -5.7002e-01,\n         -4.8809e-01, -8.5480e-01,  3.7383e-01, -2.6327e-01, -4.4017e-01,\n         -1.7042e-01,  7.8240e-01,  6.5593e-01,  3.9682e-01,  6.1350e-01,\n          6.6910e-01, -5.8099e-01, -1.2729e-01,  1.3087e-01,  2.4979e-01,\n          9.0463e-02,  9.5573e-01, -8.7745e-01, -5.3944e-02, -7.9538e-01,\n         -9.0020e-01, -1.0429e-02, -6.3410e-01, -2.6991e-01, -6.7839e-01,\n          6.8991e-01, -8.5664e-01,  5.4074e-01,  2.5057e-01, -1.9840e-01,\n         -5.3468e-01,  2.5042e-01, -5.3122e-01,  4.8517e-01, -2.3039e-01,\n          9.8263e-01,  9.5669e-01, -6.2871e-01, -3.7287e-01,  9.1808e-01,\n         -9.5680e-01, -7.3054e-01, -2.0423e-01, -3.7704e-01,  5.3158e-01,\n         -5.5107e-01,  9.4410e-01,  8.8621e-01,  6.5910e-01, -5.9173e-01,\n         -8.7734e-01, -4.4452e-01, -6.2441e-01,  1.8345e-02,  2.6674e-01,\n          9.1898e-01,  7.0334e-01,  4.5215e-01,  1.5477e-01, -3.2292e-01,\n          6.3614e-01, -9.8578e-01, -8.6722e-01, -9.2116e-01, -2.0438e-01,\n         -9.5635e-01,  9.1029e-01,  3.3865e-01,  8.6891e-01, -4.8682e-01,\n         -5.6545e-01, -8.4585e-01,  4.1545e-01,  1.4697e-01,  7.4499e-01,\n         -7.4186e-01, -4.1167e-01, -6.3849e-01, -7.9425e-01, -7.1474e-02,\n         -1.6725e-01, -6.2415e-01, -7.7895e-02, -7.4305e-01,  5.2787e-01,\n          4.8245e-01,  4.6977e-01, -9.3221e-01,  9.6142e-01,  1.0000e+00,\n          8.7032e-01,  6.2576e-01,  2.6043e-01, -9.9998e-01, -9.3788e-01,\n          9.9995e-01, -9.8948e-01, -1.0000e+00, -7.3993e-01, -5.3754e-01,\n          6.8563e-02, -1.0000e+00, -3.0134e-01,  1.0993e-01, -5.8069e-01,\n          7.9011e-01,  8.6519e-01,  6.6334e-01, -1.0000e+00,  5.5531e-01,\n          7.9444e-01, -6.8273e-01,  8.9153e-01, -5.4783e-01,  8.5564e-01,\n          5.5771e-01,  6.9861e-01, -1.2855e-01,  3.9747e-01, -9.7520e-01,\n         -5.9382e-01, -7.9269e-01, -8.9581e-01,  9.9980e-01,  9.9248e-02,\n         -7.1784e-01, -5.3887e-01,  7.9213e-01,  7.2667e-03,  1.0741e-01,\n         -8.6744e-01, -3.0254e-01,  5.2122e-01,  5.6968e-01,  3.0697e-01,\n          2.7829e-01, -1.3250e-01,  3.7797e-01,  3.5936e-01,  8.6241e-02,\n          6.5188e-01, -7.8581e-01, -2.3990e-02,  3.9677e-01,  2.9169e-01,\n         -7.4401e-01, -9.3657e-01,  7.7300e-01, -2.3792e-01,  7.5010e-01,\n          1.0000e+00,  7.2673e-01, -4.1205e-01,  5.5583e-01,  3.0370e-01,\n         -5.8846e-01,  1.0000e+00,  7.9738e-01, -9.0979e-01, -6.6592e-01,\n          7.6298e-01, -6.2132e-01, -7.7240e-01,  9.9498e-01, -3.7270e-01,\n         -8.7361e-01, -5.2872e-01,  9.4385e-01, -9.5239e-01,  9.9918e-01,\n         -4.5485e-01, -8.8839e-01,  8.3818e-01,  7.8258e-01, -5.8362e-01,\n         -5.2211e-01,  2.8821e-02, -7.6797e-01,  3.9479e-01, -4.3449e-01,\n          4.8557e-01,  1.9137e-01, -4.4436e-03,  6.8384e-01,  1.6296e-01,\n         -6.7678e-01,  2.0941e-01, -7.0660e-01, -1.5576e-01,  9.6065e-01,\n          4.1788e-01, -2.0698e-01, -8.8920e-02, -2.7851e-01, -8.6436e-01,\n         -9.0030e-01,  7.6115e-01,  1.0000e+00, -4.2347e-02,  9.2810e-01,\n         -3.2609e-01, -1.1601e-01,  7.6556e-02,  6.2215e-01,  5.5409e-01,\n         -1.5557e-01, -5.8778e-01,  8.2372e-01, -4.4559e-01, -9.5695e-01,\n          2.3920e-01,  1.5621e-01, -1.8932e-01,  9.9992e-01,  3.4455e-01,\n          2.7785e-01,  4.8869e-01,  9.7985e-01,  1.2123e-02,  1.5760e-01,\n          9.4338e-01,  9.5431e-01, -2.4670e-01,  7.1301e-01,  1.6395e-01,\n         -9.1902e-01, -2.9367e-01, -5.6091e-01,  8.2864e-02, -8.6072e-01,\n          1.0045e-01, -8.1766e-01,  8.9445e-01,  9.5519e-01,  3.7974e-01,\n          1.6428e-01,  8.3312e-01,  1.0000e+00, -9.8540e-01,  2.2744e-01,\n          7.9729e-01, -2.7107e-01, -9.9997e-01, -1.5196e-04, -3.6338e-01,\n         -1.2888e-01, -8.9895e-01, -3.9675e-01,  9.5275e-02, -8.7694e-01,\n          8.7259e-01,  7.3736e-01, -6.3866e-01, -8.7836e-01, -5.3952e-01,\n          3.8029e-01,  8.2281e-02, -9.9608e-01, -4.7665e-01, -2.8731e-01,\n          5.5651e-01, -3.8107e-01, -6.4363e-01, -4.2192e-01, -3.5137e-01,\n          4.1607e-01, -1.9183e-01,  6.2999e-01,  9.2827e-01,  7.2474e-01,\n         -9.6024e-01, -4.7600e-01, -5.6839e-02, -4.2833e-01,  6.1923e-01,\n         -6.5076e-01, -9.5072e-01, -2.0124e-01,  1.0000e+00, -1.1769e-01,\n          9.5465e-01,  3.3081e-01,  2.7900e-01, -2.0819e-01,  3.1738e-01,\n          9.7415e-01,  2.8186e-01, -7.6092e-01, -8.6825e-01,  8.0483e-01,\n         -5.0071e-01,  5.8275e-01,  9.0219e-01,  8.0464e-01,  4.3357e-01,\n          9.1644e-01,  1.8520e-01, -1.0470e-02, -6.6955e-02,  9.1749e-01,\n         -5.6698e-02, -3.6595e-01, -3.5708e-01, -1.4219e-01, -3.1479e-01,\n          6.1602e-01,  1.0000e+00,  2.6784e-01,  7.7581e-01, -9.4108e-01,\n         -8.7218e-01, -6.6301e-01,  1.0000e+00,  7.0394e-01, -3.7093e-01,\n          4.4596e-01,  4.6609e-01, -1.6196e-01,  1.2609e-01, -2.2340e-01,\n         -3.2369e-01,  2.7568e-01,  1.4218e-01,  7.8667e-01, -4.8022e-01,\n         -9.3212e-01, -5.9068e-01,  3.4132e-01, -8.4641e-01,  9.9999e-01,\n         -5.8762e-01, -2.4817e-01, -2.1803e-01, -5.9153e-01, -9.0153e-01,\n         -6.2096e-02, -8.9386e-01, -1.8735e-01,  2.5682e-01,  7.9349e-01,\n          3.8490e-01, -6.3735e-01, -6.9540e-01,  8.3634e-01,  7.3290e-01,\n         -9.4176e-01, -7.7765e-01,  8.1436e-01, -8.3566e-01,  6.4903e-01,\n          1.0000e+00,  4.8774e-01,  4.4023e-01,  7.5930e-02, -3.2230e-01,\n          4.4445e-01, -7.9360e-01,  3.6513e-01, -8.2476e-01, -4.4221e-01,\n         -1.9913e-01,  3.4394e-01, -1.6068e-01, -8.4861e-01,  7.5981e-02,\n          3.2635e-01, -6.2073e-01, -5.6273e-01, -1.3778e-02,  4.4581e-01,\n          5.4840e-01, -2.7247e-01, -1.6441e-01,  2.3364e-01,  9.0320e-02,\n         -4.4573e-01, -4.7720e-01, -5.1088e-01, -1.0000e+00,  3.9913e-01,\n         -1.0000e+00,  6.3140e-01,  2.6997e-01, -2.0522e-01,  6.4446e-01,\n          8.9535e-01,  7.9128e-01, -4.2473e-01, -9.2832e-01,  2.9445e-01,\n          3.8726e-01, -3.5147e-01, -1.4712e-01, -2.4331e-01,  3.6506e-01,\n         -1.1074e-01,  3.0147e-01, -7.7704e-01,  7.1269e-01, -3.0761e-01,\n          1.0000e+00,  2.4892e-01, -4.2761e-01, -3.6417e-01,  2.5862e-01,\n         -2.9382e-01,  1.0000e+00, -9.3798e-02, -8.9436e-01,  3.7350e-01,\n         -7.8972e-01, -6.0232e-01,  4.7087e-01,  1.4877e-01, -7.0357e-01,\n         -9.5183e-01,  3.7305e-01,  4.8407e-01, -7.1330e-01,  7.6172e-01,\n         -3.5378e-01, -4.6132e-01,  8.5328e-02,  9.6855e-01,  9.3842e-01,\n          6.7007e-01,  4.5927e-01, -8.5576e-01, -5.3646e-01,  8.9675e-01,\n          2.9143e-01, -4.8709e-01,  1.4774e-01,  1.0000e+00,  4.4341e-01,\n         -7.8597e-01,  2.6452e-01, -8.2354e-01, -1.3105e-01, -8.2840e-01,\n          2.9209e-01,  2.1272e-01,  7.6796e-01, -3.4143e-01,  7.3560e-01,\n         -9.2232e-01,  1.2953e-01, -5.1920e-01, -7.0030e-01,  3.0870e-01,\n         -7.3938e-01, -9.0843e-01, -9.0789e-01,  6.8067e-01, -2.9995e-01,\n         -1.3688e-01,  2.9807e-01,  8.8721e-02,  3.8320e-01,  3.7907e-01,\n         -1.0000e+00,  8.2361e-01,  4.3105e-01,  9.0323e-01,  8.4777e-01,\n          8.2425e-01,  7.7038e-01,  3.4351e-01, -9.0495e-01, -3.7316e-01,\n         -3.1706e-01, -3.1218e-01,  5.0647e-01,  6.8359e-01,  6.0040e-01,\n          1.9903e-01, -5.0796e-01, -7.0890e-01, -8.1465e-01, -9.7855e-01,\n         -9.6754e-01,  5.1544e-01, -6.5849e-01, -1.4164e-01,  8.9444e-01,\n         -5.0000e-02, -1.5493e-01, -3.1448e-01, -9.0064e-01,  2.2260e-01,\n          4.0317e-01, -1.3909e-01,  5.7329e-02,  4.0753e-01,  5.2156e-01,\n          6.5553e-01,  8.6643e-01, -9.3422e-01,  5.5153e-01, -8.4335e-01,\n          4.4102e-01,  9.5761e-01, -8.9940e-01,  9.5909e-02,  7.6769e-01,\n         -2.1159e-01,  3.0813e-01, -2.8968e-01, -2.6445e-01,  7.9634e-01,\n         -3.5189e-01,  4.6153e-01, -4.2751e-01,  1.2668e-01, -4.3487e-01,\n         -2.4559e-01, -5.0632e-01, -4.1360e-01,  6.0186e-01, -3.0505e-03,\n          6.6026e-01,  9.3351e-01, -1.3465e-01, -5.1754e-01, -4.5243e-02,\n         -8.0939e-01, -7.9774e-01,  4.0735e-01,  3.8867e-02, -2.8360e-01,\n          8.6788e-01, -6.6490e-02,  9.7830e-01,  4.7661e-01, -3.3393e-01,\n         -3.7814e-01, -4.2969e-01,  5.3066e-01, -7.7054e-01, -5.9246e-01,\n         -4.6809e-01,  6.0525e-01,  2.5718e-01,  1.0000e+00, -8.7896e-01,\n         -9.1013e-01, -7.4345e-01, -3.8568e-01,  4.0054e-01, -4.4582e-01,\n         -1.0000e+00,  3.2784e-01, -6.4760e-01,  8.0087e-01, -6.8343e-01,\n          8.9602e-01, -5.9155e-01, -7.5991e-01, -4.8572e-01,  8.6559e-01,\n          8.8322e-01, -5.0129e-01, -4.9732e-01,  5.2962e-01, -3.4280e-01,\n          9.8162e-01,  5.7197e-01, -4.3897e-01, -1.5350e-01,  7.1398e-01,\n         -9.1926e-01, -6.2192e-01,  5.4504e-01]], grad_fn=<TanhBackward>))'


Delete the model and endpoint to release resources and stop incurring costs.



We have successfully created a scalable, highly available, RESTful API that is backed by a BERT model! It can be used for downstream NLP tasks like text classification. If you are still interested in learning more, check out some of the more advanced features of SageMaker hosting, like Monitor models for data and model quality, bias, and explainability to detect concept drift, Automatically Scale Amazon SageMaker Models to dynamically adjust the number of instances, or Give SageMaker Hosted Endpoints Access to Resources in Your Amazon VPC to control network access to/from your endpoint.

You can also read the blog Deploy machine learning models to Amazon SageMaker using the ezsmdeploy Python package and a few lines of code. The ezsmdeploy package automates most of this process.