エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

サーバ作業も生成AIで圧倒的勝利!(を得られるか?)

こんにちはエムスリーでSREエンジニアをやっている山本です。

このブログはSREチームブログリレーの3日目の記事になります。

生成AIによるコーディング支援、テスト自動化は常に盛り上がっています。

運用面での生成AI活用についてももちろん取り上げられることはありますが、まだまだ盛り上がりが少ない気もしないではありません。我々SREエンジニアもこのビッグウェーブに乗るべく旅立つこととしました。

生成AIと運用

AIで運用を効率化すること自体はAIOpsなどと呼ばれており、特に新しい概念ではありません。各種運用作業をAIで自動化することは昔から行われています。それに加えてパブリッククラウドと密接に連携しているAmazon Q Developerなどを利用して自動的にクラウド内の各所を調査するようなものを最近はよく見かけます。

今回は少し古い構成かもしれませんが、Linuxサーバそのもので行う各種運用について、Gemini CLIで実際に作業を実施した例をお伝えします。なお、Gemini CLIを使ったこと自体にはたいした意味はありません。Claude Codeでも良かったと思います。

インストール

当然ですが、Gemini CLIをインストールする必要があります。多くの場合にはローカルの開発マシンにインストールするかと思いますが、サーバ運用での利用ですのでリモートマシンのホームディレクトリにインストールしました。

# nvmのインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# LTSのnodeをインストール
nvm install --lts

# npmを利用してgemini-cliをインストール
npm install -g @google/gemini-cli

もちろん、GOOGLE_API_KEY や、Vertex AIを使う場合ならばその設定は必要です。

そして、ここで認証が必要です。

$ gemini -p "hello"


Code Assist login required.
Attempting to open authentication page in your browser.
Otherwise navigate to:

https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=(以下略)

gemini コマンドで初回起動した時に出てくるURLが認証用のURLです。このURLをクリックして適切なGoogleの認証を実施することで有効となります。 私の環境では、ブラウザを起動しての認証の結果 http://localhost:38653/oauth2callback?state=(以下略) のようなURLへのリダイレクトが行われたので、404となってしまいました。インストール先サーバでcurlを利用して当該URLを叩いて認証を成功させてあります。

curl http://localhost:38653/oauth2callback?state=(以下略)

AIOpsにGemini CLI

サーバでGemini CLIを動かすということ

サーバで生成AIを動かすということは当然ながらAIにコマンドを実行させることによるリスクを考える必要があります。原理的にはrootユーザで起動し、 --yolo モードで人間の確認なしに実行させることも可能であったりしますが、そのリスクが大きくなることは認識する必要があります。

今回の検証作業では「踏み台となるサーバ(そこからSSHを実行する)」「壊れても全く構わない動作検証用サーバ」にGemini CLIをインストールして作業を実施するという形にしています。また、コマンド実行については人間の許可を得ながら実施という形にしています。

具体例1(メール運用での活用)

私はメールサーバの運用も実施しているのですが、たまにトラブルが発生します。例えば到達率が下がっているとかいったものです。今まではワンライナーを即席で作りながらログをチェックしていましたが、Gemini CLIと対話しながら集計してもらいます。

ログのチェックをしてほしい。/var/log/maillogとそのrotate前の古いデータを見て、1日ごと送信数(sent)、遅延(deffered)、失敗(bounced, ,expired)をtableで出して。7月分だけでいい。

スクリプトのフォーマットの認識ミスもありましたが、特に問題なく最終的に集計されました。(実際の数字とは入れ替えてありますが、出てきたテーブルはまさにこの形です。)

✦ 承知いたしました。先ほどの集計結果を整形して、罫線付きのテーブルで表示します。



  ┌────────────┬────────┬──────────┬─────────┬─────────┐
  │ Date       │ Sent   │ Deferred │ Bounced │ Expired │
  ├────────────┼────────┼──────────┼─────────┼─────────┤
  │ 2025-07-01 │ 229222 │ 14435    │ 5455    │ 524     │
  │ 2025-07-02 │ 244869 │ 15318    │ 5842    │ 543     │
  │ 2025-07-03 │ 240854 │ 17299    │ 6153    │ 576     │
  │ 2025-07-04 │ 241815 │ 16447    │ 5811    │ 631     │
  │ 2025-07-05 │ 247869 │ 20584    │ 5848    │ 692     │
  │ 2025-07-06 │ 200725 │ 20647    │ 7292    │ 855     │
  │ 2025-07-07 │ 199731 │ 16292    │ 5317    │ 573     │
  │ 2025-07-08 │ 240617 │ 17091    │ 8104    │ 649     │
  │ 2025-07-09 │ 229003 │ 16169    │ 6905    │ 498     │
  │ 2025-07-10 │ 246336 │ 21165    │ 5968    │ 537     │
  │ 2025-07-11 │ 252123 │ 20056    │ 6537    │ 901     │
  │ 2025-07-12 │ 255586 │ 21096    │ 5710    │ 581     │
  │ 2025-07-13 │ 164969 │ 19921    │ 2841    │ 918     │
  │ 2025-07-14 │ 183282 │ 13393    │ 3588    │ 399     │
  │ 2025-07-15 │ 254644 │ 15671    │ 3565    │ 451     │
  └────────────┴────────┴──────────┴─────────┴─────────┘

