Featured image of post Upgrade Docker Graylog From 5.2 to 6.0

Upgrade Docker Graylog From 5.2 to 6.0

升級概要

首先,簡單描述升級方式的重點:

  • Mongo DB: mongo:5.0 -> mongo:6.0
    根據官方自己寫的 Version Compatibility,Graylog 6.0.x 版可支援的 Mongo DB 版本為 5.0.7 ~ 7.x,秉持著有新不用舊的心態,一開始我是升 7.0,結果大暴死,Mongo DB container 陷入一個無限重啟的循環,看 log 好幾遍連怎麼死的都不知道,最後改成 6.0,啥也沒幹就啟動了。
  • Graylog Datanode: graylog/graylog-datanode:5.0 -> graylog/graylog-datanode:6.0
    最一開始直接拿了官方給的 docker-compose 版本直接跑起來,現在要升級時,突然發現 compose file 裡面是跑 datanode,而不 ES 或是 OS,Version Compatibility 對於 datanode 也隻字未提。
  • Graylog: graylog/graylog:5.0 -> graylog/graylog:6.0
  • datanode 的 ENV VAR GRAYLOG_DATANODE_NODE_ID_FILE 似乎沒用處,可以刪掉或註解

升級前的 docker-compose.yml

目前的 docker-compose.yml 內容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
version: "3.8"

# For DataNode setup, graylog starts with a preflight UI, this is a change from just using OpenSearch/Elasticsearch.
# Please take a look at the README at the top of this repo or the regular docs for more info.

services:
  mongodb:
    image: "mongo:5.0"
    environment:
      TZ: "Asia/Taipei"
    volumes:
      - "mongodb_data:/data/db"
    restart: "on-failure"

  # For DataNode setup, graylog starts with a preflight UI, this is a change from just using OpenSearch/Elasticsearch.
  # Please take a look at the README at the top of this repo or the regular docs for more info.
  datanode:
    image: "${DATANODE_IMAGE:-graylog/graylog-datanode:5.2}"
    hostname: "datanode"
    environment:
      TZ: "Asia/Taipei"
      GRAYLOG_DATANODE_NODE_ID_FILE: "/var/lib/graylog-datanode/node-id"
      GRAYLOG_DATANODE_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET:?Please configure GRAYLOG_PASSWORD_SECRET in the .env file}"
      GRAYLOG_DATANODE_ROOT_PASSWORD_SHA2: "${GRAYLOG_ROOT_PASSWORD_SHA2:?Please configure GRAYLOG_ROOT_PASSWORD_SHA2 in the .env file}"
      GRAYLOG_DATANODE_MONGODB_URI: "mongodb://mongodb:27017/graylog"
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - "${IP_ADDRESS}:8999:8999/tcp"   # DataNode API
      - "${IP_ADDRESS}:9200:9200/tcp"
      - "${IP_ADDRESS}:9300:9300/tcp"
    volumes:
      - "graylog-datanode:/var/lib/graylog-datanode"
    restart: "on-failure"

  graylog:
    hostname: "server"
    image: "${GRAYLOG_IMAGE:-graylog/graylog:5.2}"
    depends_on:
      mongodb:
        condition: "service_started"
    entrypoint: "/usr/bin/tini --  /docker-entrypoint.sh"
    environment:
      TZ: "Asia/Taipei"
      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/data/node-id"
      GRAYLOG_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET:?Please configure GRAYLOG_PASSWORD_SECRET in the .env file}"
      GRAYLOG_ROOT_PASSWORD_SHA2: "${GRAYLOG_ROOT_PASSWORD_SHA2:?Please configure GRAYLOG_ROOT_PASSWORD_SHA2 in the .env file}"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_HTTP_EXTERNAL_URI: "http://localhost:9000/"
      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
    ports:
    - "${IP_ADDRESS}:5044:5044/tcp"   # Beats
    - "${IP_ADDRESS}:5140:5140/udp"   # Syslog UDP
    - "${IP_ADDRESS}:5140:5140/tcp"   # Syslog TCP
    - "${IP_ADDRESS}:5555:5555/tcp"   # RAW TCP
    - "${IP_ADDRESS}:5555:5555/udp"   # RAW UDP
    - "${IP_ADDRESS}:9000:9000/tcp"   # Server API
    - "${IP_ADDRESS}:12201:12201/tcp" # GELF TCP
    - "${IP_ADDRESS}:12201:12201/udp" # GELF UDP
    #- "${IP_ADDRESS}:10000:10000/tcp" # Custom TCP port
    #- "${IP_ADDRESS}:10000:10000/udp" # Custom UDP port
    - "${IP_ADDRESS}:13301:13301/tcp" # Forwarder data
    - "${IP_ADDRESS}:13302:13302/tcp" # Forwarder config

    ##### temp perserve #####
    - "172.16.1.72:12201:12201/udp" # GELF UDP
    ##### temp perserve #####
    volumes:
      - "graylog_data:/usr/share/graylog/data/data"
      - "graylog_journal:/usr/share/graylog/data/journal"
      - "graylog_plugin:/usr/share/graylog/plugin"
    restart: "on-failure"

