DEV Community

Python-T Point
Python-T Point

Posted on • Originally published at pythontpoint.in

🐍 CI/CD Python App Service vs AKS — Which One Should You Use?

💡 Overview — Differences

ci cd python app service vs aks

The architectural contrast between Azure App Service and Azure Kubernetes Service (AKS) drives every CI/CD decision for Python deployments.

📑 Table of Contents

  • 💡 Overview — Differences
  • 🚀 CI/CD Pipeline Basics — Components
  • 🏭 Deploy to Azure App Service — Process
  • 🔧 Build and Publish Artifact
  • 🚀 Deploy via Azure Web App
  • 🐳 Deploy to AKS — Process
  • 🔨 Build Docker Image
  • 📦 Push and Deploy
  • 📊 Comparison — Metrics
  • 🟩 Final Thoughts
  • ❓ Frequently Asked Questions
  • Can I reuse the same Azure DevOps pipeline for both App Service and AKS?
  • Do I need to write a Dockerfile for App Service?
  • How does scaling differ between the two services?
  • 📚 References & Further Reading

🚀 CI/CD Pipeline Basics — Components

A CI/CD pipeline for Python on Azure typically follows these stages:

  • Source checkout – retrieve the repository.
  • Build stage – install dependencies, run linting, execute unit tests.
  • Package stage – create a wheel or Docker image.
  • Deploy stage – invoke Azure CLI or kubectl to roll out the new version.

Across most production Azure DevOps workloads, a single YAML definition can be reused across environments by parameterizing the target service.

# azure-pipelines.yml
trigger: - main variables: - name: pythonVersion value: '3.11' stages: - stage: Build jobs: - job: Build pool: vmImage: 'ubuntu-latest' steps: - task: UsePythonVersion@0 inputs: versionSpec: $(pythonVersion) - script: | python -m pip install -upgrade pip pip install -r requirements.txt pytest -q displayName: 'Run tests' - script: | python -m pip wheel -no-deps -w dist . displayName: 'Build wheel' - publish: $(System.DefaultWorkingDirectory)/dist artifact: wheel
Enter fullscreen mode Exit fullscreen mode

What this does: (More onPythonTPoint tutorials)

  • trigger: runs the pipeline on pushes to main.
  • UsePythonVersion@0: pins the interpreter, preventing version drift between agents.
  • pytest -q: executes unit tests; any failure aborts the pipeline.
  • python -m pip wheel: creates a binary wheel that can be consumed directly by App Service or baked into a Docker image for AKS.

Key point: Parameterizing the deployment target keeps the CI logic DRY while supporting both App Service and AKS.


🏭 Deploy to Azure App Service — Process

Push a Python wheel to Azure App Service using the Azure CLI.

🔧 Build and Publish Artifact

The build stage already produced a .whl file. The next step uploads it to a private Azure Storage container that App Service can read. (Also read: ⚙️ Building a Jenkins Docker CI CD pipeline tutorial made easy)

$ az storage container create \ -account-name mystorageacct \ -name python-artifacts \ -public-access off
{ "created": true, "hasImmutabilityPolicy": false, "hasLegalHold": false
}



$ az storage blob upload \ -account-name mystorageacct \ -container-name python-artifacts \ -name myapp-1.0.0-py3-none-any.whl \ -file $(Pipeline.Workspace)/wheel/myapp-1.0.0-py3-none-any.whl
{ "etag": "\"0x8D9F7C3A2B5E9C5\"", "lastModified": "-09-15T12:34:56+00:00", "metadata": {}
}
Enter fullscreen mode Exit fullscreen mode

What this does:

  • az storage container create: creates a private container for the wheel.
  • az storage blob upload: copies the wheel into the container, making it reachable via a SAS URL.

🚀 Deploy via Azure Web App

App Service installs the wheel at startup using a custom startup command. The CLI command sets the WEBSITE_RUN_FROM_PACKAGE app setting to the generated SAS URL.

$ SAS_URL=$(az storage blob generate-sas \ -account-name mystorageacct \ -container-name python-artifacts \ -name myapp-1.0.0-py3-none-any.whl \ -permissions r \ -expiry -01-01T00:00:00Z \ -output tsv)



$ az webapp config appsettings set \ -resource-group myResourceGroup \ -name myPythonApp \ -settings WEBSITE_RUN_FROM_PACKAGE=$SAS_URL
{ "properties": { "WEBSITE_RUN_FROM_PACKAGE": "https://mystorageacct.blob.core.windows.net/python-artifacts/myapp-1.0.0-py3-none-any.whl?sv=-11-02&ss;=b&srt;=sco&sp;=r&se;=-01-01T00:00:00Z&sig;=..." }
}
Enter fullscreen mode Exit fullscreen mode

What this does:

  • generate-sas: creates a time‑limited read‑only URL for the wheel.
  • appsettings set: instructs App Service to download and install the wheel on each instance start.

Key point: Deploying a wheel avoids container image builds, reducing build time and storage costs compared with AKS.


🐳 Deploy to AKS — Process

Containerize the Python project and apply Kubernetes manifests to run it on AKS.

🔨 Build Docker Image

The Dockerfile builds a lightweight image based on python:3.11-slim and copies the wheel produced earlier. (Also read: 🐍 Azure App Service vs AKS for Django deployment — which one should you use?)

# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY myapp-1.0.0-py3-none-any.whl .
RUN pip install -no-cache-dir myapp-1.0.0-py3-none-any.whl
CMD ["python", "-m", "myapp"]
Enter fullscreen mode Exit fullscreen mode

What this does:

  • FROM python:3.11-slim: uses a minimal base image (~85 MB) to keep the final size low.
  • COPY … .: brings the wheel into the image.
  • pip install: installs the wheel in an isolated environment.
  • CMD: launches the Python module when the container starts.

    $ docker build -t myregistry.azurecr.io/myapp:1.0.0 .
    Sending build context to Docker daemon 12.3MB
    Step 1/5: FROM python:3.11-slim --> 2f2c9c7e6e5c
    Step 2/5: WORKDIR /app --> Using cache --> 3b1d8f8a7c2e
    Step 3/5: COPY myapp-1.0.0-py3-none-any.whl . --> 5d6e9f4c1a8b
    Step 4/5: RUN pip install -no-cache-dir myapp-1.0.0-py3-none-any.whl --> Running in 7c9e2d1f4b6a
    Successfully installed myapp-1.0.0
    Removing intermediate container 7c9e2d1f4b6a --> a4f3c2d5e9f1
    Step 5/5: CMD ["python", "-m", "myapp"] --> Running in 9b0d1e2a3c4f
    Removing intermediate container 9b0d1e2a3c4f --> d3e7f2a9b0c1
    Successfully built d3e7f2a9b0c1
    Successfully tagged myregistry.azurecr.io/myapp:1.0.0

📦 Push and Deploy

After pushing the image to Azure Container Registry, a Kubernetes Deployment manifest defines the desired state.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: myapp-deployment
spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: myregistry.azurecr.io/myapp:1.0.0 ports: - containerPort: 8080 resources: limits: cpu: "500m" memory: "256Mi"
Enter fullscreen mode Exit fullscreen mode

What this does:

  • replicas: 3 – the Deployment controller maintains three pod instances, providing horizontal scaling.
  • resources.limits – enforces cgroup limits, preventing a runaway Python process from exhausting node memory.

    $ az acr login -name myregistry
    Login Succeeded.

    $ docker push myregistry.azurecr.io/myapp:1.0.0
    The push refers to repository [myregistry.azurecr.io/myapp]
    d3e7f2a9b0c1: Pushed
    ...
    latest: digest: sha256:7c9e2d1f4b6a... size: 2365

    $ kubectl apply -f deployment.yaml
    deployment.apps/myapp-deployment created

    $ kubectl get pods -l app=myapp
    NAME READY STATUS RESTARTS AGE
    myapp-deployment-7c9f5b6c9d-abcde 1/1 Running 0 12s
    myapp-deployment-7c9f5b6c9d-fghij 1/1 Running 0 12s
    myapp-deployment-7c9f5b6c9d-klmno 1/1 Running 0 12s

Key point: AKS requires a container image and a manifest; the extra layer grants control over replica count, resource limits, and rollout strategies unavailable in App Service.


📊 Comparison — Metrics

A side‑by‑side quantitative view of the two deployment targets for Python workloads.

Aspect App Service AKS
Build time ~2 min (wheel only) ~5 min (Docker image)
Startup latency ~1 s (cold start) ~3 s (container pull)
Scaling granularity Instance‑level (Azure autoscaler) Pod‑level (Horizontal Pod Autoscaler)
Operational overhead Low (no infra code) Medium (manifests, Helm, RBAC)
Cost per vCPU‑hour Higher (managed platform premium) Lower (pay‑as‑you‑go nodes)

Choosing the right target is a trade‑off between operational simplicity and fine‑grained control.

Key point: For a single‑service Python API with modest traffic, the App Service path reduces CI/CD complexity; for microservice ecosystems or custom networking, AKS provides the necessary flexibility.


🟩 Final Thoughts

Implementing ci cd python app service vs aks is not a binary decision; the pipeline can serve both targets by parameterizing the deployment step. The underlying mechanism—wheel distribution for App Service versus container image for AKS—determines build duration and runtime observability.

When rapid iteration and platform‑managed runtime are priorities, the App Service flow delivers the smallest CI/CD surface. When pod‑level scaling, custom sidecars, or multi‑service orchestration are required, the AKS route justifies the additional manifest and image layers. Align the choice with the operational model of your team, not with a perceived “newness” of Kubernetes.

❓ Frequently Asked Questions

Can I reuse the same Azure DevOps pipeline for both App Service and AKS?

Yes. Define a pipeline variable that selects either the App Service deployment block or the AKS manifest block, keeping CI stages identical and branching only at the final deploy step.

Do I need to write a Dockerfile for App Service?

No. App Service can run a Python wheel directly; Docker is required only when targeting AKS or a custom runtime not supported by App Service.

How does scaling differ between the two services?

App Service scales at the instance level using Azure’s built‑in autoscaler, which adds or removes whole instances based on CPU or request count. AKS scales at the pod level via the Horizontal Pod Autoscaler, allowing more granular allocation of CPU and memory.

💡 Want to practise this hands-on? DigitalOcean gives new accounts $200 free credit for 60 days — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.

📚 Recommended reading: Best DevOps & cloud books on Amazon — from Linux fundamentals to Kubernetes in production, curated for working engineers.

📚 References & Further Reading

  • Official Azure App Service docs – deployment and configuration guide: learn.microsoft.com
  • Official Azure Kubernetes Service documentation – cluster and workload management: learn.microsoft.com

Top comments (0)