Docker has revolutionized how we deploy and manage applications, and Alpine Linux’s minimal footprint makes it an ideal host for containerized workloads. I’ve been running Docker on Alpine in production for years, and I’ll show you exactly how to set it up properly.
Alpine’s small size and security-focused design make it perfect for Docker hosts. You get the container benefits without the overhead of larger distributions, plus better security and resource efficiency.
Why Alpine Linux for Docker
Alpine brings several advantages as a Docker host:
- Minimal attack surface with fewer packages and services
- Small memory footprint leaving more resources for containers
- Fast boot times for quick scaling and recovery
- Security-hardened by default with grsec/PaX patches
- Package efficiency with musl libc and busybox utilities
What You’ll Accomplish
- Install Docker CE with proper configuration
- Set up Docker daemon for production use
- Configure container networking and storage
- Implement security best practices
- Set up monitoring and logging
- Create automated container management
Prerequisites
Before starting, ensure you have:
- Alpine Linux 3.15 or newer installed
- Root access or sudo privileges
- At least 2GB RAM and 20GB storage
- Network connectivity for package downloads
- Basic understanding of containerization concepts
Let’s update the system first:
apk update && apk upgrade
Installing Docker Engine
Method 1: Installing from Alpine Repositories
What we’re doing: Installing Docker directly from Alpine’s official repositories for the most stable experience.
# Install Docker and related packages
apk add docker docker-compose docker-cli-buildx
# Add docker-compose plugin for newer compose functionality
apk add docker-cli-compose
# Install additional useful tools
apk add git curl bash
Method 2: Installing Docker CE from Docker’s Repository
What we’re doing: Installing the latest Docker CE version directly from Docker’s official repository.
# Install dependencies
apk add curl gnupg
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-20.10.21.tgz -o docker.tgz
# Extract Docker binaries
tar -xzf docker.tgz
cp docker/* /usr/bin/
rm -rf docker docker.tgz
# Create Docker service file
cat > /etc/init.d/docker << 'EOF'
#!/sbin/openrc-run
name="Docker daemon"
command="/usr/bin/dockerd"
command_background="yes"
pidfile="/run/docker.pid"
command_user="root"
start_stop_daemon_args="--background --make-pidfile"
depend() {
after net
}
start_pre() {
checkpath -d -m 0755 -o root:root /run/docker
}
EOF
chmod +x /etc/init.d/docker
Enabling and Starting Docker
What we’re doing: Configuring Docker to start automatically and verifying the installation.
# Add Docker to default runlevel
rc-update add docker default
# Start Docker service
service docker start
# Verify Docker installation
docker --version
docker info
# Test Docker with hello-world container
docker run hello-world
Configuring Docker Daemon
Docker Daemon Configuration
What we’re doing: Creating a production-ready Docker daemon configuration.
# Create Docker configuration directory
mkdir -p /etc/docker
# Create comprehensive daemon configuration
cat > /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"data-root": "/var/lib/docker",
"storage-driver": "overlay2",
"live-restore": true,
"userland-proxy": false,
"experimental": false,
"metrics-addr": "127.0.0.1:9323",
"insecure-registries": [],
"registry-mirrors": [],
"default-runtime": "runc",
"runtimes": {
"runc": {
"path": "runc",
"runtimeArgs": []
}
},
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"debug": false,
"hosts": ["unix:///var/run/docker.sock"],
"tls": false,
"icc": true,
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"ipv6": false,
"bridge": "docker0",
"fixed-cidr": "172.17.0.0/16"
}
EOF
# Restart Docker to apply new configuration
service docker restart
# Verify configuration
docker info | grep -E "(Storage Driver|Logging Driver|Docker Root Dir)"
Docker Storage Configuration
What we’re doing: Optimizing Docker storage for Alpine Linux with proper overlay2 configuration.
# Check current storage driver
docker info | grep "Storage Driver"
# If not using overlay2, clean up and reconfigure
if [ "$(docker info --format '{{.Driver}}')" != "overlay2" ]; then
echo "Switching to overlay2 storage driver..."
# Stop Docker
service docker stop
# Backup existing data
tar -czf /root/docker-backup-$(date +%Y%m%d).tar.gz /var/lib/docker
# Clean existing data
rm -rf /var/lib/docker/*
# Ensure overlay2 prerequisites
modprobe overlay
echo 'overlay' >> /etc/modules
# Start Docker with new configuration
service docker start
fi
# Verify overlay2 is active
docker info | grep -A5 "Storage Driver"
Container Runtime Security
What we’re doing: Implementing security best practices for container runtime.
# Create Docker security configuration
cat > /etc/docker/seccomp-default.json << 'EOF'
{
"defaultAction": "SCMP_ACT_ERRNO",
"archMap": [
{
"architecture": "SCMP_ARCH_X86_64",
"subArchitectures": [
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
]
}
],
"syscalls": [
{
"names": [
"accept",
"accept4",
"access",
"bind",
"brk",
"chdir",
"chmod",
"chown",
"chown32",
"clock_getres",
"clock_gettime",
"clock_nanosleep",
"close",
"connect",
"copy_file_range",
"creat",
"dup",
"dup2",
"dup3",
"epoll_create",
"epoll_create1",
"epoll_ctl",
"epoll_pwait",
"epoll_wait",
"eventfd",
"eventfd2",
"execve",
"execveat",
"exit",
"exit_group",
"faccessat",
"fadvise64",
"fadvise64_64",
"fallocate",
"fanotify_mark",
"fchdir",
"fchmod",
"fchmodat",
"fchown",
"fchown32",
"fchownat",
"fcntl",
"fcntl64",
"fdatasync",
"fgetxattr",
"flistxattr",
"flock",
"fork",
"fremovexattr",
"fsetxattr",
"fstat",
"fstat64",
"fstatat64",
"fstatfs",
"fstatfs64",
"fsync",
"ftruncate",
"ftruncate64",
"futex",
"getcwd",
"getdents",
"getdents64",
"getegid",
"getegid32",
"geteuid",
"geteuid32",
"getgid",
"getgid32",
"getgroups",
"getgroups32",
"getpeername",
"getpgrp",
"getpid",
"getppid",
"getpriority",
"getrandom",
"getresgid",
"getresgid32",
"getresuid",
"getresuid32",
"getrlimit",
"get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
"get_thread_area",
"gettid",
"gettimeofday",
"getuid",
"getuid32",
"getxattr",
"inotify_add_watch",
"inotify_init",
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
"ioctl",
"io_destroy",
"io_getevents",
"ioprio_get",
"ioprio_set",
"io_setup",
"io_submit",
"ipc",
"kill",
"lchown",
"lchown32",
"lgetxattr",
"link",
"linkat",
"listen",
"listxattr",
"llistxattr",
"lremovexattr",
"lseek",
"lsetxattr",
"lstat",
"lstat64",
"madvise",
"memfd_create",
"mincore",
"mkdir",
"mkdirat",
"mknod",
"mknodat",
"mlock",
"mlock2",
"mlockall",
"mmap",
"mmap2",
"mprotect",
"mq_getsetattr",
"mq_notify",
"mq_open",
"mq_timedreceive",
"mq_timedsend",
"mq_unlink",
"mremap",
"msgctl",
"msgget",
"msgrcv",
"msgsnd",
"msync",
"munlock",
"munlockall",
"munmap",
"nanosleep",
"newfstatat",
"_newselect",
"open",
"openat",
"pause",
"pipe",
"pipe2",
"poll",
"ppoll",
"prctl",
"pread64",
"preadv",
"prlimit64",
"pselect6",
"ptrace",
"pwrite64",
"pwritev",
"read",
"readahead",
"readlink",
"readlinkat",
"readv",
"recv",
"recvfrom",
"recvmmsg",
"recvmsg",
"remap_file_pages",
"removexattr",
"rename",
"renameat",
"renameat2",
"restart_syscall",
"rmdir",
"rt_sigaction",
"rt_sigpending",
"rt_sigprocmask",
"rt_sigqueueinfo",
"rt_sigreturn",
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_tgsigqueueinfo",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
"sched_get_priority_max",
"sched_get_priority_min",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_setaffinity",
"sched_setattr",
"sched_setparam",
"sched_setscheduler",
"sched_yield",
"seccomp",
"select",
"semctl",
"semget",
"semop",
"semtimedop",
"send",
"sendfile",
"sendfile64",
"sendmmsg",
"sendmsg",
"sendto",
"setfsgid",
"setfsgid32",
"setfsuid",
"setfsuid32",
"setgid",
"setgid32",
"setgroups",
"setgroups32",
"setitimer",
"setpgid",
"setpriority",
"setregid",
"setregid32",
"setresgid",
"setresgid32",
"setresuid",
"setresuid32",
"setreuid",
"setreuid32",
"setrlimit",
"set_robust_list",
"setsid",
"setsockopt",
"set_thread_area",
"set_tid_address",
"setuid",
"setuid32",
"setxattr",
"shmat",
"shmctl",
"shmdt",
"shmget",
"shutdown",
"sigaltstack",
"signalfd",
"signalfd4",
"sigreturn",
"socket",
"socketcall",
"socketpair",
"splice",
"stat",
"stat64",
"statfs",
"statfs64",
"statx",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"sysinfo",
"tee",
"tgkill",
"time",
"timer_create",
"timer_delete",
"timerfd_create",
"timerfd_gettime",
"timerfd_settime",
"timer_getoverrun",
"timer_gettime",
"timer_settime",
"times",
"tkill",
"truncate",
"truncate64",
"ugetrlimit",
"umask",
"uname",
"unlink",
"unlinkat",
"utime",
"utimensat",
"utimes",
"vfork",
"vmsplice",
"wait4",
"waitid",
"waitpid",
"write",
"writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
EOF
# Update daemon.json to use custom seccomp profile
cat > /tmp/daemon-update.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"data-root": "/var/lib/docker",
"storage-driver": "overlay2",
"live-restore": true,
"userland-proxy": false,
"experimental": false,
"metrics-addr": "127.0.0.1:9323",
"seccomp-profile": "/etc/docker/seccomp-default.json",
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"debug": false,
"hosts": ["unix:///var/run/docker.sock"],
"no-new-privileges": true
}
EOF
cp /tmp/daemon-update.json /etc/docker/daemon.json
service docker restart
User Management and Permissions
Setting Up Docker User Groups
What we’re doing: Creating proper user permissions for Docker access without requiring root.
# Create docker group if it doesn't exist
addgroup docker
# Add your user to docker group (replace 'username' with actual username)
adduser $USER docker
# Create non-root user for Docker operations
adduser -D -s /bin/bash dockeruser
adduser dockeruser docker
# Set up proper permissions
chown root:docker /var/run/docker.sock
chmod 660 /var/run/docker.sock
# Test non-root access
su - dockeruser -c "docker ps"
Docker Socket Security
What we’re doing: Implementing secure Docker socket access with proper permissions.
# Create systemd override for Docker socket security
mkdir -p /etc/systemd/system/docker.socket.d
cat > /etc/systemd/system/docker.socket.d/override.conf << 'EOF'
[Socket]
SocketMode=0660
SocketUser=root
SocketGroup=docker
EOF
# Create Docker security wrapper script
cat > /usr/local/bin/docker-secure << 'EOF'
#!/bin/bash
# Check if user is in docker group
if groups $USER | grep -q docker; then
exec docker "$@"
else
echo "Error: User $USER is not in the docker group"
echo "Please run: sudo adduser $USER docker"
exit 1
fi
EOF
chmod +x /usr/local/bin/docker-secure
Network Configuration
Docker Network Management
What we’re doing: Setting up Docker networking with custom bridge networks and security policies.
# Create custom bridge network for better isolation
docker network create \
--driver bridge \
--subnet=172.20.0.0/16 \
--ip-range=172.20.240.0/20 \
--gateway=172.20.0.1 \
custom-bridge
# Create overlay network for multi-host setups
docker network create \
--driver overlay \
--subnet=10.0.0.0/24 \
--attachable \
secure-overlay
# List networks to verify
docker network ls
# Test network connectivity
docker run --rm --network custom-bridge alpine ping -c 2 google.com
Firewall Integration
What we’re doing: Configuring iptables to work properly with Docker networking.
# Install iptables if not present
apk add iptables
# Create Docker-aware firewall script
cat > /etc/firewall/docker-rules.sh << 'EOF'
#!/bin/sh
# Allow Docker bridge traffic
iptables -A INPUT -i docker0 -j ACCEPT
iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT
# Allow established Docker connections
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# Block direct access to Docker daemon from external networks
iptables -A INPUT -p tcp --dport 2376 -i eth0 -j DROP
# Allow Docker API access only from localhost
iptables -A INPUT -p tcp --dport 2376 -s 127.0.0.1 -j ACCEPT
# Custom bridge network rules
iptables -A FORWARD -i br-$(docker network ls --filter name=custom-bridge -q | cut -c1-12) -j ACCEPT
EOF
chmod +x /etc/firewall/docker-rules.sh
# Apply Docker firewall rules
/etc/firewall/docker-rules.sh
# Make rules persistent
/etc/init.d/iptables save
Storage Management
Docker Volume Configuration
What we’re doing: Setting up Docker volumes with proper storage backends and encryption support.
# Create dedicated directory for Docker volumes
mkdir -p /var/lib/docker/volumes
chmod 700 /var/lib/docker/volumes
# Create encrypted volume for sensitive data
dd if=/dev/urandom of=/var/lib/docker/encrypted.img bs=1M count=1000
# Set up LUKS encryption for the volume
apk add cryptsetup
cryptsetup luksFormat /var/lib/docker/encrypted.img
# Create mount script for encrypted volumes
cat > /usr/local/bin/mount-docker-encrypted.sh << 'EOF'
#!/bin/sh
ENCRYPTED_FILE="/var/lib/docker/encrypted.img"
MOUNT_POINT="/var/lib/docker/volumes/encrypted"
# Open encrypted volume
cryptsetup luksOpen $ENCRYPTED_FILE docker-encrypted
# Create filesystem if needed
if ! blkid /dev/mapper/docker-encrypted; then
mkfs.ext4 /dev/mapper/docker-encrypted
fi
# Create mount point and mount
mkdir -p $MOUNT_POINT
mount /dev/mapper/docker-encrypted $MOUNT_POINT
# Set proper permissions
chown root:docker $MOUNT_POINT
chmod 770 $MOUNT_POINT
echo "Encrypted Docker volume mounted at $MOUNT_POINT"
EOF
chmod +x /usr/local/bin/mount-docker-encrypted.sh
# Create volume backup script
cat > /usr/local/bin/backup-docker-volumes.sh << 'EOF'
#!/bin/sh
BACKUP_DIR="/backup/docker-volumes"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Stop containers using volumes
docker stop $(docker ps -q)
# Create volume backup
tar -czf $BACKUP_DIR/volumes-$DATE.tar.gz /var/lib/docker/volumes/
# Start containers again
docker start $(docker ps -aq)
echo "Docker volumes backed up to $BACKUP_DIR/volumes-$DATE.tar.gz"
EOF
chmod +x /usr/local/bin/backup-docker-volumes.sh
Container Image Management
What we’re doing: Implementing image security scanning and management policies.
# Install Docker security scanning tools
docker pull aquasec/trivy
# Create image scanning script
cat > /usr/local/bin/scan-docker-images.sh << 'EOF'
#!/bin/sh
echo "Scanning Docker images for vulnerabilities..."
# Scan all local images
for image in $(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>"); do
echo "Scanning $image..."
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v $HOME/.cache:/root/.cache/ \
aquasec/trivy:latest image --severity HIGH,CRITICAL $image
done
echo "Image security scan completed"
EOF
chmod +x /usr/local/bin/scan-docker-images.sh
# Create image cleanup script
cat > /usr/local/bin/cleanup-docker-images.sh << 'EOF'
#!/bin/sh
echo "Cleaning up Docker images..."
# Remove dangling images
docker image prune -f
# Remove images older than 30 days
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}" | \
awk '$4 < "'$(date -d '30 days ago' '+%Y-%m-%d')'" {print $3}' | \
xargs -r docker rmi
# Remove unused volumes
docker volume prune -f
echo "Docker cleanup completed"
EOF
chmod +x /usr/local/bin/cleanup-docker-images.sh
# Schedule weekly cleanup
echo "0 2 * * 0 /usr/local/bin/cleanup-docker-images.sh" | crontab -
Monitoring and Logging
Docker Metrics and Monitoring
What we’re doing: Setting up comprehensive Docker monitoring with Prometheus metrics.
# Install monitoring tools
apk add prometheus node-exporter
# Create Docker metrics collection script
cat > /usr/local/bin/docker-metrics.sh << 'EOF'
#!/bin/sh
METRICS_FILE="/var/log/docker-metrics.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Docker Metrics Collection" >> $METRICS_FILE
# Container statistics
echo "Running containers: $(docker ps -q | wc -l)" >> $METRICS_FILE
echo "Total containers: $(docker ps -aq | wc -l)" >> $METRICS_FILE
echo "Total images: $(docker images -q | wc -l)" >> $METRICS_FILE
echo "Total volumes: $(docker volume ls -q | wc -l)" >> $METRICS_FILE
# System resources
echo "Docker daemon memory usage:" >> $METRICS_FILE
ps aux | grep dockerd | grep -v grep | awk '{print $6}' >> $METRICS_FILE
# Disk usage
echo "Docker disk usage:" >> $METRICS_FILE
docker system df >> $METRICS_FILE
echo "[$DATE] Metrics collection completed" >> $METRICS_FILE
EOF
chmod +x /usr/local/bin/docker-metrics.sh
# Create container health monitoring
cat > /usr/local/bin/monitor-containers.sh << 'EOF'
#!/bin/sh
LOG_FILE="/var/log/container-health.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
# Check container health
for container in $(docker ps --format "{{.Names}}"); do
health=$(docker inspect --format='{{.State.Health.Status}}' $container 2>/dev/null || echo "no-healthcheck")
status=$(docker inspect --format='{{.State.Status}}' $container)
if [ "$status" != "running" ]; then
echo "[$DATE] ALERT: Container $container is $status" >> $LOG_FILE
# Restart unhealthy containers
docker restart $container
echo "[$DATE] Restarted container $container" >> $LOG_FILE
elif [ "$health" = "unhealthy" ]; then
echo "[$DATE] WARNING: Container $container is unhealthy" >> $LOG_FILE
fi
done
EOF
chmod +x /usr/local/bin/monitor-containers.sh
# Schedule monitoring
echo "*/5 * * * * /usr/local/bin/docker-metrics.sh" | crontab -
echo "*/2 * * * * /usr/local/bin/monitor-containers.sh" | crontab -
Centralized Logging Setup
What we’re doing: Configuring centralized logging for all Docker containers.
# Create log aggregation configuration
mkdir -p /etc/docker/logging
cat > /etc/docker/logging/logrotate.conf << 'EOF'
/var/lib/docker/containers/*/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
maxsize 100M
}
EOF
# Create container logging script
cat > /usr/local/bin/container-logs.sh << 'EOF'
#!/bin/sh
LOG_DIR="/var/log/containers"
DATE=$(date +%Y%m%d)
mkdir -p $LOG_DIR
# Export logs for all running containers
for container in $(docker ps --format "{{.Names}}"); do
echo "Exporting logs for $container..."
docker logs --since 24h $container > $LOG_DIR/${container}-${DATE}.log 2>&1
done
# Compress old logs
find $LOG_DIR -name "*.log" -mtime +1 -exec gzip {} \;
# Remove logs older than 30 days
find $LOG_DIR -name "*.log.gz" -mtime +30 -delete
echo "Container log export completed"
EOF
chmod +x /usr/local/bin/container-logs.sh
# Schedule daily log export
echo "0 1 * * * /usr/local/bin/container-logs.sh" | crontab -
Testing and Validation
Docker Installation Validation
What we’re doing: Creating comprehensive tests to validate Docker installation and configuration.
cat > /usr/local/bin/test-docker-installation.sh << 'EOF'
#!/bin/sh
echo "Docker Installation Validation Test"
echo "=================================="
# Test Docker version
echo "Testing Docker version..."
docker --version && echo "✓ Docker CLI working" || echo "✗ Docker CLI failed"
# Test Docker daemon
echo "Testing Docker daemon..."
docker info > /dev/null 2>&1 && echo "✓ Docker daemon running" || echo "✗ Docker daemon failed"
# Test container creation
echo "Testing container creation..."
docker run --rm hello-world > /dev/null 2>&1 && echo "✓ Container creation works" || echo "✗ Container creation failed"
# Test networking
echo "Testing Docker networking..."
docker run --rm alpine ping -c 1 google.com > /dev/null 2>&1 && echo "✓ Container networking works" || echo "✗ Container networking failed"
# Test volumes
echo "Testing Docker volumes..."
docker volume create test-volume > /dev/null 2>&1
docker run --rm -v test-volume:/data alpine touch /data/test > /dev/null 2>&1
docker volume rm test-volume > /dev/null 2>&1
echo "✓ Volume operations work"
# Test image operations
echo "Testing image operations..."
docker pull alpine:latest > /dev/null 2>&1 && echo "✓ Image pull works" || echo "✗ Image pull failed"
# Test resource limits
echo "Testing resource limits..."
docker run --rm --memory=128m --cpus=0.5 alpine echo "Resource limits test" > /dev/null 2>&1 && echo "✓ Resource limits work" || echo "✗ Resource limits failed"
echo ""
echo "Docker validation completed"
EOF
chmod +x /usr/local/bin/test-docker-installation.sh
# Run validation test
/usr/local/bin/test-docker-installation.sh
Production Optimization
Performance Tuning
What we’re doing: Optimizing Docker for production workloads on Alpine Linux.
# Create performance optimization script
cat > /usr/local/bin/optimize-docker.sh << 'EOF'
#!/bin/sh
echo "Optimizing Docker for production..."
# Kernel parameters for containers
cat >> /etc/sysctl.d/99-docker.conf << 'SYSCTL_EOF'
# Container networking optimization
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
# Container memory management
vm.swappiness = 1
vm.dirty_ratio = 80
vm.dirty_background_ratio = 5
# Container file system optimization
fs.inotify.max_user_instances = 1024
fs.inotify.max_user_watches = 1048576
# Container process limits
kernel.pid_max = 4194304
SYSCTL_EOF
sysctl -p /etc/sysctl.d/99-docker.conf
# Optimize Docker daemon startup
cat > /etc/conf.d/docker << 'CONF_EOF'
# Docker daemon startup options
DOCKER_OPTS="--storage-opt overlay2.size=20G --default-ulimit nofile=65536:65536"
CONF_EOF
# Create container resource monitoring
cat > /usr/local/bin/monitor-resources.sh << 'MON_EOF'
#!/bin/sh
# Monitor container resource usage
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}" > /var/log/docker-stats.log
# Alert on high resource usage
docker stats --no-stream --format "{{.Container}} {{.CPUPerc}}" | \
while read container cpu; do
cpu_num=$(echo $cpu | sed 's/%//')
if [ "${cpu_num%.*}" -gt 80 ]; then
echo "HIGH CPU: Container $container using $cpu" | logger -t docker-monitor
fi
done
MON_EOF
chmod +x /usr/local/bin/monitor-resources.sh
echo "Docker optimization completed"
EOF
chmod +x /usr/local/bin/optimize-docker.sh
# Apply optimizations
/usr/local/bin/optimize-docker.sh
Troubleshooting Common Issues
Docker Troubleshooting Guide
# Check Docker service status
service docker status
# View Docker daemon logs
tail -f /var/log/docker.log
# Check Docker disk usage
docker system df
# Diagnose networking issues
docker network ls
iptables -L -n | grep docker
# Check container logs
docker logs <container-name>
# Inspect container configuration
docker inspect <container-name>
# Test Docker socket permissions
ls -la /var/run/docker.sock
# Verify storage driver
docker info | grep -i storage
Common Fix Scripts
# Fix Docker socket permissions
sudo chown root:docker /var/run/docker.sock
sudo chmod 660 /var/run/docker.sock
# Reset Docker networking
sudo service docker stop
sudo ip link delete docker0
sudo service docker start
# Clean Docker system
docker system prune -a --volumes -f
Conclusion
You now have a fully configured Docker installation on Alpine Linux with enterprise-grade security, monitoring, and management capabilities. This setup includes:
- Production-ready Docker daemon with optimized configuration
- Security hardening with custom seccomp profiles and network isolation
- Comprehensive monitoring with metrics collection and health checks
- Automated maintenance with image scanning and cleanup procedures
- Volume management with encryption support and backup strategies
- Performance optimization for container workloads
Your Docker environment is ready for production deployments. Remember to regularly update Docker, monitor container health, and maintain security best practices as your containerized infrastructure grows.