Docker makes deployment simple, but simple does not automatically mean secure. A container is not a security mechanism, it is an isolation mechanism. What runs inside is up to you.
These six measures take less than an hour combined, but they close the most common attack vectors we see in production.
1. Do Not Run as Root
By default, every container process runs as root (UID 0). If an attacker escapes the container, they have root privileges on the host.
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --omit=dev
RUN addgroup -S app && adduser -S app -G app
USER app
CMD ["node", "server.js"]2. Read-Only Filesystem
A container that cannot write cannot drop malware, manipulate configuration, or install a backdoor.
services:
api:
image: myapp:latest
read_only: true
tmpfs:
- /tmp
- /run3. Never Mount the Docker Socket
Mounting the Docker socket into a container gives it full control over the entire Docker daemon and therefore the host.
# Never do this:
volumes:
- /var/run/docker.sock:/var/run/docker.sock4. Set Resource Limits
Without limits, a single compromised container can bring down the entire host.
services:
worker:
image: myworker:latest
mem_limit: 512m
memswap_limit: 512m
cpus: "0.5"
pids_limit: 1005. Do Not Bake Secrets into the Image
ENV DB_PASSWORD=supersecret in your Dockerfile ends up in every image layer, is visible in docker inspect, and gets stored in container registries forever.
# Never do this:
ENV DB_PASSWORD=mypassword123
# Pass at runtime:
docker run --env-file .env myapp:latest6. Scan Images Regularly
Every image is a snapshot. Dependencies that are secure today may have known CVEs tomorrow.
# Docker Scout (install plugin if needed):
# docker scout install
docker scout cves myapp:latest
# Trivy:
trivy image myapp:latestConclusion
Containerization gives you isolation, not security. These six measures are the minimum requirements for any production Docker workload.