このような出力のためには以下のようなスクリプトが内部で作られています。一つ一つは難しくなくとも単純に作成するのが面倒ですので、シェルスクリプトやawkを頑張らずにすぐにやっていけるところは非常に楽です。なお、今回の場合はファイルが巨大なのでスクリプトにもいくつか注文をつけました。

#!/bin/bash
cat << 'EOF' | ssh サーバ名 "bash -s"
zcat -f /var/log/maillog* | awk '
BEGIN {
    print "Date       | Sent | Deferred | Bounced | Expired";
    print "-----------|------|----------|---------|--------";
}
/^2025-07-[0-9][0-9]/ {
    day = substr($0, 1, 10);
    if (/ status=sent/)        { sent[day]++; }
    else if (/ status=deferred/) { deferred[day]++; }
    else if (/ status=bounced/)  { bounced[day]++; }
    else if (/ status=expired/)  { expired[day]++; }
}
END {
    for (i = 1; i <= 15; i++) {
        day_str = sprintf("%02d", i);
        date = "2025-07-" day_str;
        printf "%s | %-4d | %-8d | %-7d | %d\n",
               date,
               sent[date]+0,
               deferred[date]+0,
               bounced[date]+0,
               expired[date]+0;
    }
}'
EOF

Geminiにはこのスクリプトの出力を読んだ上で罫線でテーブルをきれいにしてもらいました。

それ以外にも色々と注文をつけていきます。

次に、送信先ドメインごとに送信失敗が多く起きているものを教えて欲しい。できるだけ、サブドメインを見過ぎないように。

このような指示を出します。これも例によって実際のものとは数字やドメインを入れ替えてありますが、簡単に集計してくれます。

✦ お待たせいたしました。7月分のログから、送信に失敗した(bouncedまたはexpired)メールの宛先ドメインを集計しました。サブドメインをある程度まとめた上で、失敗数の多い順にリストアップしてい
  ます。



  ┌────────┬────────────────┐
  │ 失敗数  │ ドメイン        │
  ├────────┼────────────────┤
  │ 10454  │  example.jp    │
  │ 8057   │  example.net   │
  │ 6553   │  example.com   │
  │ 5498   │  example2.jp   │
  │ 4984   │  example2.com  │
  │ 3395   │  example3.com  │
  │ 3095   │  example.ne.jp │
  │ 2676   │  example4.com  │
  │ 1565   │  example2.ne.jp│
  │ 1030   │  example.or.jp │
  │ 1025   │  example3.ne.jp│
  │ 825    │  example4.ne.jp│
  │ 768    │  example5.ne.jp│
  │ 681    │  example6.ne.jp|
  │ 655    │  example7.ne.jp│
  │ 648    │  example8.ne.jp│
  │ 624    │  example5.com  │
  │ 554    │  example9.ne.jp│
  │ 527    │  example2.net  │
  │ 449    │  example6.com  │
  └────────┴────────────────┘

  この結果から、特に example.jp、example.net、example.com 向けのメールで多くの送信失敗が発生していることがわかります。

example.jpについて、deferredの原因メッセージを集計して

✦ example.jp宛の遅延理由を集計した結果は、以下の通りです。



  ┌────────┬──────────────────────────────────────────────────────────┐
  │  件数   │ エラーメッセージ                                          │
  ├────────┼──────────────────────────────────────────────────────────┤
  │ 134641 │ 452-4.2.2 The recipient's inbox is out of storage space. │
  │ 2      │ 421-4.3.0 Temporary System Problem. Try again later      │
  └────────┴──────────────────────────────────────────────────────────┘


  この結果から、example.jp宛の遅延の99.99%以上が、「受信者のメールボックス容量不足」によるものであることが断定できます。


  「一時的なシステムの問題(Temporary System Problem)」も2件ありますが、これは無視できる範囲です。


  したがって、example.jpへのメール到達性を改善するには、送信リストから、長期間アクティブでない、あるいはメールボックスが満杯になっている受信者を特定し、リストから除外するなどのクリーニ
  ング作業が最も効果的です。

