docs(solana-rpc): expand agave and geyser runbook
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
Step 002: Plan wdrozenia Solana RPC (Agave mainnet, non-voting, private RPC + Yellowstone gRPC + monitoring + NOC tmux)
|
||||
Step 002: Plan wdrozenia Solana RPC (Agave mainnet, non-voting, private RPC + Geyser->Postgres + monitoring + NOC tmux)
|
||||
|
||||
Zalozenia (default):
|
||||
- WG iface: wg0, WG subnet: 10.66.66.0/24, WG IP baremetala: 10.66.66.1
|
||||
- Public iface: eth0, public IP: 149.50.116.219
|
||||
- RPC: 8899 (HTTP), WS: 8900
|
||||
- Yellowstone gRPC: 10000 (tylko po WG)
|
||||
- RPC: 8899 (HTTP), WS: 8900 (WS = RPC_PORT+1)
|
||||
- Postgres (lokalnie): 5432 (DB: geyser, user: geyser)
|
||||
- (Optional) Yellowstone gRPC: 10000 (tylko po WG)
|
||||
- Prometheus: 9090, Grafana: 3000, node_exporter: 9100 (tylko po WG)
|
||||
- Dynamic port range (cluster): 8000-8020/udp (public eth0)
|
||||
- User: solana
|
||||
@@ -28,6 +29,7 @@ Zalozenia (default):
|
||||
sysstat iotop \
|
||||
ethtool nstat \
|
||||
chrony curl jq git ca-certificates \
|
||||
ripgrep \
|
||||
smartmontools nvme-cli \
|
||||
build-essential pkg-config libssl-dev \
|
||||
clang llvm-dev libclang-dev \
|
||||
@@ -46,6 +48,15 @@ Zalozenia (default):
|
||||
# sudo chown solana:solana /var/lib/solana/identity.json
|
||||
# sudo chmod 600 /var/lib/solana/identity.json
|
||||
|
||||
2A) Storage (rekomendowane)
|
||||
# Variant A: jesli /dev/nvme0n1 jest wolny i chcesz go podzielic 50/50:
|
||||
# doc/step-002a-storage-nvme0n1-xfs.txt
|
||||
#
|
||||
# Variant B (mpabi): masz juz 2x NVMe z XFS:
|
||||
# - SOLACCT na accounts (nvme0n1p1)
|
||||
# - SOLLEDG na ledger (nvme1n1p1)
|
||||
# doc/step-002a-storage-existing-solacct-solledg-xfs.txt
|
||||
|
||||
3) Firewall/WG binding (private-only)
|
||||
# UFW: deny everything inbound by default
|
||||
sudo ufw default deny incoming
|
||||
@@ -102,39 +113,16 @@ EOF
|
||||
sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"'
|
||||
|
||||
# Copy binaries to /opt/solana/bin (avoid symlink permission gotchas)
|
||||
sudo bash -lc '
|
||||
set -e
|
||||
SRC="/var/lib/solana/.local/share/solana/install/active_release/bin"
|
||||
DST="/opt/solana/bin"
|
||||
for f in "$SRC"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
install -m 0755 "$f" "$DST/$(basename "$f")"
|
||||
done
|
||||
'
|
||||
sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/
|
||||
sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \;
|
||||
|
||||
/opt/solana/bin/solana --version || true
|
||||
/opt/solana/bin/solana-keygen --version
|
||||
|
||||
# Build agave-validator (pin tag + toolchain)
|
||||
AGAVE_VERSION_TAG="v2.3.13"
|
||||
AGAVE_RUST_TOOLCHAIN="1.86.0"
|
||||
AGAVE_SRC_DIR="/var/lib/solana/src/agave"
|
||||
|
||||
sudo -u solana -H bash -lc "curl -sSfL https://sh.rustup.rs | sh -s -- -y --default-toolchain '${AGAVE_RUST_TOOLCHAIN}'"
|
||||
sudo -u solana -H bash -lc "
|
||||
set -euo pipefail
|
||||
export PATH=/var/lib/solana/.cargo/bin:\$PATH
|
||||
rustup toolchain install '${AGAVE_RUST_TOOLCHAIN}'
|
||||
mkdir -p '$(dirname \"$AGAVE_SRC_DIR\")'
|
||||
rm -rf '${AGAVE_SRC_DIR}'
|
||||
git clone --depth 1 --branch '${AGAVE_VERSION_TAG}' https://github.com/anza-xyz/agave.git '${AGAVE_SRC_DIR}'
|
||||
cd '${AGAVE_SRC_DIR}'
|
||||
cargo +${AGAVE_RUST_TOOLCHAIN} build --release -p agave-validator
|
||||
"
|
||||
|
||||
sudo install -o root -g root -m 0755 \
|
||||
"${AGAVE_SRC_DIR}/target/release/agave-validator" \
|
||||
/opt/solana/bin/agave-validator
|
||||
# Uwaga: dla nowszych stable release'ow binarka moze nie byc publikowana,
|
||||
# wiec build ze zrodel jest wymagany.
|
||||
# doc/step-002f-agave-build-from-source-latest.txt
|
||||
|
||||
# Identity (create once)
|
||||
if [ ! -f /var/lib/solana/identity.json ]; then
|
||||
@@ -148,15 +136,20 @@ EOF
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getGenesisHash"}' \
|
||||
https://api.mainnet-beta.solana.com | jq -r .result)"
|
||||
echo "$GENESIS_HASH"
|
||||
# Oczekiwane (mainnet): 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
|
||||
|
||||
# systemd unit (bind RPC to WG/localhost only)
|
||||
# NOTE: agave-validator expects sockets on the same IP in many setups.
|
||||
# We keep bind 0.0.0.0 but rely on UFW to ensure private-only access to RPC/WS.
|
||||
sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<EOF
|
||||
# UWAGA: w unit file NIE uzywaj `\\` na koncu linii w ExecStart.
|
||||
# Jesli wpiszesz `\\`, agave-validator dostanie literalny argument `\` i padnie z:
|
||||
# "error: The subcommand '\\' wasn't recognized"
|
||||
#
|
||||
# Najprosciej: ExecStart w 1 linii, bez "kontynuacji" backslashami.
|
||||
# Ale: zeby uniknac problemow z wklejaniem/lamaniem linii, ponizej jest bezpieczna wersja wielolinijkowa.
|
||||
sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<'EOF'
|
||||
[Unit]
|
||||
Description=Agave validator (mainnet, RPC-only, non-voting)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
After=network-online.target wg-quick@wg0.service
|
||||
Wants=network-online.target wg-quick@wg0.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@@ -168,22 +161,21 @@ LimitNOFILE=1048576
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
TimeoutStopSec=120
|
||||
ExecStart=/opt/solana/bin/agave-validator \\
|
||||
--identity /var/lib/solana/identity.json \\
|
||||
--no-voting \\
|
||||
--ledger /var/lib/solana/ledger \\
|
||||
--accounts /var/lib/solana/accounts \\
|
||||
--log /var/log/solana/validator.log \\
|
||||
--bind-address 0.0.0.0 \\
|
||||
--rpc-bind-address 0.0.0.0 \\
|
||||
--rpc-port 8899 \\
|
||||
--rpc-pubsub-bind-address 0.0.0.0 \\
|
||||
--rpc-pubsub-port 8900 \\
|
||||
--dynamic-port-range 8000-8020 \\
|
||||
--entrypoint entrypoint.mainnet-beta.solana.com:8001 \\
|
||||
--expected-genesis-hash ${GENESIS_HASH} \\
|
||||
--full-rpc-api \\
|
||||
--limit-ledger-size
|
||||
ExecStart=/opt/solana/bin/agave-validator \
|
||||
--identity /var/lib/solana/identity.json \
|
||||
--no-voting \
|
||||
--private-rpc \
|
||||
--ledger /var/lib/solana/ledger \
|
||||
--accounts /var/lib/solana/accounts \
|
||||
--log /var/log/solana/validator.log \
|
||||
--bind-address 0.0.0.0 \
|
||||
--rpc-bind-address 10.66.66.1 \
|
||||
--rpc-port 8899 \
|
||||
--dynamic-port-range 8000-8020 \
|
||||
--entrypoint entrypoint.mainnet-beta.solana.com:8001 \
|
||||
--expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \
|
||||
--full-rpc-api \
|
||||
--limit-ledger-size 50000000
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
@@ -199,15 +191,24 @@ EOF
|
||||
systemctl is-active agave-validator
|
||||
journalctl -u agave-validator -n 80 --no-pager
|
||||
|
||||
5) Yellowstone gRPC (plugin) (placeholder)
|
||||
# TODO (next step): install/build yellowstone geyser plugin matching Agave 3.0.15,
|
||||
# put plugin .so under /opt/solana/plugins/, write /etc/solana/yellowstone-geyser.json,
|
||||
# and add to ExecStart:
|
||||
# --geyser-plugin-config /etc/solana/yellowstone-geyser.json
|
||||
# Jesli padnie na genesis (brak genesis.tar.bz2):
|
||||
# doc/step-002c-genesis-download-mainnet.txt
|
||||
#
|
||||
# Verification (after enable):
|
||||
# journalctl -u agave-validator | rg -i 'geyser|yellowstone|plugin'
|
||||
# ss -lntp | rg ':10000\\b'
|
||||
# Jesli padnie na snapshot (mainnet wymaga snapshot):
|
||||
# doc/step-002d-snapshot-download-mainnet.txt
|
||||
#
|
||||
# Jesli chcesz najpierw odpalic validator z CLI (test), zanim przepniesz na systemd:
|
||||
# doc/step-002e-agave-validator-run-cli.txt
|
||||
|
||||
5) Geyser plugin -> Postgres
|
||||
# Krok po kroku:
|
||||
# doc/step-003-geyser-plugin-postgres.txt
|
||||
#
|
||||
# W skrocie:
|
||||
# - budujesz plugin .so i wrzucasz do /opt/solana/plugins/
|
||||
# - tworzysz /etc/solana/geyser-postgres.json
|
||||
# - dopisujesz do ExecStart:
|
||||
# --geyser-plugin-config /etc/solana/geyser-postgres.json
|
||||
|
||||
6) Drift DLOB (2 markets) (on VPS, not baremetal) (placeholder)
|
||||
# VPS env:
|
||||
@@ -258,4 +259,3 @@ EOF
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getSlot"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
|
||||
|
||||
@@ -5,25 +5,29 @@ Stan startowy:
|
||||
- SSH po publicznym eth0 jest odciete (UFW deny na eth0:22), SSH dziala tylko po wg0.
|
||||
- RPC ma byc prywatny: porty 8899/8900 tylko po wg0, ale node ma miec publiczne porty klastra (UDP dynamic range) zeby syncowal.
|
||||
|
||||
UWAGA o bind:
|
||||
- `agave-validator` praktycznie wymaga, zeby wszystkie sockety byly na tym samym IP.
|
||||
- Dlatego w tym kroku bindujemy usluge na 0.0.0.0 i zabezpieczamy dostep firewall-em:
|
||||
- eth0: blokujemy TCP 8899/8900
|
||||
- wg0: pozwalamy TCP 8899/8900
|
||||
- eth0: pozwalamy UDP dynamic port range (np. 8000-8020) dla klastra
|
||||
UWAGA o prywatnosci:
|
||||
- RPC/WS bindujemy na wg0 (10.66.66.1), zeby NIE wystawic RPC na publicznym eth0 nawet gdy UFW jest wylaczone.
|
||||
- Dodatkowo i tak robimy UFW "deny" na eth0:8899/8900 (defense-in-depth).
|
||||
|
||||
Parametry (dostosuj, przyklad mainnet):
|
||||
- PUBLIC_IFACE=eth0
|
||||
- WG_IFACE=wg0
|
||||
- WG_IP=10.66.66.1
|
||||
- ENDPOINT_RPC_PORT=8899
|
||||
- ENDPOINT_WS_PORT=8900
|
||||
- ENDPOINT_WS_PORT=8900 (WS = RPC_PORT+1)
|
||||
- DYNAMIC_PORT_RANGE="8000:8020"
|
||||
|
||||
0) Storage (rekomendowane)
|
||||
Jesli masz osobny NVMe na dane (ledger/accounts), zrob najpierw:
|
||||
doc/step-002a-storage-nvme0n1-xfs.txt
|
||||
albo (mpabi, 2x NVMe z juz istniejacym XFS):
|
||||
doc/step-002a-storage-existing-solacct-solledg-xfs.txt
|
||||
|
||||
1) Bazowe pakiety
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
chrony curl jq git \
|
||||
ripgrep \
|
||||
smartmontools nvme-cli \
|
||||
build-essential pkg-config libssl-dev \
|
||||
clang llvm-dev libclang-dev \
|
||||
@@ -38,6 +42,10 @@ Parametry (dostosuj, przyklad mainnet):
|
||||
sudo install -d -o solana -g solana -m 0750 \
|
||||
/var/lib/solana /var/lib/solana/ledger /var/lib/solana/accounts /var/log/solana
|
||||
|
||||
# Jesli ledger/accounts sa mountpointami (Step 002A), upewnij sie, ze root FS jest writable dla usera solana:
|
||||
sudo chown solana:solana /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
sudo chmod 750 /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
|
||||
3) Sysctl + ulimit (baseline pod Agave)
|
||||
sudo tee /etc/sysctl.d/90-agave.conf >/dev/null <<'EOF'
|
||||
fs.file-max = 2000000
|
||||
@@ -83,44 +91,19 @@ EOF
|
||||
5) Narzedzia Solana/Anza (dla `solana`): solana-keygen itd.
|
||||
sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"'
|
||||
|
||||
ACTIVE_RELEASE_BIN_DIR="/var/lib/solana/.local/share/solana/install/active_release/bin"
|
||||
test -d "$ACTIVE_RELEASE_BIN_DIR" || { echo "Missing: $ACTIVE_RELEASE_BIN_DIR" >&2; exit 1; }
|
||||
for bin in "$ACTIVE_RELEASE_BIN_DIR"/*; do
|
||||
sudo ln -sfn "$bin" "/opt/solana/bin/$(basename "$bin")"
|
||||
done
|
||||
test -x /opt/solana/bin/solana-keygen
|
||||
# Weryfikacja, ze installer utworzyl active_release/bin (bez exit, zeby nie ubijac pane/tmux):
|
||||
sudo -u solana -H bash -lc 'ls -ld ~/.local/share/solana/install/active_release/bin && ls -1 ~/.local/share/solana/install/active_release/bin | head'
|
||||
|
||||
# Kopiuj binarki do /opt/solana/bin (zamiast symlinkow - mniej problemow z uprawnieniami)
|
||||
sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/
|
||||
sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \;
|
||||
|
||||
/opt/solana/bin/solana-keygen --version
|
||||
|
||||
6) Build `agave-validator` ze zrodel i instalacja do /opt/solana/bin
|
||||
AGAVE_VERSION_TAG="v2.3.13"
|
||||
AGAVE_RUST_TOOLCHAIN="1.86.0"
|
||||
AGAVE_SRC_DIR="/var/lib/solana/src/agave"
|
||||
|
||||
sudo -u solana -H bash -lc \
|
||||
"curl -sSfL https://sh.rustup.rs | sh -s -- -y --default-toolchain '${AGAVE_RUST_TOOLCHAIN}'"
|
||||
|
||||
sudo -u solana -H bash -lc "
|
||||
set -euo pipefail
|
||||
export PATH=/var/lib/solana/.cargo/bin:\$PATH
|
||||
rustup toolchain install '${AGAVE_RUST_TOOLCHAIN}'
|
||||
|
||||
mkdir -p '$(dirname "$AGAVE_SRC_DIR")'
|
||||
if [ ! -d '${AGAVE_SRC_DIR}/.git' ]; then
|
||||
git clone --depth 1 --branch '${AGAVE_VERSION_TAG}' https://github.com/anza-xyz/agave.git '${AGAVE_SRC_DIR}'
|
||||
else
|
||||
cd '${AGAVE_SRC_DIR}'
|
||||
git fetch --tags --prune
|
||||
git checkout '${AGAVE_VERSION_TAG}'
|
||||
fi
|
||||
|
||||
cd '${AGAVE_SRC_DIR}'
|
||||
cargo +${AGAVE_RUST_TOOLCHAIN} build --release -p agave-validator
|
||||
"
|
||||
|
||||
sudo install -o root -g root -m 0755 \
|
||||
"${AGAVE_SRC_DIR}/target/release/agave-validator" \
|
||||
/opt/solana/bin/agave-validator
|
||||
|
||||
test -x /opt/solana/bin/agave-validator
|
||||
# Najnowszy stable release dla mainnet wybieraj z GitHub Releases (tag v3.0.x).
|
||||
# Krok po kroku (w tym automatyczny wybor tagu):
|
||||
doc/step-002f-agave-build-from-source-latest.txt
|
||||
|
||||
7) Identity (tylko raz) + backup poza hostem
|
||||
if [ ! -f /var/lib/solana/identity.json ]; then
|
||||
@@ -146,14 +129,21 @@ Testnet:
|
||||
https://api.testnet.solana.com | jq -r .result)"
|
||||
echo "$GENESIS_HASH"
|
||||
|
||||
9) Systemd unit: /etc/systemd/system/solana-rpc.service
|
||||
Minimalny unit (RPC node, non-voting). Bind na 0.0.0.0 + firewall robi prywatnosc RPC.
|
||||
9) Systemd unit: /etc/systemd/system/agave-validator.service
|
||||
Minimalny unit (RPC node, non-voting). RPC/WS bind na wg0 (10.66.66.1).
|
||||
Jesli widzisz w logach:
|
||||
"error: The subcommand '\\' wasn't recognized"
|
||||
to zrob:
|
||||
doc/step-002b-agave-validator-systemd.txt
|
||||
|
||||
sudo tee /etc/systemd/system/solana-rpc.service >/dev/null <<'EOF'
|
||||
Jesli chcesz najpierw odpalic recznie z CLI (test) przed systemd:
|
||||
doc/step-002e-agave-validator-run-cli.txt
|
||||
|
||||
sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<'EOF'
|
||||
[Unit]
|
||||
Description=Solana RPC node (Agave)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Description=Agave validator (mainnet, RPC-only, non-voting)
|
||||
After=network-online.target wg-quick@wg0.service
|
||||
Wants=network-online.target wg-quick@wg0.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@@ -168,16 +158,18 @@ TimeoutStopSec=120
|
||||
ExecStart=/opt/solana/bin/agave-validator \
|
||||
--identity /var/lib/solana/identity.json \
|
||||
--no-voting \
|
||||
--private-rpc \
|
||||
--ledger /var/lib/solana/ledger \
|
||||
--accounts /var/lib/solana/accounts \
|
||||
--log /var/log/solana/validator.log \
|
||||
--bind-address 0.0.0.0 \
|
||||
--rpc-bind-address 0.0.0.0 \
|
||||
--rpc-bind-address 10.66.66.1 \
|
||||
--rpc-port 8899 \
|
||||
--dynamic-port-range 8000-8020 \
|
||||
--entrypoint entrypoint.mainnet-beta.solana.com:8001 \
|
||||
--expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \
|
||||
--full-rpc-api \
|
||||
--limit-ledger-size \
|
||||
--log /var/log/solana/validator.log
|
||||
--limit-ledger-size 50000000
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
@@ -188,20 +180,20 @@ WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now solana-rpc
|
||||
sudo systemctl enable --now agave-validator
|
||||
|
||||
Jesli chcesz dodac genesis hash:
|
||||
- dopisz w ExecStart linie:
|
||||
--expected-genesis-hash <GENESIS_HASH>
|
||||
|
||||
10) Weryfikacja
|
||||
systemctl is-active solana-rpc
|
||||
journalctl -u solana-rpc -n 200 --no-pager
|
||||
systemctl is-active agave-validator
|
||||
journalctl -u agave-validator -n 200 --no-pager
|
||||
|
||||
# z samego hosta:
|
||||
# z samego hosta (getHealth moze zwracac blad dopoki node nie dogoni klastra):
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' \
|
||||
http://127.0.0.1:8899 | jq .
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
|
||||
# z laptopa/VPS po WG:
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
@@ -211,5 +203,12 @@ Jesli chcesz dodac genesis hash:
|
||||
Jesli cos nie dziala:
|
||||
- `sudo wg show` (czy WG jest OK)
|
||||
- `sudo ufw status verbose` (czy RPC nie jest blokowane po wg0)
|
||||
- `journalctl -u solana-rpc -n 200 --no-pager` (logi Agave)
|
||||
- `journalctl -u agave-validator -n 200 --no-pager` (logi Agave)
|
||||
|
||||
Typowe fixy:
|
||||
- "error: The subcommand '\\' wasn't recognized":
|
||||
doc/step-002b-agave-validator-systemd.txt
|
||||
- "failed to open genesis" / brak `genesis.tar.bz2`:
|
||||
doc/step-002c-genesis-download-mainnet.txt
|
||||
- "did you forget to provide a snapshot" (mainnet bez snapshot nie ruszy):
|
||||
doc/step-002d-snapshot-download-mainnet.txt
|
||||
|
||||
51
doc/step-002a-storage-existing-solacct-solledg-xfs.txt
Normal file
51
doc/step-002a-storage-existing-solacct-solledg-xfs.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
Step 002A (variant): Storage na 2x NVMe (XFS juz istnieje) -> SOLACCT=accounts, SOLLEDG=ledger
|
||||
|
||||
Context (wg hosta mpabi):
|
||||
- /dev/nvme0n1p1: XFS LABEL=SOLACCT (nowy dysk na accounts)
|
||||
- /dev/nvme1n1p1: XFS LABEL=SOLLEDG (stary dysk ~63% used na ledger)
|
||||
|
||||
Cel:
|
||||
- NIE formatowac (bez kasowania danych), tylko zamontowac i spiac w /etc/fstab:
|
||||
- /var/lib/solana/accounts -> SOLACCT
|
||||
- /var/lib/solana/ledger -> SOLLEDG
|
||||
|
||||
0) Check (zanim dotkniesz fstab)
|
||||
lsblk -f
|
||||
sudo blkid /dev/nvme0n1p1 /dev/nvme1n1p1
|
||||
|
||||
# Upewnij sie, ze NIC nie jest zamontowane w /var/lib/solana/*:
|
||||
findmnt /var/lib/solana/accounts || true
|
||||
findmnt /var/lib/solana/ledger || true
|
||||
|
||||
1) Mountpointy
|
||||
sudo getent group solana >/dev/null || sudo groupadd --system solana
|
||||
sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \
|
||||
--home-dir /var/lib/solana --create-home --shell /bin/bash solana
|
||||
|
||||
sudo install -d -o solana -g solana -m 0750 /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
2) /etc/fstab (po UUID)
|
||||
UUID_ACCTS="$(sudo blkid -s UUID -o value /dev/nvme0n1p1)"
|
||||
UUID_LEDGER="$(sudo blkid -s UUID -o value /dev/nvme1n1p1)"
|
||||
|
||||
echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
|
||||
sudo mount -a
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
3) Permissions (po mount) - krytyczne
|
||||
sudo chown solana:solana /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
sudo chmod 750 /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
4) Weryfikacja
|
||||
df -hT /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
findmnt /var/lib/solana/accounts
|
||||
findmnt /var/lib/solana/ledger
|
||||
stat -c '%U:%G %a %n' /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
5) Uwaga (bezpieczenstwo / dane)
|
||||
- Jesli na SOLLEDG masz stare dane ledgera z innej instalacji, to validator moze startowac na "starym stanie".
|
||||
Wtedy najlepiej wyczyscic ledger przed pobraniem snapshotow:
|
||||
doc/step-002d-snapshot-download-mainnet.txt (sekcja czyszczenia)
|
||||
|
||||
64
doc/step-002a-storage-nvme0n1-xfs.txt
Normal file
64
doc/step-002a-storage-nvme0n1-xfs.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
Step 002A: Storage pod Solana data (nvme0n1 -> XFS -> /var/lib/solana/{ledger,accounts})
|
||||
|
||||
Cel:
|
||||
- system zostaje na md1 (/)
|
||||
- dane Solany (ledger/accounts) ida na osobny NVMe: /dev/nvme0n1
|
||||
|
||||
UWAGA: kroki nizej KASUJA dane na /dev/nvme0n1.
|
||||
|
||||
0) Check (czy nvme0n1 jest do wyczyszczenia)
|
||||
lsblk /dev/nvme0n1
|
||||
sudo wipefs -n /dev/nvme0n1
|
||||
sudo lsblk -f /dev/nvme0n1
|
||||
|
||||
1) Partycje (50/50)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y parted
|
||||
|
||||
sudo parted -s /dev/nvme0n1 mklabel gpt
|
||||
sudo parted -s /dev/nvme0n1 mkpart primary 0% 50%
|
||||
sudo parted -s /dev/nvme0n1 mkpart primary 50% 100%
|
||||
sudo partprobe /dev/nvme0n1
|
||||
sudo udevadm settle
|
||||
|
||||
lsblk /dev/nvme0n1
|
||||
ls -l /dev/nvme0n1p1 /dev/nvme0n1p2
|
||||
|
||||
2) Format XFS
|
||||
Uwaga: mkfs.xfs na Ubuntu ma limit label <= 12 znakow.
|
||||
|
||||
sudo mkfs.xfs -f -L sol_ledger /dev/nvme0n1p1
|
||||
sudo mkfs.xfs -f -L sol_accts /dev/nvme0n1p2
|
||||
sudo blkid /dev/nvme0n1p1 /dev/nvme0n1p2
|
||||
|
||||
3) Mountpointy + fstab (po UUID)
|
||||
sudo install -d -o solana -g solana -m 0750 /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
|
||||
UUID_LEDGER="$(sudo blkid -s UUID -o value /dev/nvme0n1p1)"
|
||||
UUID_ACCTS="$(sudo blkid -s UUID -o value /dev/nvme0n1p2)"
|
||||
|
||||
echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
|
||||
sudo mount -a
|
||||
|
||||
# systemd pokazuje hint po edycji fstab - to jest OK, ale zrob reload:
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
4) WAŻNE: ustaw ownera na zamontowanych filesystemach
|
||||
Po mount, root filesystemu jest domyslnie root:root 755, wiec validator uruchamiany jako solana nie zapisze ledger/accounts.
|
||||
|
||||
sudo chown solana:solana /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
sudo chmod 750 /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
|
||||
5) Weryfikacja
|
||||
df -hT /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
findmnt /var/lib/solana/ledger
|
||||
findmnt /var/lib/solana/accounts
|
||||
|
||||
stat -c '%U:%G %a %n' /var/lib/solana/ledger /var/lib/solana/accounts
|
||||
|
||||
Dla tego hosta (z wdrozenia):
|
||||
- /dev/nvme0n1p1 (LABEL=sol_ledger) UUID=56a2c342-3162-43f2-9649-e0dd25db870d
|
||||
- /dev/nvme0n1p2 (LABEL=sol_accts) UUID=ae5d6625-0910-489a-bbe3-6fd156439e03
|
||||
|
||||
79
doc/step-002b-agave-validator-systemd.txt
Normal file
79
doc/step-002b-agave-validator-systemd.txt
Normal file
@@ -0,0 +1,79 @@
|
||||
Step 002B: agave-validator pod systemd (RPC-only, non-voting) + fix na problemy z ExecStart
|
||||
|
||||
Ten krok naprawia 2 typowe bledy po wklejeniu unit-a:
|
||||
1) "error: The subcommand '\\' wasn't recognized"
|
||||
2) RPC nie startuje, bo ExecStart zostal "polamany" (brakuje --rpc-port albo --log ma sciezke do katalogu)
|
||||
|
||||
Przyczyna:
|
||||
- W unit file kontynuacja linii w ExecStart to JEDEN backslash na koncu linii: `\`
|
||||
- NIE uzywaj `\\` (dwa backslashe) bo wtedy do programu trafia literalny argument `\` i validator pada.
|
||||
- Dodatkowo: unikaj bardzo dlugich linii, bo clipboard/paste potrafi je rozciac (i systemd wtedy ignoruje reszte).
|
||||
|
||||
0) Stop/wycisz restart loop
|
||||
sudo systemctl disable --now agave-validator
|
||||
sudo systemctl reset-failed agave-validator
|
||||
|
||||
1) Wrzuc poprawny unit (wielolinijkowy ExecStart z poprawna kontynuacja `\`)
|
||||
sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<'EOF'
|
||||
[Unit]
|
||||
Description=Agave validator (mainnet, RPC-only, non-voting)
|
||||
After=network-online.target wg-quick@wg0.service
|
||||
Wants=network-online.target wg-quick@wg0.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=solana
|
||||
Group=solana
|
||||
WorkingDirectory=/var/lib/solana
|
||||
Environment=RUST_LOG=info
|
||||
LimitNOFILE=1048576
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
TimeoutStopSec=120
|
||||
ExecStart=/opt/solana/bin/agave-validator \
|
||||
--identity /var/lib/solana/identity.json \
|
||||
--no-voting \
|
||||
--private-rpc \
|
||||
--ledger /var/lib/solana/ledger \
|
||||
--accounts /var/lib/solana/accounts \
|
||||
--log /var/log/solana/validator.log \
|
||||
--bind-address 0.0.0.0 \
|
||||
--rpc-bind-address 10.66.66.1 \
|
||||
--rpc-port 8899 \
|
||||
--dynamic-port-range 8000-8025 \
|
||||
--entrypoint entrypoint.mainnet-beta.solana.com:8001 \
|
||||
--entrypoint entrypoint2.mainnet-beta.solana.com:8001 \
|
||||
--entrypoint entrypoint3.mainnet-beta.solana.com:8001 \
|
||||
--expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \
|
||||
--full-rpc-api \
|
||||
--limit-ledger-size 50000000 \
|
||||
--geyser-plugin-config /etc/solana/yellowstone-geyser.json
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
ReadWritePaths=/var/lib/solana/ledger /var/lib/solana/accounts /var/log/solana /var/lib/solana
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
2) Reload + start
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now agave-validator
|
||||
|
||||
3) Weryfikacja (na hoście)
|
||||
# Sprawdz, czy systemd widzi kompletne argv[] (ma byc --rpc-port 8899 i poprawna sciezka --log):
|
||||
systemctl show agave-validator -p ExecStart --no-pager
|
||||
|
||||
sudo systemctl status agave-validator --no-pager -l
|
||||
|
||||
# Czy porty sluchaja (RPC/WS na wg0):
|
||||
sudo ss -lntp | egrep ':8899\\b|:8900\\b' || true
|
||||
|
||||
# getHealth moze zwracac blad dopoki node nie dogoni klastra, wiec sprawdz getVersion:
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
|
||||
# Logi:
|
||||
sudo journalctl -u agave-validator -n 120 --no-pager
|
||||
34
doc/step-002c-genesis-download-mainnet.txt
Normal file
34
doc/step-002c-genesis-download-mainnet.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
Step 002C: Download genesis (mainnet) do /var/lib/solana/ledger (fix na "failed to open genesis")
|
||||
|
||||
Objaw w logach:
|
||||
Failed to load genesis_config ... missing genesis.bin
|
||||
Extracting "/var/lib/solana/ledger/genesis.tar.bz2"...
|
||||
Failed to start validator: failed to open genesis ... No such file or directory
|
||||
|
||||
Fix:
|
||||
- Zaciagnij genesis archive na dysk i zrestartuj serwis.
|
||||
|
||||
1) Zatrzymaj validator (zeby nie robil restart loop)
|
||||
sudo systemctl stop agave-validator
|
||||
|
||||
2) Pobierz genesis.tar.bz2 do ledger (jako user `solana`)
|
||||
sudo -u solana -H bash -lc '
|
||||
cd /var/lib/solana/ledger
|
||||
rm -f genesis.tar.bz2 genesis.bin
|
||||
curl -sSfL https://api.mainnet-beta.solana.com/genesis.tar.bz2 -o genesis.tar.bz2
|
||||
ls -lh genesis.tar.bz2
|
||||
'
|
||||
|
||||
Oczekiwane:
|
||||
- plik genesis.tar.bz2 istnieje (ok. kilkadziesiat KB)
|
||||
|
||||
3) Start + logi
|
||||
sudo systemctl start agave-validator
|
||||
systemctl status agave-validator --no-pager -l
|
||||
sudo journalctl -u agave-validator -n 80 --no-pager
|
||||
|
||||
4) RPC check (local/WG)
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
|
||||
49
doc/step-002d-snapshot-download-mainnet.txt
Normal file
49
doc/step-002d-snapshot-download-mainnet.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
Step 002D: Download snapshot (mainnet) do /var/lib/solana/ledger (wymagane na mainnet)
|
||||
|
||||
Objaw (bez snapshot):
|
||||
Failed to start validator: ... did you forget to provide a snapshot
|
||||
|
||||
UWAGA:
|
||||
- Snapshot full jest DUZY (setki GB). Ten krok moze trwac dlugo.
|
||||
- Pobieramy full + incremental z oficjalnego endpointu (api.mainnet-beta.solana.com).
|
||||
|
||||
0) Stop validator
|
||||
sudo systemctl stop agave-validator
|
||||
|
||||
1) (Opcjonalnie, polecane) wyczysc stare dane ledger (zostaw genesis.*)
|
||||
sudo -u solana -H bash -lc '
|
||||
cd /var/lib/solana/ledger
|
||||
rm -rf rocksdb snapshots accounts_index accounts_hash_cache admin.rpc ledger.lock
|
||||
ls -la | head
|
||||
'
|
||||
|
||||
2) Pobierz FULL + INCREMENTAL snapshot do ledger (jako user `solana`)
|
||||
sudo -u solana -H bash -lc '
|
||||
set -euo pipefail
|
||||
cd /var/lib/solana/ledger
|
||||
|
||||
FULL_REL="$(curl -sI https://api.mainnet-beta.solana.com/snapshot.tar.bz2 | awk "/^location:/{print \\$2}" | tr -d "\\r")"
|
||||
INC_REL="$(curl -sI https://api.mainnet-beta.solana.com/incremental-snapshot.tar.bz2 | awk "/^location:/{print \\$2}" | tr -d "\\r")"
|
||||
|
||||
echo "FULL_REL=$FULL_REL"
|
||||
echo "INC_REL=$INC_REL"
|
||||
|
||||
FULL_URL="https://api.mainnet-beta.solana.com${FULL_REL}"
|
||||
INC_URL="https://api.mainnet-beta.solana.com${INC_REL}"
|
||||
|
||||
FULL_FILE="$(basename "$FULL_REL")"
|
||||
INC_FILE="$(basename "$INC_REL")"
|
||||
|
||||
echo "Downloading FULL: $FULL_FILE"
|
||||
curl -fSL "$FULL_URL" -o "$FULL_FILE"
|
||||
ls -lh "$FULL_FILE"
|
||||
|
||||
echo "Downloading INC: $INC_FILE"
|
||||
curl -fSL "$INC_URL" -o "$INC_FILE"
|
||||
ls -lh "$INC_FILE"
|
||||
'
|
||||
|
||||
3) Start validator + logi
|
||||
sudo systemctl start agave-validator
|
||||
sudo journalctl -u agave-validator -n 80 --no-pager
|
||||
|
||||
71
doc/step-002e-agave-validator-run-cli.txt
Normal file
71
doc/step-002e-agave-validator-run-cli.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
Step 002E: Start agave-validator z linii polecen (test przed systemd)
|
||||
|
||||
Cel:
|
||||
- Odpalic `agave-validator` recznie (w tmux), potwierdzic ze RPC dziala.
|
||||
- Dopiero potem przepiac na systemd (Step 002B).
|
||||
|
||||
Preconditions:
|
||||
- Masz genesis + snapshoty:
|
||||
- doc/step-002c-genesis-download-mainnet.txt
|
||||
- doc/step-002d-snapshot-download-mainnet.txt
|
||||
- WireGuard dziala (RPC ma byc prywatne po wg0).
|
||||
|
||||
0) Upewnij sie, ze systemd nie trzyma procesu na portach
|
||||
```bash
|
||||
sudo systemctl stop agave-validator || true
|
||||
sudo systemctl disable agave-validator || true
|
||||
```
|
||||
|
||||
1) Odpal w tmux (zeby proces nie zginal po rozlaczeniu SSH)
|
||||
```bash
|
||||
tmux new -s agave-rpc
|
||||
```
|
||||
|
||||
2) Start (dzialajaca komenda z wdrozenia)
|
||||
```bash
|
||||
sudo bash -lc '
|
||||
set -euo pipefail
|
||||
ulimit -n 1048576
|
||||
exec sudo -u solana -H /opt/solana/bin/agave-validator \
|
||||
--identity /var/lib/solana/identity.json \
|
||||
--no-voting \
|
||||
--private-rpc \
|
||||
--ledger /var/lib/solana/ledger \
|
||||
--accounts /var/lib/solana/accounts \
|
||||
--log - \
|
||||
--bind-address 0.0.0.0 \
|
||||
--rpc-bind-address 10.66.66.1 \
|
||||
--rpc-port 8899 \
|
||||
--dynamic-port-range 8000-8020 \
|
||||
--entrypoint entrypoint.mainnet-beta.solana.com:8001 \
|
||||
--entrypoint entrypoint2.mainnet-beta.solana.com:8001 \
|
||||
--entrypoint entrypoint3.mainnet-beta.solana.com:8001 \
|
||||
--expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \
|
||||
--full-rpc-api \
|
||||
--limit-ledger-size 50000000
|
||||
'
|
||||
```
|
||||
|
||||
3) Weryfikacja (w drugim oknie / innym terminalu)
|
||||
```bash
|
||||
ss -lnt | egrep ':8899\\b|:8900\\b' || true
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
```
|
||||
|
||||
4) Detach z tmux
|
||||
- `Ctrl+b d`
|
||||
|
||||
5) Stop (gdy chcesz zatrzymac recznie)
|
||||
- `tmux attach -t agave-rpc`
|
||||
- `Ctrl+c` (zatrzyma validator)
|
||||
- `exit`
|
||||
|
||||
Next:
|
||||
- Jak komenda dziala stabilnie, wrzuc unit i odpal przez systemd:
|
||||
doc/step-002b-agave-validator-systemd.txt
|
||||
|
||||
70
doc/step-002f-agave-build-from-source-latest.txt
Normal file
70
doc/step-002f-agave-build-from-source-latest.txt
Normal file
@@ -0,0 +1,70 @@
|
||||
Step 002F: Build Agave (agave-validator) z najnowszych zrodel (pin do releasu) i instalacja do /opt/solana/bin
|
||||
|
||||
Cel:
|
||||
- Zbudowac `agave-validator` ze zrodel z pinu do konkretnego releasu (stable dla mainnet).
|
||||
- Nie robic "floating HEAD" (zeby nie wjechal update bez kontroli).
|
||||
|
||||
Konwencja:
|
||||
- "najnowsza wersja" = najnowszy stabilny release dla mainnet z GitHub Releases repo `anza-xyz/agave`.
|
||||
(Zweryfikuj przed startem: tag typu v3.0.x.)
|
||||
|
||||
0) Packages (build deps)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential pkg-config libssl-dev \
|
||||
clang llvm-dev libclang-dev \
|
||||
cmake protobuf-compiler libudev-dev zlib1g-dev \
|
||||
curl jq git ca-certificates
|
||||
|
||||
1) Uzytkownik + katalogi
|
||||
sudo getent group solana >/dev/null || sudo groupadd --system solana
|
||||
sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \
|
||||
--home-dir /var/lib/solana --create-home --shell /bin/bash solana
|
||||
|
||||
sudo install -d -o root -g root -m 0755 /opt/solana/bin
|
||||
sudo install -d -o solana -g solana -m 0750 /var/lib/solana/src
|
||||
|
||||
2) Wybierz tag releasu (stable dla mainnet)
|
||||
# Opcja A (manual): sprawdz Releases i wpisz tag, np.:
|
||||
AGAVE_VERSION_TAG="v3.0.13"
|
||||
|
||||
# Opcja B (CLI): pobierz liste tagow i wybierz najwyzszy semver (bez rc/beta)
|
||||
# (Uwaga: to korzysta z network; jesli nie masz neta - uzyj opcji A.)
|
||||
AGAVE_VERSION_TAG="$(
|
||||
git ls-remote --refs --tags https://github.com/anza-xyz/agave.git 'v*' \
|
||||
| awk -F/ '{print $NF}' \
|
||||
| rg -v '(rc|beta|alpha)' \
|
||||
| sort -V \
|
||||
| tail -n1
|
||||
)"
|
||||
echo "AGAVE_VERSION_TAG=$AGAVE_VERSION_TAG"
|
||||
|
||||
3) Rust toolchain
|
||||
# Rekomendacja: uzyj rustup (Agave ma pinned toolchain w repo).
|
||||
sudo -u solana -H bash -lc 'command -v rustup >/dev/null 2>&1 || (curl -sSfL https://sh.rustup.rs | sh -s -- -y)'
|
||||
|
||||
4) Clone + build (pin do tagu)
|
||||
AGAVE_SRC_DIR="/var/lib/solana/src/agave-${AGAVE_VERSION_TAG}"
|
||||
|
||||
sudo -u solana -H bash -lc "
|
||||
set -euo pipefail
|
||||
export PATH=/var/lib/solana/.cargo/bin:\$PATH
|
||||
rm -rf \"${AGAVE_SRC_DIR}\"
|
||||
git clone --depth 1 --branch \"${AGAVE_VERSION_TAG}\" https://github.com/anza-xyz/agave.git \"${AGAVE_SRC_DIR}\"
|
||||
cd \"${AGAVE_SRC_DIR}\"
|
||||
|
||||
# Agave ma wrapper `./cargo`, ktory bierze pinned toolchain z repo.
|
||||
./cargo build --release -p agave-validator
|
||||
"
|
||||
|
||||
5) Install do /opt/solana/bin
|
||||
sudo install -o root -g root -m 0755 \
|
||||
"${AGAVE_SRC_DIR}/target/release/agave-validator" \
|
||||
/opt/solana/bin/agave-validator
|
||||
|
||||
/opt/solana/bin/agave-validator --version
|
||||
|
||||
6) Uwagi (operacyjne)
|
||||
- Jesli budujesz pluginy (Geyser), trzymaj je na tym samym pinned releasie i najlepiej w tej samej "epoce" API.
|
||||
- Po update do nowego releasu: buduj validator + pluginy ponownie i restartuj systemd.
|
||||
|
||||
264
doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt
Normal file
264
doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt
Normal file
@@ -0,0 +1,264 @@
|
||||
Runbook (mpabi): Agave RPC (mainnet, private) + Geyser plugin -> Postgres
|
||||
|
||||
Cel:
|
||||
- Na mpabi odpalic prywatny Agave RPC (non-voting) po WireGuard (wg0).
|
||||
- Zbudowac Agave ze zrodel (pinned release).
|
||||
- (Po starcie) dodac Geyser plugin zapisujacy do PostgreSQL.
|
||||
|
||||
Skrot (kolejnosc):
|
||||
1) Preconditions: WG + UFW (SSH tylko po wg0).
|
||||
2) Storage: SOLACCT->/var/lib/solana/accounts, SOLLEDG->/var/lib/solana/ledger (+ decyzja: wipe czy kontynuacja).
|
||||
3) Pakiety + sysctl/limits.
|
||||
4) /opt/solana/bin: Anza tools (solana-keygen itd.).
|
||||
5) Build Agave ze zrodel (pin tag) + install do /opt/solana/bin/agave-validator.
|
||||
6) Identity (0600).
|
||||
7) Genesis + snapshot (mainnet).
|
||||
8) Systemd: agave-validator (User=solana) + RPC smoke test po WG.
|
||||
9) Geyser plugin -> Postgres + dopiecie do systemd + weryfikacja.
|
||||
|
||||
Konwencja:
|
||||
- Komendy uruchamiasz jako user: `user` (z sudo).
|
||||
- Validator dziala jako uzytkownik systemowy: `solana`.
|
||||
- Biny instalujemy do /opt/solana/bin (root-owned, stabilne sciezki).
|
||||
- Dane runtime:
|
||||
- ledger: /var/lib/solana/ledger (SOLLEDG = /dev/nvme1n1p1)
|
||||
- accounts: /var/lib/solana/accounts (SOLACCT = /dev/nvme0n1p1)
|
||||
|
||||
Parametry hosta (mpabi):
|
||||
- Public iface: enp6s0, public IP: 149.50.116.219
|
||||
- WireGuard iface: wg0, WG IP: 10.66.66.1
|
||||
- RPC: 8899, WS: 8900
|
||||
- Cluster inbound UDP: 8000-8020 (na public)
|
||||
|
||||
=====================
|
||||
0) Preconditions
|
||||
=====================
|
||||
1) WireGuard up:
|
||||
ip -4 a show wg0
|
||||
wg show
|
||||
|
||||
2) SSH powinno byc tylko po wg0 (defense-in-depth):
|
||||
sudo ufw status verbose
|
||||
|
||||
3) Upewnij sie, ze masz sudo do operacji operatorskich (systemctl/journalctl/ufw).
|
||||
|
||||
=====================
|
||||
1) Storage: mount SOLACCT/SOLLEDG
|
||||
=====================
|
||||
UWAGA: ten wariant NIE formatuje dyskow (bez kasowania), tylko montuje istniejace XFS.
|
||||
|
||||
UUIDs (wg lsblk -f):
|
||||
- SOLACCT: 055bf4e7-00f0-45a0-a995-2413b14428c4 (/dev/nvme0n1p1)
|
||||
- SOLLEDG: 6ac7a8c6-efc7-4803-a3dc-a66ea2ef0125 (/dev/nvme1n1p1)
|
||||
|
||||
1) (Opcjonalnie) obejrzyj co zajmuje SOLLEDG (zanim podepniesz pod /var/lib/solana/ledger):
|
||||
sudo mkdir -p /mnt/solledg
|
||||
sudo mount /dev/nvme1n1p1 /mnt/solledg
|
||||
sudo du -sh /mnt/solledg/* 2>/dev/null | sort -h | tail
|
||||
sudo umount /mnt/solledg
|
||||
|
||||
2) Utworz usera solana + mountpointy:
|
||||
sudo getent group solana >/dev/null || sudo groupadd --system solana
|
||||
sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \
|
||||
--home-dir /var/lib/solana --create-home --shell /bin/bash solana
|
||||
|
||||
sudo install -d -o solana -g solana -m 0750 /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
3) Dodaj wpisy do /etc/fstab (sprawdz czy nie ma juz duplikatow):
|
||||
grep -nE '(/var/lib/solana/(accounts|ledger))' /etc/fstab || true
|
||||
|
||||
UUID_ACCTS="055bf4e7-00f0-45a0-a995-2413b14428c4"
|
||||
UUID_LEDGER="6ac7a8c6-efc7-4803-a3dc-a66ea2ef0125"
|
||||
|
||||
echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null
|
||||
|
||||
sudo mount -a
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
4) Permissions (krytyczne):
|
||||
sudo chown solana:solana /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
sudo chmod 750 /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
5) Verify:
|
||||
df -hT /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
findmnt /var/lib/solana/accounts
|
||||
findmnt /var/lib/solana/ledger
|
||||
stat -c '%U:%G %a %n' /var/lib/solana/accounts /var/lib/solana/ledger
|
||||
|
||||
DECYZJA: co robimy z SOLLEDG (63% used)?
|
||||
- Opcja A: zostawiamy (jesli to stary ledger Solany i chcesz kontynuowac).
|
||||
- Opcja B: czyscimy i robimy sync od nowa (destrukcyjne, rekomendowane dla powtarzalnosci):
|
||||
sudo systemctl stop agave-validator 2>/dev/null || true
|
||||
sudo -u solana -H bash -lc '
|
||||
cd /var/lib/solana/ledger
|
||||
rm -rf rocksdb snapshots accounts_index accounts_hash_cache admin.rpc ledger.lock
|
||||
'
|
||||
|
||||
=====================
|
||||
2) Pakiety + sysctl/limits
|
||||
=====================
|
||||
1) Pakiety:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
chrony curl jq git ca-certificates ripgrep \
|
||||
smartmontools nvme-cli \
|
||||
build-essential pkg-config libssl-dev \
|
||||
clang llvm-dev libclang-dev \
|
||||
cmake protobuf-compiler libudev-dev zlib1g-dev
|
||||
|
||||
2) Sysctl:
|
||||
sudo tee /etc/sysctl.d/90-agave.conf >/dev/null <<'EOF'
|
||||
fs.file-max = 2000000
|
||||
vm.max_map_count = 1000000
|
||||
net.core.somaxconn = 65535
|
||||
net.core.netdev_max_backlog = 250000
|
||||
net.core.rmem_max = 134217728
|
||||
net.core.wmem_max = 134217728
|
||||
EOF
|
||||
sudo sysctl --system
|
||||
|
||||
3) ulimit:
|
||||
sudo tee /etc/security/limits.d/90-solana.conf >/dev/null <<'EOF'
|
||||
* soft nofile 1000000
|
||||
* hard nofile 1000000
|
||||
EOF
|
||||
|
||||
=====================
|
||||
3) Firewall (UFW) dla prywatnego RPC
|
||||
=====================
|
||||
Docelowo:
|
||||
- SSH 22/tcp: tylko wg0
|
||||
- RPC 8899/tcp, WS 8900/tcp: tylko wg0 (dodatkowo bind na 10.66.66.1)
|
||||
- WireGuard: 51820/udp (public)
|
||||
- Cluster sync: 8000-8020/udp (public)
|
||||
|
||||
Komendy (jesli jeszcze nie ustawione):
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw allow 51820/udp
|
||||
|
||||
sudo ufw allow in on wg0 to any port 22 proto tcp
|
||||
sudo ufw deny in on enp6s0 to any port 22 proto tcp
|
||||
|
||||
sudo ufw allow in on wg0 to any port 8899 proto tcp
|
||||
sudo ufw allow in on wg0 to any port 8900 proto tcp
|
||||
sudo ufw deny in on enp6s0 to any port 8899 proto tcp
|
||||
sudo ufw deny in on enp6s0 to any port 8900 proto tcp
|
||||
|
||||
sudo ufw allow in on enp6s0 to any port 8000:8020 proto udp
|
||||
|
||||
sudo ufw enable
|
||||
sudo ufw status verbose
|
||||
|
||||
=====================
|
||||
4) Instalacja narzedzi Solana/Anza do /opt/solana/bin
|
||||
=====================
|
||||
1) Installer (jako solana):
|
||||
sudo install -d -o root -g root -m 0755 /opt/solana/bin
|
||||
sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"'
|
||||
|
||||
2) Skopiuj biny do /opt/solana/bin:
|
||||
sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/
|
||||
sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \;
|
||||
|
||||
3) Verify:
|
||||
/opt/solana/bin/solana --version || true
|
||||
/opt/solana/bin/solana-keygen --version
|
||||
|
||||
=====================
|
||||
5) Build + install agave-validator (pinned latest stable)
|
||||
=====================
|
||||
Patrz:
|
||||
- trade-iac/doc/step-002f-agave-build-from-source-latest.txt
|
||||
|
||||
Skrót:
|
||||
1) Wybierz TAG (np. v3.0.x) i zbuduj jako solana do /var/lib/solana/src/
|
||||
2) Zainstaluj binarke do /opt/solana/bin/agave-validator
|
||||
3) Verify:
|
||||
/opt/solana/bin/agave-validator --version
|
||||
|
||||
=====================
|
||||
6) Identity
|
||||
=====================
|
||||
1) Utworz raz:
|
||||
if [ ! -f /var/lib/solana/identity.json ]; then
|
||||
sudo -u solana -H /opt/solana/bin/solana-keygen new --no-passphrase -o /var/lib/solana/identity.json
|
||||
sudo chown solana:solana /var/lib/solana/identity.json
|
||||
sudo chmod 0600 /var/lib/solana/identity.json
|
||||
fi
|
||||
|
||||
2) Zapisz pubkey do notatek:
|
||||
sudo -u solana -H /opt/solana/bin/solana-keygen pubkey /var/lib/solana/identity.json
|
||||
|
||||
=====================
|
||||
7) Genesis + snapshot (mainnet)
|
||||
=====================
|
||||
1) Genesis:
|
||||
patrz: trade-iac/doc/step-002c-genesis-download-mainnet.txt
|
||||
|
||||
2) Snapshot (wymagany na mainnet):
|
||||
patrz: trade-iac/doc/step-002d-snapshot-download-mainnet.txt
|
||||
|
||||
=====================
|
||||
8) Systemd: agave-validator (RPC-only)
|
||||
=====================
|
||||
Unit template:
|
||||
- trade-iac/doc/step-002b-agave-validator-systemd.txt
|
||||
|
||||
Wazne:
|
||||
- `User=solana`
|
||||
- `--rpc-bind-address 10.66.66.1`
|
||||
- `--private-rpc`
|
||||
- nie uzywaj `\\` w ExecStart (tylko pojedynczy `\` na koncu linii)
|
||||
|
||||
Start/verify:
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now agave-validator
|
||||
systemctl is-active agave-validator
|
||||
sudo journalctl -u agave-validator -n 120 --no-pager
|
||||
|
||||
RPC smoke test (po WG):
|
||||
curl -sS -H 'content-type: application/json' \
|
||||
--data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \
|
||||
http://10.66.66.1:8899 | jq .
|
||||
|
||||
Manual run (exports + komenda w plikach na mpabi):
|
||||
# Zawiera "solana export" (PATH + SOLANA_RPC_URL) i helper `agave_run()`:
|
||||
# - /etc/solana/agave-env.sh
|
||||
# - /etc/solana/agave-validator.args
|
||||
sudo -u solana -H bash -lc 'source /etc/solana/agave-env.sh; agave_run'
|
||||
|
||||
=====================
|
||||
9) Geyser plugin -> PostgreSQL
|
||||
=====================
|
||||
Krok po kroku:
|
||||
- trade-iac/doc/step-003-geyser-plugin-postgres.txt
|
||||
|
||||
Skrót:
|
||||
1) Postgres:
|
||||
sudo apt-get install -y postgresql
|
||||
sudo systemctl enable --now postgresql
|
||||
|
||||
2) DB/user:
|
||||
sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'geyser') THEN
|
||||
CREATE ROLE geyser LOGIN PASSWORD 'CHANGE_ME';
|
||||
END IF;
|
||||
END $$;
|
||||
CREATE DATABASE geyser OWNER geyser;
|
||||
SQL
|
||||
|
||||
3) Build plugin (.so) i instaluj do /opt/solana/plugins/
|
||||
4) Skopiuj example JSON config do /etc/solana/geyser-postgres.json, ustaw DSN, selektory.
|
||||
5) Dopisz do unit ExecStart:
|
||||
--geyser-plugin-config /etc/solana/geyser-postgres.json
|
||||
i zrestartuj:
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart agave-validator
|
||||
|
||||
Verify:
|
||||
sudo journalctl -u agave-validator -n 200 --no-pager | rg -i 'geyser|plugin|postgres' || true
|
||||
sudo -u postgres psql -d geyser -c '\\dt' | head
|
||||
122
doc/step-003-geyser-plugin-postgres.txt
Normal file
122
doc/step-003-geyser-plugin-postgres.txt
Normal file
@@ -0,0 +1,122 @@
|
||||
Step 003: Geyser plugin -> PostgreSQL (Agave) na prywatnym RPC node
|
||||
|
||||
Cel:
|
||||
- Wlaczyc Geyser plugin zapisujacy eventy do Postgresa.
|
||||
- Na poczatek: dzialajace end-to-end (plugin laduje sie w validatorze + dane wpadaja do DB).
|
||||
|
||||
Wazne ryzyka:
|
||||
- Pisanie wszystkiego do Postgresa na mainnet generuje OGROMNY write load.
|
||||
Jezeli DB bedzie na tym samym hoście co validator, latwo o IO contention i spadek performance sync.
|
||||
- Rekomendacja: startuj od selektorow (filtrow), np. tylko programy ktore bot potrzebuje.
|
||||
|
||||
0) Preconditions
|
||||
- Agave dziala pod systemd:
|
||||
- doc/step-002b-agave-validator-systemd.txt
|
||||
- Masz pinned Agave release (tag) i go nie zmieniasz "w locie":
|
||||
- doc/step-002f-agave-build-from-source-latest.txt
|
||||
|
||||
1) Postgres (lokalnie, minimalny setup)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y postgresql postgresql-contrib
|
||||
sudo systemctl enable --now postgresql
|
||||
|
||||
# DB + user (dostosuj haslo; nie commituj do repo)
|
||||
sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'geyser') THEN
|
||||
CREATE ROLE geyser LOGIN PASSWORD 'CHANGE_ME';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE DATABASE geyser OWNER geyser;
|
||||
SQL
|
||||
|
||||
2) Build plugin ze zrodel (Anza Agave plugin Postgres)
|
||||
# Repo:
|
||||
# https://github.com/anza-xyz/agave-geyser-plugin-postgres
|
||||
#
|
||||
# Uwaga: plugin i validator musza byc kompatybilne wersjami interfejsu.
|
||||
# Najbezpieczniej: build pluginu po update Agave i test "plugin loaded".
|
||||
#
|
||||
# Opcjonalnie: pin plugin do tagu/commit (np. pod ten sam release co Agave).
|
||||
# PLUGIN_REF="main" # albo tag/commit
|
||||
|
||||
sudo install -d -o root -g root -m 0755 /opt/solana/plugins
|
||||
sudo install -d -o solana -g solana -m 0750 /var/lib/solana/src
|
||||
|
||||
PLUGIN_SRC_DIR="/var/lib/solana/src/agave-geyser-plugin-postgres"
|
||||
|
||||
sudo -u solana -H bash -lc "
|
||||
set -euo pipefail
|
||||
export PATH=/var/lib/solana/.cargo/bin:\$PATH
|
||||
rm -rf \"${PLUGIN_SRC_DIR}\"
|
||||
git clone https://github.com/anza-xyz/agave-geyser-plugin-postgres.git \"${PLUGIN_SRC_DIR}\"
|
||||
cd \"${PLUGIN_SRC_DIR}\"
|
||||
if [ \"${PLUGIN_REF:-main}\" != \"main\" ]; then git checkout \"${PLUGIN_REF}\"; fi
|
||||
cargo build --release
|
||||
"
|
||||
|
||||
# Typowa nazwa .so (sprawdz `ls target/release/*.so`):
|
||||
sudo cp -a "${PLUGIN_SRC_DIR}"/target/release/*.so /opt/solana/plugins/
|
||||
sudo chmod 0755 /opt/solana/plugins/*.so
|
||||
|
||||
3) Schema w Postgres
|
||||
# Plugin repo ma SQL do stworzenia schematu. Najpierw znajdz plik:
|
||||
sudo -u solana -H bash -lc '
|
||||
cd /var/lib/solana/src/agave-geyser-plugin-postgres
|
||||
find . -maxdepth 3 -type f -iname \"*schema*.sql\" -o -type f -iname \"create*.sql\" | sort
|
||||
'
|
||||
|
||||
# Potem wykonaj jako postgres na DB geyser (podmien sciezke na znaleziony plik):
|
||||
# sudo -u postgres psql -d geyser -f /var/lib/solana/src/agave-geyser-plugin-postgres/scripts/create_schema.sql
|
||||
|
||||
4) Konfig pluginu (JSON)
|
||||
# Najbezpieczniej: skopiuj example config z repo pluginu i zmien tylko:
|
||||
# - sciezke do .so
|
||||
# - connection string
|
||||
# - selektory (na poczatek mozesz dac \"*\" tylko na smoke test, potem zawęz)
|
||||
#
|
||||
# Znajdz przyklad w repo:
|
||||
sudo -u solana -H bash -lc '
|
||||
cd /var/lib/solana/src/agave-geyser-plugin-postgres
|
||||
find . -maxdepth 4 -type f -iname \"*.json\" | sort
|
||||
rg -n \"connection_str|libpath|accounts_selector|transaction_selector|selector\" -S . || true
|
||||
'
|
||||
|
||||
sudo install -d -o root -g root -m 0755 /etc/solana
|
||||
|
||||
# Start od skopiowania example (podmien sciezke jesli repo ma inna nazwe pliku):
|
||||
# sudo cp -a /var/lib/solana/src/agave-geyser-plugin-postgres/config.json /etc/solana/geyser-postgres.json
|
||||
|
||||
# Uprawnienia: config zawiera haslo, ale validator (User=solana) musi go czytac.
|
||||
if [ -f /etc/solana/geyser-postgres.json ]; then
|
||||
sudo chown root:solana /etc/solana/geyser-postgres.json
|
||||
sudo chmod 0640 /etc/solana/geyser-postgres.json
|
||||
fi
|
||||
|
||||
5) Wlaczenie pluginu w agave-validator (systemd)
|
||||
# Sprawdz, jak na Twojej wersji nazywa sie flaga:
|
||||
/opt/solana/bin/agave-validator --help | rg -n \"geyser|plugin\" || true
|
||||
|
||||
# Docelowo (w unit file) dopisz:
|
||||
# --geyser-plugin-config /etc/solana/geyser-postgres.json
|
||||
#
|
||||
# Nastepnie:
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart agave-validator
|
||||
|
||||
6) Weryfikacja
|
||||
sudo journalctl -u agave-validator -n 200 --no-pager | rg -i \"geyser|plugin|postgres\" || true
|
||||
|
||||
# Czy w DB pojawiaja sie tabele (zalezy od schema.sql):
|
||||
sudo -u postgres psql -d geyser -c \"\\dt\" | head
|
||||
|
||||
# Czy rosną inserty (przyklad - dostosuj nazwy tabel):
|
||||
# sudo -u postgres psql -d geyser -c 'select count(*) from account;'
|
||||
|
||||
7) Performance (minimum sanity)
|
||||
- Jezeli validator zacznie znacząco odstawać, zacznij od:
|
||||
- zawężenia selektorow (unikaj \"*\" po smoke tescie)
|
||||
- zmniejszenia batch/threads
|
||||
- przeniesienia DB na osobny host (lub przynajmniej na osobny NVMe)
|
||||
Reference in New Issue
Block a user