volumes:
  mongodb_data:
  graylog-datanode:
  graylog_data:
  graylog_journal:
  graylog_plugin:

注意:如果有使用到第三方外掛套件

這邊要特別注意,如果有使用到第三方外掛套件,要特別注意是否相容於 Graylog 6.0。

如果需要升級外掛版本的話,請先準備好相應的外掛版本,在升級過程中替換掉,否則 Graylog 升級後會陷入無限重啟的死循環內。

以這邊的例子,我有使用 wizecore/graylog2-output-syslog 這個 Syslog Output 外掛。

在 Graylog 5.2 時使用的外掛版本是 v4.2.6,對應 Graylog 6.0 的外掛版本是 v6.0.0。

因為外掛程式載入錯誤而陷入無限重啟的死循環時,log 大概長得像這樣:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2024-06-26 15:55:58,286 INFO : org.mongodb.driver.cluster - Waiting for server to become available for operation with ID 11. Remaining time: 30000 ms. Selector: ReadPreferenceServerSelector{readPreference=primary}, topology description: {type=UNKNOWN, servers=[{address=mongodb:27017, type=UNKNOWN, state=CONNECTING}].
2024-06-26 15:55:59,015 INFO : org.graylog2.bootstrap.preflight.SearchDbPreflightCheck - Connected to (Elastic/Open)Search version <OpenSearch:2.12.0>
2024-06-26 15:55:59,095 INFO : org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator null
2024-06-26 15:56:00,376 ERROR: org.graylog2.bootstrap.CmdLineTool - Guice error (more detail on log level debug): No injectable constructor for type com.wizecore.graylog2.plugin.SyslogOutput.
2024-06-26 15:56:00,376 ERROR: org.graylog2.bootstrap.CmdLineTool - Guice error (more detail on log level debug): No implementation for com.wizecore.graylog2.plugin.SyslogOutput$Factory was bound.
2024-06-26 15:56:00,376 ERROR: org.graylog2.bootstrap.CmdLineTool - Startup error:
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) [Guice/MissingConstructor]: No injectable constructor for type SyslogOutput.
class SyslogOutput does not have a @Inject annotated constructor or a no-arg constructor.
Requested by:
1  : SyslogOutput.class(SyslogOutput.java:43)
     while locating SyslogOutput
Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:
     at SyslogOutput$Factory.create(SyslogOutput.java:271)
1) [Guice/MissingConstructor]: No injectable constructor for type SyslogOutput.
Learn more:
class SyslogOutput does not have a @Inject annotated constructor or a no-arg constructor.
  https://github.com/google/guice/wiki/MISSING_CONSTRUCTOR
Requested by:
2) [Guice/MissingImplementation]: No implementation for SyslogOutput$Factory was bound.
1  : SyslogOutput.class(SyslogOutput.java:43)
     while locating SyslogOutput
     at SyslogOutput$Factory.create(SyslogOutput.java:271)
Learn more:
  https://github.com/google/guice/wiki/MISSING_CONSTRUCTOR
Requested by:
2) [Guice/MissingImplementation]: No implementation for SyslogOutput$Factory was bound.
1  : Graylog2Module.installOutput(Graylog2Module.java:267)
Requested by:
      \_ installed by: PluginBindings -> SyslogOutputModule
1  : Graylog2Module.installOutput(Graylog2Module.java:267)
Learn more:
      \_ installed by: PluginBindings -> SyslogOutputModule
  https://github.com/google/guice/wiki/MISSING_IMPLEMENTATION
Learn more:
2 errors
======================
  https://github.com/google/guice/wiki/MISSING_IMPLEMENTATION
