This guide shows you how to build and deploy AI workloads that can run on any major GPU cloud provider—or move between them—without rewriting your code or reconfiguring your infrastructure. You’ll learn the key practices for containerization, orchestration, and storage that make your deployments portable, so you can avoid proprietary APIs, pricing changes, or availability issues locking you in. By the end, you’ll have a clear path to deploy the same model on AWS, Azure, GCP, or a bare-metal provider with minimal friction.
What You’ll Need
- An existing AI/ML project (training or inference) with code in a version-controlled repository.
- Docker installed locally, and familiarity with basic Docker commands.
- Access to at least one GPU cloud provider (AWS, Azure, GCP, or others) to test deployments.
- Basic understanding of Kubernetes (or willingness to learn) if you plan to use orchestration.
- An object storage account (e.g., S3, GCS, Azure Blob) for model artifacts and datasets.
Step-by-Step
- Containerize your AI application. Write a Dockerfile that includes your runtime (Python, CUDA, etc.), your code, and your dependencies. Use a base image that is GPU-ready, such as
nvidia/cuda:12.2.0-runtime-ubuntu22.04for inference, ortensorflow/tensorflow:2.13.0-gpufor TensorFlow. Pin all package versions in arequirements.txtor environment file. Build and test the image locally withdocker build -t my-ai-app .and run it withdocker run --gpus all my-ai-appto ensure it works. - Use environment variables for all configuration. Never hardcode cloud-specific endpoints, credentials, or paths. Instead, read them from environment variables. For example, set
MODEL_PATH,DATA_BUCKET, andAPI_KEYas env vars. This makes the same container runnable on any provider by simply changing the environment. - Abstract cloud services with provider-agnostic interfaces. For object storage, use libraries like
boto3with an S3-compatible endpoint (most clouds support S3 API). For databases or queues, use standard protocols (e.g., PostgreSQL, Redis) instead of proprietary managed services. If you must use a cloud-specific service, wrap it behind an interface you can reimplement for another provider. - Store model artifacts and datasets in a portable way. Keep model weights and data in object storage, and download them at runtime to a local cache (e.g.,
/tmp/models). Use a consistent directory structure and avoid absolute paths. This way, you can point the container to any storage provider by changing the bucket URL and credentials. - Use Kubernetes for orchestration (if needed). Write Kubernetes manifests (Deployment, Service, Ingress) that are provider-neutral. Use standard resource requests for GPU (e.g.,
nvidia.com/gpu: 1) and avoid cloud-specific annotations. For managed Kubernetes services (EKS, AKS, GKE), the manifests remain the same; only the cluster setup differs. Alternatively, use a tool like Docker Compose for simpler single-node deployments. - Implement a model serving layer with a standard API. Use a framework like FastAPI, TensorFlow Serving, or Triton Inference Server to expose your model via REST or gRPC. These are cloud-agnostic and can be containerized easily. Avoid using provider-specific serving solutions (e.g., SageMaker endpoints) unless you wrap them.
- Automate deployment with CI/CD. Create a pipeline that builds your Docker image, pushes it to a container registry (e.g., Docker Hub, GHCR, or any cloud registry), and deploys it to your target cluster. Use IaC tools like Terraform to provision infrastructure, but keep the Terraform modules generic (e.g., use the same module for AWS, Azure, GCP with different providers).
- Test portability by deploying to a second provider. Once your app runs on one cloud, try deploying the same container to another provider. This will reveal any hidden dependencies. For example, deploy to AWS ECS, then to GCP Cloud Run, and adjust until it works on both with only env var changes.
- Document your deployment process. Write a README that explains how to deploy your app on any provider: what env vars to set, which ports to expose, and how to scale. This helps others (and your future self) avoid lock-in.
Common Mistakes
- Hardcoding cloud-specific paths or URLs (e.g.,
s3://my-bucketvsgs://my-bucket) in your code. Always use env vars. - Using proprietary managed services like AWS SageMaker, Azure ML, or GCP AI Platform without abstraction. These tie you to a specific provider’s SDK and APIs.
- Not pinning dependencies – if you use
pip install numpywithout a version, your container may break on a different cloud due to different base images. - Assuming all clouds have the same GPU driver versions – always specify CUDA version in your base image and test on each provider.
- Storing model files inside the container image – this makes the image huge and hard to update. Download from storage at runtime.
- Ignoring network egress costs – moving large datasets between clouds can be expensive; plan your storage location accordingly.
Tips
- Use a tool like Docker Buildx to build multi-arch images if you might use ARM-based GPUs (e.g., Graviton) in the future.
- For Kubernetes, use Helm charts to package your app – they are provider-agnostic and easy to customize per cloud.
- Consider using a multi-cloud framework like Kubeflow or Ray for distributed training – they abstract away the underlying cloud.
- Set up a local GPU environment (or use a bare-metal provider) to test your container without any cloud dependencies.
- Use a service mesh like Istio if you need advanced traffic management – it works across clouds.
- Regularly review your cloud bill to identify services that are hard to migrate away from, and replace them early.
Troubleshooting
Issue: Container runs locally but fails on a cloud provider. Check the GPU driver version. Run nvidia-smi inside the container to see if the GPU is visible. If not, ensure your base image matches the CUDA version of the cloud’s driver. Also check that you’ve requested GPU resources in your orchestration (e.g., resources.limits: nvidia.com/gpu: 1).
Issue: Can’t connect to object storage. Verify your env vars for endpoint URL, access key, and secret. For S3-compatible services, ensure you set the correct region and path-style access if needed. Test with a simple aws s3 ls command (using the AWS CLI) from within the container.
Issue: Model download is slow or fails. Use a caching layer like a local SSD or a CDN. If the model is large (e.g., >10GB), consider using a faster storage class or pre-loading the model during build time (if it’s not too large).
Issue: Kubernetes deployment fails with GPU resource errors. Ensure the cluster has GPU nodes and the NVIDIA device plugin is installed. Check kubectl describe pod for events. If using a managed service, you may need to enable GPU support in the node pool.
Issue: Different behavior on different clouds due to environment differences. Use a deterministic base image and lock all system packages. Run your tests in a CI environment that mimics the cloud environment (e.g., use the same OS and CUDA version).
Frequently Asked Questions
Q: Can I really avoid vendor lock-in completely? No, but you can minimize it. You’ll still depend on some cloud APIs (e.g., for authentication), but by following these practices, you can switch providers with minimal code changes.
Q: Is it worth the extra effort for small projects? If you’re just experimenting, maybe not. But if you plan to scale or have long-term projects, the upfront work pays off when you need to move or negotiate pricing.
Q: What about using multi-cloud frameworks like Kubeflow? Kubeflow is a good option for ML pipelines, but it adds complexity. Start with simple containers and add orchestration only when needed.
Q: How do I handle GPUs that are specific to one vendor (e.g., AWS Inferentia)? Avoid using vendor-specific hardware unless you absolutely need it. If you do, abstract it behind an interface so you can fall back to standard GPUs.
Q: What if my model is too large to download at runtime? You can bake it into the image, but that makes the image huge and slows down deployment. Consider using a shared file system like EFS or a high-speed object storage with caching.
Q: Does using Kubernetes guarantee portability? No, but it helps. You still need to ensure your manifests don’t use cloud-specific annotations or storage classes. Use generic storage classes and test on multiple clusters.
Related
General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.
More in this bed
- How to Live Stream Using the Twitch Mobile App
- How to Change GPS Location on Android
- Change Window Border Width in Windows
- Enable iTunes Notification Center Widget on Mac
- Windows 10 Activation Error 0xc004c003: Fixes
- Modify Web Captures with JavaScript: A How-To