TT Lab
はじめる
学ぶ 学習パス コース

vimとtmux

tmuxはクライアント-サーバだ

TT Labで続きを見る

一言でいうと

tmuxでコマンドを実際に実行しているのは、自分のターミナルではなくサーバープロセスです。自分のターミナルは、そのサーバーにつながっている画面にすぎないので、画面が消えても作業は動き続けます。

なぜ必要なのか

リモートサーバーでデプロイスクリプトを実行している最中に、Wi-Fiが切れました。再接続してみると、スクリプトは途中で死んでおり、半分だけ適用された状態が残っていました。一度くらいは、誰でも経験します。

なぜ死んだのでしょうか。SSH接続が切れると、そのセッションの制御端末が消え、カーネルはセッションリーダーにSIGHUPを送ります。シェルはそれを自分のジョブに伝播します。デプロイスクリプトは自分のシェルの子だったので、一緒に死にます。

nohupやsetsidで、この連鎖を断ち切ることもできます。しかしそうすると、作業は生き残りますが、画面をもう一度見ることはできません。進捗を見るにはログファイルを別に見る必要があり、途中で入力を与えることもできません。

tmuxは、別の方向で解決します。コマンドを自分のシェルの子ではなく、tmuxサーバーの子にするのです。tmuxサーバーは、自分のSSHセッションとは無関係の別のプロセスで、各ウィンドウの疑似端末(pty)を所有します。自分のターミナルは、その画面を受け取って見るクライアントにすぎません。そのため、クライアントが消えても、サーバーとその子たちには何も起こりません。再接続してtmux attachすれば、画面までそのまま戻ってきます。

どう動くのか

構造は4階層で、それぞれに身近な例えがあります。

階層 例え コマンド
Server オペレーティングシステム 最初のセッションを作るときに自動で起動します
Session デスクトップ / 作業スペース tmux new -s dev
Window ブラウザーのタブ prefix + c
Pane 画面分割 prefix + % / "

すべてのキー入力は、プレフィックスキーを先に押して手を離してから、コマンドのキーを押す2段階です。デフォルトはCtrl-bで、多くの人が手に楽なCtrl-aに変更します。このとき、シェルの「行頭へ」のショートカットと重なるので、bind C-a send-prefixを一緒に入れて、2回押すと元のキーが渡されるようにします。

セッション操作の核心となるコマンドは5つだけ知っていれば、初日は十分です(以下のコマンドのプレースホルダーは、すべてセッション名です)。

そして、実務で最も役に立つ慣用句が1つあります。tmux new -A -s devというコマンドは、セッションがあればアタッチし、なければ作成します。シェルのaliasに登録しておけば、毎回存在するかどうかを確認する必要がありません。

現場での姿

夜間マイグレーション。DBサーバーに接続して、tmux new -s migrationでセッションを作り、マイグレーションを開始したらデタッチして、帰宅します。翌日アタッチすれば、進捗がそのまま見えます。nohupと違い、画面と入力が生きているという点が異なります。

開発環境の3分割。左にエディター、右上に開発サーバー、右下にテスト監視。この配置を毎回手で作る代わりに、スクリプト1行で再現します。ここでよく抜けるのが-c "#{pane_current_path}"です。これがないと、新しく作ったペインがホームディレクトリで開くため、毎回cdを打ち直す必要があります。

複数サーバーの同時運用。4台のサーバーにそれぞれsshでつないだペインを4つ作ってsynchronize-panesを有効にすると、入力したすべてのコマンドが4か所で同時に実行されます。危険な分だけ強力なので、有効/無効の状態をステータスバーに表示しておくとよいです。

用語の落とし穴が1つあります。tmuxのsplit-window -hは「横に分ける」ではなく、左右に分けるという意味です(水平方向に配置)。-vは上下です。紛らわしいので、会話するときは「左右分割・上下分割」と言い、フラグは別に覚えるほうがよいです。

最初の日に変えるべき設定が2つあります。base-index 1とpane-base-index 1です。キー0がキーボードの右端にあって不便だからです。そしてhistory-limitはデフォルトが2000行なので、ログを少し見ただけで切れてしまいます。5万行くらいが、実用的な上限です。

切れても生き残る作業を作る

tmuxを使う最大の理由は、画面分割ではなく、接続が切れても作業が続くことです。その性質をきちんと使うには、いくつか決めておく必要があります。

セッションに名前を付けます。番号は、アタッチやデタッチを繰り返すと変わります。名前があれば、「あればアタッチし、なければ作成する」1行が可能になります。

tmux new-session -A -s deploy      # 있으면 attach, 없으면 새로

この1行をスクリプトに入れておけば、接続するたびに同じ場所に戻れます。

長い作業には、専用のウィンドウを1つ与えます。マイグレーションや大容量のコピーは、そのウィンドウでだけ実行し、そのウィンドウの名前を作業名に変えておきます。数時間後に戻ってきても、どのウィンドウが何かがわかります。

Ctrl-b ,        창 이름 바꾸기
Ctrl-b w        창 목록에서 고르기
Ctrl-b d        떼어 내기(작업은 계속 돈다)

このコードブロックの韓国語コメントは、上から順に、ウィンドウ名の変更、ウィンドウ一覧から選択、切り離し(作業は動き続けます)という意味です。

スクロールの代わりに、コピーモードを使います。ターミナルのスクロールバーは、tmuxの中ではうまく動作しません。Ctrl-b [でコピーモードに入ると、上にさかのぼりながら検索までできます。デフォルトの履歴が2,000行なので、長いログは切れてしまうため、増やしておきます。

set -g history-limit 50000

入れ子になる場合に備えます。リモートサーバーでさらにtmuxを起動すると、プレフィックスキーが重なります。内側に送るには、Ctrl-bを2回押します。頻繁にそうするなら、内側のセッションのプレフィックスキーを別のキーに変えるほうがよいです。

複数人が同じセッションを見られます。障害対応で、画面共有の代わりに使えます。ただし、同じセッションにアタッチすると、ウィンドウサイズが最も小さい画面に合わせられます。それぞれが別のウィンドウを見たいときは、セッションを分けて作ります。

tmux new-session -t deploy -s deploy-2   # 창은 공유, 보기는 따로

tmuxが死ぬと、すべて消えます。サーバーが再起動すると、セッションは残りません。本当に生き残らなければならない作業は、tmuxではなくsystemdユニットやバッチジョブとして作ります。tmuxは、人がアタッチしている作業のためのツールです。

次のラボですること

2つのラボが続きます。tmux-basicsでは、セッションとウィンドウを作ってデタッチ状態を確認し、設定ファイルが実際にサーバーに反映されるかを検証します。tmux-panesでは、ペインの分割・タイトル・拡大・同期を扱い、最後に開発レイアウトを再現するスクリプトを作ります。どちらのラボも最後のステップが自動化スクリプトである理由は、手で作った配置は翌日消えますが、スクリプトは残るからです。