Day 36: Docker Container Deployment - Running Nginx with Alpine 🐳

Welcome back! 👋 Day 36 of the 100 Days Cloud DevOps Challenge, and today we're deploying Docker containers in production! This is fundamental container operations - creating, running, and managing containerized applications. Let's containerize! 🎯
🎯 The Mission - Deploy Nginx Container on Application Server
It's deployment day, and the DevOps team needs a containerized web server:
📋 TASK TICKET #DEV-8036 - Nginx Container Deployment
Priority: HIGH
Type: Docker Container Operations
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROJECT: Application Server Infrastructure
Team: Nautilus DevOps
Server: Application Server 3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BACKGROUND:
└─ Testing application deployment workflows
└─ Need nginx web server containerized
└─ Using lightweight Alpine Linux base
└─ Target: Application Server 3
REQUIREMENTS:
1. Container Specifications:
└─ Name: nginx_3
└─ Image: nginx:alpine
└─ Server: Application Server 3
2. Container State:
└─ Status: Running
└─ Health: Active
└─ Accessible: Yes
3. Verification:
└─ Container exists
└─ Container running
└─ Nginx responding
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATUS: READY TO DEPLOY
DEADLINE: Today
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This is containerization in action! From bare metal to isolated, portable applications! 🚀
🤔 Why Docker Containers Matter - The Container Revolution
The Traditional Deployment Problem
Before containers:
Scenario: Deploy application to 3 servers
Server 1: Ubuntu 18.04, Python 3.6
Server 2: CentOS 7, Python 3.7
Server 3: Ubuntu 20.04, Python 3.8
Problems:
❌ "Works on my machine" syndrome
❌ Dependency conflicts
❌ Environment inconsistencies
❌ Complex setup procedures
❌ Difficult to scale
❌ Resource waste (full VMs)
With Docker containers:
Same application, packaged once:
├─ Container image includes everything
├─ Runs identically everywhere
├─ Isolated from host system
├─ Lightweight (shares kernel)
└─ Deploys in seconds
Result:
✅ Consistent environments
✅ Fast deployment
✅ Easy scaling
✅ Efficient resource usage
✅ Portable across clouds
Real stat: 89% of organizations now use containers in production! 📊
Understanding Docker Containers
What is a container?
A container is a lightweight, standalone, executable package that includes everything needed to run software:
Docker Container Structure:
┌─────────────────────────────────────┐
│ Your Application (nginx) │
├─────────────────────────────────────┤
│ Runtime Dependencies │
│ (libraries, configs) │
├─────────────────────────────────────┤
│ Base OS (Alpine Linux) │
│ (minimal, just essentials) │
├─────────────────────────────────────┤
│ Docker Engine │
├─────────────────────────────────────┤
│ Host Operating System │
│ (shared kernel) │
└─────────────────────────────────────┘
vs Traditional VM:
┌─────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────┤
│ Dependencies │
├─────────────────────────────────────┤
│ Guest OS (full OS!) │
│ (GBs of overhead) │
├─────────────────────────────────────┤
│ Hypervisor │
├─────────────────────────────────────┤
│ Host Operating System │
└─────────────────────────────────────┘
Key differences:
Containers: Share host kernel, MBs in size, start in milliseconds
VMs: Full OS per instance, GBs in size, start in minutes
Why Nginx with Alpine?
Nginx - The web server:
High-performance HTTP server
Reverse proxy and load balancer
Powers 33% of all websites
Low memory footprint
Event-driven architecture
Alpine Linux - The minimal base:
Only ~5 MB base image
Security-focused (minimal attack surface)
Uses musl libc and busybox
Fast downloads and deployments
Standard for Docker images
nginx:alpine comparison:
nginx:latest → 142 MB
nginx:alpine → 23 MB (6x smaller!)
Benefits:
✅ Faster pulls (less download time)
✅ Smaller storage footprint
✅ Reduced attack surface
✅ Quicker deployments
✅ Lower bandwidth costs
Real-World Container Use Cases
Use Case 1: Microservices Architecture
E-commerce Platform:
├─ nginx_frontend (UI)
├─ api_gateway (routing)
├─ user_service (authentication)
├─ product_service (catalog)
├─ order_service (checkout)
└─ payment_service (transactions)
Each in own container, scales independently!
Use Case 2: Development Environments
Developer workflow:
1. Pull container: docker pull nginx:alpine
2. Run locally: docker run nginx:alpine
3. Identical to production!
4. No "works on my machine" issues
Use Case 3: CI/CD Pipelines
Build → Test → Deploy
Each stage in container
Reproducible, isolated builds
🏗️ Understanding the Setup
Application Server 3 Details:
Server: stapp03
User: banner
Password: BigGr33n
Role: Application Server 3
Current State:
├─ Docker installed
├─ Docker daemon running
└─ No nginx container yet
Target State:
├─ Container: nginx_3
├─ Image: nginx:alpine
├─ Status: Running
└─ Port: 80 (default)
Docker Architecture:
Application Server 3 (stapp03)
Docker Engine
├─ Docker Daemon (dockerd)
│ └─ Manages containers
│
├─ Docker CLI (docker command)
│ └─ User interface
│
└─ Container Runtime
└─ nginx_3 container
├─ nginx:alpine image
├─ Nginx process (PID 1)
├─ Port 80 exposed
└─ Isolated filesystem
Container Lifecycle:
Image Pull → Container Create → Container Start → Running
1. Pull nginx:alpine
└─ Downloads from Docker Hub
2. Create nginx_3
└─ Container created (not running)
3. Start nginx_3
└─ Nginx process starts
4. Running state
└─ Ready to serve traffic
🛠️ Complete Step-by-Step Implementation
Phase 1: Access and Verify Server
Step 1.1: SSH to Application Server 3
# Connect to Application Server 3
ssh banner@stapp03
# Password: BigGr33n
You're logged in! ✅
Step 1.2: Verify Docker Installation
# Check Docker version
docker --version
Expected output:
Docker version 24.0.7, build afdd53b
Docker installed! ✅
Step 1.3: Verify Docker Service Running
# Check Docker daemon status
sudo systemctl status docker
Expected output:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled)
Active: active (running) since [timestamp]
Docker daemon active! ✅
If Docker not running:
# Start Docker service
sudo systemctl start docker
# Enable on boot
sudo systemctl enable docker
Step 1.4: Check Existing Containers
# List all containers
sudo docker ps -a
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
No containers yet - clean slate! ✅
Step 1.5: Verify Docker Hub Access
# Test connectivity to Docker Hub
sudo docker search nginx
Should show nginx images available! ✅
Phase 2: Pull Nginx Alpine Image
Step 2.1: Pull the Image
# Pull nginx with alpine tag
sudo docker pull nginx:alpine
Expected output:
alpine: Pulling from library/nginx
96526aa774ef: Pull complete
b66f8c90f155: Pull complete
e4c6d57711e5: Pull complete
9e7b158d2e68: Pull complete
7f1ff86bec17: Pull complete
ec638d5e6d10: Pull complete
9d880a5f4e3a: Pull complete
bcc29e6aed37: Pull complete
Digest: sha256:a59278fd22a9d411121e190b8cec8aa57b306aa3332459197777583beb728f59
Status: Downloaded newer image for nginx:alpine
docker.io/library/nginx:alpine
Image downloaded! 🎉
What just happened:
Connected to Docker Hub (docker.io)
Downloaded nginx repository
Retrieved alpine tag (latest alpine version)
Pulled all layers (8 in this case)
Stored in local image cache
Step 2.2: Verify Image Downloaded
# List local images
sudo docker images
Expected output:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine a99a39d070bf 2 weeks ago 23.5MB
Image ready to use! ✅
Step 2.3: Inspect Image Details
# View detailed image information
sudo docker image inspect nginx:alpine
Shows:
Image layers
Creation date
Environment variables
Exposed ports (80, 443)
Entry point command
Step 2.4: View Image History
# See how image was built
sudo docker history nginx:alpine
Shows build layers and sizes! ✅
Phase 3: Create and Run Container
Step 3.1: Run Container (Single Command)
# Create and start nginx_3 container
sudo docker run -d --name nginx_3 nginx:alpine
Expected output:
f8e7d9c6b5a4e3d2c1b0a9f8e7d6c5b4a3e2d1c0b9a8f7e6d5c4b3a2e1d0c9b8
Container ID returned - success! 🎊
Command breakdown:
docker run= create and start container-d= detached mode (background)--name nginx_3= container namenginx:alpine= image to use
What happened internally:
Docker checked for nginx:alpine image (found locally)
Created new container from image
Assigned name "nginx_3"
Started container in background
Nginx process started inside container
Step 3.2: Alternative - Create Then Start
# If you want explicit steps:
# Create container (doesn't start)
sudo docker create --name nginx_3 nginx:alpine
# Start the container
sudo docker start nginx_3
Both approaches valid! Our one-liner is faster. ✅
Phase 4: Verify Container Running
Step 4.1: Check Container Status
# List running containers
sudo docker ps
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8e7d9c6b5a4 nginx:alpine "/docker-entrypoint.…" 30 seconds ago Up 28 seconds 80/tcp nginx_3
Container running! ✅
Key information:
STATUS: "Up 28 seconds" = running
PORTS: "80/tcp" = nginx listening on port 80
NAMES: "nginx_3" = our container name
COMMAND: Shows entrypoint script
Step 4.2: View All Containers (Including Stopped)
# Include stopped containers
sudo docker ps -a
Should only show nginx_3 (running) ✅
Step 4.3: Check Container Logs
# View nginx logs
sudo docker logs nginx_3
Expected output:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
Nginx started successfully! ✅
Step 4.4: Inspect Container Details
# Get detailed container information
sudo docker inspect nginx_3
Shows:
Container ID (full)
Network settings
IP address
Mounted volumes
Environment variables
State information
Step 4.5: Check Container Stats
# View resource usage
sudo docker stats nginx_3 --no-stream
Expected output:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
f8e7d9c6b5a4 nginx_3 0.00% 3.5MiB / 7.77GiB 0.04% 656B / 0B 0B / 0B 3
Resource usage minimal! ✅
Phase 5: Test Nginx Functionality
Step 5.1: Get Container IP Address
# Extract container IP
sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx_3
Expected output (example):
172.17.0.2
Container has IP address! ✅
Step 5.2: Test Nginx from Host
# Curl the container IP
curl http://172.17.0.2
Expected output (HTML):
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...
</body>
</html>
Nginx serving pages! 🎉
Step 5.3: Check Nginx Process Inside Container
# Execute command inside container
sudo docker exec nginx_3 ps aux
Expected output:
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
29 nginx 0:00 nginx: worker process
30 nginx 0:00 nginx: worker process
Nginx processes running! ✅
Step 5.4: Verify Nginx Configuration
# Check nginx config inside container
sudo docker exec nginx_3 nginx -t
Expected output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Configuration valid! ✅
Step 5.5: Test with Head Request
# Check HTTP headers
curl -I http://172.17.0.2
Expected output:
HTTP/1.1 200 OK
Server: nginx/1.25.3
Date: [current date]
Content-Type: text/html
Content-Length: 615
Last-Modified: [date]
Connection: keep-alive
ETag: "..."
Accept-Ranges: bytes
HTTP 200 - server responding! ✅
Phase 6: Final Verification
Step 6.1: Confirm Container Name
# Verify exact name
sudo docker ps --filter "name=nginx_3" --format "table {{.Names}}\t{{.Status}}"
Expected output:
NAMES STATUS
nginx_3 Up 5 minutes
Correct name and running! ✅
Step 6.2: Verify Image Tag
# Check which image version
sudo docker inspect nginx_3 | grep "Image"
Should show nginx:alpine! ✅
Step 6.3: Check Container Health
# View container state
sudo docker inspect nginx_3 | grep "Status"
Expected output:
"Status": "running",
Container healthy! ✅
Step 6.4: Verify Restart Policy
# Check restart behavior
sudo docker inspect nginx_3 | grep -A 2 "RestartPolicy"
Shows restart configuration ✅
Step 6.5: Final Status Check
# Complete overview
sudo docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
Expected output:
NAMES IMAGE STATUS PORTS
nginx_3 nginx:alpine Up 10 minutes 80/tcp
ALL REQUIREMENTS MET! 🎉🎊🎈
🔍 Understanding What We Accomplished
Container Architecture
What exists now:
Application Server 3 (stapp03)
Host OS (CentOS/RHEL)
├─ Docker Engine
│ └─ Container: nginx_3
│ ├─ Image: nginx:alpine (23.5 MB)
│ ├─ Process: nginx master (PID 1)
│ ├─ Workers: nginx workers
│ ├─ Network: bridge (172.17.0.2)
│ ├─ Filesystem: isolated
│ └─ State: Running
│
└─ Port 80 (inside container)
Docker Run Command Explained
Our command: sudo docker run -d --name nginx_3 nginx:alpine
What each part does:
docker run
└─ Create and start container
-d (--detach)
└─ Run in background
└─ Returns container ID
└─ Terminal not attached
--name nginx_3
└─ Give container a name
└─ Instead of random name
└─ Easier to reference
nginx:alpine
└─ Image to use
└─ Format: repository:tag
└─ Pulls if not local
Additional common flags (not used but useful):
-p 8080:80
└─ Port mapping: host:container
└─ Access on http://server:8080
-v /host/path:/container/path
└─ Mount volume
└─ Persist data
-e KEY=value
└─ Environment variable
└─ Configuration
--restart=always
└─ Auto-restart container
└─ On failure or reboot
--rm
└─ Remove container when stops
└─ For temporary containers
Container vs Image
Crucial difference:
Image (nginx:alpine)
├─ Read-only template
├─ Stored in /var/lib/docker/image
├─ Can create many containers
├─ Like a class in OOP
└─ 23.5 MB
Container (nginx_3)
├─ Running instance of image
├─ Has writeable layer
├─ Has state (running/stopped)
├─ Like an object in OOP
└─ Process with PID
Analogy:
Image = Recipe
Container = Cake made from recipe
You can make many cakes (containers) from one recipe (image)!
Container Lifecycle States
Created → Starting → Running → Stopping → Stopped → Removed
Created:
└─ docker create nginx_3
└─ Exists but not running
Running:
└─ docker start nginx_3
└─ Process active
Stopped:
└─ docker stop nginx_3
└─ Process terminated, container remains
Removed:
└─ docker rm nginx_3
└─ Container deleted
Networking Explained
Default bridge network:
Docker Host
├─ docker0 bridge (172.17.0.1)
│
├─ Container: nginx_3 (172.17.0.2)
│ └─ Can reach: other containers, internet
│
└─ Host processes
└─ Can reach: 172.17.0.2 directly
External world:
└─ Cannot reach container (no port mapping)
To expose externally:
# Would need port mapping:
docker run -d -p 8080:80 --name nginx_3 nginx:alpine
# Then accessible at: http://stapp03:8080
💡 Key Takeaways
✨ Containers are lightweight - only 23.5 MB for nginx:alpine
✨ Docker run creates and starts in one command
✨ -d flag runs detached (background process)
✨ --name assigns custom name (instead of random)
✨ Alpine images are minimal (security and size)
✨ Containers are isolated (own filesystem, processes)
✨ docker ps shows running containers only
✨ docker ps -a shows all including stopped
✨ docker logs shows output from container
✨ docker exec runs commands inside container
✨ Container ≠ Image (instance vs template)
🎓 Interview Questions
Q1: What's the difference between a Docker image and a Docker container?
Answer: Image is template, container is running instance. Image: Read-only layers, blueprint for containers, stored once, shared by many containers, created from Dockerfile. Example: nginx:alpine image (23.5 MB). Container: Running instance of image, has writeable layer on top, independent lifecycle, isolated process namespace, can have multiple from same image. Example: nginx_3 container from nginx:alpine. Analogy: Image = ISO file, Container = running virtual machine. Or Image = Class, Container = Object. In practice: docker pull nginx:alpine downloads image, docker run nginx:alpine creates container. One image can spawn hundreds of containers.
Q2: Explain what happens when you run docker run -d --name nginx_3 nginx:alpine.
Answer: Multi-step process: 1) Image check: Docker checks if nginx:alpine exists locally. If not, pulls from Docker Hub. 2) Container creation: Creates new container with name nginx_3, assigns unique container ID, sets up container filesystem (layered with image). 3) Network setup: Attaches to default bridge network, assigns IP (e.g., 172.17.0.2). 4) Start process: Runs container's entrypoint (nginx), PID 1 inside container. 5) Detached mode: Returns control to terminal immediately, container runs in background. Result: Container running, nginx serving on port 80 (internal), accessible via container IP. Can manage with: docker stop nginx_3, docker start nginx_3, docker rm nginx_3.
Q3: Why use Alpine Linux for Docker images? What are trade-offs?
Answer: Alpine prioritizes small size and security. Advantages: Size (5 MB vs 100+ MB for Ubuntu), security (minimal packages = smaller attack surface), speed (faster downloads, quicker deployments), efficiency (more containers per host). Disadvantages: Uses musl libc not glibc (compatibility issues), missing common tools (bash, vim need installation), some binary packages incompatible, less familiar for developers used to Debian/Ubuntu. Best for: Production containers, microservices, CI/CD pipelines, cloud deployments. Avoid when: Need specific glibc dependencies, complex system tools required, team unfamiliar with Alpine. Comparison: nginx:latest = 142 MB, nginx:alpine = 23.5 MB (6x smaller!). For our use case (simple nginx), Alpine perfect choice.
Q4: How would you troubleshoot if the container starts but nginx doesn't respond?
Answer: Systematic debugging approach: 1) Check container running: docker ps (verify status = "Up"). 2) View logs: docker logs nginx_3 (errors in startup?). 3) Exec into container: docker exec -it nginx_3 sh, then ps aux (nginx processes running?), nginx -t (config valid?). 4) Check networking: docker inspect nginx_3 | grep IPAddress, curl http://<container-ip> (reachable?). 5) Verify ports: docker port nginx_3 (correct ports?). 6) Check resources: docker stats nginx_3 (CPU/memory issues?). 7) Inspect events: docker events (system events). Common issues: Port conflict (another service on 80), configuration error (bad nginx.conf), permission issues (file ownership), resource limits (out of memory). Solution pattern: Check logs first (80% of issues visible there), then process/network, finally resources.
Q5: What's the difference between docker stop and docker kill?
Answer: Graceful vs forceful shutdown. docker stop: Sends SIGTERM (signal 15) to container, allows cleanup (close connections, save state, flush buffers), waits 10 seconds (default grace period), if still running, sends SIGKILL. Use for: Production containers, database containers, any container needing graceful shutdown. docker kill: Immediately sends SIGKILL (signal 9), no cleanup opportunity, instant termination. Use for: Frozen containers, emergency situations, testing failure scenarios. Example: docker stop nginx_3 - nginx finishes serving current requests, closes connections, shuts down cleanly. docker kill nginx_3 - nginx terminated mid-request, possible data loss. Best practice: Always use docker stop unless container unresponsive. Can customize grace period: docker stop -t 30 nginx_3 (30 second wait).
Q6: How do you persist data in containers? Why is it important?
Answer: Containers are ephemeral - data lost when removed. Problem: Container writes to /var/log/nginx, docker rm nginx_3 deletes logs. Solutions: 1) Volumes (recommended): docker run -v nginx-logs:/var/log/nginx nginx:alpine. Docker manages storage, persists across containers, can be backed up. 2) Bind mounts: docker run -v /host/logs:/var/log/nginx nginx:alpine. Maps host directory, direct host access, less portable. 3) tmpfs mounts: docker run --tmpfs /tmp nginx:alpine. Memory storage, fast but volatile. Why important: Databases need persistent storage, logs for debugging, configuration files, user uploads. Best practices: Use named volumes for application data, bind mounts for development, never store data in container layer. Our nginx_3: Doesn't persist data (demo only). Production would need: docker run -d -v nginx-logs:/var/log/nginx -v nginx-conf:/etc/nginx --name nginx_3 nginx:alpine.
🌟 Container Management Commands
Basic Operations:
# Create and start
docker run -d --name nginx_3 nginx:alpine
# Stop container
docker stop nginx_3
# Start stopped container
docker start nginx_3
# Restart container
docker restart nginx_3
# Remove container (must be stopped)
docker rm nginx_3
# Force remove running container
docker rm -f nginx_3
Inspection Commands:
# List running containers
docker ps
# List all containers
docker ps -a
# View logs
docker logs nginx_3
# Follow logs (real-time)
docker logs -f nginx_3
# View resource usage
docker stats nginx_3
# Detailed info
docker inspect nginx_3
Interaction Commands:
# Execute command
docker exec nginx_3 ls -la
# Interactive shell
docker exec -it nginx_3 sh
# Copy file to container
docker cp file.txt nginx_3:/tmp/
# Copy from container
docker cp nginx_3:/etc/nginx/nginx.conf .
🚀 Advanced Scenarios
Scenario 1: Port Mapping for External Access
# Expose nginx on host port 8080
docker run -d -p 8080:80 --name nginx_3 nginx:alpine
# Access from anywhere
curl http://stapp03:8080
Scenario 2: Custom Configuration
# Mount custom nginx.conf
docker run -d \
-v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
--name nginx_3 \
nginx:alpine
Scenario 3: Environment Variables
# Pass environment variables
docker run -d \
-e NGINX_HOST=example.com \
-e NGINX_PORT=80 \
--name nginx_3 \
nginx:alpine
Scenario 4: Resource Limits
# Limit CPU and memory
docker run -d \
--cpus="0.5" \
--memory="256m" \
--name nginx_3 \
nginx:alpine
Scenario 5: Health Checks
# Add health check
docker run -d \
--health-cmd="curl -f http://localhost/ || exit 1" \
--health-interval=30s \
--health-timeout=3s \
--health-retries=3 \
--name nginx_3 \
nginx:alpine
Scenario 6: Auto-Restart
# Always restart on failure
docker run -d \
--restart=always \
--name nginx_3 \
nginx:alpine
🎯 Production Best Practices
1. Always use specific tags:
# Good
docker run nginx:1.25.3-alpine
# Bad (unpredictable)
docker run nginx:latest
2. Implement health checks:
# Ensure container health monitored
--health-cmd="..."
3. Set resource limits:
# Prevent resource exhaustion
--cpus="1.0" --memory="512m"
4. Use restart policies:
# Auto-recovery from failures
--restart=unless-stopped
5. Mount logs externally:
# Persistent logging
-v /var/log/nginx:/var/log/nginx
🎉 Final Thoughts
You've successfully deployed a containerized application! This is the foundation of modern DevOps:
What you accomplished:
✅ Deployed nginx container on Application Server 3
✅ Used minimal Alpine Linux base (23.5 MB!)
✅ Container running and serving web traffic
✅ Verified functionality with multiple checks
✅ Understood container vs image concepts
Real-world impact:
Fast deployment: Seconds instead of hours
Consistency: Identical environments everywhere
Scalability: Easily replicate containers
Efficiency: Multiple containers per host
Portability: Run anywhere Docker runs
This is modern infrastructure! Companies run thousands of containers like this in production! 💪
🚀 What's Next?
Day 36 complete! 🎉 You've mastered Docker container deployment!
Skills Mastered Today:
✅ Docker container creation
✅ Running nginx with Alpine
✅ Container verification and inspection
✅ Basic troubleshooting
✅ Understanding container architecture
Coming up: More Docker adventures - multi-container applications, Docker Compose, container orchestration with Kubernetes!
Day: 36/100
Challenge: KodeKloud Cloud DevOps
Date: December 12, 2025
Topic: Docker Nginx Container Deployment
How many containers do you run in production? What's your container strategy? Share your Docker journey! 🐳




