Deploying the LokiStack Operator in OpenShift requires establishing an S3-compatible Object Storage bucket (such as AWS S3, MinIO, or OpenShift Data Foundation NooBaa), storing the bucket credentials in a Kubernetes Secret, and defining a LokiStack Custom Resource.
Step 1: Install the Loki Operator via OLM
Before creating the LokiStack instance, install the Loki Operator from OperatorHub into the openshift-operators-redhat namespace.
YAML
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: loki-operator
namespace: openshift-operators-redhat
spec:
channel: stable-5.x # Or the matching channel for your OCP release
name: loki-operator
source: redhat-operators
sourceNamespace: openshift-marketplace
Step 2: Create the Object Storage Credentials Secret
Loki requires access to an S3-compatible object storage bucket to store chunked log data and index files.
Create a Secret in the openshift-logging namespace containing your S3 bucket access keys and endpoint configuration:
YAML
apiVersion: v1
kind: Secret
metadata:
name: logging-loki-s3
namespace: openshift-logging
stringData:
access_key_id: "YOUR_S3_ACCESS_KEY"
access_key_secret: "YOUR_S3_SECRET_KEY"
bucketnames: "ocp-loki-logs-bucket"
endpoint: "https://s3.us-east-1.amazonaws.com" # Or internal MinIO/NooBaa endpoint URL
region: "us-east-1"
type: Opaque
Note for AWS IAM Roles for Service Accounts (IRSA) / STS: If using AWS IRSA or ROSA with STS, you can omit access_key_id and access_key_secret in favor of an AWS IAM role annotation on the service account.
Step 3: Deploy the LokiStack Custom Resource
Define the size and replication footprint of your Loki cluster using the LokiStack CRD. Red Hat provides pre-tuned size profiles (1x.extra-small, 1x.small, 1x.medium, etc.) to automatically calculate resource limits and replica counts.
YAML
apiVersion: loki.grafana.com/v1
kind: LokiStack
metadata:
name: logging-loki
namespace: openshift-logging
spec:
size: 1x.small # Pre-tuned production profile (extra-small, small, medium)
storage:
schemas:
- version: v13
effectiveDate: "2024-01-01"
secret:
name: logging-loki-s3
type: s3
storageClassName: fast-ssd # Fast block storage PVCs for Loki write-ahead logs (WAL)
managementState: Managed
replication:
factor: 2 # Number of chunk replicas across Loki ingesters
Apply the manifest:
oc apply -f lokistack.yaml
Step 4: Verify Deployment Health
Check that the Loki components (Ingester, Querier, Query-Frontend, Distributor, Compactor, Gateway) are fully provisioned and healthy:
Verify Pod Readiness: Bashoc get pods -n openshift-logging -l app.kubernetes.io/name=loki
Verify LokiStack CR Status: Bashoc get lokistack logging-loki -n openshift-logging -o jsonpath='{.status.conditions}' | jq Ensure all conditions (such as Pending, Ready) transition to Status: "True".
Step 5: Connect Vector to Loki (ClusterLogForwarder)
Now that LokiStack is running, configure the ClusterLogForwarder to collect and stream logs into your new Loki instance using the internal Gateway route.
The Cluster Monitoring Operator (CMO) is a core, default-installed OpenShift operator responsible for deploying, managing, and maintaining the platform’s entire observability stack.
It implements a fully managed Prometheus-based monitoring solution designed to monitor core OpenShift platform components, node infrastructure, and (optionally) user-defined workload applications.
1. Architecture and Key Components
The CMO acts as a high-level orchestrator. It manages custom resources (CRs), deployments, daemonsets, and configurations across the cluster (primarily within the openshift-monitoring and openshift-user-workload-monitoring namespaces).
Metrics Exporters: Includes node-exporter (host system metrics), kube-state-metrics (Kubernetes object state), and OpenShift component exporters.
Telemeter Client: Sends a curated, anonymized subset of platform health metrics back to Red Hat Insights for proactive support.
2. Core Responsibilities
Automated Configuration & Reconciliation: You do not manage raw Prometheus YAML configs directly. Instead, you modify a central ConfigMap (cluster-monitoring-config), and the CMO reconciles and applies those changes across all underlying Prometheus and Alertmanager instances.
Platform Health Enforcement: CMO ensures critical alert rules (e.g., etcd high latency, node disk pressure, API server errors) are always active and cannot be accidentally deleted by cluster users.
User Workload Monitoring (UWM): By default, CMO only monitors OpenShift platform components. However, administrators can enable UWM in the CMO configuration to allow developers to deploy ServiceMonitor and PodMonitor CRDs for custom application metrics in their own namespaces.
3. Key Configuration Example
To configure CMO settings (such as setting retention periods, persistent volume claims, or enabling User Workload Monitoring), administrators edit the cluster-monitoring-config ConfigMap in the openshift-monitoring namespace.
YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-monitoring-config
namespace: openshift-monitoring
data:
config.yaml: |
# Enable User Workload Monitoring for application metrics
enableUserWorkload: true
# Configure Platform Prometheus Retention and Storage
prometheusK8s:
retention: 15d
volumeClaimTemplate:
metadata:
name: prometheus-pvc
spec:
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
# Configure Alertmanager Storage
alertmanagerMain:
volumeClaimTemplate:
metadata:
name: alertmanager-pvc
spec:
storageClassName: fast-ssd
resources:
requests:
storage: 10Gi
4. Useful oc Commands for Troubleshooting CMO
Check CMO Operator Status: oc get clusteroperator monitoring
View Monitoring Pods: oc get pods -n openshift-monitoring
View User Workload Monitoring Pods (if enabled): oc get pods -n openshift-user-workload-monitoring
While OpenShift Container Platform (OCP) runs dozens of background operators, a select group of essential core and day-2 operators are critical for architecture, security, and cluster operations.
1. The Core Infrastructure Operators (The Engine)
These operators are installed automatically by default and manage the fundamental lifecycle of the cluster itself.
Cluster Version Operator (CVO): The “master controller” of OpenShift. It checks the update payload image, manages the lifecycle of all other cluster operators, and ensures the cluster stays in its declared version state.
Machine Config Operator (MCO): Manages the host operating system (Red Hat Enterprise Linux CoreOS / RHCOS). Any change to kernel settings, SSH keys, network configurations, or storage mounts on host nodes is applied declaratively via the MCO.
Ingress Operator: Manages the HAProxy-based routers that handle incoming HTTP/HTTPS traffic from outside the cluster into internal application services.
Executes containerized build steps directly inside Kubernetes pods without requiring a central Jenkins server.
OpenShift Virtualization (KubeVirt)
Modernization / Hybrid Compute
Allows traditional Virtual Machines (Linux/Windows) to run alongside containers on the same nodes.
3. Observability & Operations
Operators that provide operational visibility and cluster-wide telemetry.
Cluster Monitoring Operator (CMO): Deploy and manage the built-in Prometheus, Grafana, and Alertmanager stack to collect cluster and node-level metrics.
Red Hat OpenShift Logging (Vector / OpenSearch / Loki): Aggregates, parses, and stores logs from cluster components, host nodes, and application containers.
Node Feature Discovery (NFD) & GPU Operators: Automatically detects specialized hardware (like NVIDIA GPUs or SR-IOV network interfaces) on host nodes and applies corresponding labels for workload scheduling.
Performing an etcd backup is a mandatory step before any major OpenShift Container Platform (OCP) lifecycle operation (such as cluster updates or major infrastructure changes).
OpenShift provides built-in scripts to automate the backup process and restore state directly onto control plane (master) nodes.
Part 1: How to Back Up etcd
The backup script creates a snapshot of the etcd database along with static pod resources, certificates, and API keys.
1.Establish a Debug Session on a Control Plane Node:Prerequisite: Cluster-admin rights required.
Select an active master node and start a debug pod on it:
oc debug node/master-0
2.Set Root Directory Context:
Inside the debug shell, switch your filesystem context to access the host system drives:
chroot /host
3.Execute the Built-in Cluster Backup Script:
Run the automated backup script provided in the RHCOS image, specifying a target output directory:
found latest kube-apiserver: /etc/kubernetes/static-pod-resources/kube-apiserver-pod-12
etcdctl version: 3.5.x
snapshot saved at /var/usr/temp/etcd-backup/snapshot_2026-08-29_110156.db
...
etcd backup complete!
4.Verify and Save Backup Artifacts:
Check that both the snapshot DB file and static pod resource archives were generated:
ls -lh /var/usr/temp/etcd-backup
Important: Copy these files off the host node to a secure external storage location (S3 bucket, NFS share, or local admin machine) via oc cp or scp.
Part 2: How to Restore etcd (Disaster Recovery)
Use this process if the cluster’s state database suffers unrecoverable corruption or consensus loss across the control plane.
Warning: A restore is a destructive, high-impact action. It resets the cluster state back to the exact point in time when the backup snapshot was taken.
1.Identify the Recovery Master Node:
Select one surviving master node (master-0) to act as the primary recovery host. Transfer your backup files to this node if they aren’t already present on /var/usr/temp/etcd-backup.
2.Stop the Control Plane Static Pods on ALL Master Nodes:
Open SSH or debug sessions to every master node in the cluster and move the static pod manifests out of /etc/kubernetes/manifests/ to stop kube-apiserver, etcd, and kube-controller-manager:
Clears corrupted local etcd member data on master-0.
Restores the snapshot DB.
Generates a single-member etcd cluster configuration.
4.Restart Kubelet on the Recovery Node:
Restart kubelet on master-0 to re-initialize static pods:
systemctl restart kubelet
5.Force etcd Operator Redeployment:
Exit the host debug shell back to your workstation CLI and patch the Cluster Version / etcd Operator to force quorum reconciliation across the remaining control plane nodes:
# Force the etcd operator to re-evaluate cluster membership
A canary update strategy allows you to test an OpenShift node operating system and config update on a small subset of worker nodes (e.g., a non-critical worker pool) before committing the change across your entire production cluster.
By default, OpenShift updates all nodes in a MachineConfigPool (MCP) automatically once the control plane is updated. Pausing an MCP freezes the Machine Config Operator (MCO) from updating that specific group of nodes.
Step 1: Create a Dedicated Canary MachineConfigPool
Instead of applying updates directly to the default worker pool, isolate 1 or 2 nodes into a custom canary pool.
Before starting the cluster-wide upgrade, pause the default worker pool so its nodes remain on the current version while the control plane and your canary pool update.
Never upgrade a sick cluster. Every check below exists because upgrading on top of an existing problem turns a recoverable issue into a potential outage.
Phase 1 — Pre-Upgrade Preparation (Days Before)
1.1 Know Your Upgrade Path
OCP does not support arbitrary version jumps. Upgrades must follow a validated graph:
4.12 → 4.13 → 4.14 ✅ valid sequential path
4.12 → 4.14 ❌ may not be supported (check the graph)
4.14.5 → 4.14.12 ✅ z-stream (patch) always OK
4.14.12 → 4.15.0 ✅ minor version (must check graph)
For each blocking PDB, verify whether it will open up during drain (more replicas than minAvailable) or whether it is misconfigured and will permanently block node drains.
Controlled by MachineConfigPool maxUnavailable setting
│
▼
6. CVO marks upgrade complete
clusterversion: Progressing=False, Available=True
3.5 Control Worker Upgrade Speed
By default only 1 worker upgrades at a time. For large clusters you can safely increase this:
# Check current maxUnavailable (default is 1)
oc get mcp worker -ojsonpath='{.spec.maxUnavailable}'
# Allow up to 20% of workers to upgrade simultaneously
oc patch mcp worker \
--type merge \
--patch'{"spec":{"maxUnavailable":"20%"}}'
⚠️ Never set maxUnavailable higher than your workloads can tolerate. If minAvailable in your PDBs is 2 and you only have 3 replicas, draining 2 workers simultaneously will block.
Phase 4 — During the Upgrade
Watch for Stuck Upgrades
# If upgrade appears frozen, check:
# 1. Any operator stuck progressing?
oc get co | grep-v"True.*False.*False"
# 2. Any node stuck draining?
oc get nodes | grep SchedulingDisabled
# 3. Any pods blocking drain (PDB)?
oc get pdb -A | grep-v"^NAMESPACE"
# 4. Pending CSRs (workers trying to re-join after reboot)
oc get csr | grep Pending
oc get csr -o name | xargs oc adm certificate approve
# 5. Any pods stuck Terminating (blocking node drain)?
oc get pods -A | grep Terminating
# Force delete if stuck:
oc delete pod <pod> -n <ns> --grace-period=0--force
Approve Pending CSRs
After each node reboots, it issues a CSR to re-register with the cluster. In some configurations these need manual approval:
# Watch for and approve all pending CSRs
watch -n10"oc get csr | grep Pending"
# Approve all at once
oc get csr -o name | xargs oc adm certificate approve
This script is a pre-flight gate before triggering an OCP upgrade. It runs 7 sequential checks and blocks the upgrade if any critical condition is detected. Think of it as a checklist that a senior SRE would run manually — automated.
1. Verify Active CLI Session & Cluster Admin Access
2. Check ClusterVersion Operator (CVO) Status
What is the CVO? The Cluster Version Operator is the top-level operator that manages the OCP version and coordinates all upgrades. If it’s unhealthy or busy, no upgrade should start.
What the jsonpath queries extract:
The clusterversion object has a status.conditions array:
yaml
status:
conditions:
-type: Available
status:"True"← extracted by first query
-type: Progressing
status:"False"← extracted by second query
-type: Degraded
status:"False"
The condition check:
Available
Progressing
Meaning
Action
True
False
CVO healthy and idle
✅ OK to upgrade
True
True
Upgrade already running
❌ Block
False
False
CVO degraded/broken
❌ Block
False
True
Upgrade running AND broken
❌ Block
Equivalent manual check:
oc get clusterversion
# NAME VERSION AVAILABLE PROGRESSING SINCE STATUS
# version 4.14.12 True False 5d Cluster version is 4.14.12
3. Audit Core Cluster Operators
4. Check MachineConfigPools (MCP)
What are MCPs?
MachineConfigPools define groups of nodes and the configuration applied to them. During an upgrade, the MCP controller drains and reboots each node to apply the new RHCOS and MachineConfig.
master MCP → controls all 3 master nodes
worker MCP → controls all worker nodes
infra MCP → controls infra nodes (if defined)
Degraded MCP check: A degraded MCP means at least one node in the pool failed to apply its MachineConfig — it didn’t reboot correctly, got stuck, or had a rendering error. Upgrading on top of a degraded MCP compounds the problem.
5. Check Node Readiness
6. Audit PodDisruptionBudgets (PDB) for Potential Deadlocks
What is a PDB?
A PodDisruptionBudget is a policy that limits how many pods of an application can be voluntarily disrupted (evicted) at once:
7. Check Active Critical Alerts
What oc get alerts does:
This uses the OpenShift alerts API resource — a custom OCP resource that surfaces Prometheus AlertManager alerts via the Kubernetes API:
The 2>/dev/null || echo "": oc get alerts is not available on all OCP versions or configurations. The 2>/dev/null suppresses errors and || echo "" ensures FIRING_CRITICALS is empty (not unset) if the command fails — avoiding the -u unset variable trap.
Why critical alerts block an upgrade:
A firing critical alert means something is actively broken in the cluster. Upgrading on top of an existing critical condition risks:
Making a broken component worse during its own operator-driven upgrade
Masking the original problem behind upgrade noise
A critical alert like etcdMemberDown means your etcd quorum is at risk — the worst time to upgrade
Complete flow:
START │ ├─ [1/7] oc whoami → HARD EXIT if not logged in ├─ [2/7] CVO Available+Idle → ERRORS++ if degraded or progressing ├─ [3/7] Cluster Operators → ERRORS++ if any Degraded or Unavailable ├─ [4/7] MachineConfigPools → ERRORS++ if Degraded / WARN if Paused ├─ [5/7] Node Readiness → ERRORS++ if any NotReady ├─ [6/7] PDB Deadlocks → WARN only (no ERRORS++) └─ [7/7] Critical Alerts → ERRORS++ if any firing │ ├─ ERRORS == 0 → exit 0 (safe to upgrade) └─ ERRORS > 0 → exit 1 (do not upgrade)
The script :
#!/usr/bin/env bash
#
# OCP Pre-Upgrade Health Check Automation Script
# Validates cluster readiness before initiating an OpenShift platform update.
Planning an OpenShift Container Platform (OCP) upgrade requires structured validation across 5 distinct phases. Because OpenShift performs rolling updates of both the control plane and the host OS (RHCOS), executing pre-upgrade checks prevents node-drain locks, degraded operators, or broken API dependencies.
Phase 1: Pre-Upgrade Review & Path Mapping
Verify Your Upgrade Path:
OpenShift does not support skipping Y-stream releases (e.g., jumping from 4.14 to 4.16 directly). You must upgrade sequentially (4.14 → 4.15 → 4.16).
Check your configured update channel (stable-4.x, fast-4.x, or eus-4.x).For enterprise production environments, stick to stable-4.x or eus-4.x (Extended Update Support).
Query the OpenShift Update Service (OSUS) via CLI: adm upgrade
Audit Deprecated & Removed Kubernetes APIs:
Before a minor version jump (e.g., 4.15 → 4.16), check if your workloads use removed K8s API versions.
Review cluster alerts for API deprecations and migrate manifests accordingly. OCP will block minor version upgrades if administrator acknowledgment is missing for API removals.
Check Operator & OLM Compatibility:
Non-core platform operators (installed via OperatorHub/OLM) must be upgraded to versions compatible with the target OCP release before updating the cluster core.
Phase 2: Cluster Health & Capacity Assessment
Run a complete health scan. Never trigger an upgrade on a degraded cluster.
Verify ClusterOperator Status:Ensure all core operators report AVAILABLE=True, PROGRESSING=False, and DEGRADED=False: oc get clusteroperator
Verify MachineConfigPool (MCP) Health:Ensure all node pools are updated and none are paused or degraded: oc get mcp(If an MCP is paused for canary testing, verify it is intentional before proceeding.)
Node Capacity: During node-draining, remaining workers must have enough CPU/RAM capacity to host evacuated workloads.
PDB Deadlocks: Inspect custom PodDisruptionBudgets (oc get pdb -A). If minAvailable is set equal to the total replica count (or maxUnavailable: 0), node drains will stall, hanging the upgrade loop.
Clear Active Alerts:In the console, go to Observe → Alerting and resolve all critical alerts.
Phase 3: Mandatory Backups (Non-Negotiable)
Because OpenShift updates are fail-forward (rolling back to an older minor version is not supported), taking backups prior to execution is mandatory:
Backup etcd: Take a manual snapshot of the etcd database from a control plane node: oc debug node/<master-node-name> -- /usr/local/bin/cluster-backup.sh /host/var/usr/temp/etcd-backup
Export Cluster Custom Resources (CRDs): Export your custom deployment manifests, routes, and secret configurations using a GitOps tool (ArgoCD/ACM) or CLI backups.
For a senior Azure architect interview, I’d design this as a layered enterprise platform: ingestion → lakehouse → AI/ML → API serving → security/governance → observability. Azure’s current architecture guidance supports combining ADLS, Databricks/data pipelines, private networking, API Management, and Microsoft Foundry/Azure OpenAI for this pattern. (Microsoft Learn)
ADLS Gen2 gives you the scalable storage foundation for analytics and AI, while Databricks can provide Spark processing, Delta Lake/lakehouse processing and ML workflows. Microsoft recommends Unity Catalog as the modern Databricks governance/access pattern for storage rather than older direct-access configurations. (Microsoft Learn)
1. Data lake and pipelines
I would make ADLS Gen2 the system of record and divide it into:
Bronze
↓
Raw source data
↓
Silver
↓
Validated / cleaned / standardized
↓
Gold
↓
Business-ready / ML-ready datasets
Data arrives through Azure Data Factory for batch ingestion and Event Hubs for streaming workloads. ADF is designed to create and schedule data-driven ingestion and transformation workflows across different data stores. (Microsoft Learn)
For heavy transformation:
ADF
|
+----> Databricks Jobs
|
+--> Spark
+--> Delta Lake
+--> Feature engineering
+--> ML pipelines
2. AI model layer
I would support two types of models.
For foundation models:
Microsoft Foundry
|
Azure OpenAI / Foundry models
|
+-----+-----+
| |
GPT/LLM Embeddings
For custom ML models:
ADLS
|
Databricks
|
Training
|
MLflow
|
Model registry
|
Deployment
|
AKS / managed inference endpoint
This separation is useful because I don’t want to run a GPT-class foundation model myself unless there is a strong requirement. Managed Foundry models handle that side, while proprietary classifiers, forecasting models and specialized models can follow a traditional MLOps lifecycle.
3. RAG architecture
For enterprise GenAI, I’d normally add Azure AI Search.
Offline pipeline
Documents
|
ADLS
|
Databricks / AI Search ingestion
|
Chunk documents
|
Generate embeddings
|
Azure AI Search
Vector index
Runtime
User
|
v
APIM
|
v
AKS AI API
|
+---- query ----> Azure AI Search
| |
| Relevant
| documents
| |
+<--------------------+
|
| Prompt + context
v
Azure OpenAI
|
v
Grounded answer
Azure AI Search can provide integrated vectorization and retrieval for Azure OpenAI RAG workloads, reducing the amount of custom embedding/indexing code required in some designs.
4. API architecture
I would not expose the model endpoint directly.
Instead:
Client
|
Front Door/WAF
|
APIM
|
AI orchestration API
|
+-------+---------+---------+
| | | |
GPT Search Databricks Business
APIs
APIM becomes the enterprise control point for:
OAuth2/OIDC and Microsoft Entra ID authentication
JWT validation
throttling and quotas
request/response policies
API versioning
usage/cost controls
model routing
observability
Microsoft now specifically documents APIM as a gateway in front of Foundry/Azure OpenAI workloads for centralized routing, load balancing, throttling and observability. (Microsoft Learn)
For multiple model deployments, APIM can also use backend pools to distribute requests across several backends. (Microsoft Learn)
5. AKS application layer
For an enterprise deployment I’d use:
AKS
|
+-- System Node Pool
|
+-- API Node Pool
| |
| +-- REST APIs
| +-- AI orchestration
| +-- RAG services
|
+-- ML Node Pool
|
+-- Custom inference
+-- GPU workloads if required
Then use:
HPA
|
Pod scaling
Cluster Autoscaler
|
Node scaling
The Azure Architecture Center maintains a dedicated baseline AKS architecture specifically for production infrastructure design. (Microsoft Learn)
6. Enterprise networking
This is where I would spend significant interview time.
Azure Landing Zone
HUB VNET
+----------------+
On-Prem -------->| ExpressRoute |
| Azure Firewall |
| DNS Resolver |
+-------+--------+
|
VNet Peering
|
+---------+----------+
| AI Spoke VNet |
| |
| AKS |
| APIM |
| Private Endpoints |
+---------+----------+
|
Private Link only
|
+----------------+----------------+
| | |
ADLS Azure OpenAI AI Search
| | |
Private Private Private
Endpoint Endpoint Endpoint
For regulated environments, I would disable public access where supported and use Private Link/private endpoints for PaaS resources. Private endpoints assign a private VNet IP to reach the service rather than traversing a public endpoint. (Microsoft Learn)
Private DNS is critical:
AKS
|
DNS query
|
Azure DNS Private Resolver
|
Private DNS Zone
|
Private Endpoint IP
|
Azure OpenAI / ADLS / AI Search
Microsoft’s Foundry landing-zone architecture explicitly uses private DNS zones to resolve private endpoints securely from workload networks. (Microsoft Learn)
7. Identity and secrets
Avoid credentials in applications.
Pod
|
AKS Workload Identity
|
Microsoft Entra ID
|
+----------+----------+----------+
| | | |
ADLS Key Vault AI Search Azure OpenAI
Use:
Microsoft Entra ID → managed identities/workload identity → Azure RBAC
rather than embedding storage keys or model API keys inside Kubernetes Secrets whenever possible.
Key Vault stores unavoidable secrets, certificates and keys.
8. Governance
For a banking/regulated enterprise I’d add:
Microsoft Purview
|
Data classification
Lineage
Sensitive-data discovery
Governance
Azure Policy
|
Landing-zone guardrails
Private endpoints required
Allowed regions
Allowed SKUs
Databricks Unity Catalog
|
Tables
Files
Models
Permissions
Lineage
9. Observability
The entire stack feeds centralized monitoring:
AKS
Azure OpenAI
APIM
Databricks
AI Search
ADF
|
v
Azure Monitor
|
Log Analytics
|
Application Insights
|
Microsoft Sentinel
For AI specifically, capture:
Model latency
Token consumption
HTTP 429s
Model errors
APIM latency
Retrieval latency
Prompt/response safety signals
Cost per application
Model quality
Microsoft provides an architecture specifically for advanced monitoring of Foundry/Azure OpenAI models through a gateway.
10. CI/CD + MLOps
I’d separate application, infrastructure, data and model deployment pipelines:
GitHub / Azure DevOps
|
+---- Terraform/Bicep
| |
| Azure Infrastructure
|
+---- App CI/CD
| |
| ACR
| |
| AKS
|
+---- DataOps
| |
| Databricks / ADF
|
+---- MLOps
|
Training
|
MLflow
|
Validation
|
Registry
|
Deployment
The interview answer I’d memorize
If the interviewer asks:
“Design an Azure architecture to host AI models, APIs, a data lake and supporting pipelines.”
You can answer:
“I’d build the platform around ADLS Gen2 as the enterprise data lake, with Data Factory and Event Hubs handling batch and streaming ingestion. Databricks would provide the lakehouse, Spark transformations, ML training and model lifecycle capabilities. For generative AI I’d use Microsoft Foundry/Azure OpenAI and Azure AI Search for RAG and vector retrieval.
Application and AI orchestration APIs would run on AKS and be exposed through Azure API Management, which provides authentication, throttling, model routing and API governance.
From a security perspective I’d deploy the platform into an Azure landing-zone hub-and-spoke architecture, use private endpoints for ADLS, AI Search and model services, use Entra ID and workload identities instead of static credentials, and Key Vault where secrets are unavoidable.
Finally, I’d use Azure Monitor, Log Analytics, Application Insights and Sentinel for centralized observability, with Terraform and CI/CD pipelines managing infrastructure and application deployments.”
That’s approximately a 90-second architect-level answer, while still giving the interviewer several areas—AKS, networking, AI, data, security and MLOps—to drill into. (Microsoft Learn)
For an enterprise Azure analytics platform, I would use a polyglot data architecture: each storage technology handles the workload it is best suited for, while ADLS Gen2 becomes the central analytical system of record. Microsoft’s current guidance supports ADLS-based medallion/lakehouse architectures and emphasizes storage layout, file formats, partitioning, and parallelism for analytical performance. (Microsoft Learn)
Reference architecture
DATA SOURCES
|
+----------------------+----------------------+
| | |
Applications Enterprise DBs Files / APIs
| | |
v v v
Cosmos DB Azure SQL / ADF / Event
operational DB SQL Server Hubs
| | |
+----------------------+----------------------+
|
v
Azure Data Factory
/ Event Hubs / Databricks
|
v
+--------------------------------+
| Azure Blob / ADLS Gen2 |
| |
| BRONZE - Raw |
| SILVER - Cleaned |
| GOLD - Curated |
+---------------+----------------+
|
Delta / Parquet
|
Azure Databricks
Spark / SQL
|
+--------------+-------------+
| |
v v
Azure SQL DB / AI / ML
SQL serving layer workloads
|
v
Power BI / APIs /
Analytics applications
Azure Data Factory can directly copy and transform data into ADLS Gen2, making it appropriate as the orchestration and ingestion layer. (Microsoft Learn)
1. Azure Blob Storage / ADLS Gen2
This should contain the largest volume of analytical data.
Conceptually:
Storage Account
│
├── bronze/
│ ├── cosmos/
│ ├── sql/
│ ├── api/
│ └── documents/
│
├── silver/
│ ├── customers/
│ ├── transactions/
│ └── products/
│
└── gold/
├── customer_360/
├── revenue/
├── risk/
└── ai_training/
I would normally enable the hierarchical namespace, effectively using Azure Data Lake Storage Gen2 capabilities on Azure Blob Storage. ADLS Gen2 is designed for large-scale analytical workloads. (Microsoft Learn)
Bronze — immutable/raw
Keep data as close to the source as possible:
Cosmos JSON
SQL extracts
CSV
JSON
Avro
application logs
documents
Example:
/bronze/cosmos/orders/year=2026/month=08/day=11/
/bronze/sql/customer/year=2026/month=08/day=11/
Do not let consumers directly modify Bronze.
2. Silver — analytical processing
Databricks transforms Bronze into standardized datasets:
Bronze
|
v
Azure Databricks
|
+-- schema enforcement
+-- data cleaning
+-- deduplication
+-- joins
+-- standardization
+-- quality checks
+-- PII handling
|
v
Silver
For example:
bronze:
customer JSON + transactions + CRM
↓
silver:
Customer
Transaction
Account
Product
I’d generally use Delta Lake/Parquet rather than CSV for analytical datasets. A lakehouse architecture combines scalable object storage with data-management and warehouse-style capabilities. (Microsoft Learn)
3. Gold — business-ready analytics
Gold contains datasets optimized for consumption rather than raw ingestion.
Silver
|
+----------+
| |
v v
Customer360 SalesMetrics
| |
+----+-----+
|
GOLD
Example:
/gold/customer360/
/gold/monthly_revenue/
/gold/risk_analysis/
/gold/executive_reporting/
The Gold layer can then feed:
Power BI
Azure SQL
APIs
Databricks SQL
Machine learning
AI/RAG
This Bronze → Silver → Gold medallion structure is a common Azure lakehouse design; Microsoft’s architecture guidance also shows ADF ingestion, Databricks processing and Azure SQL as a downstream serving store. (Microsoft Learn)
4. Where Cosmos DB fits
This distinction matters in interviews:
Cosmos DB should generally not become your primary enterprise data lake.
Use Cosmos DB for:
High transaction volume
+
Low-latency access
+
Semi-structured JSON
+
Global distribution
+
Application operational data
Example:
{
"customerId":"C10001",
"eventType":"purchase",
"productId":"P889",
"amount":142.75,
"timestamp":"2026-08-11T18:05:03"
}
An application might use:
Web/Mobile App
|
v
API
|
v
Cosmos DB
latency: milliseconds
Analytics should normally be separated:
OLTP Analytics
Application
|
v
Cosmos DB
|
+---------------------> Analytics platform
|
v
ADLS/Lakehouse
That prevents heavy analytical queries from competing with production application traffic.
5. Cosmos DB analytics: an important current change
This is worth knowing for a 2026 interview.
Historically, you would often hear:
Cosmos DB
|
Analytical Store
|
Synapse Link
|
Synapse Analytics
But Microsoft now states that Azure Synapse Link for Cosmos DB isn’t supported for new projects and recommends Azure Cosmos DB Mirroring for Microsoft Fabric for new implementations. (Microsoft Learn)
So for a new Fabric-centric design:
Cosmos DB
|
| zero-ETL mirroring
v
Microsoft Fabric
|
OneLake
|
Analytics / Power BI
For an existing estate that already uses Synapse Link, analytical store can still separate analytical access from the transactional workload and provide near-real-time analytical data without traditional ETL. (Microsoft Learn)
That’s a very useful distinction to make in an interview because many older architecture diagrams still recommend Synapse Link as the default for new solutions.
6. Where Azure SQL fits
I would use Azure SQL primarily for structured relational workloads and analytical serving, rather than storing petabytes of raw lake data.
For example:
ADLS Gold
|
Databricks
|
v
Azure SQL
Serving DB
|
+--------+--------+
| |
Power BI APIs
Azure SQL could contain:
DimCustomer
DimProduct
DimDate
FactSales
FactOrders
FactRevenue
Conceptually:
FactSales
|
+-------+-------+
| | |
Customer Product Date
That structure works well when consumers expect SQL semantics, relational joins, predictable schemas and conventional BI integration.
Microsoft’s medallion reference architecture explicitly describes Azure SQL as a persisted downstream serving store after ADF ingestion and Databricks processing. (Microsoft Learn)
7. Don’t query operational SQL for every report
This is an important architecture rule.
Avoid:
Power BI
|
v
Production Azure SQL
when complex BI queries could impact application traffic.
Instead:
Production SQL
|
| CDC / incremental ingestion
v
ADF
|
v
ADLS Bronze
|
Databricks
|
ADLS Gold
|
+----> BI serving layer
|
+----> Power BI
This creates separation between:
OLTP
many small
INSERT/UPDATE/SELECT
and OLAP
SELECT SUM(...)
FROM billions_of_rows
GROUP BY ...
8. File format optimization
For analytics, the storage format matters considerably.
I would prefer:
RAW
CSV / JSON / original source
|
v
Bronze
transform
↓
Silver / Gold
Parquet / Delta
Why?
Parquet is column-oriented.
Imagine:
customer_id
name
country
age
salary
transaction_total
If a query needs only:
SELECT country, SUM(transaction_total)
FROM sales
GROUPBY country;
a columnar format can avoid unnecessarily reading all unrelated columns.
ADLS performance guidance emphasizes that file format, file size and directory structure affect both performance and cost, and recommends parallelizing ingestion and access. (Microsoft Learn)
9. Partitioning
Don’t create:
/data/everything.parquet
and don’t create millions of tiny files either.
Use useful business/query partitions:
/sales/
year=2026/
month=08/
day=11/
part-00001.parquet
part-00002.parquet
Then:
WHEREyear=2026
ANDmonth=8
allows the processing engine to avoid scanning irrelevant partitions.
Possible partition keys:
date
region
source_system
business_domain
But avoid partitioning on very high-cardinality fields such as:
customer_id
transaction_id
GUID
because that can create a huge number of directories/files.
10. Handle the small-file problem
An enterprise ingestion system can easily produce:
10 million × 10 KB JSON files
which is inefficient for analytical processing.
I’d periodically compact them:
10,000 tiny files
↓
Databricks
↓
10–100 appropriately sized
Parquet / Delta files
Microsoft’s ADLS guidance notes that larger files generally provide better analytical performance and lower transaction overhead compared with large numbers of tiny files. (Microsoft Learn)
11. Data flow between the three storage systems
A good architecture might look like this:
OPERATIONAL SYSTEMS
┌──────────────────┐
│ Cosmos DB │
│ JSON/events │
└────────┬─────────┘
|
|
┌─────────────┐ | ┌─────────────┐
│ Azure SQL │ | │ APIs/Files │
│ OLTP │ | │ SaaS │
└──────┬──────┘ | └──────┬──────┘
| | |
+---------------+----------------+
|
ADF / Streaming
|
v
┌─────────────────────┐
│ Azure Blob/ADLS G2 │
│ │
│ BRONZE │
│ SILVER │
│ GOLD │
└──────────┬──────────┘
|
Databricks
Spark / Delta
|
+------------+------------+
| |
v v
Azure SQL AI / ML
analytical serving Models
|
v
Power BI
12. Security architecture
For an enterprise deployment:
Azure Landing Zone
|
VNet
|
Private Endpoints
|
+---------------+---------------+
| | |
ADLS Cosmos DB Azure SQL
I would add:
Microsoft Entra ID
|
Managed Identity
|
Azure RBAC
and:
Key Vault
|
CMK/secrets/certificates
Plus:
disable public network access where appropriate;
use private endpoints;
use managed identities rather than embedded account keys;
encrypt data at rest and in transit;
apply least-privilege RBAC;
classify sensitive datasets;
maintain audit logs and lineage.
13. Analytics performance design
My high-level optimization rules would be:
Layer
Optimization
ADLS
Parquet/Delta
ADLS
sensible partitioning
ADLS
avoid tiny files
Databricks
distributed Spark
Cosmos DB
good partition key
Cosmos DB
isolate operational from analytical workloads
SQL
indexes appropriate to serving queries
SQL
dimensional/star schemas where appropriate
Pipelines
incremental loads
Pipelines
parallel ingestion
Gold
pre-aggregated datasets
Microsoft specifically recommends maximizing parallel reads/writes for ADLS analytical workloads rather than serializing large ingestion jobs. (Microsoft Learn)
“I would use a polyglot storage architecture. Azure Blob Storage with ADLS Gen2 would be the central analytical data lake because it provides low-cost scalable storage for structured, semi-structured and unstructured data.
I would organize it using Bronze, Silver and Gold zones. Raw data from Azure SQL, Cosmos DB, APIs and other systems lands unchanged in Bronze. Databricks then performs schema enforcement, quality checks, deduplication and transformations, storing Silver and Gold datasets primarily in Delta or Parquet formats.
Cosmos DB remains the operational store for low-latency, high-volume JSON workloads rather than becoming the primary data lake. Azure SQL handles relational transactional workloads and can also provide a curated SQL serving layer for BI applications.
For performance, I’d use incremental ingestion, parallel processing, appropriate partitioning, columnar storage and file compaction. From a security perspective, all three platforms would use Entra ID, managed identities, RBAC and private endpoints.
Finally, I keep operational and analytical workloads isolated so large BI or ML queries never affect production databases.”
One particularly good 2026 interview point is to mention that although Cosmos DB Synapse Link appears in many older architectures, Microsoft now recommends Cosmos DB Mirroring for Microsoft Fabric for new projects rather than starting a new Synapse Link implementation. (Microsoft Learn)