How to run Graylog 6, MongoDB and Opensearch in a Docker Stack

Dear community,

I have spend the last two nights and a great part of today to figure out, how to run Graylog 6 in a Docker environment. The official Graylog documentation was partly helpful, partly misleading. I will summarize my findings here. Hopefully, this will benefit others as well.

Background
I usually run my docker container in different docker networks to separate them from each other. (-> increase security) My containers have a public facing network (-> macvlan), others have only an internal network, not open to anybody else.
If you are interested, here is all you need to know - besides the official Docker networking documentation.

Portainer is a simple tool to manage your docker containers. It provides a handy user interface.

docker compose.yaml
Here is my docker stack compose.yaml. (change xxxx into your passwords)

# version: as May 2024 https://docs.docker.com/compose/compose-file/
# https://go2docs.graylog.org/current/downloading_and_installing_graylog/docker_installation.htm

services:
# MongoDB: https://hub.docker.com/_/mongo/
  mongodb6:
    image: mongo:6.0.14
    container_name: mongodb6
    hostname: mongodb6
    environment:
      - TZ=Europe/Zurich
    restart: unless-stopped
    #DB in share for persistence
    volumes:
      - type: bind
        source: /home/uadmin/Docker/Graylog6/mongo_data/mongo_db
        target: /data/db
      - type: bind
        source: /home/uadmin/Docker/Graylog6/mongo_data/mongo_configdb
        target: /data/configdb
    deploy:
      resources:
        limits:
          memory: 500mb
    networks:
      backend2:
        ipv4_address: 10.10.14.3



  opensearch:
    image: opensearchproject/opensearch:2.12.0
    container_name: opensearch
    hostname: opensearch
    volumes:
      - /home/uadmin/Docker/Graylog6/opensearch-data:/usr/share/opensearch/data
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
      - "bootstrap.memory_lock=true"
      - "discovery.type=single-node"
      - "action.auto_create_index= false"
      - "plugins.security.ssl.http.enabled=false"
      - "plugins.security.disabled=true"
      # Can generate a password for `OPENSEARCH_INITIAL_ADMIN_PASSWORD` using a linux device via:
      # tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom  | head -c${1:-32}
      - "OPENSEARCH_INITIAL_ADMIN_PASSWORD=xxxx"
      - TZ=Europe/Zurich
    ports:
      - "9200:9200"
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    restart: unless-stopped
    networks:
      backend2:
        ipv4_address: 10.10.14.4





# Graylog: https://hub.docker.com/r/graylog/graylog/
  graylog6:
    image: graylog/graylog:6.0
    container_name: graylog6
    hostname: graylog6
    domainname: internal
    #journal and config directories in local NFS share for persistence
    volumes:
      - /home/uadmin/Docker/Graylog6/graylog_data:/usr/share/graylog/data
    entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 --  /docker-entrypoint.sh"
    environment:
#      - GRAYLOG_NODE_ID_FILE= "/usr/share/graylog/data/config/node-id"
      - GRAYLOG_HTTP_BIND_ADDRESS=192.168.60.13:9000
      - GRAYLOG_ELASTICSEARCH_HOSTS= http://opensearch:9200
      - GRAYLOG_MONGODB_URI= mongodb://mongodb6:27017/graylog
      # To make reporting (headless_shell) work inside a Docker container
      - GRAYLOG_REPORT_DISABLE_SANDBOX=true
      # CHANGE ME (must be at least 16 characters)!
      - GRAYLOG_PASSWORD_SECRET=xxxx
      # Password: "admin"
      - GRAYLOG_ROOT_PASSWORD_SHA2=xxxx
      - GRAYLOG_HTTP_EXTERNAL_URI=http://192.168.60.13:9000/
      - TZ=Europe/Zurich
    deploy:
      resources:
        limits:
          memory: 2gb
    networks:
      macvlan60:
        ipv4_address: 192.168.60.13
      backend2:
        ipv4_address: 10.10.14.2
    links:
      - mongodb6:mongo
      - opensearch
    restart: unless-stopped
    depends_on:
      mongodb6:
        condition: service_started
      opensearch:
        condition: service_started
    ports:
      # Graylog web interface and REST API
      - "9000:9000/tcp"
      # Beats
      - "5044:5044/tcp"
      # Syslog TCP
      - "5140:5140/tcp"
      - "1514:1514" #(e.g. Unifi)
      - "1515:1515" #(e.g. Tasmota)
      # Syslog UDP
      - "5140:5140/udp"
      # GELF TCP
      - "12201:12201/tcp"
      # GELF UDP
      - "12201:12201/udp"
      # Forwarder data
      - "13301:13301/tcp"
      # Forwarder config
      - "13302:13302/tcp"




