Docker & Containers

Control Resources & Harden Security

Lesson 8 of 9 · 8 min · Advanced

By default, a Docker container can consume 100% of your host's CPU and RAM. A single memory leak or infinite loop can hang your entire server. Learn to lock down resources and build layered security to keep your infrastructure bulletproof.

CPU & Memory Limits

Resource control revolves around two critical concepts:
Reservation = A soft promise ("at least this much").
Limit = A hard stop ("never more than this").

terminal

# Memory: Reserve 256MB, Hard Kill at 512MB
$ docker run -d --name web1 \
>   --memory-reservation=256m \
>   --memory=512m httpd

# CPU: Max 50% of 1 core
$ docker run -d --name web2 --cpus="0.5" httpd

# CPU Shares (Priority)
# Default is 1024. A container with 512 gets half priority.
$ docker run -d --name web3 --cpu-shares=512 httpd

# Prevent Slow Disk Swapping
# Forces the container to ONLY use RAM, no disk swap.
$ docker run -d --memory=512m --memory-swap=512m httpd

Observability & Capacity Planning

Live Container Usage

Run docker stats in your terminal. It shows real-time CPU %, Memory usage, Network I/O, and Disk I/O for all running containers.

Inspect Hard Limits

Run docker inspect <container> to verify the exact parameters. Look under the HostConfig block for Memory, CpuQuota, and CpuShares.

Real Planning Example

  • Host Specs 4 CPUs and 8 GB RAM.
  • OS Overhead Reserve 30% for OS.
    Usable CPU ≈ 2.8 | Usable RAM ≈ 5.6 GB
  • Workload Deploy 4 instances of your app.
    Give each --cpus=0.5 and --memory=1g.
  • Result Containers use 2 CPUs and 4 GB RAM total. You have a stable system, room for traffic spikes, and no crashes ✓.

Security Layers & Best Practices

Even with limits, containers can be dangerous if hacked. A bad container can attack neighbors, steal secrets, or escape to the host machine. Security isn't a single switch; it is layered protection.

10 Security Best Practices

  • 1 Minimal Base Images: Smaller image = fewer vulnerabilities. (e.g., FROM alpine:3.18)
  • 2 Never Run as Root: Create a dedicated user in the Dockerfile. If hacked, the attacker gets a limited user. (e.g., USER appuser)
  • 3 Keep Images Updated: Old images have known CVEs. Rebuild regularly with --no-cache.
  • 4 Multi-Stage Builds: Builder gets the tools; the final image only gets the compiled app. Smaller and safer.
  • 5 Drop Capabilities: Remove unnecessary Linux privileges at runtime. (--cap-drop=ALL)
  • 6 Prevent Privilege Escalation: Stop attackers from gaining extra rights. (--security-opt=no-new-privileges)
  • 7 Resource Limits: Protects against Denial of Service (DoS) attacks.
  • 8 Network Hygiene: Expose only required ports. Avoid --network host unless absolutely necessary.
  • 9 Image Scanning: Use tools like Trivy or Clair to scan images before deployment.
  • 10 One Process Per Container: Avoid running SSH inside containers or bundling multiple services together.

The Ultimate Secure Run Command

terminal

$ docker run -d --name safe-app \
>   --memory=512m --cpus="0.5" \
>   --security-opt=no-new-privileges \
>   --cap-drop=ALL \
>   --read-only \
>   --tmpfs /tmp:rw,size=64m \
>   myuser/app:1.0

Why is this so secure?

1. Limited CPU/RAM stops DoS attacks.
2. no-new-privileges blocks exploits like `sudo`.
3. cap-drop=ALL strips Linux kernel powers.
4. read-only makes the filesystem immutable; hackers can't download malware.
5. tmpfs provides just enough temporary RAM space for the app to write logs, disappearing instantly on exit.