CosmosをはじめとしてCosmos-SDKのノードを立てる際にドキュメントを見ているとCosmovisorを使えよって書いてあると思う。
アップグレードを自動で行ってくれる便利ツールってのは知ってるけどわざわざ使うのはめんどくさいな。仕組みもわかってないし、止まった時にどう対応すればいいかわからないし、なんて思っていることもあったが、出てから結構経って安定もしていると思うのでまとめてみる。
Cosmovisorとは
チェインのバイナリ(gaiadなど)を起動したりするデーモン。cosmovisorコマンド経由でgaiadなどを起動させる。チェインのアップグレードをログから検知すると新しいバイナリをDLしてアクティベーション時に自動で差し替えてくれる優れもの。(バイナリの自動DLは推奨されていないぞ)
Cosmos-sdkの一部になっていてリポジトリ内にあるのでちょっと探しずらい。
https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor
インストール
ここを参考にやっていく。
Github ReleaseにバイナリがあるのでそれをDLしてもよいし、go installでやってもよいと。
go installはバイナリの場所を見失うので、今回は前者で行う。Releaseページからcosmovisorで検索してバイナリゲット。
DLして~/bin/に配置
cosvi@deroris:~/Downloads$ wget -q https://github.com/cosmos/cosmos-sdk/releases/download/cosmovisor%2Fv1.7.1/cosmovisor-v1.7.1-linux-amd64.tar.gz
cosvi@deroris:~/Downloads$ tar zxfv cosmovisor-v1.7.1-linux-amd64.tar.gz
CHANGELOG.md
README.md
cosmovisor
cosvi@deroris:~/Downloads$ cp cosmovisor ~/bin/
cosvi@deroris:~/Downloads$ cosmovisor version
cosmovisor version: (devel)
Error: failed to run version command: DAEMON_NAME is not set
DAEMON_HOME is not set
DAEMON_DATA_BACKUP_DIR must not be empty
-
cosmovisor run
: 設定したバイナリを実行する。cosmovisor run start
->gaiad start
-
cosmovisor config
: 現在の設定を表示する。設定は環境変数で渡すので、それの値がでる。
cosmovisorセットアップ
使用するバイナリを設定する。環境変数もしくはconfigファイルで渡す。前者がデファクトのようだ。
ENVを食わせてcosmovisor initコマンドを使うとディレクトリを掘ってくれる。試しにgaiadをDLして配置してもらう。
cosvi@deroris:~/Downloads$ wget -q https://github.com/cosmos/gaia/releases/download/v25.1.0/gaiad-v25.1.0-linux-amd64
cosvi@deroris:~$ mkdir -p ~/data/cosmoshub-testnet
export DAEMON_NAME=gaiad
export DAEMON_HOME=~/data/cosmoshub-testnet
export DAEMON_ALLOW_DOWNLOAD_BINARIES=true
export DAEMON_DOWNLOAD_MUST_HAVE_CHECKSUM=true
cosvi@deroris:~/Downloads$ cosmovisor init ./gaiad-v25.1.0-linux-amd64
5:15PM INF checking on the genesis/bin directory module=cosmovisor
5:15PM INF creating directory (and any parents): "/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin" module=cosmovisor
5:15PM INF checking on the genesis/bin executable module=cosmovisor
5:15PM INF copying executable into place: "/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad" module=cosmovisor
5:15PM INF making sure "/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad" is executable module=cosmovisor
5:15PM INF checking on the current symlink and creating it if needed module=cosmovisor
5:15PM INF the current symlink points to: "/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad" module=cosmovisor
5:15PM INF cosmovisor config.toml created at: /home/cosvi/data/cosmoshub-testnet/cosmovisor/config.toml module=cosmovisor
cosvi@deroris:~/Downloads$ tree ~/data/cosmoshub-testnet/
/home/cosvi/data/cosmoshub-testnet/
└── cosmovisor
├── config.toml
├── current -> genesis
└── genesis
└── bin
└── gaiad
5 directories, 2 files
config.tomlにENVは入っているので環境変数は捨てておく。
cosvi@deroris:~/Downloads$ cat ~/data/cosmoshub-testnet/cosmovisor/config.toml
daemon_home = '/home/cosvi/data/cosmoshub-testnet'
daemon_name = 'gaiad'
daemon_allow_download_binaries = true
daemon_download_must_have_checksum = true
daemon_restart_after_upgrade = true
daemon_restart_delay = 0
daemon_shutdown_grace = 0
daemon_poll_interval = 300000000
unsafe_skip_backup = false
daemon_data_backup_dir = '/home/cosvi/data/cosmoshub-testnet'
daemon_preupgrade_max_retries = 0
daemon_grpc_address = 'localhost:9090'
cosmovisor_disable_logs = false
cosmovisor_color_logs = true
cosmovisor_timeformat_logs = 'kitchen'
cosmovisor_custom_preupgrade = ''
cosmovisor_disable_recase = false
chainの初期設定
gaiadの設定をする。cosmovisor run init xxx
となる。
cosvi@deroris:~$ cosmovisor --cosmovisor-config ~/data/cosmoshub-testnet/cosmovisor/config.toml run init deroris-moniker --home ~/data/cosmoshub-testnet/
Error: invalid path: /home/cosvi/data/cosmoshub-testnet/data must be an existing directory: stat /home/cosvi/data/cosmoshub-testnet/data: no such file or directory
ディレクトリがないと言われるので作る。
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/
/home/cosvi/data/cosmoshub-testnet/
└── cosmovisor
├── config.toml
├── current -> genesis
└── genesis
└── bin
└── gaiad
5 directories, 2 files
cosvi@deroris:~$ mkdir ~/data/cosmoshub-testnet/data
cosvi@deroris:~$ cosmovisor --cosmovisor-config ~/data/cosmoshub-testnet/cosmovisor/config.toml run init deroris-moniker --home ~/data/cosmoshub-testnet/
5:46PM INF running app args=["init","deroris-moniker","--home","/home/cosvi/data/cosmoshub-testnet/"] module=cosmovisor path=/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad
5:46PM INF starting the batch watcher loop module=cosmovisor
{
"moniker": "deroris-moniker",
"chain_id": "test-chain-TmRsc7",
"node_id": "177215901472ab18a55b3d22a2b361811039ab8a",
"gentxs_dir": "",
"app_message": {
~~snip;
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/
/home/cosvi/data/cosmoshub-testnet/
├── config
│ ├── app.toml
│ ├── client.toml
│ ├── config.toml
│ ├── genesis.json
│ ├── node_key.json
│ └── priv_validator_key.json
├── cosmovisor
│ ├── config.toml
│ ├── current -> genesis
│ └── genesis
│ └── bin
│ └── gaiad
└── data
└── priv_validator_state.json
7 directories, 9 files
testnetのgenesis.jsonとaddrbook.jsonをDL
cosvi@deroris:~$ curl -slo ~/data/cosmoshub-testnet/config/genesis.json https://raw.githubusercontent.com/cosmos/testnets/refs/heads/master/interchain-security/provider/provider-genesis.json
cosvi@deroris:~$ head ~/data/cosmoshub-testnet/config/genesis.json
{
"genesis_time": "2023-02-02T20:31:48.773794586Z",
"chain_id": "provider",
"initial_height": "1",
"consensus_params": {
"block": {
"max_bytes": "22020096",
"max_gas": "-1",
"time_iota_ms": "1000"
},
cosvi@deroris:~$ wget -qO ~/data/cosmoshub-testnet/config/addrbook.json https://snapshots.polkachu.com/testnet-addrbook/cosmos/addrbook.json
# thanks Polkachu
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/
/home/cosvi/data/cosmoshub-testnet/
├── config
│ ├── addrbook.json
│ ├── app.toml
│ ├── client.toml
│ ├── config.toml
│ ├── genesis.json
│ ├── node_key.json
│ └── priv_validator_key.json
├── cosmovisor
│ ├── config.toml
│ ├── current -> genesis
│ └── genesis
│ └── bin
│ └── gaiad
└── data
└── priv_validator_state.json
7 directories, 10 files
config/app.tomlのminimum-gas-pricesを設定する。
minimum-gas-prices = "0.25uatom"
1からsyncするのはつらいのでPolkachuのスナップショットを利用
https://polkachu.com/testnets/cosmos/snapshots
解凍するとこんな感じになる。
cosvi@deroris:~/Downloads$ tree ~/data/cosmoshub-testnet/ -L2
/home/cosvi/data/cosmoshub-testnet/
├── config
│ ├── addrbook.json
│ ├── app.toml
│ ├── app.toml~
│ ├── client.toml
│ ├── config.toml
│ ├── genesis.json
│ ├── node_key.json
│ └── priv_validator_key.json
├── cosmovisor
│ ├── config.toml
│ ├── current -> genesis
│ └── genesis
├── data
│ ├── 08-light-client
│ ├── application.db
│ ├── blockstore.db
│ ├── cs.wal
│ ├── evidence.db
│ ├── priv_validator_state.json
│ ├── snapshots
│ ├── state.db
│ └── tx_index.db
└── wasm
├── cache
├── exclusive.lock
├── state
└── wasm
18 directories, 11 files
とりあえず起動してみる。
cosvi@deroris:~/Downloads$ cosmovisor --cosmovisor-config ~/data/cosmoshub-testnet/cosmovisor/config.toml run start --home ~/data/cosmoshub-testnet/
6:11PM INF running app args=["start","--home","/home/cosvi/data/cosmoshub-testnet/"] module=cosmovisor path=/home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad
6:11PM INF starting the batch watcher loop module=cosmovisor
6:11PM INF starting node with ABCI CometBFT in-process module=server
6:11PM INF service start impl=multiAppConn module=proxy msg="Starting multiAppConn service"
6:11PM INF service start connection=query impl=localClient module=abci-client msg="Starting localClient service"
6:11PM INF service start connection=snapshot impl=localClient module=abci-client msg="Starting localClient service"
6:11PM INF service start connection=mempool impl=localClient module=abci-client msg="Starting localClient service"
6:11PM INF service start connection=consensus impl=localClient module=abci-client msg="Starting localClient service"
OK
cosvi@deroris:~$ curl -s localhost:26657/status | jq
{
"jsonrpc": "2.0",
"id": -1,
"result": {
"node_info": {
"protocol_version": {
"p2p": "8",
"block": "11",
"app": "0"
},
"id": "177215901472ab18a55b3d22a2b361811039ab8a",
"listen_addr": "tcp://0.0.0.0:26656",
"network": "provider",
"version": "0.38.17",
"channels": "40202122233038606100",
"moniker": "deroris-moniker",
"other": {
"tx_index": "on",
"rpc_address": "tcp://127.0.0.1:26657"
}
},
"sync_info": {
"latest_block_hash": "55CAEE49846E7224A8EA008A138BCA604C886059BD2BF351B9092F1A1D2029FF",
"latest_app_hash": "A79A766DEA78F78AF0D0AF0520E30E007F1D34CE7AD1A46D0B1D20ECF71FFD07",
"latest_block_height": "13317004",
"latest_block_time": "2025-08-20T07:46:34.00111111Z",
"earliest_block_hash": "7107672F6596ABBE4CC0F8D44650202A11122D416E939F0414D0153CAC0820D8",
"earliest_app_hash": "F133669F28C83E500AD3FDCB8CD33FE3ED6F97D6DBC5D8B710F5C5D66AA78D70",
"earliest_block_height": "13293001",
"earliest_block_time": "2025-08-18T17:32:19.328852675Z",
"catching_up": true
},
"validator_info": {
"address": "891B95241F42F261F3C3E3E8BB1029564E402437",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "+Xv5XrD3QUwzb4DxjfRMo6tYTSpMNqsUOslCWnBKb8I="
},
"voting_power": "0"
}
}
}
プロセス的にはcosmovisorとgaiadが動いている。
cosvi@deroris:~$ ps aux | grep cosmoshub
cosvi 561302 0.1 0.1 1290652 56608 pts/14 Sl+ 18:11 0:00 cosmovisor --cosmovisor-config /home/cosvi/data/cosmoshub-testnet/cosmovisor/config.toml run start --home /home/cosvi/data/cosmoshub-testnet/
cosvi 561312 219 6.9 3521764 2264744 pts/14 Sl+ 18:11 2:31 /home/cosvi/data/cosmoshub-testnet/cosmovisor/genesis/bin/gaiad start --home /home/cosvi/data/cosmoshub-testnet/
cosvi 561463 0.0 0.0 4728 2460 pts/16 S+ 18:12 0:00 grep --color=auto cosmoshub
cosmovisorはsystemdにしておいたほうが良いと思うので、下記のような感じでsystemdファイルを作成して、サービス登録しておく。
$ cat cosmovisor.service
[Unit]
Description=Cosmovisor daemon for cosmos provider testnet
After=network-online.target
[Service]
User=node
ExecStart=/home/cosvi/bin/cosmovisor --cosmovisor-config /home/cosvi/data/cosmoshub-testnet/cosmovisor/config.toml run start --home /home/cosvi/data/cosmoshub-testnet/
Restart=always
RestartSec=3
LimitNOFILE=infinity
LimitNPROC=infinity
[Install]
WantedBy=multi-user.target
アップグレード検知の仕組み
チェーンのdata/upgrade-info.json
ディレクトリをポーリングして、見つけたらそこに書いてあるバイナリをDLしておくようだ。data/upgrade-info.json
はチェーン側でアップグレードが承認されると勝手にできるはず。
確実に検証するにはアップグレードを待つか自前でチェーンを用意しないといけないのでまた今度
Tips
何かあった時にどうするかを考えておく。
アップグレードを手動で設定するには?
自分でDLしたバイナリを指定heightで置き換えることができる。(Propsなしのアップグレードの場合などに使える。)
add-upgradeを利用
ファイルができているのが分かる。
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/cosmovisor/
/home/cosvi/data/cosmoshub-testnet/cosmovisor/
├── config.toml
├── current -> genesis
└── genesis
└── bin
└── gaiad
4 directories, 2 files
cosvi@deroris:~$ cosmovisor --cosmovisor-config ~/data/cosmoshub-testnet/cosmovisor/config.toml add-upgrade upgradename-hehehe ~/Downloads/gaiad-v25.1.0-upgradetest-linux-amd64 --upgrade-height 13318200
6:39PM INF Using /home/cosvi/Downloads/gaiad-v25.1.0-upgradetest-linux-amd64 for upgradename-hehehe upgrade module=cosmovisor
6:39PM INF Upgrade binary located at /home/cosvi/data/cosmoshub-testnet/cosmovisor/upgrades/upgradename-hehehe/bin/gaiad module=cosmovisor
6:39PM INF /home/cosvi/data/cosmoshub-testnet/data/upgrade-info.json created, upgradename-hehehe upgrade binary will switch at height 13318200 module=cosmovisor
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/cosmovisor/
/home/cosvi/data/cosmoshub-testnet/cosmovisor/
├── config.toml
├── current -> genesis
├── genesis
│ └── bin
│ └── gaiad
└── upgrades
└── upgradename-hehehe
└── bin
└── gaiad
7 directories, 3 files
bhまで待つと。差し変わっていることが分かる。(今回は同じバイナリを名前を変えて利用)
6:40PM INF indexed block events height=13318200 module=txindex
6:40PM INF daemon shutting down in an attempt to restart module=cosmovisor 6:40PM INF starting to take backup of data directory backup start time=2025-08-20T18:40:58+09:00 module=cosmovisor
6:40PM INF backup completed backup completion time=2025-08-20T18:40:58+09:00 backup saved at=/home/cosvi/data/cosmoshub-testnet/data-backup-2025-8-20 module=cosmovisor time taken to complete backup=206.919878 6:40PM INF pre-upgrade command does not exist. continuing the upgrade. module=cosmovisor 6:40PM INF upgrade detected, relaunching app=gaiad module=cosmovisor 6:40PM INF running app args=["start","--home","/home/cosvi/data/cosmoshub-testnet/"] module=cosmovisor path=/home/cosvi/data/cosmoshub-testnet/cosmovisor/upgrades/upgradename-hehehe/bin/gaiad
6:40PM INF starting the batch watcher loop module=cosmovisor 6:40PM INF starting node with ABCI CometBFT in-process module=server 6:40PM INF service start impl=multiAppConn module=proxy msg="Starting multiAppConn service"
6:40PM INF service start connection=query impl=localClient module=abci-client msg="Starting localClient service" 6:40PM INF service start connection=snapshot impl=localClient module=abci-client msg="Starting localClient service"
6:40PM INF service start connection=mempool impl=localClient module=abci-client msg="Starting localClient service" 6:40PM INF service start connection=consensus impl=localClient module=abci-client msg="Starting localClient service"
6:40PM INF service start impl=EventBus module=events msg="Starting EventBus service" 6:40PM INF service start impl=PubSub module=pubsub msg="Starting PubSub service" 6:40PM INF service start impl=IndexerService module=txindex msg="Starting IndexerService service" 6:40PM INF ABCI Handshake App Info hash=A2C9DDF5FA222D4A1F0BF78815D294F42287822E3F5A65CA81E1F39CEBBF684F height=13318200 module=consensus protocol-version=0 software-version=v25.1.0 6:40PM INF ABCI Replay Blocks appHeight=13318200 module=consensus stateHeight=13318200 storeHeight=13318200 6:40PM INF Completed ABCI Handshake - CometBFT and App are synced appHash=A2C9DDF5FA222D4A1F0BF78815D294F42287822E3F5A65CA81E1F39CEBBF684F appHeight=13318200 module=consensus
6:40PM INF Version info abci=2.0.0 block=11 commit_hash= module=server p2p=8 tendermint_version=0.38.17 6:40PM INF This node is not a validator addr=891B95241F42F261F3C3E3E8BB1029564E402437 module=consensus pubKey=PubKeyEd25519{F97BF95EB0F7414C336F80F18DF44CA3AB584D2A4C36AB143AC9425A704A6FC2}
6:40PM INF P2P Node ID ID=177215901472ab18a55b3d22a2b361811039ab8a file=/home/cosvi/data/cosmoshub-testnet/config/node_key.json module=p2p
6:40PM INF Adding persistent peers addrs=[] module=p2p
6:40PM INF Adding unconditional peer ids ids=[] module=p2p
6:40PM INF Add our address to book addr=177215901472ab18a55b3d22a2b361811039ab8a@0.0.0.0:26656 book=/home/cosvi/data/cosmoshub-testnet/config/addrbook.json module=p2p
6:40PM INF service start impl=Node module=server msg="Starting Node service"
6:40PM INF service start impl="P2P Switch" module=p2p msg="Starting P2P Switch service"
6:40PM INF service start impl=Mempool module=mempool msg="Starting Mempool service" 6:40PM INF service start impl=Reactor module=blocksync msg="Starting Reactor service" 6:40PM INF service start impl=BlockPool module=blocksync msg="Starting BlockPool service"
6:40PM INF service start impl=ConsensusReactor module=consensus msg="Starting Consensus service"
6:40PM INF serve module=rpc-server msg="Starting RPC HTTP server on 127.0.0.1:26657"
6:40PM INF Reactor module=consensus waitSync=true
6:40PM INF service start impl=Evidence module=evidence msg="Starting Evidence service"
6:40PM INF service start impl=StateSync module=statesync msg="Starting StateSync service"
6:40PM INF service start impl=PEX module=pex msg="Starting PEX service"
6:40PM INF service start book=/home/cosvi/data/cosmoshub-testnet/config/addrbook.json impl=AddrBook module=p2p msg="Starting AddrBook service"
6:40PM INF Saving AddrBook to file book=/home/cosvi/data/cosmoshub-testnet/config/addrbook.json module=p2p size=1397
6:40PM INF Ensure peers module=pex numDialing=0 numInPeers=0 numOutPeers=0 numToDial=10
cosvi@deroris:~$ tree ~/data/cosmoshub-testnet/cosmovisor/
/home/cosvi/data/cosmoshub-testnet/cosmovisor/
├── config.toml
├── current -> upgrades/upgradename-hehehe
├── genesis
│ └── bin
│ └── gaiad
└── upgrades
└── upgradename-hehehe
├── bin
│ └── gaiad
└── upgrade-info.json
7 directories, 4 files
途中からcosmovisorを導入する場合
すでに動いているところにcomovisorを入れる場合には?
gaiadが動いているところでcosmovisor initまで行って最後に切り替えればよろし。
バックアップは忘れずに。
古いところに置いてあるgaiadは削除すること。(どれを使っているか分からなくならないように)
最後に
ちょっと長くなりましたので、その他検証はまた今度とします。simdというお試しバイナリがあるのでそちらを使うときに検証しようと思います。simappを使ったほうが検証しやすそうですね。
https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor#example-simapp-upgrade
cosmovisorを過信しすぎないように注意してください。アクティベーション時にはちゃんと見ておくのが必要かと思います。