このようにAIと対話しながら、本当に遅延が起きているのか? バウンスが起きているとしてその原因はなんなのか?特定ドメインなのかといったものをチェックしていくことになります。

100台サーバがあったとして100台にGemini CLIを入れるというものではなく、特定の1台の作業サーバにインストールした上で作業対象サーバにSSHさせて確認するという作業を実施しています。この形ならば本番サーバにいきなりAIツールを入れるということなしに作業ができます。

具体例2(簡単な作業)

これ以外でもあえて実験的にGemini CLIにいろいろなことをさせてみました。

  • 特定サーバに接続できなかった時間があった際の障害調査
    • 関係するsyslogやsarデータその他を横断的に見るように指示
    • 他のいくつかのサーバについてもログを見るように指示
  • 特定のcronの登録を多数サーバに対して実施
    • ansibleなどによって管理するのが一番かもしれないがそれが整備されていないものもある

調査の場合には完璧な作業ができるというわけでもありませんが、面倒なログの確認などを一気にやってもらえるのは楽でした。結果が返ってきたら追加の指示を出しながら、自分は別の作業を実施すればよいのです。

具体例3(特定のサーバの設定変更)

私は先日とあるサーバのOSをupdateを試みました。そのOS上で動作しているアプリケーションがそのままだと動かなくなることはわかっていたので、あえてGeminiと対話しながら順番にアップデートを試みました。具体的には mod_php から php-fpmへの置き換えが必要となり、それに伴って設定ファイルが大幅に変更となります。(mod_phpではApacheのプロセスで動くのですが、php-fpmになるのでphp-fpmがサーバとして動作し、そこにApacheが繋ぐ形になります。)

この例の場合は作業場所がOSアップデートの検証用サーバですので直接的にGemini CLIを検証用サーバにインストールしています。

やるべきことは大体想像がついていたのですが、次のように指示しました。

このサーバはAmazon Linux 2023です。Apache + php-fpm + PHP8でアプリケーションを動かしたいと思います。 アプリケーションのコードは XXXに設置しています。Apacheもphp-fpmもインストール済です。 元々動いていたアプリケーションは古いOSであり Apache + mod_php + PHP7で動作しています。 元々のアプリケーションのApacheのconfigは XXX に設置しました。また利用しているアプリケーションのコードは XXXにあります。その中で特に注目する必要があるのは XXXX/.htaccessです。ここでphp_valueを設定していることに注意してください。 さて、このサーバにあるApacheのconfigはそのまま古いOSにあるものをコピーしてきています。そのままだと動きません。ここからphp-fpmに適合するように書き換えていってください。

思い通りに読み取ってくれない

もっとちゃんとしたプロンプトで指示できたかもしれませんが、ある程度の下準備だけを実施してここから開始してみました。

なお、Geminiについては起動したディレクトリ以下しか直接的には読めないようですので例えば / で gemini コマンドを実行することになります。検証用サーバなので大きな支障はありませんが、今回のようにサーバ全体のファイルへのアクセスを認める場合にはあまり大きな権限を持ったユーザでのgeminiの実行には危険もあることは認識する必要があります。私の場合は一般ユーザで起動しています。

通常はGemini CLIはプロジェクトのファイルしか読まないという利用なので、該当プロジェクトのディレクトリで起動すれば良いのですが今回の場合は少し事情が異なります。

また、どうしても権限的に読めないファイルについてはシェルコマンドを実行して読んでもらうことは可能です。

! sudo cat /etc/shadow

! command の形で自分でコマンドを実行し、その出力結果を読んでもらうことも可能ですので、重要なコマンドは自分で実施という選択もできます。

さて、それに沿ってGeminiに移行作業を実施してもらいました。結論から言えば、主なところでは次の作業が必要なのです。(ロードバランサその他は設定済であり、サーバ側さえ動かせれば十分でした。)

  • /etc/php-fpm.d/ に適切なファイルを設置して起動する
  • /etc/httpd/conf.d/XXX.conf の書き換え(mod_phpからphp-fpm)
  • /path/.htaccess の書き換え
  • /path/.user.ini の定義(元々 .htaccessにあった内容の一部を置き換える)

