Layer2 —— Systemd 自动化管理 OP Stack 组件

简介

在部署和运行 Optimism 的过程中,手动启动各个组件既繁琐又容易出错。本文将详细介绍如何使用 systemd 服务来自动化管理 OP Stack 的各个核心组件,包括 op-geth、op-node、op-batcher 和 op-proposer。

⚠️本文中的路径 /home/eth/optimism/ 仅作示例,使用前请根据自己的部署目录修改

一、Why Systemd?

Systemd 是现代 Linux 发行版的标准初始化系统和服务管理器,它提供了以下优势:

  • 自动重启:当服务异常退出时自动重启
  • 依赖管理:确保服务按正确顺序启动
  • 日志管理:集中管理服务日志
  • 开机自启:系统重启后自动启动服务

二、启动脚本

2.1 创建脚本目录

1
2
3
cd ~/optimism/
mkdir -p scripts
cd scripts/

2.2 创建启动脚本

OP-Geth 启动脚本

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
cat > ./op-geth_starter.sh << 'EOF'
#!/bin/bash

LOG_DIR="/home/eth/optimism/logs/op-geth"
mkdir -p $LOG_DIR

echo "Starting Geth node at $(date)"
cd /home/eth/optimism/op-geth

source /home/eth/optimism/.envrc

exec ./build/bin/geth \
--datadir ./datadir \
--http \
--http.corsdomain="*" \
--http.vhosts="*" \
--http.addr=0.0.0.0 \
--http.api=web3,debug,eth,txpool,net,engine,miner \
--ws \
--ws.addr=0.0.0.0 \
--ws.port=8546 \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine,miner \
--syncmode=full \
--gcmode=archive \
--nodiscover \
--maxpeers=0 \
--networkid=$L2_CHAIN_ID \
--authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \
--authrpc.jwtsecret=./jwt.txt \
--rollup.disabletxpoolgossip=true
EOF

OP-Node 启动脚本

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
cat > ./op-node_starter.sh << 'EOF'
#!/bin/bash

LOG_DIR="/home/eth/optimism/logs/op-node"
mkdir -p $LOG_DIR

echo "Starting OP-Node at $(date)"
cd /home/eth/optimism/op-node

source /home/eth/optimism/.envrc

exec ./bin/op-node \
--l2=http://localhost:8551 \
--l2.jwt-secret=./jwt.txt \
--sequencer.enabled \
--sequencer.l1-confs=5 \
--verifier.l1-confs=4 \
--rollup.config=../.deployer/rollup.json \
--rpc.addr=0.0.0.0 \
--rpc.port=9545 \
--p2p.disable \
--rpc.enable-admin \
--p2p.sequencer.key=$GS_SEQUENCER_PRIVATE_KEY \
--l1=$L1_RPC_URL \
--l1.rpckind=$L1_RPC_KIND \
--l1.beacon=$L1_BEACON_URL
EOF

OP-Batcher 启动脚本

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
cat > ./op-batcher_starter.sh << 'EOF'
#!/bin/bash

LOG_DIR="/home/eth/optimism/logs/op-batcher"
mkdir -p $LOG_DIR

echo "Starting OP-Batcher at $(date)"
cd /home/eth/optimism/op-batcher

source /home/eth/optimism/.envrc

exec ./bin/op-batcher \
--l2-eth-rpc=http://localhost:8545 \
--rollup-rpc=http://localhost:9545 \
--poll-interval=1s \
--sub-safety-margin=6 \
--num-confirmations=1 \
--safe-abort-nonce-too-low-count=3 \
--resubmission-timeout=30s \
--rpc.addr=0.0.0.0 \
--rpc.port=8548 \
--rpc.enable-admin \
--max-channel-duration=25 \
--l1-eth-rpc=$L1_RPC_URL \
--private-key=$GS_BATCHER_PRIVATE_KEY
EOF

OP-Proposer 启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cat > ./op-proposer_starter.sh << 'EOF'
#!/bin/bash

LOG_DIR="/home/eth/optimism/logs/op-proposer"
mkdir -p $LOG_DIR

echo "Starting OP-Proposer at $(date)"
cd /home/eth/optimism/op-proposer

source /home/eth/optimism/.envrc

exec ./bin/op-proposer \
--poll-interval=12s \
--rpc.port=8560 \
--rollup-rpc=http://localhost:9545 \
--private-key=$GS_PROPOSER_PRIVATE_KEY \
--l1-eth-rpc=$L1_RPC_URL
EOF

2.3 设置脚本权限

1
chmod +x op-geth_starter.sh op-node_starter.sh op-batcher_starter.sh  op-proposer_starter.sh

2.4 测试脚本

此时可以尝试启动一下脚本,检查脚本是否正常工作

1
2
3
4
5
6
7
8
9
10
11
# 启动 L2 节点的 Geth
./op-geth_starter.sh

# 启动 OP Node
./op-node_starter.sh

# 启动 Batcher
./op-batcher_starter.sh

# 启动 Proposer
./op-proposer_starter.sh

三、Systemd 服务文件

3.1 创建服务文件目录

1
2
3
cd ~/optimism/
mkdir -p service
cd service/

3.2 创建 Systemd 服务文件

OP-Geth 服务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat > ./op-geth.service << 'EOF'
[Unit]
Description=OP-Geth Execution Client
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Group=root