# Volumes for persisting data, see https://docs.docker.com/engine/admin/volumes/volumes/
volumes:
  mongo_db:
  mongo_configdb:
  opensearch-data:
  graylog_data:
    driver: local


# Network specifications
networks:
  macvlan60:
    external: true
  backend2:
    internal: true
    ipam:
      driver: default
      config:
        - subnet: "10.10.14.0/24"

important inputs and differences to the official documentation

persistent data
The official documentation states, that the graylog container runs with the user 1100. On my host system, I called it graylog. In order to get the persistance to work, you need to change the owner of the folders and subfolders to this user. (I also did a sudo chmod -R 777..., not sure, of this is really necessary.)
Be aware, that opensearch is not running under that user. The opensearch folder need to be owned by the user 1000 (-> name uadmin in my case).

root@ubuntu:/home/uadmin/Docker/Graylog6# ls -lah
total 20K
drwxrwxrwx  5 graylog graylog 4.0K May 11 23:03 .
drwxrwxrwx 12 root    root    4.0K May 11 20:38 ..
drwxrwxrwx  8 graylog graylog 4.0K May 12 20:18 graylog_data
drwxr-xr-x  4 graylog graylog 4.0K May 11 23:03 mongo_data
drwxrwxrwx  3 uadmin  uadmin  4.0K May 11 23:40 opensearch-data

node-id
This file contains the node-id. It is automatically generated. In the official documentation, the path to this file is included as an environment variable .

- GRAYLOG_NODE_ID_FILE= "/usr/share/graylog/data/config/node-id"

This did not work for me. I had to remove this line. The same information will be provided by the graylog.conf.

graylog.conf
This is a file, you need to get from github. Follow the official documentation, Custom Configuration Files. Check the folder permissions to be sure, graylog can use it.

Graylog environment variables
The official documentation puts the environment variables for the Graylog container in brackets. I had to remove them. see compose.yaml above.

opensearch port 9200
Because of my docker network setup, you need to map the opensearch port 9200. Otherwise, graylog cannot reach opensearch.

entrypoint: “/usr/bin/tini – wait-for-it elasticsearch:9200 – /docker-entrypoint.sh”
In some of the official examples, it says elasticsearch:9200. I had to change this to opensearch:9200, as this is the name of the opensearch container.

Well, this is all I can remember. :slight_smile:

Know, I have to find out, how to migrate my data from Graylog 5.2, MongoDB 5.0.13 and Elasticsearch 7.10.2 to the new containers…

1 Like

for the record: this is how I finally upgraded from 5.2 to 6.0.1:

I have been struggling with the docker setup for 6 for a few days now. The docs are terrible (incorrect syntax/contradictions/etc). This post helped me solve the last few pieces! Thank you!

Best guide so far, yet i still cannot create a simple, basic server…

The error i get is:

Error response from daemon: network macvlan60 not found

My yaml file is as follows:

