Why Docker
Docker containerisation packages apps with their dependencies for consistent environments and easy migration. DMIT cloud servers support Docker. This article covers the complete flow of deploying services with Docker on DMIT.
Install Docker
# Debian/Ubuntu
apt update
apt install ca-certificates curl gnupg -y
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# Verify
docker --version
docker compose version
docker run hello-world
Docker Compose
Compose is installed via the docker-compose-plugin package. Verify:
docker compose version
Use docker compose (space) not the old docker-compose (hyphen).
Basic usage
Run a single container
# Run Nginx
docker run -d --name web -p 80:80 nginx:alpine
# List running containers
docker ps
# View logs
docker logs web
# Enter container
docker exec -it web sh
# Stop and remove
docker stop web
docker rm web
Build with Dockerfile
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# Build and run
docker build -t myapp:latest .
docker run -d --name myapp -p 3000:3000 myapp:latest
Compose multi-service orchestration
Typical web app: Nginx + Node.js + PostgreSQL.
# docker-compose.yml
services:
web:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./certs:/etc/nginx/certs
depends_on:
- app
app:
build: ./app
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
# Start all services
docker compose up -d
# View status
docker compose ps
# View logs
docker compose logs -f
# Stop
docker compose down
# Rebuild and start
docker compose up -d --build
Data persistence
Containers are stateless — persist data via volumes:
# Named volume (Docker-managed)
volumes:
- db_data:/var/lib/postgresql/data
# Bind mount (host directory)
volumes:
- ./uploads:/app/uploads
- ./config:/app/config
Networking
# Custom network
docker network create mynet
# Containers communicate by service name
services:
app:
networks:
- mynet
db:
networks:
- mynet
networks:
mynet:
driver: bridge
Containers on the same network can reach each other by service name (e.g. db:5432) without exposing ports to the host.
IPv6 with Docker
DMIT provides IPv6 by default. Enable Docker IPv6 in /etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef::/64",
"experimental": true,
"ip6tables": true
}
systemctl restart docker
More IPv6 config in IPv6 Setup Guide.
Resource limits
Limit container resources to prevent a single container from exhausting the host:
services:
app:
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
memory: 256M
More resource management in Performance Tuning.
Log management
Docker logs grow unbounded by default — configure rotation:
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Security
- Don't run as root in containers — use the
USERinstruction - Restrict container privileges:
security_opt: [no-new-privileges:true] - Never expose the Docker Socket (ports 2375/2376) to the public internet
- Update images regularly:
docker compose pull && docker compose up -d - Use
.dockerignoreto exclude sensitive files
SSH hardening in SSH Hardening.
Backing up Docker data
# Backup named volume
docker run --rm -v db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_data.tar.gz /data
# Restore
docker run --rm -v db_data:/data -v $(pwd):/backup alpine tar xzf /backup/db_data.tar.gz /data
More backup strategies in Monitoring and Backup.
Common issues
Container can't access the internet?
docker run --rm alpine nslookup google.com
docker network inspect bridge
Port already in use?
ss -tlnp | grep :80
# Stop the process or change the mapped port
Out of disk space?
docker system prune -a --volumes
docker system df
More troubleshooting in Troubleshooting Guide.
Checklist
| Item | Status |
|---|---|
| Docker installed | ✓ docker --version |
| Compose installed | ✓ docker compose version |
| Container runs as non-root | ✓ USER instruction |
| Log rotation configured | ✓ daemon.json |
| Data persisted | ✓ volumes configured |
| Resource limits set | ✓ deploy.resources |
| Docker Socket not exposed | ✓ 2375 not open |
Related: First Deploy Checklist, Migration Guide, Cost Optimisation.
Checked 2026-08-18. Docker installation commands follow the official documentation.