K3s Kubernetes Setup: Lightweight Container Orchestration
Single and multi-node Kubernetes cluster setup with K3s, kubectl usage, creating deployments and services, application management with Helm. Kubernetes guide for VPS environments.
Docker log drivers, docker logs command, Kubernetes pod logs, centralized log collection (Loki, ELK Stack), log rotation, and production log management best practices.
Logging in container environments differs from traditional server logging. Since containers are ephemeral, collecting logs centrally outside the container is critical. This guide covers Docker and Kubernetes log management, centralized log collection solutions, and production best practices.
# View container logs
docker logs CONTAINER_NAME
# View last N lines
docker logs --tail 100 CONTAINER_NAME
# Live log streaming
docker logs -f CONTAINER_NAME
# View with timestamps
docker logs -t CONTAINER_NAME
# From a specific time
docker logs --since 2024-01-01T00:00:00 CONTAINER_NAME
docker logs --since 1h CONTAINER_NAME # Last 1 hour
# Specific time range
docker logs --since 2h --until 1h CONTAINER_NAME
# Live + timestamps
docker logs -f -t CONTAINER_NAME
Docker supports different log drivers:
# Check current log driver
docker info | grep 'Logging Driver'
# View container log driver
docker inspect CONTAINER_NAME | grep LogConfig -A 5
// /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3",
"compress": "true"
}
}
# Restart Docker daemon
systemctl restart docker
# json-file with log rotation
docker run -d \
--name myapp \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
myapp:latest
# Forward to syslog
docker run -d \
--name myapp \
--log-driver syslog \
--log-opt syslog-address=udp://localhost:514 \
myapp:latest
# Disable logging (performance critical)
docker run -d \
--name myapp \
--log-driver none \
myapp:latest
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp:latest
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
compress: "true"
labels: "app,environment"
labels:
- "app=myapp"
- "environment=production"
nginx:
image: nginx:latest
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
# View pod logs
kubectl logs POD_NAME
# Specific container logs (multi-container pod)
kubectl logs POD_NAME -c CONTAINER_NAME
# Live log streaming
kubectl logs -f POD_NAME
# Last N lines
kubectl logs --tail=100 POD_NAME
# From a specific time
kubectl logs --since=1h POD_NAME
# Previous container logs (after crash)
kubectl logs --previous POD_NAME
# Logs from all pods in a deployment
kubectl logs -l app=myapp --all-containers
# With namespace
kubectl logs -n production POD_NAME
# loki-stack.yml
version: '3.8'
services:
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
volumes:
- loki-data:/loki
command: -config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:latest
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=StrongPass123!
volumes:
- grafana-data:/var/lib/grafana
volumes:
loki-data:
grafana-data:
# promtail-config.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*?)'
target_label: 'container'
- source_labels: ['__meta_docker_container_log_stream']
target_label: 'logstream'
# Install Loki Docker plugin
docker plugin install grafana/loki-docker-driver:latest \
--alias loki \
--grant-all-permissions
# Send logs to Loki at container start
docker run -d \
--name myapp \
--log-driver loki \
--log-opt loki-url="http://localhost:3100/loki/api/v1/push" \
--log-opt loki-batch-size=400 \
myapp:latest
// /etc/docker/daemon.json — Loki for all containers
{
"log-driver": "loki",
"log-opts": {
"loki-url": "http://localhost:3100/loki/api/v1/push",
"loki-batch-size": "400",
"loki-retries": "3",
"loki-max-backoff": "800ms",
"loki-timeout": "1s"
}
}
# Check Docker log file sizes
du -sh /var/lib/docker/containers/*/*-json.log
# Clear all container logs (careful!)
truncate -s 0 /var/lib/docker/containers/*/*-json.log
# Clear specific container log
truncate -s 0 $(docker inspect --format='{{.LogPath}}' CONTAINER_NAME)
# Automatic rotation with logrotate
cat > /etc/logrotate.d/docker-containers << 'EOF'
/var/lib/docker/containers/*/*.log {
rotate 7
daily
compress
size=10M
missingok
delaycompress
copytruncate
}
EOF
// Node.js — JSON logging with Winston
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console()
]
});
// Usage
logger.info('User login', {
userId: 123,
action: 'login',
ip: '192.168.1.1'
});
logger.error('Database error', {
error: err.message,
query: 'SELECT * FROM users'
});
Effective container logging is essential for troubleshooting and monitoring system health in production environments. Prevent disk overflow with Docker log rotation, set up centralized log collection with Loki or ELK Stack, and simplify log analysis with structured JSON logs. With these configurations on REXE servers, you can manage your container infrastructure with full visibility.
With the default json-file driver, logs are stored at /var/lib/docker/containers/CONTAINER_ID/CONTAINER_ID-json.log. Use docker inspect CONTAINER_NAME | grep LogPath to find the exact path. Without log rotation configured, these files can fill up your disk over time.
When a container is deleted, its logs are lost too. This is why using centralized log collection (Loki, ELK, Fluentd) in production is critical. Alternatively, you can forward to syslog with --log-driver syslog, or write to a file inside the app and make it persistent with a volume.
Two methods: 1) At the Docker daemon level, add max-size and max-file settings to /etc/docker/daemon.json (applies to all containers). 2) At container start, use --log-opt max-size=10m --log-opt max-file=3 parameters. Remember to restart Docker after changes.
Use kubectl logs -l app=myapp --all-containers with a label selector to view logs from multiple pods simultaneously. For more advanced solutions, use tools like stern or kubetail. In production, centralized log collection with Loki or ELK Stack is recommended.
JSON logs are structured and can be automatically parsed by systems like Loki and Elasticsearch. You can filter and search by specific fields (e.g., all logs where userId=123). Plain text logs require regex parsing, which is both slow and error-prone.
Single and multi-node Kubernetes cluster setup with K3s, kubectl usage, creating deployments and services, application management with Helm. Kubernetes guide for VPS environments.
Docker volume types (named, bind mount, tmpfs), volume management, Docker network modes (bridge, host, overlay), creating custom networks and container communication. Comprehensive guide.
Docker security best practices: non-root user, read-only filesystem, seccomp profiles, image scanning, Docker socket security, network isolation, and secrets management.