Deploying Docker Applications to Azure Kubernetes Service
Kubernetes as a foundational technology
In today’s cloud-native development landscape, Kubernetes has become a foundational technology for managing containerized applications. Its flexibility, scalability, and support across platforms make it a cornerstone of modern DevOps workflows.
This guide will walk you through deploying a Docker-based
application to Azure Kubernetes Service (AKS) using Azure
DevOps CI/CD pipelines. Along the way, you'll gain insights into
Kubernetes architecture, Azure Container Registry, and practical CI/CD
implementation strategies.
✅ Kubernetes History at a
Glance
- Origins
at Google: Kubernetes was born from Google’s internal container
orchestration system called Borg, which they’d been using for over a
decade to manage billions of containers per week.
- First
Announcement: Kubernetes was announced publicly by Google in June
2014.
- Open
Source Release: The first open-source version was released shortly
after, and it was donated to the Cloud Native Computing Foundation
(CNCF) in 2015.
- Version
1.0: Official Kubernetes v1.0 was released on July 21, 2015.
- Rapid
Growth: Since then, Kubernetes has had regular quarterly
releases, with strong backing from a broad community including Google,
Microsoft, Red Hat, AWS, and others.
- Why
Open Source?: Google open-sourced it to standardize orchestration
across clouds and avoid vendor lock-in, encouraging a neutral ecosystem
(via CNCF).
What is Kubernetes?
Kubernetes is an open-source container
orchestration system for automating application deployment, scaling, and
management. It handles the scheduling and operation of containerized
applications across clusters of machines, ensuring high availability, fault tolerance,
and optimal resource utilization.
Key Features
- Automated deployment & scaling
- Self-healing (automatic restarts and
replacements)
- Service discovery & load balancing
- Efficient resource utilization
- Declarative configuration and automation
Core Concepts: Containers, Pods and Nodes
📦 Containers
A container is a lightweight, isolated runtime environment that contains an application and its dependencies.
- Run the actual application
- Are created from container images
- Run inside Pods
🧱 Pods
A Pod is the smallest and most basic
deployable unit in Kubernetes. It represents a single instance of a running
process and may contain one or more containers that share:
- Storage volumes
- IP addresses
- Networking
- Configuration details
Each pod is scheduled to run on a Node and
represents an isolated environment.
Example: A frontend pod with one container, or a backend pod
with two containers and a shared volume.
🖥️ Nodes
A Node is a worker machine (VM or physical
server) that runs the containerized workloads. It includes:
- A container runtime (like Docker)
- Kubelet: to communicate with the Kubernetes control
plane
- Kube-proxy: for networking
Nodes are managed by the Kubernetes Master (or control plane),
which schedules and distributes pods.
Azure Kubernetes Service (AKS)
AKS is a managed Kubernetes service provided by
Microsoft Azure. It abstracts the complexity of Kubernetes setup and operation,
making it easy to deploy and manage containerized applications in the cloud.
Benefits of AKS:
- No need to manage master nodes
- Automatic upgrades and patching
- Integrated monitoring
- Horizontal scaling
- Secure with Azure Active Directory integration
- Native support for Kubernetes YAML deployments
AKS supports deploying infrastructure using Kubernetes manifests (YAML files),
allowing infrastructure-as-code integration directly into the deployment
pipeline.
Azure Container Registry (ACR)
The Azure Container Registry (ACR) is a
private registry service that stores Docker images for container deployments.
It enables:
- Secure image storage
- Integration with Azure services (App Services, AKS,
etc.)
- CI/CD pipelines pulling and pushing images
seamlessly
In this workflow, ACR is used to:
- Store built Docker images
- Serve as the image source for deployments to AKS
To enable AKS to pull images from ACR, a role assignment is
required to authenticate AKS with ACR using a service principal.
CI/CD Workflow Overview
Here’s the high-level deployment workflow using Azure
DevOps CI/CD pipelines:
🛠 Continuous Integration
(CI)
- Developer commits code → triggers CI pipeline
- CI pipeline:
- Pulls base Docker image (e.g., .NET Core)
- Builds and packages the application
- Pushes Docker image to ACR
- Publishes artifacts: .yaml manifest, .dacpac (SQL
package)
🚀 Continuous Deployment (CD)
- Release pipeline triggered post-build
- CD pipeline:
- Deploys database via .dacpac to Azure
SQL
- Authenticates AKS with ACR
- Deploys image to AKS using Kubernetes manifest
- Creates a load balancer for frontend access
Detailed Demo Steps
📦 Step 1: Project &
Extension Setup
- Create an Azure DevOps project
- Install necessary extensions:
- Kubernetes: for image deployments
- Replace Tokens: for dynamic config
replacements in YAML and appsettings
🌐 Step 2: Provision Azure Resources
Using Azure Cloud Shell & CLI:
- Create a Resource Group
- Create AKS cluster (2 pods, 3
nodes)
- Create Azure Container Registry (ACR)
- Create Azure SQL Server and Database
Enable monitoring during AKS creation to utilize built-in logging and
performance tracking.
🔐 Step 3: Grant AKS
Access to ACR
- Retrieve the AKS service principal ID
- Retrieve the ACR resource ID
- Create a role assignment so AKS
can pull images from ACR
🧪 Step 4: Configure CI Build Pipeline
Build tasks include:
- Replace Tokens in appsettings.json and aks-deployment.yaml
- Pull base image (.NET Core) from public
registry
- Build Docker image with application
- Tag and push image to ACR
- Publish artifacts (YAML & DACPAC)
🚀 Step 5: Configure CD Release Pipeline
Release tasks include:
- Deploy Database using DACPAC
- Authenticate with ACR and AKS
- Deploy Kubernetes resources:
·
Use aks-deployment.yaml to create
a LoadBalancer
·
Apply image updates to AKS
Replace Tokens task ensures environment-specific values
(e.g., server names) are injected into the manifests dynamically.
Kubernetes Dashboard & Monitoring
After deployment:
- Access the web application via the external IP
of the frontend pod
- Install and configure kubectl to interact
with the AKS cluster
- Use kubectl proxy to access
the Kubernetes Dashboard
- Grant permissions to the dashboard's service
account using cluster role binding
Monitoring with Azure:
- Navigate to Insights in the AKS
resource
- Monitor:
- Nodes
- Pods
- Controllers
- Containers
You can scale the cluster, upgrade Kubernetes versions, or
manage resources directly from Azure Portal or via CLI.
Deploying Docker-based applications to Azure Kubernetes Service using a fully
automated CI/CD pipeline provides a robust, scalable, and production-ready
DevOps workflow. By leveraging:
- AKS for orchestration,
- ACR for image management, and
- Azure DevOps for pipeline automation
You can achieve seamless deployments, efficient scaling, and reliable
management of containerized services.
Whether you're building for microservices, scaling
enterprise systems, or automating database deployments, this setup provides a
solid foundation for continuous delivery in a cloud-native world.
Containers (like Docker) allow you to package applications
with their dependencies into isolated units. But managing containers at scale,
networking them, scaling them, recovering from failure, deploying updates is
incredibly complex.
That’s exactly what Kubernetes solves. It
orchestrates these containers, placing them on nodes, monitoring their health,
and scaling them up/down automatically.
Kubernetes Components
Pod: The smallest
deployable unit in Kubernetes, representing a group of one or more containers
that share network and storage resources. Pods are the atomic unit of
scheduling and run on a single node.
Node: A worker machine in the
Kubernetes cluster that hosts pods. Nodes are the fundamental computing
hardware units that provide computational resources for running containerized
applications.
Objects: Persistent
entities in the Kubernetes system that represent the state of the cluster,
including deployments, services, pods, and other resources that define the
desired cluster configuration.
Monitoring: Tracks resource
utilization and performance of nodes, pods, and containers using commands like
kubectl top to provide insights into cluster health and resource consumption.
Deployment: A Kubernetes
object that manages the lifecycle of pods, ensuring a specified number of
replica pods are running and facilitating updates and rollbacks of application
versions.
Service: An abstraction that defines a
logical set of pods and a policy to access them, providing network connectivity
and load balancing for applications across the cluster. Kubernetes Components.
Ingress: A Kubernetes
object that manages external access to services, typically HTTP/HTTPS,
providing routing, SSL termination, and name-based virtual hosting
capabilities.
Endpoints: Represents the
network addresses of pods backing a service, dynamically updated to track which
pods are available to handle requests.
DaemonSet: Ensures a
specific pod runs on all (or selected) nodes in the cluster, typically used for
cluster-wide services like monitoring, logging, or node-level system daemons.
Jobs: Kubernetes objects
that create one or more pods to perform a specific task and ensure the task
completes successfully, useful for batch processing and one-time computational
tasks.
Rollout: Manages the
deployment and update process, allowing controlled updates, rollbacks, and
tracking of deployment revisions.
Secret: Kubernetes objects
used to store and manage sensitive information like passwords, OAuth tokens,
and SSH keys, providing a secure way to handle confidential data in the
cluster.
Basic Commands
Pod Operations:
- kubectl get pod: List all pods in the current
namespace.
- kubectl get pod -o wide: Detailed pod
information with node details.
- kubectl get pod -w: Watch live pod status
updates.
- kubectl get pod -o yaml: Export pod configuration
in YAML format.
- kubectl describe pod <pod_name>:
Detailed pod status and events.
- kubectl delete pod <pod_name>: Remove a
specific pod.
- kubectl edit pod <pod_name>: Modify pod
configuration live.
- kubectl logs <pod_name>: View pod logs.
- kubectl exec -it <pod_name> /bin/bash:
Interactive shell inside a pod.
- kubectl get pods --show-labels: List pods with
their labels.
- kubectl get pods --field-selector
status.phase=Running: Filter for currently running pods.
- kubectl top pod: View resource usage metrics
for pods.
- kubectl port-forward <pod_name>
<local_port>:<pod_port>: Forward a local port to a pod
port.
Node Management
- kubectl get nodes: List all cluster nodes.
- kubectl get node <node_name>: Get basic
node details.
- kubectl get node <node_name> -o yaml:
Export node configuration in YAML format.
- kubectl describe node <node_name>:
Detailed node information and status.
- kubectl top node: View node resource usage
(CPU/Memory).
- kubectl label node <node_name>: Add or
modify node labels.
- kubectl cordon node <node_name>: Mark a
node as unschedulable for new pods.
- kubectl uncordon node <node_name>: Mark
a node as schedulable again.
- kubectl drain node <node_name>: Prepare
a node for maintenance by evicting all pods.
Resource & Object Creation
- kubectl apply -f <file_name>.yaml:
Create resource from a YAML file.
- kubectl apply -f <file1>.yaml -f
<file2>.yaml: Create resources from multiple files.
- kubectl apply -f ./<directory_name>:
Create all resources defined in a directory.
- kubectl apply -f https://<url>: Create
resources directly from a URL.
- kubectl run <pod_name>
--image=<image_name>: Create a basic pod.
- kubectl run <pod_name>
--image=<image_name> --port <port> --expose: Create a pod
and expose it as a service.
- kubectl run <pod_name>
--image=<image_name> --dry-run=client -o yaml >
<file_name>.yaml: Generate a Pod YAML file without creating it.
- kubectl create deployment <name>
--image=<image_name>: Create a deployment.
- kubectl create deployment <name>
--image=<image_name> --dry-run=client -o yaml >
<file_name>.yaml: Generate a Deployment YAML file.
- kubectl create configmap <name>
--from-literal=<key>=<value>: Create a ConfigMap from
key-value pairs.
- kubectl create configmap <name>
--from-file=<file_name>: Create a ConfigMap from a file.
- kubectl create configmap <name>
--from-env-file=<file_name>: Create a ConfigMap from an
environment file.
- kubectl create secret generic <name>
--from-literal=<key>=<value>: Create a secret from
key-value pairs.
- kubectl create secret generic <name>
--from-file=<file_name>: Create a secret from a file.
Resource Monitoring
- kubectl top node: Display resource usage for
all nodes.
- kubectl top node <node_name>: Specific
node CPU and memory utilization.
- kubectl top pod: Display resource usage for
all pods.
- kubectl top pod <pod_name>: Specific pod
CPU and memory utilization.
- kubectl top pod -n <namespace>: View pod
resources in a specific namespace.
- kubectl top pod --sort-by=cpu: Sort pods by
CPU usage.
- kubectl top pod --sort-by=memory: Sort pods by
memory usage.
Deployment & Rollout Management
- kubectl get deployment: List all deployments.
- kubectl get deployment <deployment_name>:
Get specific deployment details.
- kubectl get deployment <deployment_name> -o
wide: Detailed deployment information.
- kubectl get deployment <deployment_name> -o
yaml: Get deployment in YAML format.
- kubectl describe deployment
<deployment_name>: Detailed deployment status.
- kubectl edit deployment <deployment_name>:
Modify deployment configuration live.
- kubectl scale deployment <deployment_name>
--replicas=<number>: Change the replica count.
- kubectl delete deployment <deployment_name>:
Remove a deployment.
- kubectl rollout restart deployment
<deployment_name>: Restart the deployment.
- kubectl rollout history deployment
<deployment_name>: View all deployment revisions.
- kubectl rollout history deployment
<deployment_name> --revision=<revision_number>: Get details
of a specific revision.
- kubectl rollout undo deployment
<deployment_name>: Undo to the previous revision.
- kubectl rollout undo deployment
<deployment_name> --to-revision=<revision_number>: Undo to
a specific revision.
Networking (Services, Ingress, Endpoints)
- kubectl get service: List all services in the
current namespace.
- kubectl get service <service_name>: Get
specific service details.
- kubectl get service <service_name> -o wide:
Detailed service information.
- kubectl get service <service_name> -o yaml:
Get service in YAML format.
- kubectl describe service <service_name>:
Detailed service status.
- kubectl edit service <service_name>:
Modify service configuration.
- kubectl delete service <service_name>:
Remove a service from the cluster.
- kubectl get ingress: List all ingresses in the
current namespace.
- kubectl get ingress -o wide: Detailed ingress
information.
- kubectl get ingress -o yaml: Get ingress in
YAML format.
- kubectl describe ingress <ingress_name>:
Detailed ingress status.
- kubectl edit ingress <ingress_name>:
Modify ingress configuration.
- kubectl delete ingress <ingress_name>:
Remove an ingress.
- kubectl get endpoints: List all endpoints in
the current namespace.
- kubectl get endpoints <endpoints_name>:
Get specific endpoint details.
- kubectl get endpoints -A: List endpoints
across all namespaces.
Cluster DaemonSets & Jobs
- kubectl get daemonset: List all daemonsets in
the current namespace.
- kubectl get daemonset <daemonset_name>:
Get specific daemonset details.
- kubectl get daemonset <daemonset_name> -o
yaml: Get daemonset in YAML format.
- kubectl describe daemonset <daemonset_name>:
Detailed daemonset status.
- kubectl edit daemonset <daemonset_name>:
Modify daemonset configuration.
- kubectl delete daemonset <daemonset_name>:
Remove a daemonset.
- kubectl get job: List all jobs in the current
namespace.
- kubectl get job <job_name>: Get specific
job details.
- kubectl get job <job_name> -o yaml: Get
job in YAML format.
- kubectl describe job <job_name>:
Detailed job status.
- kubectl edit job <job_name>: Modify job
configuration.
- kubectl delete job <job_name>: Remove a
job from the cluster.
Secrets Management
- kubectl get secret: List all secrets in the
current namespace.
- kubectl get secret <secret_name>: Get
specific secret details.
- kubectl get secret <secret_name> -o yaml:
Get secret in YAML format.
- kubectl describe secret <secret_name>:
Detailed secret information.
- kubectl edit secret <secret_name>:
Modify secret configuration.
- kubectl delete secret <secret_name>: Remove a secret from the cluster.