WorkingDirectory=/home/eth/optimism/scripts
ExecStart=/home/eth/optimism/scripts/op-geth_starter.sh

StandardOutput=append:/home/eth/optimism/logs/op-geth/geth.log
StandardError=append:/home/eth/optimism/logs/op-geth/geth.log

Restart=always
RestartSec=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

OP-Node 服务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat > ./op-node.service << 'EOF'
[Unit]
Description=OP-Node L2 Consensus Client
After=network-online.target op-geth.service
Wants=network-online.target
Requires=op-geth.service

[Service]
Type=simple
User=root
Group=root

WorkingDirectory=/home/eth/optimism/scripts
ExecStart=/home/eth/optimism/scripts/op-node_starter.sh

StandardOutput=append:/home/eth/optimism/logs/op-node/op-node.log
StandardError=append:/home/eth/optimism/logs/op-node/op-node.log

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

OP-Batcher 服务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat > ./op-batcher.service << 'EOF'
[Unit]
Description=OP-Batcher L2 Transaction Batcher
After=network-online.target op-node.service
Wants=network-online.target
Requires=op-node.service

[Service]
Type=simple
User=root
Group=root

WorkingDirectory=/home/eth/optimism/scripts
ExecStart=/home/eth/optimism/scripts/op-batcher_starter.sh

StandardOutput=append:/home/eth/optimism/logs/op-batcher/op-batcher.log
StandardError=append:/home/eth/optimism/logs/op-batcher/op-batcher.log

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

OP-Proposer 服务配置

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

cat > ./op-proposer.service << 'EOF'
[Unit]
Description=OP-Proposer L2 State Proposer
After=network-online.target op-node.service
Wants=network-online.target
Requires=op-node.service

[Service]
Type=simple
User=root
Group=root

WorkingDirectory=/home/eth/optimism/scripts
ExecStart=/home/eth/optimism/scripts/op-proposer_starter.sh

StandardOutput=append:/home/eth/optimism/logs/op-proposer/op-proposer.log
StandardError=append:/home/eth/optimism/logs/op-proposer/op-proposer.log

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

服务依赖关系说明

服务启动的依赖顺序如下:

  1. op-geth:基础执行客户端,必须首先启动
  2. op-node:依赖 op-geth 提供的 Engine API
  3. op-batcherop-proposer:都依赖 op-node 提供的 Rollup RPC

通过 AfterRequires 指令,systemd 会自动处理这些依赖关系。

3.3 安装服务文件

1
2
3
4
5
6
7
8
9
10
11
# 创建符号链接
sudo ln -sf /home/eth/optimism/service/*.service /etc/systemd/system/

# 重载 systemd 配置
sudo systemctl daemon-reload

# 检查服务文件语法是否有误
sudo systemd-analyze verify /etc/systemd/system/${service}.service

# 启用开机自启
sudo systemctl enable op-geth op-node op-batcher op-proposer

四、启动服务

1
2
3
4
5
# 启动所有服务
sudo systemctl start op-geth op-node op-batcher op-proposer

# 检查服务状态
sudo systemctl status op-geth op-node op-batcher op-proposer

启动成功状态应如下图所示:

Hooray!Systemd 配置成功!!!

五、常见故障排查

日志管理

  • OP-Geth: /home/eth/optimism/logs/op-geth/geth.log

  • OP-Node: /home/eth/optimism/logs/op-node/op-node.log

  • OP-Batcher: /home/eth/optimism/logs/op-batcher/op-batcher.log

  • OP-Proposer: /home/eth/optimism/logs/op-proposer/op-proposer.log

5.1 code=exited, status=1/FAILURE

进入的 logs 的路径通过命令 tail -n 50 YOUR_LOG_NAME 查看服务的最近日志,使用 systemd 执行脚本时不会自动加载环境变量,如果脚本中使用了环境变量但没有正确加载,就会导致找不到相关变量而报错。

解决方案:确保启动脚本中正确配置环境变量加载语句:

1
source ~/optimism/.envrc

5.2 code=exited, status=209/STDOUT

通过命令 sudo journalctl -u YOUR_SERVICE_NAME -n 50 --no-pager查看服务的最近日志。服务启动时会检查配置的路径是否可访问或存在,需要检查配置的路径是否存在以及是否具有访问权限。

排查步骤

  1. 检查 WorkingDirectory 路径是否存在
  2. 检查 ExecStart 指向的脚本文件是否存在且有执行权限
  3. 检查日志目录是否可写

5.3 其他常用调试命令示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看服务实时日志
sudo journalctl -u op-geth -f

# 查看运行组件实时日志
tail -f op-geth

# 重启服务
sudo systemctl restart op-geth op-node op-batcher op-proposer

# 停止服务
sudo systemctl stop op-geth op-node op-batcher op-proposer

# 检查所有服务状态
sudo systemctl is-active op-geth op-node op-batcher op-proposer

六、总结

通过使用 systemd 管理 OP Stack 组件,我们实现了:

  • 自动化管理:服务自动启动、重启和监控
  • 依赖管理:确保服务按正确顺序启动
  • 日志集中管理:方便问题排查和监控
  • 生产环境就绪:满足生产环境的稳定性要求

这种配置方式特别适合生产环境部署,能够显著减少手动维护工作量,提高系统的可靠性和稳定性。当遇到问题时,通过查看具体的错误代码和日志,能够快速定位和解决问题。