Phase 2: From YAML to Deployment: Building a Robust Multi-Cloud Kubernetes CLI

In the previous part of this series ( Phase 1 ), I shared why I'm building a multi-cloud CLI platform to help platform teams self-serve Kubernetes infrastructure in AWS, Azure, and GCP without needing ticket-based provisioning

In this Phase 2 blog, we dive into input validation, YAML schema enforcement, default config handling, and how we're building a resilient CLI with a clean command structure.


🎯 Objective of Phase 2

Once we allowed teams to define their infra needs in a YAML file, the next critical step was:

How do we make sure that YAML is correct, complete, and safe to process?

The answer: schema validation, fallback defaults, and structured commands.


πŸ“¦ Schema-Based Validation with JSONSchema

We created structured JSONSchema definitions for each cloud provider:

configs/schema/
β”œβ”€β”€ aws-schema.yaml
β”œβ”€β”€ azure-schema.yaml
└── gcp-schema.yaml

Each schema defines:

  • Required fields (like cloud, account, cluster, nodeGroups, addons)

  • Data types (e.g., strings, integers, booleans)

  • Nested object structures

This ensures users don’t miss critical config like cluster.version or nodeGroups[].instanceType.


🧰 Fallback Defaults for Missing Fields

We also introduced support for default values using files like:

configs/defaults/aws-defaults.yaml

If a user skips optional fields in their input config, these are merged automatically. This allows a smoother experience for teams who want a quick start.


πŸ› οΈ Centralized Validation Utility

To keep things DRY and consistent, we created:

utils/validation.py

This file contains:

def validate_config_file(config_path: str) -> dict:
    ...

Which:

  1. Loads the user YAML file

  2. Detects cloud (aws/azure/gcp)

  3. Loads the matching schema

  4. Validates it using jsonschema

  5. Returns a fully validated config dict

  6. Can later merge with defaults


🧱 CLI Command Architecture (After Phase 2)

infra-cli <command> --config-file <path>

Each CLI command now runs validation internally using the utility module.

βœ… validate

infra-cli validate --config-file examples/aws-sample.yaml
  • Purpose: Only checks schema validity

  • Output: βœ… or ❌ with helpful error messages

  • Great for CI/CD pipelines


βœ… load

infra-cli load --config-file examples/aws-sample.yaml
  • Purpose: Human-readable summary

  • Validates schema + prints cloud, cluster, region, version, environment

  • Great for devs verifying input before render


βœ… render

infra-cli render --config-file examples/aws-sample.yaml
  • Purpose: Renders a final cluster config file from templates using validated YAML

  • Internally uses Jinja2 to generate cloud-native config for eksctl, az, gcloud


βœ… apply

infra-cli apply --config-file examples/aws-sample.yaml
  • Purpose: Executes provisioning using eksctl, az aks, or gcloud

  • Validates input before applying

  • Future-proof to plug in Terraform


πŸ§ͺ Difference Between load and validate

Featureloadvalidate
PurposeHuman-readable previewPass/fail check for CI
OutputCloud, cluster, region summaryβœ…/❌ only
AudienceDev teamsAutomation/CI/CD

Both are needed β€” one for humans, one for machines.


πŸ“ Project Structure Snapshot

multi-cloud-infra-cli/
β”œβ”€β”€ cli/                    # All subcommands
β”‚   β”œβ”€β”€ render_templates.py
β”‚   β”œβ”€β”€ load_config.py
β”‚   β”œβ”€β”€ apply_infra.py
β”‚   └── validate_config.py
β”œβ”€β”€ utils/
β”‚   └── validation.py       # Shared schema validation logic
β”œβ”€β”€ configs/
β”‚   β”œβ”€β”€ schema/             # Per-cloud JSONSchema definitions
β”‚   └── defaults/           # Default config fallbacks
β”œβ”€β”€ examples/               # Sample input YAMLs
β”‚   β”œβ”€β”€ aws-sample.yaml
β”œβ”€β”€ templates/              # Jinja templates per cloud
└── output/                 # Rendered cluster config files

πŸš€ What’s Coming in Phase 3

In Phase 3, we’ll make apply actually provision infra by integrating with:

  • eksctl for AWS

  • az aks for Azure

  • gcloud container clusters for GCP

Then, we’ll move toward GitOps support so the provisioning becomes declarative and auditable.


🧠 Final Thoughts

This phase improved our CLI’s usability, safety, and developer trust. Users now get instant feedback on bad input, and confidence that render and apply won’t break due to missing fields.

Stay tuned for Phase 3 β€” where infrastructure comes to life.

πŸ‘‰ Repo Link: https://github.com/prathyushreddy123/k8-infra-cli

πŸ‘‰ Try it Now:

infra-cli validate --config-file examples/aws-sample.yaml
infra-cli load --config-file examples/aws-sample.yaml
infra-cli render --config-file examples/aws-sample.yaml

If you're building internal platforms, I'd love your feedback β€” or contributions πŸš€

0
Subscribe to my newsletter

Read articles from Prathyush Dommata directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prathyush Dommata
Prathyush Dommata

With 10 years of experience as a DevOps, SRE, and Cloud Engineer, I’ve worked across various tech stacks, always eager to explore new tools and best practices. I’m particularly interested in AI and MLOps, and I enjoy diving deep into projects to gain hands-on experience. I believe the best way to learn is by building from scratch, and through this blog, I aim to share insights, challenges, and lessons from my journey. Whether it's automation, cloud infrastructure, or AI-driven workflows, I’m always curious to explore what’s next.