2 errors
======================
Full classname legend:
Full classname legend:
======================
======================
Graylog2Module:       "org.graylog2.plugin.inject.Graylog2Module"
Graylog2Module:       "org.graylog2.plugin.inject.Graylog2Module"
PluginBindings:       "org.graylog2.shared.bindings.PluginBindings"
PluginBindings:       "org.graylog2.shared.bindings.PluginBindings"
SyslogOutput:         "com.wizecore.graylog2.plugin.SyslogOutput"
SyslogOutput:         "com.wizecore.graylog2.plugin.SyslogOutput"
SyslogOutput$Factory: "com.wizecore.graylog2.plugin.SyslogOutput$Factory"
SyslogOutput$Factory: "com.wizecore.graylog2.plugin.SyslogOutput$Factory"
SyslogOutputModule:   "com.wizecore.graylog2.plugin.SyslogOutputModule"
========================
End of classname legend:
========================
	at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:589) ~[graylog.jar:?]
SyslogOutputModule:   "com.wizecore.graylog2.plugin.SyslogOutputModule"
========================
End of classname legend:
========================
	at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:589)
	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:163)
	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
	at com.google.inject.Guice.createInjector(Guice.java:87)
	at org.graylog2.shared.bindings.GuiceInjectorHolder.createInjector(GuiceInjectorHolder.java:34)
	at org.graylog2.bootstrap.CmdLineTool.setupInjector(CmdLineTool.java:530)
	at org.graylog2.bootstrap.CmdLineTool.doRun(CmdLineTool.java:317)
	at org.graylog2.bootstrap.CmdLineTool.run(CmdLineTool.java:267)
	at org.graylog2.bootstrap.Main.main(Main.java:55)
	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:163) ~[graylog.jar:?]
	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110) ~[graylog.jar:?]
	at com.google.inject.Guice.createInjector(Guice.java:87) ~[graylog.jar:?]
	at org.graylog2.shared.bindings.GuiceInjectorHolder.createInjector(GuiceInjectorHolder.java:34) ~[graylog.jar:?]
	at org.graylog2.bootstrap.CmdLineTool.setupInjector(CmdLineTool.java:530) ~[graylog.jar:?]
	at org.graylog2.bootstrap.CmdLineTool.doRun(CmdLineTool.java:317) ~[graylog.jar:?]
	at org.graylog2.bootstrap.CmdLineTool.run(CmdLineTool.java:267) [graylog.jar:?]
	at org.graylog2.bootstrap.Main.main(Main.java:55) [graylog.jar:?]

開始升級

Step.1 升級 MongoDB

第一步先單獨升級 MongoDB 到 6.0,升級時不會影響另外兩個 container 運作。

docker-compose.yml 內 MongoDB 的版本改成 6.0 後執行 docker-compose up -d,container 啟動後透過以下指令升級功能相容性版本:

1
docker-compose exec mongodb mongosh --eval 'db.adminCommand( { setFeatureCompatibilityVersion: "6.0" } )'

正常情況得到的輸出:

1
{ ok: 1 }

Step.2 升級第三方外掛套件版本 (沒有使用的話可直接略過此步驟)

需要升級第三方外掛套件的話,不需要停止 container,直接將新版本第三方外掛套件複製到 plugin volume,並移除舊版本即可。

1
2
docker cp ./graylog-output-syslog-6.0.0.jar graylog-graylog-1:/usr/share/graylog/plugin/
docker exec graylog-graylog-1 rm -f /usr/share/graylog/plugin/graylog-output-syslog-4.2.6.jar

此步驟不需要先停止 container 再進行,如果是在停止的狀態下,需要透過其他 running container 掛載 volume 後才能將舊版外掛套件刪除。

,下載後丟到 graylog_plugin volume 裡即可,舊版本先留著,升級完成後再刪除。

Step.3 升級 Graylog 和 Datanode Image

docker-compose.yml 內的 graylog/graylog:5.2graylog/graylog-datanode:5.2 版號改成 6.0 即可。

如果要將 Community Edition 轉換為 Enterprise Edition 的話,也可以把 graylog/graylog:5.2 直接改成 graylog/graylog-enterprise:6.0,我自己測試同時升級 Major Version 與轉換到 Enterprise Edition 是沒問題,不過升級前一律建議完整備份再升級,中間會不會出什麼差錯誰也說不準。

感謝 Chris 的紀錄,照著官方的指引走到 step.7 就會卡關,不得不說 Graylog 東西好,但是文件真的有點糟糕 = =。

最後檢視環境大部分都正常,除了 Elasticsearch cluster 狀態有警告:

