サーバーを新しく立てるたびに、似たような初期設定を繰り返していないでしょうか。
Dockerを入れて、Nginxを設定して、ファイアウォールを開けて、SSL証明書を発行して、監視を仕込んで……。一つひとつは難しくなくても、積み重なると地味に時間を食いますし、「前回どう書いたか忘れた」で毎回ハマったりもします。
自分もインフラ担当として同じ作業を繰り返すうちに、定型部分をBashスクリプトとして切り出して使い回すようになりました。今回、そのスクリプト群を整理して9本、BOOTH/Gumroadで公開しました。この記事では、その中の一つ「ELKスタック自動セットアップスクリプト」を例に、実装上どういう点に気をつけたかを書いてみます。
ラインナップ
- Docker Installation and Setup(バージョン固定インストール・データルート移設・企業プロキシ対応)
- Docker自動セットアップ&管理(インストールから日々のコンテナ運用・バックアップまで)
- Nginx自動設定(サーバーブロック・gzip・セキュリティヘッダー設定)
- UFWファイアウォール自動設定(SSHポート自動検出で締め出し防止)
- Let's Encrypt SSL自動更新(証明書発行・HSTS設定・自動更新)
- サーバーバックアップ自動化(ファイル・DBバックアップ&復元・GPG暗号化・rclone対応)
- Prometheus & Grafana監視スタック構築
- ELKスタック自動セットアップ(Elasticsearch・Logstash・Kibanaを1コマンドで構築)← 今回はこれを紹介
- CentOS自動セットアップ(yum/dnf自動判別でRocky・AlmaLinuxにも対応)
Ubuntu/Debian向け(CentOS版のみRHEL系)で、1本ずつ個別に導入できます。「監視だけ追加したい」「SSL自動更新だけ欲しい」という部分導入もできるようにしています。
ELKスタック自動セットアップスクリプトの中身
install / status / start / stop / restart / uninstall のサブコマンドを持つ、よくある構成のスクリプトですが、実際に組んでみるとハマりどころがいくつかありました。
1. Elasticsearchのsecurity自動設定とdiscovery.typeの競合
Elasticsearchの.debパッケージは、新規インストール時にpostinstが「security auto-configuration」を実行し、elasticsearch.ymlにxpack.security.enabled: trueやcluster.initial_master_nodesをすでに書き込んでいます。
シングルノード構成にしたくて素朴にdiscovery.type: single-nodeを追記すると、cluster.initial_master_nodesとdiscovery.type: single-nodeは共存できず、Elasticsearchが起動時エラーで落ちます。なので、パッケージ側がすでにブートストラップ設定を書いているかどうかを見て、書いていればdiscovery.type側を追記しない(むしろ削除する)ようにしています。
if grep -qE '^cluster.initial_master_nodes:' "$es_yml" 2>/dev/null; then
log "elasticsearch.yml already auto-bootstraps via cluster.initial_master_nodes"
sed -i '/^discovery.type:/d' "$es_yml"
else
set_yaml_kv "$es_yml" "discovery.type" "single-node"
fi
set_yaml_kv "$es_yml" "xpack.security.enabled" "false"
set_yaml_kv "$es_yml" "network.host" "localhost"
2. YAMLへの追記は「重複キー」を必ず潰す
set_yaml_kvは、単純に末尾追記するのではなく、同じキーの既存行を先に全部消してから1行だけ追記します。
set_yaml_kv() {
local file="$1" key="$2" value="$3"
sed -i "/^${key}:/d" "$file"
echo "${key}: ${value}" >>"$file"
}
理由は、Elasticsearchの厳格なYAMLパーサーが重複キーを起動時エラーとして拒否するためです。パッケージのpostinstがすでにxpack.security.enabledを書き込んでいるケースや、スクリプトの旧バージョンを2回実行してしまったケースなど、「同じキーがすでに複数存在する状態」からでも安全に収束するようにしています。「最初の1件だけ置換」だと、N個重複していた場合にN-1個の重複が残ってしまうので、それも踏まえた実装です。
3. curlのエラーハンドリングの二重出力バグ
ヘルスチェック用の関数で、curl -w '%{http_code}'は接続失敗時にも000を標準出力に書きます。curl自体の終了コードは非0になるので、素朴に|| echo "unreachable"のようなフォールバックを付けると、000とunreachableが両方標準出力に出てしまいます。
check_http() {
local url="$1" code
code="$(curl -s -o /dev/null -w '%{http_code}' --max-time 3 "$url" 2>/dev/null)"
[[ "$code" == "000" || -z "$code" ]] && echo "unreachable" || echo "$code"
}
同じパターンのバグがsystemctl is-activeのチェックにも潜んでいて(非activeな状態でも意味のある文字列を標準出力に返しつつ非0で終了するため)、両方とも「フォールバックのechoを無条件に足さない」形で修正しています。
4. デフォルトのsyslogポートを514にしない
Logstashのsyslog inputをデフォルトの514番ポートにすると、Logstashは非rootのlogstashユーザーで動くためCAP_NET_BIND_SERVICEがなくbindに失敗します。素直に5514番をデフォルトにし、どうしても514番を使いたい場合はsetcapするか rootで動かす方法をコメントで案内する形にしました。
Logstash's syslog input defaults to port 5514, not the traditional 514,
because 514 needs root or CAP_NET_BIND_SERVICE and Logstash runs as an
unprivileged 'logstash' user. Grant the capability yourself:
sudo setcap 'cap_net_bind_service=+ep' /usr/share/logstash/jdk/bin/java
and reinstall with --syslog-port 514.
実行イメージ
sudo ./elk-stack.sh install --es-heap 1g --syslog-port 5514
./elk-stack.sh status
sudo ./elk-stack.sh uninstall --yes
install後は、Elasticsearch・Logstash・Kibana・nginxをまとめて有効化し、Elasticsearchの起動待ち(ヘルスチェックのポーリング、最大60秒)まで面倒を見ます。uninstallはnginx自体は残し、このスクリプトが追加したKibana用のサイト設定だけを取り除くようにしています(同じホストでnginxが他のサイトを配信している可能性があるため)。
対応環境
Ubuntu 20.04/22.04/24.04、Debian 11/12で動作確認済みです(他のスクリプトも含め、実機での動作確認を行った上で公開しています)。
入手方法
- BOOTH:https://tool-all.booth.pm (各¥500)
- Gumroad:https://raiyna02.gumroad.com (各$10)
ELKスタック以外の8本も同様の考え方(実機での動作確認、部分導入のしやすさ、失敗時の挙動への配慮)で作っています。気になる工程だけ選んで使ってもらえればと思います。
不具合報告やご要望があれば気軽にコメントください。今後もアップデートしていく予定です。