> services:
>   mongodb6:
>     image: mongo:6.0.14
>     container_name: mongodb6
>     hostname: mongodb6
>     environment:
>       - TZ=Europe/Lisbon
>     restart: unless-stopped
>     volumes:
>       - /home/docker/mongo/data:/data/db
>       - /home/docker/mongo/config:/data/configdb
>     deploy:
>       resources:
>         limits:
>           memory: 500mb
>     networks:
>       backend2:
>         ipv4_address: 10.10.14.3
> 
>   opensearch:
>     image: opensearchproject/opensearch:2.12.0
>     container_name: opensearch
>     hostname: opensearch
>     volumes:
>       - /home/docker/opensearch/data:/usr/share/opensearch/data
>     environment:
>       - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
>       - "bootstrap.memory_lock=true"
>       - "discovery.type=single-node"
>       - "action.auto_create_index= false"
>       - "plugins.security.ssl.http.enabled=false"
>       - "plugins.security.disabled=true"
>       # Can generate a password for `OPENSEARCH_INITIAL_ADMIN_PASSWORD` using a linux device via:
>       # tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom  | head -c${1:-32}
>       - "OPENSEARCH_INITIAL_ADMIN_PASSWORD=xxxx"
>       - TZ=Europe/Lisbon
>     ports:
>       - "9200:9200"
>     ulimits:
>       memlock:
>         hard: -1
>         soft: -1
>       nofile:
>         soft: 65536
>         hard: 65536
>     restart: unless-stopped
>     networks:
>       backend2:
>         ipv4_address: 10.10.14.4
> 
>   graylog6:
>     image: graylog/graylog:6.0
>     container_name: graylog6
>     hostname: graylog6
>     domainname: internal
>     volumes:
>       - /home/docker/graylog/data:/usr/share/graylog/data
>     entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 --  /docker-entrypoint.sh"
>     environment:
> #      - GRAYLOG_NODE_ID_FILE= "/usr/share/graylog/data/config/node-id"
>       - GRAYLOG_HTTP_BIND_ADDRESS=192.168.110.10:9001
>       - GRAYLOG_ELASTICSEARCH_HOSTS= http://opensearch:9200
>       - GRAYLOG_MONGODB_URI= mongodb://mongodb6:27017/graylog
>       # To make reporting (headless_shell) work inside a Docker container
>       - GRAYLOG_REPORT_DISABLE_SANDBOX=true
>       # CHANGE ME (must be at least 16 characters)!
>       - GRAYLOG_PASSWORD_SECRET=i_know_but_i_dont_tell_you
>       # Password: "admin"
>       - GRAYLOG_ROOT_PASSWORD_SHA2=i_know_but_i_dont_tell_you
>       - GRAYLOG_HTTP_EXTERNAL_URI=http://192.168.110.10:9001/
>       - TZ=Europe/Lisbon
>     deploy:
>       resources:
>         limits:
>           memory: 2gb
>     networks:
>       macvlan60:
>         ipv4_address: 192.168.110.10
>       backend2:
>         ipv4_address: 10.10.14.2
>     links:
>       - mongodb6:mongo
>       - opensearch
>     restart: unless-stopped
>     depends_on:
>       mongodb6:
>         condition: service_started
>       opensearch:
>         condition: service_started
>     ports:
>       - "9001:9000/tcp"     # Graylog web interface and REST API
>       - "5044:5044/tcp"     # Beats
>       - "514:514/tcp"       # Syslog TCP
>       - "1514:1514"         #(e.g. Unifi)
>       - "1515:1515"         #(e.g. Tasmota)
>       - "514:514/udp"       # Syslog UDP
>       - "12201:12201/tcp"   # GELF TCP
>       - "12201:12201/udp"   # GELF UDP
>       - "13301:13301/tcp"   # Forwarder data
>       - "13302:13302/tcp"   # Forwarder config
> 
> networks:
>   macvlan60:
>     external: true
>   backend2:
>     internal: true
>     ipam:
>       driver: default
>       config:
>         - subnet: "10.10.14.0/24"

If there’s any kind sould.
Greatly appreciated.

@schneich :vulcan_salute:. Many thanks. You saved me couple days. :face_holding_back_tears: