From Dockerfile to Production : Azure

Sagar HSSagar HS
4 min read

Spin up a production-ready pipeline with GitHub Actions, and about 30 minutes of elbow grease.

1 · Prerequisites & Quick Overview

You NeedWhy
Azure account (With Subscription)Spin up SQL, ACR, App Service Plan, and Web App.
GitHub repo with your .NET 8 Web APIThe CI/CD workflow lives here.
EF Core migrations already createdWorkflow auto-applies them during deploy.
Dockerfile at repo rootBuilds the API image.

Architecture at a glance

GitHub → ACR → App Service (Linux Container) ⟷ Azure SQL Database
                          ↘︎  App Insights  ↙︎

2 · Provision Azure SQL Database

2.1 Create SQL Server

SettingValue
Resource Groupstocks-api-rg
Server Namestocks-sql-server-<unique>
AuthSQL authentication
Admin / Password✍️ Save in password manager

Azure Portal → Create a resource → “SQL Server” → Review + Create.

2.2 Create StocksDb Database

  1. Open your new SQL Server → Databases+ New Database

  2. Tier 🡒 Basic, 5 DTUs, 2 GB.

2.3 Networking / Firewall

ActionClick
Allow Azure servicesYes
Add client IPv4Add client IP
Save💾

2.4 Get Connection String

SQL DB → Connection strings → copy ADO.NET string → replace {user} / {password}.


3 · Create App-Service Resources

3.1 App Service Plan

SettingValue
Plan namestocks-api-plan
OSLinux
TierBasic B1
RegionSame as SQL

3.2 Azure Container Registry (ACR)

SettingValue
Namestocksacr<unique>
SKUBasic
Admin userEnable

3.3 Web App for Containers

SettingValue
Namestocks-api-<unique>
PublishDocker Container
Planstocks-api-plan
Image SourceACR → stocks-api:latest (workflow pushes this)

4 · Configure Web-App Settings

  1. Configuration → Application settings

    • ASPNETCORE_ENVIRONMENT = Production
  2. Connection strings

    • Name DefaultConnection

    • Paste SQL string

    • Type SQLAzure

  3. Save & Restart.


5 · Generate & Store Secrets

5.1 Service Principal (AZURE_CREDENTIALS)

az login
SUBID=$(az account show --query id --output tsv)

az ad sp create-for-rbac \
  --name "github-actions" \
  --role contributor \
  --scopes /subscriptions/$SUBID/resourceGroups/stocks-api-rg \
  --sdk-auth

Copy the JSON output → save as AZURE_CREDENTIALS secret.

5.2 ACR Credentials

Portal → ACR → Access keys → copy:

GitHub SecretValue
REGISTRY_LOGIN_SERVERstocksacr.azurecr.io
REGISTRY_USERNAME(username)
REGISTRY_PASSWORD(password)

5.3 DB Connection

SecretValue
DB_CONNECTION_STRING(ADO.NET string)

Add all secrets under Repo → Settings → Secrets → Actions.


6 · Step 5 — GitHub Actions Workflow

Build and Deploy
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up .NET
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: '8.0.x'

    - run: dotnet tool install -g dotnet-ef

    - run: dotnet restore
    - run: dotnet build --no-restore -c Release
    - run: dotnet test --no-build -c Release

    - name: Update Database
      if: github.event_name != 'pull_request'
      run: dotnet ef database update -c Release
      env:
        ConnectionStrings__DefaultConnection: ${{ secrets.DB_CONNECTION_STRING }}

    - uses: docker/setup-buildx-action@v2

    - name: Login to ACR
      uses: docker/login-action@v2
      with:
        registry: ${{ secrets.REGISTRY_LOGIN_SERVER }}
        username: ${{ secrets.REGISTRY_USERNAME }}
        password: ${{ secrets.REGISTRY_PASSWORD }}

    - name: Build & Push Image
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: |
          ${{ secrets.REGISTRY_LOGIN_SERVER }}/stocks-api:${{ github.sha }}
          ${{ secrets.REGISTRY_LOGIN_SERVER }}/stocks-api:latest

    - name: Azure Login
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Deploy to Web App
      uses: azure/webapps-deploy@v2
      with:
        app-name: stocks-api-<unique>
        images: ${{ secrets.REGISTRY_LOGIN_SERVER }}/stocks-api:${{ github.sha }}

    - run: az logout

🔑 Don’t forget: Dockerfile must expose port 80

ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80

7 · Ship & Verify

git add .
git commit -m "CI/CD: Azure SQL + ACR deploy"
git push origin main
  1. GitHub → Actions → watch the build.

  2. Upon success, open:

https://stocks-api-<unique>.azurewebsites.net/swagger/index.html

Test endpoints — your API is live!


8 · Observability with App Insights

  1. Web App → Application InsightsTurn on.

  2. Live Metrics, traces, and failure sampling appear automatically.


9 · Troubleshooting Playbook

SymptomLikely CauseQuick Fix
503 / 504App listens on wrong portEnsure ASPNETCORE_URLS=http://+:80
EF Core migration failsBad DB_CONNECTION_STRINGCheck secret & firewall settings
Docker push deniedWrong ACR credsRe-generate REGISTRY_PASSWORD
Service principal auth errorInsufficient RBAC scopeRe-create SP with correct RG scope
0
Subscribe to my newsletter

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

Written by

Sagar HS
Sagar HS

Software engineer with 4 + years delivering high-performance .NET APIs, polished React front-ends, and hands-off CI/CD pipelines. Hackathon quests include AgroCropProtocol, a crop-insurance DApp recognised with a World coin pool prize and ZK Memory Organ, a zk-SNARK privacy prototype highlighted by Torus at ETH-Oxford. Recent experiments like Fracture Log keep me exploring AI observability.