Upgrade Mailu Version¶
How to upgrade Mailu to a newer version safely.
Problem¶
You need to upgrade your Mailu deployment to a newer version to get security fixes, new features, or bug fixes.
Solution¶
Update the image tag in your MailuChart configuration, regenerate manifests, and apply with proper backup and testing procedures.
Before You Start¶
Critical prerequisites:
✅ Backup all data (see Backup and Restore)
✅ Review Mailu release notes for breaking changes
✅ Test in non-production environment first
✅ Schedule maintenance window for production upgrades
✅ Document current version for potential rollback
Check Current Version¶
Identify your current Mailu version:
# Check image version in running pods
kubectl get pods -n mailu -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
# Example output:
# mailu-admin-xxx ghcr.io/mailu/admin:2024.06
# mailu-front-xxx ghcr.io/mailu/nginx:2024.06
Review Release Notes¶
Check Mailu releases for:
Breaking changes (configuration, database migrations)
New features (optional components, configuration options)
Bug fixes (relevant to your deployment)
Upgrade notes (special procedures)
Common breaking changes to watch for:
Database schema migrations
Configuration file format changes
Removed/renamed environment variables
Component version incompatibilities
Upgrade Procedure¶
Step 1: Backup Everything¶
Before making any changes, create backups:
# Backup database
kubectl exec -n postgres postgres-1 -- pg_dump -U postgres mailu > mailu-db-backup-$(date +%Y%m%d).sql
# Backup PVCs (using Longhorn or your backup solution)
# See backup-restore.md for detailed procedures
Step 2: Update Image Version¶
Edit your CDK8S configuration to specify the new version:
import { App } from 'cdk8s';
import { MailuChart } from 'cdk8s-mailu';
const app = new App();
new MailuChart(app, 'mailu', {
namespace: 'mailu',
domain: 'example.com',
hostnames: ['mail.example.com'],
subnet: '10.42.0.0/16',
// ... other config ...
images: {
registry: 'ghcr.io/mailu',
tag: '2025.01', // Updated from 2024.06
pullPolicy: 'IfNotPresent',
},
});
app.synth();
Version selection:
Stable releases: Use tagged versions (e.g.,
2024.06,2025.01)Latest stable: Use
latesttag (not recommended for production)Testing: Use
mastertag (pre-release, unstable)
Step 3: Regenerate Manifests¶
# Compile and synthesize with new version
npm run build
# Review changes in generated manifests
git diff dist/mailu.k8s.yaml
# Look for image version changes
grep "image:" dist/mailu.k8s.yaml
Step 4: Apply Upgrade (Rolling Update)¶
Apply the updated manifests using kubectl:
# Apply changes (triggers rolling update)
kubectl apply -f dist/mailu.k8s.yaml
# Watch rollout status
kubectl rollout status deployment -n mailu mailu-admin
kubectl rollout status deployment -n mailu mailu-front
kubectl rollout status deployment -n mailu mailu-postfix
kubectl rollout status deployment -n mailu mailu-dovecot
kubectl rollout status deployment -n mailu mailu-rspamd
# Watch pods restart with new images
kubectl get pods -n mailu -w
Rolling update behavior:
Pods restart one at a time (high availability maintained)
Old pods remain running until new pods are ready
Database migrations run automatically on admin pod startup
Step 5: Verify Upgrade¶
Check that all pods are running the new version:
# Verify image versions
kubectl get pods -n mailu -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
# Check pod status (all should be Running)
kubectl get pods -n mailu
# Check admin pod logs for migration messages
kubectl logs -n mailu -l app.kubernetes.io/component=admin | grep -i migration
# Test basic functionality
curl -I https://mail.example.com/admin # Should return 200 OK
Step 6: Test Functionality¶
Perform smoke tests after upgrade:
Admin UI:
[ ] Login to admin interface:
https://mail.example.com/admin[ ] Check user list loads
[ ] Verify domain settings
Webmail:
[ ] Login to webmail:
https://mail.example.com/webmail[ ] Send test email
[ ] Receive test email
Mail Protocols:
# Test SMTP (send mail)
telnet mail.example.com 587
# Test IMAP (check mailbox)
openssl s_client -connect mail.example.com:993
Upgrade Patterns¶
Minor Version Upgrade (Same Year)¶
Example: 2024.06 → 2024.12
Risk: Low (usually bug fixes and minor features)
Procedure: Standard rolling update (steps above)
Major Version Upgrade (Year Change)¶
Example: 2024.06 → 2025.01
Risk: Medium (potential breaking changes)
Additional steps:
Review migration guide in release notes
Test in staging environment first
Plan for longer maintenance window
Have rollback plan ready
Multi-Version Jump¶
Example: 2023.10 → 2025.01 (skipping versions)
Risk: High (multiple breaking changes possible)
Recommended approach:
Don’t skip major versions - upgrade incrementally
Test each intermediate version in staging
Read all release notes between versions
Budget extra time for troubleshooting
Safer path: 2023.10 → 2024.06 → 2024.12 → 2025.01
Rollback Procedure¶
If the upgrade fails or causes issues, rollback to the previous version:
Quick Rollback (Image Version Only)¶
# Revert to previous image version in CDK8S config
# images.tag: '2024.06' # Back to previous version
# Regenerate and apply
npm run build
kubectl apply -f dist/mailu.k8s.yaml
# Force restart pods with old version
kubectl rollout restart deployment -n mailu mailu-admin
kubectl rollout restart deployment -n mailu mailu-front
# ... restart other components
Full Rollback (Database Restore)¶
If database migrations caused problems:
# Stop Mailu pods
kubectl scale deployment -n mailu --all --replicas=0
# Restore database from backup
kubectl exec -n postgres postgres-1 -- psql -U postgres mailu < mailu-db-backup-YYYYMMDD.sql
# Restore PVCs if needed (see backup-restore.md)
# Start pods with old version
kubectl scale deployment -n mailu --all --replicas=1
Automated Upgrade Testing¶
Create a test script to validate upgrades:
#!/bin/bash
set -e
NAMESPACE="mailu"
DOMAIN="mail.example.com"
echo "Testing Mailu deployment after upgrade..."
# Test 1: All pods running
echo "Checking pod status..."
kubectl wait --for=condition=ready pod -n $NAMESPACE -l app.kubernetes.io/part-of=mailu --timeout=300s
# Test 2: Admin UI accessible
echo "Testing admin UI..."
curl -f -s https://$DOMAIN/admin | grep -q "Mailu" || { echo "Admin UI test failed"; exit 1; }
# Test 3: Database connection
echo "Testing database connection..."
kubectl exec -n $NAMESPACE -l app.kubernetes.io/component=admin -- python3 -c "
from mailu import db
db.init_app()
print('Database connection: OK')
" || { echo "Database test failed"; exit 1; }
# Test 4: SMTP connectivity
echo "Testing SMTP..."
timeout 5 bash -c "echo 'QUIT' | openssl s_client -connect $DOMAIN:587 -starttls smtp 2>&1" | grep -q "250 HELP" || { echo "SMTP test failed"; exit 1; }
echo "All tests passed!"
Save as test-upgrade.sh and run after applying upgrade.
Troubleshooting¶
Pods stuck in ImagePullBackOff¶
Symptom: New pods cannot pull image.
Causes:
Invalid image tag (version doesn’t exist)
Registry authentication issues
Network connectivity problems
# Check image availability
docker pull ghcr.io/mailu/admin:2025.01
# Check pod events
kubectl describe pod -n mailu <pod-name> | grep -A 10 Events
Solution: Verify image tag exists at ghcr.io/mailu.
Database migration failures¶
Symptom: Admin pod CrashLoopBackOff with migration errors in logs.
# Check admin pod logs
kubectl logs -n mailu -l app.kubernetes.io/component=admin | grep -i error
Solution:
May require manual migration steps
Rollback and test in staging first
Version mismatch between components¶
Symptom: Components unable to communicate, inconsistent behavior.
Cause: Not all pods updated to new version (partial rollout).
# Check versions across all pods
kubectl get pods -n mailu -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}' | sort -u
Solution: Force restart all deployments:
kubectl rollout restart deployment -n mailu --all
Performance degradation after upgrade¶
Symptom: Slower response times, higher resource usage.
Investigation:
# Check resource usage
kubectl top pods -n mailu
# Check logs for errors
kubectl logs -n mailu -l app.kubernetes.io/part-of=mailu --tail=100
Solutions:
Adjust resource limits (see Scale Resources)
Review new configuration options in release notes
Check for new default settings affecting performance
Upgrade Checklist¶
Use this checklist for production upgrades:
Pre-Upgrade:
[ ] Review Mailu release notes
[ ] Backup database (pg_dump)
[ ] Backup all PVCs
[ ] Document current version
[ ] Test upgrade in staging
[ ] Schedule maintenance window
[ ] Notify users of downtime
Upgrade:
[ ] Update CDK8S configuration
[ ] Regenerate manifests
[ ] Review manifest diff
[ ] Apply manifests
[ ] Monitor pod rollout
[ ] Check admin pod logs for migrations
Post-Upgrade:
[ ] Verify all pods running
[ ] Test admin UI
[ ] Test webmail
[ ] Test SMTP/IMAP
[ ] Check logs for errors
[ ] Monitor performance
[ ] Document new version
[ ] Notify users of completion
See Also¶
Backup and Restore - Critical for safe upgrades
Component Specifications - Version compatibility
Mailu Documentation - Official upgrade guides
Scale Resources - Adjust resources after upgrade