Building and Deploying Services Using Docker
Note: This plan was generated by GitHub Copilot Workspaces.
Introduction
In this blog post, we will explore how to use Docker to containerize a web application and deploy it to Azure App Services. This approach ensures that your application runs consistently across different environments without dependency issues.
Prerequisites
Basic understanding of Docker An Azure account Docker installed on your local machine Azure CLI installed
Step 1: Understanding Docker and Containers
Docker is a platform that enables developers to create, deploy, and run applications in containers. Containers are lightweight, portable, and self-sufficient units that include everything needed to run an application, such as code, runtime, libraries, and system tools.
Key Concepts
- Image: A lightweight, stand-alone, and executable software package that includes everything needed to run a piece of software, including the code, runtime, libraries, and dependencies.
- Container: A runtime instance of an image. It is a lightweight, portable, and self-sufficient unit that can run anywhere.
- Dockerfile: A text file that contains a series of instructions on how to build a Docker image.
- Docker Hub: A cloud-based repository where Docker users can create, test, store, and distribute container images.
Step 2: Containerizing Your Application
1. Create a Dockerfile in your project directory. 2. Define the base image and dependencies. 3. Copy your application code into the container. 4. Expose the necessary ports. 5. Build the Docker image.
Example Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.8-slim
# Set the working directory in the container
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
Step 3: Testing Locally
1. Run the Docker container locally. 2. Test the application to ensure it works as expected.
Running the Container
docker build -t myapp .
docker run -p 4000:80 myapp
Step 4: Pushing to Docker Hub
1. Tag your Docker image. 2. Push the image to Docker Hub.
Pushing the Image
docker tag myapp mydockerhubusername/myapp
docker push mydockerhubusername/myapp
Step 5: Running Docker on Mac
Docker Desktop for Mac is the easiest way to get started with Docker on macOS. It includes Docker Engine, Docker CLI client, Docker Compose, Docker Content Trust, Kubernetes, and Credential Helper.
Installation Steps
1. Download Docker Desktop for Mac from the Docker website. 2. Open the downloaded file and drag the Docker icon to the Applications folder. 3. Launch Docker from the Applications folder. 4. Follow the on-screen instructions to complete the installation.
Running Docker Commands
Once Docker Desktop is installed, you can run Docker commands from the terminal. For example:
docker --version
docker run hello-world
Step 6: Deploying Docker Containers in the Cloud
Azure App Services provides a fully managed platform for building, deploying, and scaling web apps. You can deploy Docker containers to Azure App Services using the Azure CLI.
Deployment Steps
1. Create an Azure App Service. 2. Configure the App Service to use your Docker image. 3. Deploy the Docker container to Azure.
Example Deployment
# Log in to Azure
az login
# Create a resource group
az group create --name myResourceGroup --location eastus
# Create an App Service plan
az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku B1 --is-linux
# Create a web app
az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name myUniqueAppName --deployment-container-image-name mydockerhubusername/myapp
# Configure the web app to use the Docker image
az webapp config container set --name myUniqueAppName --resource-group myResourceGroup --docker-custom-image-name mydockerhubusername/myapp
# Browse to the web app
az webapp browse --name myUniqueAppName --resource-group myResourceGroup
Step 7: Timeline and Daily Plan
To get a good understanding of Docker and containers, follow this daily plan:
Day 1: Introduction to Docker
-
- Read Docker documentation and tutorials.*
-
- Install Docker on your local machine.*
-
- Run your first Docker container.*
Day 2: Understanding Docker Images and Containers
-
- Learn about Docker images and containers.*
-
- Create your first Dockerfile.*
-
- Build and run a Docker image.*
Day 3: Docker Networking and Volumes
-
- Learn about Docker networking.*
-
- Understand Docker volumes and persistent storage.*
-
- Practice using Docker networking and volumes.*
Day 4: Docker Compose
-
- Learn about Docker Compose.*
-
- Create a Docker Compose file for a multi-container application.*
-
- Run and manage multi-container applications using Docker Compose.*
Day 5: Deploying Docker Containers to the Cloud
-
- Learn about deploying Docker containers to the cloud.*
-
- Deploy a Docker container to Azure App Services.*
-
- Test and monitor your deployed application.*
Conclusion
By following these steps, you can easily containerize your web application using Docker and deploy it to Azure App Services, ensuring a smooth and consistent deployment process.
Additional Resources
Background & Prerequisites — What You Need to Cover Beyond the Existing Content
The current content covers Docker basics well. Below are the deeper topics needed to make this blog production-grade and differentiated.
1. Docker Internals — How Containers Actually Work
Why: Understanding internals helps debug issues and make better architectural decisions.
- Linux namespaces — Containers use kernel namespaces to isolate: PID (process IDs), NET (network stack), MNT (filesystem mounts), UTS (hostname), IPC (inter-process communication), USER (user/group IDs). Each container gets its own isolated view of these resources.
- cgroups (Control Groups) — Limit and account for resource usage: CPU, memory, disk I/O, network. When you set --memory=512m in Docker, it's a cgroup limit.
- Union filesystem (OverlayFS) — Images are layered. Each Dockerfile instruction creates a layer. Layers are read-only; the container gets a thin read-write layer on top. This enables image sharing and efficient storage.
- Container runtime — Docker daemon → containerd → runc. runc is the OCI (Open Container Initiative) reference implementation that actually creates the container using namespaces and cgroups.
2. Multi-Stage Builds
Why: Critical for production — reduces image size by 50-90%.
- Problem — Build tools (compilers, dev dependencies) bloat the final image. A Python image with build tools can be 1GB+.
- Solution — Stage 1: install dependencies, compile code. Stage 2: copy only the built artifacts and runtime dependencies into a slim base image.
- Example pattern — Build stage uses python:3.12 (full, ~900MB), runtime stage uses python:3.12-slim (~150MB) or python:3.12-alpine (~50MB but compatibility issues).
3. Docker Compose for Multi-Container Apps
Why: Real applications have multiple services (web app + database + cache + worker).
- docker-compose.yml — Declarative definition of services, networks, volumes. Version 3.x syntax.
- Service dependencies — depends_on, health checks, restart policies.
- Networking — Services on the same network can reach each other by service name (DNS resolution). Custom networks for isolation.
- Volumes — Named volumes for persistent data (databases). Bind mounts for development (live code reload).
- Environment variables — .env file, environment section, secrets management.
4. Container Security Best Practices
Why: Production containers need hardening.
- Run as non-root — Add USER appuser in Dockerfile. Never run as root in production.
- Minimal base images — Use slim or distroless images. Fewer packages = smaller attack surface.
- Image scanning — Use docker scout, Trivy, or Snyk to scan for CVEs in your image layers.
- Secrets management — Never put secrets in Dockerfile or image layers. Use environment variables, Docker secrets, or Azure Key Vault.
- Read-only filesystem — Run containers with --read-only flag. Write only to specific tmpfs mounts.
5. Azure Container Apps vs App Service (Deeper Comparison)
Why: The blog covers App Service. Container Apps is the newer alternative. - Container Apps — Serverless, scale to zero, built-in Dapr support, KEDA-based autoscaling, ingress management. Better for microservices. - App Service — PaaS, always running (minimum 1 instance), integrated CI/CD, custom domains, SSL, deployment slots. Better for traditional web apps. - AKS — Full Kubernetes control. For complex multi-service architectures with specific orchestration needs.
TODO / Remaining Work
- [ ] Replace the generated placeholder content with actual hands-on experience
- [ ] Add Docker internals section with diagrams (namespaces, cgroups, overlay filesystem)
- [ ] Write a real multi-stage Dockerfile for the blog app itself
- [ ] Add Docker Compose example with Flask + PostgreSQL + Redis
- [ ] Document container security best practices with examples
- [ ] Compare Azure Container Apps vs App Service with a decision matrix
- [ ] Add monitoring section (container logs, Azure Monitor, health probes)
- [ ] Include troubleshooting section (common Docker errors and fixes)
- [ ] Replace the daily plan with actual implementation journal