Cron-Ausdruck Vollständiger Leitfaden | Von Grundlagen bis Fortgeschrittene
Umfassende Anleitung zu Cron-Ausdruck-Syntax mit 10 Praxisbeispielen, Debugging-Techniken, Best Practices und FAQ. Beherrschen Sie Linux-Zeitplanungsaufgaben.
Learn by doing
Practice with the while reading - free, no registration required
Real-World Examples
Case Study 1: Automatisierte Datenbanksicherung
Problem
Ein Startup benötigte zuverlässige tägliche PostgreSQL-Sicherungen. Die ersten Versuche schlugen fehl, Cron-Protokolle zeigten "command not found"-Fehler.
Solution
Das Problem lag daran, dass pg_dump Umgebungsvariablen benötigte und das Skript relative Pfade verwendete. Die Lösung bestand darin, Umgebungsvariablen am Anfang des Skripts zu setzen, absolute Pfade zu verwenden, Protokollierung und Fehlerbehandlung hinzuzufügen:
#!/bin/bash
# Datenbank-Sicherungsskript
# Umgebungsvariablen
export PGPASSWORD='your_password'
export PATH=/usr/local/bin:/usr/bin:/bin
# Konfiguration
DB_NAME="mydb"
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql"
# Sicherung erstellen
/usr/bin/pg_dump -h localhost -U postgres "$DB_NAME" > "$BACKUP_FILE" 2>&1
# Erfolg prüfen
if [ $? -eq 0 ]; then
echo "Sicherung erfolgreich: $BACKUP_FILE" >> /var/log/db_backup.log
# Behalte Sicherungen der letzten 7 Tage
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql" -mtime +7 -delete
else
echo "Sicherung fehlgeschlagen, Fehlermeldungen prüfen" >> /var/log/db_backup.log
exit 1
fi
Case Study 2: Mikroservice-Health-Check
Problem
Ein in Kubernetes bereitgestellter Mikroservice benötigte regelmäßige Health-Checks. Der Service blieb manchmal hängen und benötigte einen automatischen Neustart.
Solution
Kubernetes CronJob-Ressource erstellen, die regelmäßig den Health-Check-Endpunkt aufruft:
apiVersion: batch/v1
kind: CronJob
metadata:
name: health-check
spec:
schedule: "*/5 * * * *" # Alle 5 Minuten
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: health-check
image: curlimages/curl:latest
imagePullPolicy: Always
command:
- /bin/sh
- -c
- |-
response=$(curl -s -o /dev/null -w "%{http_code}" http://service:8080/health)
if [ $response -ne 200 ]; then
echo "Health-Check fehlgeschlagen, HTTP-Status: $response"
# Neustart auslösen
kubectl rollout restart deployment/my-service
fi
restartPolicy: OnFailure
Case Study 3: Protokollrotation und -archivierung
Problem
Webserver-Protokolldateien wuchsen schnell, Speicherplatz reichte oft nicht aus. Automatische Rotation, Komprimierung und Bereinigung waren erforderlich.
Solution
logrotate mit cron für Protokollmanagement verwenden:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
lastaction
# Komprimierte Protokolle älter als 7 Tage in Archiv verschieben
find /var/log/nginx -name "*.gz" -mtime +7 -exec mv {} /archive/nginx/ \;
endaction
}
# Cron-Aufgabe (logrotate erstellt automatisch)
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.conf
Case Study 4: Zeitgeplante E-Mail-Berichte
Problem
Die Finanzabteilung benötigte jeden Morgen um 8 Uhr einen Umsatzbericht des Vortags per E-Mail.
Solution
Skript erstellen, das Berichte generiert und per E-Mail sendet:
#!/usr/bin/env python3
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import subprocess
from datetime import datetime, timedelta
def generate_report():
"""Umsatzbericht generieren"""
yesterday = datetime.now() - timedelta(days=1)
date_str = yesterday.strftime('%Y-%m-%d')
# SQL-Abfrage ausführen
cmd = f'''
mysql -u reporter -ppassword -h db.internal -e "
SELECT product, SUM(amount) as revenue
FROM sales
WHERE DATE(created_at) = '{date_str}'
GROUP BY product
"
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def send_email(report):
"""E-Mail senden"""
msg = MIMEMultipart()
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg['Subject'] = f'Umsatzbericht - {datetime.now().strftime("%Y-%m-%d")}'
body = f'''
Umsatzbericht
{'='*40}
{report}
{'='*40}
Diese E-Mail wurde automatisch erstellt, bitte nicht antworten.
'''
msg.attach(MIMEText(body, 'plain'))
with smtplib.SMTP('smtp.company.com', 587) as server:
server.starttls()
server.login('[email protected]', 'password')
server.send_message(msg)
if __name__ == '__main__':
report = generate_report()
send_email(report)
Case Study 5: Synchronisation verteilter zeitgeplanter Aufgaben
Problem
Auf mehreren Servern laufende zeitgeplante Aufgaben mussten sicherstellen, dass zur gleichen Zeit nur eine ausführt wird, um doppelte Verarbeitung zu vermeiden.
Solution
Verteilte Sperre verwenden, um gegenseitigen Ausschluss zu gewährleisten:
#!/bin/bash
# Verteilte Datenverarbeitungsaufgabe
LOCK_FILE="/tmp/data_processing.lock"
LOCK_TIMEOUT=3600 # 1 Stunde Timeout
REDIS_HOST="redis.internal"
# Sperre erwerben
acquire_lock() {
redis-cli -h "$REDIS_HOST" SETNX "$LOCK_FILE" "$HOSTNAME:$$" > /dev/null
return $?
}
# Sperre freigeben
release_lock() {
redis-cli -h "$REDIS_HOST" DEL "$LOCK_FILE" > /dev/null
}
# Hauptlogik
main() {
echo "Datenverarbeitung starten..."
# Prüfen, ob Sperre abgelaufen
lock_time=$(redis-cli -h "$REDIS_HOST" GET "$LOCK_FILE.ttl")
if [ -n "$lock_time" ]; then
current_time=$(date +%s)
if [ $((current_time - lock_time)) -gt $LOCK_TIMEOUT ]; then
echo "Sperre abgelaufen, erzwinge Erwerb"
release_lock
fi
fi
# Versuch, Sperre zu erwerben
if ! acquire_lock; then
owner=$(redis-cli -h "$REDIS_HOST" GET "$LOCK_FILE")
echo "Aufgabe läuft bereits: $owner"
exit 0
fi
# Sperren-Timeout setzen
redis-cli -h "$REDIS_HOST" SETEX "$LOCK_FILE.ttl" "$LOCK_TIMEOUT" "$(date +%s)" > /dev/null
# Aufgabe ausführen
python3 /scripts/process_data.py
# Sperre freigeben
release_lock
echo "Datenverarbeitung abgeschlossen"
}
# Ausführung
main
Case Study 6: Schrittweise Bereitstellung
Problem
Alle Server müssen ohne Service-Unterbrechung schrittweise aktualisiert werden, je 5 Server im Abstand von 2 Minuten.
Solution
Cron-gesteuertes schrittweises Bereitstellungssystem:
#!/bin/bash
# Skript für schrittweise Bereitstellung
DEPLOYMENT_CONFIG="/etc/deployment/config.json"
CURRENT_BATCH=$(cat /var/run/deployment_batch 2>/dev/null || echo 0)
BATCH_SIZE=5
BATCH_DELAY=120 # 2 Minuten
# Serverliste abrufen
servers=$(jq -r '.servers[]' "$DEPLOYMENT_CONFIG")
total_servers=$(echo "$servers" | wc -l)
# Aktuelles Batch berechnen
start=$((CURRENT_BATCH * BATCH_SIZE))
end=$((start + BATCH_SIZE))
echo "Starte Bereitstellung Batch $((CURRENT_BATCH + 1)), Server $start-$end"
# Aktuelles Batch bereitstellen
echo "$servers" | sed -n "${start},${end}p" | while read server; do
echo "Bereitstellung auf $server ..."
ssh "$server" 'bash -s' < /scripts/update_service.sh
done
# Fortschritt speichern
if [ $end -lt $total_servers ]; then
echo $((CURRENT_BATCH + 1)) > /var/run/deployment_batch
echo "Batch abgeschlossen, warte auf nächstes..."
else
echo "Alle Batches bereitgestellt"
rm -f /var/run/deployment_batch
fi
Case Study 7: Automatische Zertifikatserneuerung
Problem
SSL-Zertifikate müssen alle 90 Tage erneuert werden, manuelle Vorgänge werden vergessen und verursachen Service-Unterbrechungen.
Solution
Let's Encrypt automatische Erneuerung verwenden:
#!/bin/bash
# Automatische SSL-Zertifikatserneuerung
DOMAINS="example.com www.example.com api.example.com"
EMAIL="[email protected]"
CERT_DIR="/etc/letsencrypt/live"
LOG_FILE="/var/log/cert_renewal.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Zertifikatsablauf prüfen
check_cert_expiry() {
local domain=$1
local cert_file="$CERT_DIR/$domain/cert.pem"
if [ ! -f "$cert_file" ]; then
log "Zertifikat nicht vorhanden: $domain"
return 1
fi
# Verbleibende Tage berechnen
expiry_date=$(openssl x509 -enddate -noout -in "$cert_file" | cut -d= -f2)
expiry_epoch=$(date -d "$expiry_date" +%s)
current_epoch=$(date +%s)
days_left=$(( (expiry_epoch - current_epoch) / 86400 ))
echo $days_left
}
# Zertifikat erneuern
renew_cert() {
log "Beginne Zertifikatserneuerung: $DOMAINS"
certbot certonly --non-interactive --agree-tos --email "$EMAIL" --webroot -w /var/www/html -d $DOMAINS >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
log "Zertifikat erfolgreich erneuert"
# nginx neu laden
systemctl reload nginx
# Benachrichtigung senden
echo "Zertifikat erfolgreich erneuert" | mail -s "Zertifikatserneuerung" "$EMAIL"
else
log "Zertifikatserneuerung fehlgeschlagen"
echo "Zertifikatserneuerung fehlgeschlagen, Protokolle prüfen" | mail -s "Erneuerung fehlgeschlagen" "$EMAIL"
exit 1
fi
}
# Hauptlogik
for domain in $DOMAINS; do
days_left=$(check_cert_expiry "$domain")
if [ $days_left -lt 30 ]; then
log "Zertifikat läuft in $days_left Tagen ab, beginne Erneuerung"
renew_cert
else
log "Zertifikat hat noch $days_left Tage, keine Erneuerung nötig"
fi
done
Case Study 8: Cache-Vorwärmung
Problem
E-Commerce-Website hatte während Spitzenlastzeiten niedrige Cache-Trefferquoten, benötigte Vorwärmung vor Spitzenlast.
Solution
Automatische Vorwärmung beliebter Produkt-Caches vor Spitzenlast:
#!/usr/bin/env python3
import requests
import json
from datetime import datetime
API_BASE = "https://api.example.com"
CACHE_ENDPOINT = f"{API_BASE}/cache/warmup"
def get_popular_products():
"""Beliebte Produkte abrufen"""
response = requests.get(f"{API_BASE}/analytics/popular", params={
'limit': 1000,
'time_range': '24h'
})
return response.json()['products']
def warmup_cache(product_ids):
"""Cache vorwärmen"""
chunks = [product_ids[i:i+50] for i in range(0, len(product_ids), 50)]
for chunk in chunks:
try:
response = requests.post(CACHE_ENDPOINT, json={
'product_ids': chunk,
'ttl': 3600
}, timeout=30)
if response.status_code == 200:
print(f"Vorwärmung erfolgreich: {len(chunk)} Produkte")
else:
print(f"Vorwärmung fehlgeschlagen: {response.text}")
except Exception as e:
print(f"Vorwärmungsfehler: {e}")
def main():
print(f"[{datetime.now()}] Cache-Vorwärmung starten")
try:
# Beliebte Produkte abrufen
products = get_popular_products()
product_ids = [p['id'] for p in products]
print(f"{len(product_ids)} beliebte Produkte abgerufen")
# Cache vorwärmen
warmup_cache(product_ids)
print(f"[{datetime.now()}] Cache-Vorwärmung abgeschlossen")
except Exception as e:
print(f"Vorwärmung fehlgeschlagen: {e}")
exit 1)
if __name__ == '__main__':
main()
Case Study 9: Datensynchronisation und -bereinigung
Problem
Anonymisierte Produktdaten mussten in Testumgebung synchronisiert werden, wobei nur die letzten 30 Tage erhalten blieben.
Solution
Datensynchronisations- und Bereinigungsskript erstellen:
#!/bin/bash
# Datenbanksynchronisation mit Testumgebung
PROD_DB="production"
TEST_DB="test_staging"
RETENTION_DAYS=30
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# Produktdaten exportieren (anonymisiert)
dump_data() {
log "Produktdatenexport starten..."
mysqldump -h prod-db.internal -u exporter -ppassword \
--single-transaction \
--quick \
--lock-tables=false \
--where="DATE(created_at) >= DATE(NOW()) - INTERVAL $RETENTION_DAYS DAY" \
"$PROD_DB" \
users orders products \
| gzip > /tmp/dump.sql.gz
# Anonymisierung
zcat /tmp/dump.sql.gz | sed \
-e 's/"\(email\|phone\|ssn\)":"[^"]*"/"\1":"***"/g' \
-e 's/"\(credit_card\|password\)":"[^"]*"/"\1":"***"/g' \
| gzip > /tmp/dump_anon.sql.gz
log "Datenexport und Anonymisierung abgeschlossen"
}
# In Testumgebung importieren
import_data() {
log "Import in Testumgebung starten..."
gunzip < /tmp/dump_anon.sql.gz | mysql -h test-db.internal -u importer -ppassword "$TEST_DB"
log "Datenimport abgeschlossen"
}
# Temporäre Dateien bereinigen
cleanup() {
log "Temporäre Dateien bereinigen..."
rm -f /tmp/dump*.sql.gz
}
# Alte Testumgebungsdaten bereinigen
cleanup_old_data() {
log "Alte Testumgebungsdaten bereinigen..."
mysql -h test-db.internal -u admin -ppassword "$TEST_DB" <<EOF
DELETE FROM orders WHERE DATE(created_at) < DATE(NOW()) - INTERVAL $RETENTION_DAYS DAY;
DELETE FROM audit_logs WHERE DATE(created_at) < DATE(NOW()) - INTERVAL $RETENTION_DAYS DAY;
OPTIMIZE TABLE users, orders, products;
EOF
log "Bereinigung alter Daten abgeschlossen"
}
# Hauptprozess
main() {
log "===== Datensynchronisation starten ====="
dump_data
import_data
cleanup_old_data
cleanup
log "===== Datensynchronisation abgeschlossen ====="
}
main
Case Study 10: Überwachungs- und Alarmintegration
Problem
Bei Fehlschlagen zeitgeplanter Aufgaben muss das Betriebsteam sofort benachrichtigt werden, Integration in bestehendes Überwachungssystem erforderlich.
Solution
Prometheus und Alertmanager für Alarmintegration verwenden:
#!/bin/bash
# Aufgaben-Wrapper mit Überwachungsintegration
TASK_NAME="data_import"
TASK_COMMAND="/usr/bin/python3 /scripts/import.py"
LOG_FILE="/var/log/tasks/${TASK_NAME}.log"
METRICS_FILE="/var/lib/node_exporter/textfile_collector/${TASK_NAME}.prom"
# Initialisierung
START_TIME=$(date +%s)
echo "# HELP task_last_success_timestamp Letzte Erfolgszeit" > "$METRICS_FILE"
echo "# TYPE task_last_success_timestamp gauge" >> "$METRICS_FILE"
# Aufgabe ausführen
run_task() {
echo "[$(date)] Aufgaben-Ausführung starten: $TASK_NAME" >> "$LOG_FILE"
$TASK_COMMAND >> "$LOG_FILE" 2>&1
EXIT_CODE=$?
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
if [ $EXIT_CODE -eq 0 ]; then
echo "[$(date)] Aufgabe erfolgreich, Dauer: ${DURATION}s" >> "$LOG_FILE"
# Erfolgsmetrik protokollieren
echo "task_last_success_timestamp{task="$TASK_NAME"} $END_TIME" >> "$METRICS_FILE"
echo "task_duration_seconds{task="$TASK_NAME",status="success"} $DURATION" >> "$METRICS_FILE"
else
echo "[$(date)] Aufgabe fehlgeschlagen, Exit-Code: $EXIT_CODE" >> "$LOG_FILE"
# Fehlermetrik protokollieren
echo "task_last_success_timestamp{task="$TASK_NAME"} 0" >> "$METRICS_FILE"
echo "task_duration_seconds{task="$TASK_NAME",status="failed"} $DURATION" >> "$METRICS_FILE"
# Alarm senden
curl -X POST http://alertmanager:9093/api/v1/alerts -d '[
{
"labels": {
"alertname": "TaskFailed",
"task": "'$TASK_NAME'",
"severity": "critical"
},
"annotations": {
"summary": "Aufgabe fehlgeschlagen: '$TASK_NAME'",
"description": "Exit-Code: '$EXIT_CODE', Protokoll: '$LOG_FILE'"
}
}
]'
exit 1
fi
}
run_task