Elasticsearch cluster datanode-cluster is yellow. Shards: 42 active, 0 initializing, 0 relocating, 2 unassigned, What does this mean?

看了一下官方說明,可以手動介入也可以試著放置 play,在放置兩天後它自己修復了。

Elasticsearch cluster datanode-cluster is green. Shards: 47 active, 0 initializing, 0 relocating, 0 unassigned, What does this mean?

以下為升級完成後的完整 docker-compose.yml 檔案內容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
version: "3.8"

# For DataNode setup, graylog starts with a preflight UI, this is a change from just using OpenSearch/Elasticsearch.
# Please take a look at the README at the top of this repo or the regular docs for more info.

services:
  mongodb:
    image: "mongo:6.0"
    environment:
      TZ: "Asia/Taipei"
    volumes:
      - "mongodb_data:/data/db"
    restart: "on-failure"

  # For DataNode setup, graylog starts with a preflight UI, this is a change from just using OpenSearch/Elasticsearch.
  # Please take a look at the README at the top of this repo or the regular docs for more info.
  datanode:
    image: "${DATANODE_IMAGE:-graylog/graylog-datanode:6.0}"
    hostname: "datanode"
    environment:
      TZ: "Asia/Taipei"
      # deprecated on 6.0
      # GRAYLOG_DATANODE_NODE_ID_FILE: "/var/lib/graylog-datanode/node-id"
      GRAYLOG_DATANODE_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET:?Please configure GRAYLOG_PASSWORD_SECRET in the .env file}"
      GRAYLOG_DATANODE_ROOT_PASSWORD_SHA2: "${GRAYLOG_ROOT_PASSWORD_SHA2:?Please configure GRAYLOG_ROOT_PASSWORD_SHA2 in the .env file}"
      GRAYLOG_DATANODE_MONGODB_URI: "mongodb://mongodb:27017/graylog"
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - "${IP_ADDRESS}:8999:8999/tcp"  # Graylog Data Node REST API
      - "${IP_ADDRESS}:9200:9200/tcp"  # OpenSearch REST API
      - "${IP_ADDRESS}:9300:9300/tcp"  # OpenSearch Transport API
    volumes:
      - "graylog-datanode:/var/lib/graylog-datanode"
    restart: "on-failure"

  graylog:
    hostname: "server"
    image: "${GRAYLOG_IMAGE:-graylog/graylog:6.0}"
    depends_on:
      mongodb:
        condition: "service_started"
    entrypoint: "/usr/bin/tini --  /docker-entrypoint.sh"
    environment:
      TZ: "Asia/Taipei"
      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/data/node-id"
      GRAYLOG_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET:?Please configure GRAYLOG_PASSWORD_SECRET in the .env file}"
      GRAYLOG_ROOT_PASSWORD_SHA2: "${GRAYLOG_ROOT_PASSWORD_SHA2:?Please configure GRAYLOG_ROOT_PASSWORD_SHA2 in the .env file}"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_HTTP_EXTERNAL_URI: "http://localhost:9000/"
      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
    ports:
    - "${IP_ADDRESS}:5044:5044/tcp"   # Beats
    - "${IP_ADDRESS}:5140:5140/udp"   # Syslog UDP
    - "${IP_ADDRESS}:5140:5140/tcp"   # Syslog TCP
    - "${IP_ADDRESS}:5555:5555/tcp"   # RAW TCP
    - "${IP_ADDRESS}:5555:5555/udp"   # RAW UDP
    - "${IP_ADDRESS}:9000:9000/tcp"   # Server API
    - "${IP_ADDRESS}:12201:12201/tcp" # GELF TCP
    - "${IP_ADDRESS}:12201:12201/udp" # GELF UDP
    #- "${IP_ADDRESS}:10000:10000/tcp" # Custom TCP port
    #- "${IP_ADDRESS}:10000:10000/udp" # Custom UDP port
    - "${IP_ADDRESS}:13301:13301/tcp" # Forwarder data
    - "${IP_ADDRESS}:13302:13302/tcp" # Forwarder config

    volumes:
      - "graylog_data:/usr/share/graylog/data/data"
      - "graylog_journal:/usr/share/graylog/data/journal"
      - "graylog_plugin:/usr/share/graylog/plugin"
    restart: "on-failure"

volumes:
  mongodb_data:
  graylog-datanode:
  graylog_data:
  graylog_journal:
  graylog_plugin:
comments powered by Disqus