This guide covers deploying Graylog with the new GeoIP sidecar container for automatic MaxMind database updates.
The GeoIP sidecar is a lightweight container that runs alongside Graylog and automatically updates MaxMind GeoIP databases on a configurable schedule. It replaces the previous Kubernetes CronJob approach, eliminating RWO volume multi-attach errors on multi-node clusters.
- MaxMind account ID and license key (from MaxMind website)
- Graylog Helm chart v1.0.0 or later
- Kubernetes 1.21+
helm install graylog charts/graylog \
--set graylog.config.geolocation.enabled=true \
--set graylog.config.geolocation.sidecar.enabled=true \
--set graylog.config.geolocation.maxmindGeoIp.accountId=YOUR_ACCOUNT_ID \
--set graylog.config.geolocation.maxmindGeoIp.licenseKey=YOUR_LICENSE_KEYIf you're using an external secret management system, put the MaxMind credentials in a
Secret of their own and point the sidecar at it. This is independent of
global.existingSecretName: the primary Graylog Secret is not expected to carry MaxMind
credentials.
kubectl create secret generic graylog-geoip \
--from-literal=GEO_IP_MAXMIND_ACCOUNT_ID=YOUR_ACCOUNT_ID \
--from-literal=GEO_IP_MAXMIND_LICENSE_KEY=YOUR_LICENSE_KEYThen deploy with:
helm install graylog charts/graylog \
--set graylog.config.geolocation.enabled=true \
--set graylog.config.geolocation.sidecar.enabled=true \
--set graylog.config.geolocation.maxmindGeoIp.existingSecret=graylog-geoipWhen the Secret uses different key names, override them:
graylog:
config:
geolocation:
maxmindGeoIp:
existingSecret: graylog-geoip
accountIdKey: accountId
licenseKeyKey: licenseKeySee examples/graylog-geoip-secret.yaml for a complete manifest.
graylog:
config:
geolocation:
enabled: true # Set to false to disable GeoIP completely
sidecar:
enabled: true # Set to false to disable sidecar (not recommended)Set the cron schedule for database updates (default: daily at midnight UTC):
graylog:
config:
geolocation:
sidecar:
schedule: "0 2 * * *" # 2 AM UTC
# Other options:
# schedule: "*/6 * * * *" # Every 6 hours
# schedule: "0 0 * * 0" # Weekly on SundayBy default, the chart downloads GeoLite2-City and GeoLite2-ASN databases. To use different editions:
graylog:
config:
geolocation:
maxmindGeoIp:
editionIds: "GeoIP2-City GeoIP2-ISP GeoIP2-Enterprise"Available editions depend on your MaxMind account. Space-separated format.
Adjust CPU/memory allocation for the sidecar:
graylog:
config:
geolocation:
sidecar:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi# View logs from the sidecar
kubectl logs -f deployment/graylog -c geoip-updater
# Check if sidecar is running
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].name}' | grep geoip-updaterWhen the sidecar updates the database:
[2026-07-17 02:00:00 UTC] GeoIP Sidecar started
[2026-07-17 02:00:00 UTC] Cron schedule: 0 2 * * *
[2026-07-17 02:00:00 UTC] Database directory: /usr/share/data/geolocation
[2026-07-17 02:00:00 UTC] Starting GeoIP database update...
[2026-07-17 02:00:15 UTC] GeoIP database update completed successfully
# Exec into Graylog pod and check database files
kubectl exec -it pod/graylog-0 -- ls -lah /usr/share/data/geolocation/
# Output should show .mmdb files:
# -rw-r--r-- 1 root root 61M Jul 17 02:00 GeoLite2-City.mmdb
# -rw-r--r-- 1 root root 6.3M Jul 17 02:00 GeoLite2-ASN.mmdbError: Pod crashes with "ImagePullBackOff"
- Verify network access to Docker Hub
- Check
imagePullSecretsif using a private registry - Verify image tag exists:
maxmindinc/geoipupdate:v7.1.1
Error: "GeoIP sidecar is enabled but MaxMind credentials are not provided"
- Set
graylog.config.geolocation.maxmindGeoIp.accountId - Set
graylog.config.geolocation.maxmindGeoIp.licenseKey - OR set
graylog.config.geolocation.maxmindGeoIp.existingSecretto a Secret containingGEO_IP_MAXMIND_ACCOUNT_IDandGEO_IP_MAXMIND_LICENSE_KEY(or your own key names viaaccountIdKey/licenseKeyKey)
Check 1: Verify sidecar is running
kubectl get pods graylog-0 -o jsonpath='{.spec.containers[*].name}'Check 2: Check sidecar logs for errors
kubectl logs graylog-0 -c geoip-updater --tail=50Check 3: Verify credentials are correct
- MaxMind account ID and license key are valid
- Account has permission to download selected editions
Check 4: Check volume permissions
kubectl exec -it pod/graylog-0 -c geoip-updater -- \
touch /usr/share/data/geolocation/test.txt && \
rm /usr/share/data/geolocation/test.txtError: "No databases matched the edition ids: GeoIP2-Enterprise"
- Verify the edition is available on your MaxMind account
- Check you have the correct license for that edition
- Account must have permission to download that edition
If you were previously using the CronJob approach:
- The CronJob has been removed from the chart
- Sidecar is now the only method for GeoIP updates
- Existing deployments should automatically switch to sidecar on upgrade
- No data loss - GeoIP databases persist on the volume
helm upgrade graylog charts/graylog \
--set graylog.config.geolocation.enabled=true \
--set graylog.config.geolocation.sidecar.enabled=true \
--set graylog.config.geolocation.maxmindGeoIp.accountId=YOUR_ACCOUNT_ID \
--set graylog.config.geolocation.maxmindGeoIp.licenseKey=YOUR_LICENSE_KEY- CPU: Typically <10m during updates, <1m during idle
- Memory: ~128Mi under normal operation
- Network: Depends on database size (~100-200MB download)
- First update: ~2-3 minutes (download + unpack)
- Subsequent updates: ~1-2 minutes (incremental updates)
- Schedule updates during off-peak hours
- Avoid overlap with other backup operations
- Consider timezone of your cluster (schedule uses UTC)
- For HA deployments, updates happen on each pod independently
The sidecar runs with the following security context by default:
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
runAsNonRoot: false
runAsUser: 0
seccompProfile:
type: RuntimeDefaultThe runAsUser: 0 and runAsNonRoot: false are required for the sidecar to write to the volume. The root container then writes files that Graylog (running as uid 1100) can read.
- Credentials stored in Kubernetes Secret
- Secret referenced via
valueFrom.secretKeyRef(never exposed as plaintext env var) - Use RBAC to restrict Secret access
- Consider using encrypted storage for secrets at rest
To use a different geoipupdate image version:
graylog:
config:
geolocation:
sidecar:
image:
tag: "7.0.0" # Change versionIf using values overrides, you can add custom env vars:
graylog:
config:
geolocation:
sidecar:
# Add to existing graylog.config.geolocation.sidecar.enabled configuration
extraEnv:
- name: GEOIPUPDATE_PROXY
value: "proxy.example.com:8080"Run the functional test suite:
./tests/functional/geoip_sidecar_functional_tests.shExpected output: 15 passing tests