🐳 Day 18: Container Deployments - Hands-On Guide

Building and deploying Docker containers (Windows)

Duration: 4 hours | Module: Release Management

Lab 1: Create Dockerfile for Java App 📝

Objective: Create Dockerfile and build container image
Time: 30 minutes

Exercise 1.1: Create Dockerfile

1 Navigate to Calculator Project
cd $env:USERPROFILE\Desktop\testing-demo\calculator
2 Create Dockerfile
notepad Dockerfile

Add Dockerfile content:

# Use official OpenJDK runtime FROM openjdk:11-jre-slim # Set working directory WORKDIR /app # Copy JAR file from target directory COPY target/calculator-*.jar app.jar # Expose port 8080 EXPOSE 8080 # Run the application ENTRYPOINT ["java", "-jar", "app.jar"]

Save and close

3 Build JAR File First
# Maven needs to create JAR before Docker build mvn clean package -DskipTests [INFO] BUILD SUCCESS [INFO] Total time: 15.234 s # Verify JAR created dir target\*.jar calculator-1.0-SNAPSHOT.jar
4 Build Docker Image
# Build Docker image docker build -t calculator:1.0 . Sending build context to Docker daemon 15.87MB Step 1/5 : FROM openjdk:11-jre-slim Step 2/5 : WORKDIR /app Step 3/5 : COPY target/calculator-*.jar app.jar Step 4/5 : EXPOSE 8080 Step 5/5 : ENTRYPOINT ["java", "-jar", "app.jar"] Successfully built abc123def456 Successfully tagged calculator:1.0
5 Verify Image Created
docker images REPOSITORY TAG IMAGE ID CREATED SIZE calculator 1.0 abc123def456 30 seconds ago 220MB openjdk 11-jre xyz789abc123 2 weeks ago 200MB
6 Run Container Locally
# Run container in detached mode docker run -d -p 8080:8080 --name calculator-app calculator:1.0 a1b2c3d4e5f6... # Check if running docker ps CONTAINER ID IMAGE STATUS PORTS a1b2c3d4e5f6 calculator:1.0 Up 5 seconds 0.0.0.0:8080->8080/tcp # Test application (if it has endpoints) curl http://localhost:8080 # View logs docker logs calculator-app # Stop and remove docker stop calculator-app docker rm calculator-app
✅ Checkpoint: Docker image built and tested locally

Lab 2: Multi-Stage Dockerfile 🏗️

Objective: Create optimized Dockerfile that builds AND runs app
Time: 25 minutes

Exercise 2.1: Create Multi-Stage Dockerfile

1 Create Multi-Stage Dockerfile
notepad Dockerfile.multistage
# ============================================ # STAGE 1: BUILD # ============================================ FROM maven:3.8-openjdk-11 AS build # Set build directory WORKDIR /build # Copy pom.xml and download dependencies COPY pom.xml . RUN mvn dependency:go-offline # Copy source code COPY src ./src # Build JAR RUN mvn clean package -DskipTests # ============================================ # STAGE 2: RUNTIME # ============================================ FROM openjdk:11-jre-slim # Create app directory WORKDIR /app # Copy JAR from build stage COPY --from=build /build/target/*.jar app.jar # Create non-root user for security RUN useradd -m appuser USER appuser # Expose application port EXPOSE 8080 # Health check HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/health || exit 1 # Run application ENTRYPOINT ["java", "-jar", "app.jar"]

Save and close

2 Build Multi-Stage Image
# Build using multi-stage Dockerfile docker build -f Dockerfile.multistage -t calculator:1.0-optimized . Step 1/12 : FROM maven:3.8-openjdk-11 AS build Step 2/12 : WORKDIR /build ... Step 12/12 : ENTRYPOINT ["java", "-jar", "app.jar"] Successfully built xyz123abc456 Successfully tagged calculator:1.0-optimized
3 Compare Image Sizes
docker images calculator REPOSITORY TAG SIZE calculator 1.0 220MB (basic) calculator 1.0-optimized 185MB (multi-stage) ✅
Multi-stage is smaller! Build tools not included in final image
✅ Checkpoint: Optimized multi-stage Docker image created

Lab 3: Push Image to Azure Container Registry 🏪

Objective: Store container image in Azure Container Registry
Time: 35 minutes

Exercise 3.1: Create Azure Container Registry

1 Create ACR (Azure Portal or CLI)
# Login to Azure az login # Create resource group (if needed) az group create --name myResourceGroup --location eastus # Create container registry az acr create ` --resource-group myResourceGroup ` --name myCalculatorACR ` --sku Basic { "loginServer": "mycalculatoracr.azurecr.io", "name": "myCalculatorACR", "provisioningState": "Succeeded" }
💡 ACR Name Rules:
  • 5-50 characters
  • Alphanumeric only (no hyphens)
  • Globally unique
2 Login to ACR
# Login to Azure Container Registry az acr login --name myCalculatorACR Login Succeeded
3 Tag Image for ACR
# Tag image with ACR repository name docker tag calculator:1.0 mycalculatoracr.azurecr.io/calculator:1.0 # Verify tag docker images mycalculatoracr.azurecr.io/calculator REPOSITORY TAG IMAGE ID mycalculatoracr.azurecr.io/calculator 1.0 abc123def456
4 Push Image to ACR
# Push image to Azure Container Registry docker push mycalculatoracr.azurecr.io/calculator:1.0 The push refers to repository [mycalculatoracr.azurecr.io/calculator] 5f70bf18a086: Pushed 1.0: digest: sha256:abc123... size: 1234
5 Verify in ACR
# List repositories in ACR az acr repository list --name myCalculatorACR [ "calculator" ] # List tags for calculator repository az acr repository show-tags --name myCalculatorACR --repository calculator [ "1.0" ]
✅ Checkpoint: Container image stored in Azure Container Registry