これによってすぐに設定ができる…と思ったのは甘かったようです。

繰り返しの対話の結果

何度も何度も何度も対話しました。

  • このファイルを読んでほしい
  • このエラーログを読んでくれ
  • こちらの旧バージョンにあった設定値が抜けている

といろいろに注文を出しました。

手取り足取り作業の進め方を教える

私のやり方に問題があった可能性は否定できませんが、まだまだ大いに課題ありです。自力でやった方が早かったかと思います。

何度も間違えながら進めてようやくアプリケーションのページが開くところまでは到達しましたので結果として自分でようやく納得してくれた内容を次のように最後に出力してもらいました。最終的にはきちんと理解してくれたことがわかります。

  mod_php 構成 (/old) の特徴


  old の .htaccess で最も特徴的なのは、PHPの設定を php_value と php_flag というディレクティブで行っている点です。



    1 # PHPの設定値を直接.htaccessに記述
    2 php_value memory_limit 2048M
    3 php_value post_max_size 800M
    4 # ...など
    5
    6 # フロントコントローラーの実現方法
    7 <Files ~ "index.html$">
    8     # 1. .htmlファイルをPHPとして処理させる
    9     AddType application/x-httpd-php .html
   10     # 2. 自動でinclude.phpを読み込ませる
   11     php_value auto_prepend_file "/path/public_html/source/php/include.php"
   12 </Files>

(中略)

  これにより、責務が明確に分離され、よりクリーンでメンテナンスしやすく、パフォーマンスも高い構成(PHP-FPM)へと移行できた、というわけですね。この背景をご説明いただき、
  ありがとうございました。アプリケーションの進化の過程がよく理解できました。

これはサーバ上で実施したので、開発環境側のdockerコンテナもOSを変更せねばなりません。

では、この構成の変更の注意点をmarkdownとしてプロンプトに出して。

としてこの内容をmarkdownにしてもらいました。これを使って、今度は開発環境を構成するリポジトリに対して変更させることになると思います。その意味では実施した作業のまとめとしては意味があります。

まとめ

  • サーバにGemini CLIをインストールして、従来だとスクリプトが必要だったような作業を自動化することは可能
  • 簡単な調査や多数のサーバに対しての設定なども同じく可能
  • サーバ内の設定を調査してアプリケーションを作り替えるという作業は少なくとも今回のテスト実施ではそこまで効率的ではない
    • 最終的にはなんとか手作業ほとんどなしに実施できたが、人間側の知識がそれなりに必要であった
    • 最終的に行った作業は取りまとめてくれたので、そのmarkdownの再活用は可能(人間がやると「で? 何やったっけ?」になりやすい)

感想

正直なところ、私の力なのかAIの力なのかが及ばずで、手探り状態にあり本格活用はできていない状態です。ただ、知識を蓄えて我々のサーバの構成を知ってもらえれば活用ができるのかもしれません。クラウドのサーバレスなものを利用する場合と異なってLinuxを直接に使っているものはどうしても活用法が多岐にわたるため一般論のような形の知識しか持たぬAIがいきなり太刀打ちするのは難しく、曲がりなりにも前提知識がある人間がやった方が高速になるということではないかと想像します。

生成AIを利用した開発の場合はリポジトリを全舐めする程度に留まりますからファイル数も限られますが、今回のようにLinuxサーバに対して適用する場合、設定やファイル群を全舐めすることは現実的ではありません。ですからGemini CLIもそこには及ばず、(人間がやる場合もそういうことはありますが)一般的に手掛かりとなるであろうファイルだけをいくつか見つけてそこに集中するという動きではないかと想像しました。

未確認ですがその他活用できそうなものとして次のようなものを想定しています。要するにやることはわかってるが面倒な作業です。スクリプトや目でのチェックを行なっていたものを簡単に実施させるという意味があります。

  • tcpdumpの結果をAIに食わせればかなり上手く解析してくれそう
  • 多数サーバに勝手にログインして例えば利用OS、ディスク使用率、その他を一覧表にするようなもの(元々ツールを入れていない場合)
  • 脆弱性(例えば特定のパッケージ、portの空き具合)などを横断的に調査して報告させる

生成AIは日進月歩で進化していますので、現状で満足するようなことはせず、上手い使い方を模索していきたいと思います!

We are Hiring!

エムスリーではSREを募集中です。 もしSREの仕事に興味をお持ちいただけたならぜひ詳細をご確認ください。SRE以外にも多数の職種がありますので他の職種ももちろん大歓迎です!

jobs.m3.com

open.talentio.com