Lab 4: Build Docker Image in Azure Pipeline 🔧

Objective: Automate Docker build and push in CI/CD pipeline
Time: 40 minutes

Exercise 4.1: Create Service Connection to ACR

1 Create Service Connection
  • Azure DevOps → Project Settings → Service connections
  • Click "+ New service connection"
  • Select "Docker Registry"
  • Choose "Azure Container Registry"
  • Select your subscription
  • Select your ACR: myCalculatorACR
  • Name: ACR-Connection
  • Click "Save"

Exercise 4.2: Create Docker Build Pipeline

1 Create Pipeline YAML
notepad azure-pipelines-docker.yml

Complete Docker pipeline:

# Docker Build and Push Pipeline trigger: - main variables: dockerRegistryServiceConnection: 'ACR-Connection' imageRepository: 'calculator' containerRegistry: 'mycalculatoracr.azurecr.io' dockerfilePath: 'Dockerfile' tag: '$(Build.BuildId)' stages: - stage: Build displayName: 'Build and Push Docker Image' jobs: - job: BuildJob pool: vmImage: 'ubuntu-latest' steps: # Build JAR - task: Maven@3 displayName: 'Build JAR' inputs: mavenPomFile: 'pom.xml' goals: 'clean package -DskipTests' # Build and push Docker image - task: Docker@2 displayName: 'Build and Push Image' inputs: command: 'buildAndPush' repository: $(imageRepository) dockerfile: $(dockerfilePath) containerRegistry: $(dockerRegistryServiceConnection) tags: | $(tag) latest

Save and close

2 Commit and Run Pipeline
git add Dockerfile azure-pipelines-docker.yml git commit -m "Add Docker build pipeline" git push
3 Monitor Pipeline
  • Create pipeline in Azure DevOps
  • Watch execution:
  • ✅ Build JAR with Maven
  • ✅ Build Docker image
  • ✅ Push to ACR
  • ✅ Tag as "latest" and with build ID
4 Verify in ACR
az acr repository show-tags --name myCalculatorACR --repository calculator [ "1234", "latest" ]
✅ Checkpoint: Docker build automated in pipeline, image in ACR

Lab 5: Deploy Container to Azure 🚀

Objective: Deploy container to Azure Container Instances
Time: 30 minutes

Exercise 5.1: Deploy to ACI

1 Add Deployment Stage
notepad azure-pipelines-docker.yml

Add deployment stage after build:

# Deploy to Azure Container Instances - stage: Deploy displayName: 'Deploy to ACI' dependsOn: Build jobs: - deployment: DeployACI environment: 'Production' pool: vmImage: 'ubuntu-latest' strategy: runOnce: deploy: steps: - task: AzureCLI@2 displayName: 'Deploy Container' inputs: azureSubscription: 'Azure-Subscription' scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | # Delete old container if exists az container delete \ --resource-group myResourceGroup \ --name calculator-app \ --yes || true # Create new container az container create \ --resource-group myResourceGroup \ --name calculator-app \ --image $(containerRegistry)/$(imageRepository):$(Build.BuildId) \ --cpu 1 \ --memory 1 \ --registry-login-server $(containerRegistry) \ --registry-username $(acrUsername) \ --registry-password $(acrPassword) \ --dns-name-label calculator-app-demo \ --ports 8080 # Show container info az container show \ --resource-group myResourceGroup \ --name calculator-app \ --query "{FQDN:ipAddress.fqdn,State:instanceView.state}" \ --output table
2 Add ACR Credentials as Variables
  • Go to Pipelines → Library
  • Create variable group: acr-credentials
  • Add variables:
    • acrUsername - Your ACR username
    • acrPassword - Your ACR password (mark as secret 🔒)

Get ACR credentials:

az acr credential show --name myCalculatorACR { "passwords": [ { "name": "password", "value": "xxxxxxxxxxxxx" } ], "username": "myCalculatorACR" }
3 Reference Variable Group

Add to Deploy stage in YAML:

- stage: Deploy variables: - group: acr-credentials jobs: - deployment: DeployACI ...
4 Run Complete Pipeline
git add . git commit -m "Add ACI deployment" git push

Pipeline will:

  1. Build JAR with Maven
  2. Build Docker image
  3. Push to ACR
  4. Deploy to ACI
  5. Container running in Azure! 🎉
5 Access Deployed Container
# Get container URL az container show ` --resource-group myResourceGroup ` --name calculator-app ` --query "ipAddress.fqdn" ` --output tsv calculator-app-demo.eastus.azurecontainer.io # Access in browser start http://calculator-app-demo.eastus.azurecontainer.io:8080
✅ Checkpoint: Container deployed and running in Azure!

🎯 Lab Summary

What You've Accomplished:

  • ✅ Created Dockerfile for Java application
  • ✅ Built Docker images locally
  • ✅ Created multi-stage Dockerfile (optimized)
  • ✅ Created Azure Container Registry
  • ✅ Pushed images to ACR
  • ✅ Automated Docker build in pipeline
  • ✅ Deployed container to Azure Container Instances

Container Workflow Mastered:

  1. Develop: Write code locally
  2. Dockerize: Create Dockerfile
  3. Build: Create container image
  4. Push: Store in ACR
  5. Deploy: Run in ACI/AKS

🎉 Day 18 Complete!

You've mastered Docker container deployments!

Ready for Day 19: Kubernetes & AKS Deployments