Flisan's Personal Blog

← 記事一覧へ


活動記録

SSH + Zellij を使って開発サーバ上で開発する環境を作る

AI supported researching for this この記事を書くにあたって、AI と協力して調査しました

フライさんです!

普段(個人)開発をする時、持ち運ぶパソコンはクライアント機として、実際の計算処理は自宅のサーバにより行うような形で行なっています。この記事は、その環境をどのように成り立たせているかのご紹介です。

使われ方

アーキテクチャ構造

図にするとこんな感じ:

重要なのはプロジェクトごとに Zellij セッションを持っているという点です。これによって、SSH 接続が切れてもサーバ側に状態が残り続けるので、環境が変わっても/しばらくしたあとも同じ状態で作業を再開することができます。

特に、Zellij はセッションが終わったあともその構造を覚えておくことができるので (Resurrection)、あとから作業を復帰する時に前の作業の状態を再現できるという旨味もあるでしょうか(これは人によって好みがありそうですが)。

インターフェース

こんな感じの CLI コマンドで実行します:

ssh -t home-prime wk iris
  # 
  # → iris にマッチするリポジトリが検索される
  #   → /path/to/pastel-biota/iris
  # → この作業ディレクトリで...
  #   * すでにセッションがある場合、zellij attach "P.iris"
  #   * ない場合、 zellij --new-session-with-layout dev --session "P.iris"

便利に使うためにやっていること

リポジトリ検索/セッション管理をスクリプト化

Zellij セッションを識別するセッション名は、リポジトリ名から決めていると述べました。
一方で、セッションを識別するために、いちいち名前をすべて打つのは不便です。

ssh -t home-prime start-dev loxygenK/home-garden  # 🤷‍♂ 長い!

幸いリポジトリは管理ツールを使っているので構造や置き場所は規則があります。これに従って、名前で前方一致検索ができると便利でしょうか。

ssh -t home-prime start-dev home-gar  # 🙆‍♂ 良さそう

一方で、Zellij コマンドの実行についても考える必要があります。特に、「既存のセッションがある場合はそれにアタッチ、ない場合は作る」、という処理が必要です。

zellij attach-or-create L.home-garden  # ← こういうことはできない

というような形で、シンプルなワークフローにしてはそれなりに気にするべきことがあります。というわけで、このようなスクリプトを組んでいます#2:

#!/usr/bin/env zsh

# License: CC-BY-4.0 (Flisan, E-mail: me at f4n.dev)

set -eu

REPO_REGISTRY=/path/to/repo/registry

function _main {
  local repo_name=$1;

  if [ -z "$repo_name" ]; then
    echo "[!] No repository name was specified"
    return 1
  fi

  # --- リポジトリ検索
  local repo_path=$(ls -1d $REPO_REGISTRY/*/${repo_name}*)
  # = /path/to/repo/registry/OWNER/REPO

  if [ $(echo "$repo_path" | wc -l) -ne 1 ]; then
    echo "[!] No, or multiple repositories were found"
    return 1
  fi

  # --- セッション名生成
  local repo=${${repo_path:-}#"$REPO_REGISTRY"/}  # = "OWNER/REPO"
  local parts=(${(s[/])repo})  # = ("OWNER" "REPO")
  local owner=${parts[@]:0:1}  # = "OWNER"
  local repo=${parts[@]:1:1}  # = "REPO"
  local owner_tag=${owner[1]:u}  # = "O"
  local session=$owner_tag.$repo  # = "O.REPO"

  # --- セッションにアタッチ / 生成
  local found_session=$(zellij list-sessions | grep $session)

  # セッションの作業ディレクトリをリポジトリルートに設定
  cd $repo_path

  if [ -z "$found_session" ]; then
    # 未実行、新規セッション作成
    systemd-run --scope --user --unit=woka-zellij__$session zellij --new-session-with-layout dev --session $session || true
  elif echo $found_session | grep EXITED > /dev/null; then
    # Resurrect 可能、zellij attach でセッション復元
    systemd-run --scope --user --unit=woka-zellij__$session zellij attach $session || true
  else
    # 実行中のセッションがある。アタッチ
    zellij attach $session || true
  fi
  
  # `systemd-run --scope --user --unit=*` は後述します

  cd -
}

_main $@

これは wk という名前で PATH の通っている場所に置いている#3ので、 SSH コマンドは次のようにできます:

ssh -t home-prime wk iris

これで pastel-biota/iris が解決され、P.iris Zellij セッション下で作業ができるようになります。便利ですね!

SSH のオプションを簡単に指定できるようにしています

便宜上、コマンド例では ssh -t home-prime と書いていましたが、実のところは woka という自作 SSH ラッパーツールを使っています。なので実際はこう:

woka -p 8000 wk iris

#  woka の設定ファイルから、デフォルトのサーバ "home-prime" が自動指定される
#  woka が `ssh -t home-prime -L "8000:localhost:8000" wk iris` 相当を実行する

SSH コマンドは結構長くなりがちです。ポートフォワード等は、-L 8000:localhost:8000 みたいな指定をしないといけないですし、いろいろなポートを一度に転送したいみたいな需要もあるので、かなり煩雑になりがちです。

なので、ここらへんのオプションをより DSL 化して便利に使える自作ツールを使っています。今のところはこういう機能があります:

特に何も指定をしない場合は、これだけで普段使っているサーバにアクセスできるようになります!

woka wk iris  # 💯 短い!

うれしいこと

クライアント端末のポータビリティが上がる

MacBook 等のクライアント端末に、リポジトリ等失いたくない情報が入らないので、クライアント端末の入れ替えがかなり容易になります。例えば、クリーンインストール等をしても開発環境はそのままです。また、クライアント側はあまり性能を追求しなくても良くなるので(ターミナルが開ければ 🙆‍♂)、使用する PC の選択肢も広がります!

また、ビルド等の各種処理をサーバで受け持てるので、バッテリーや熱等、負荷の心配をあまりしなくていいのは気が楽です。

その他、Linux デスクトップ環境を持っていて、普段使いの環境がよくスクラップされるような場合だと特にここが効きます: Linux 環境を吹き飛ばしても、SSH の認証情報だけ準備すれば、それで開発環境にアクセスできるようになります!

開発環境を立ち上げるコストが低い

ただのスクリプトなので、開発環境の立ち上げは非常にコストが低いです。ssh を実行すれば、0.5 秒もしないですぐに Zellij セッションが出迎えてくれます!

つらいこと

ネットワークに依存する!

Tailscale を間違えて落としたり、通信環境が重いような場所だと、SSH が通らなくなり苦労します。たいていの PJ は開発環境を再現できるので、さっとリポジトリを clone しておくなどでしのいでいます。

物理環境に依存する開発で困る

Android アプリとか、、普段開発しないのでいいんですが、USB 等が絡むような環境の場合は、そのたびに開発の仕方を模索する必要があります。楽しさはありますが、コストを払う必要があるのは事実です

おわりに/おすすめできる?

私は Web エンジニアなので、TCP/IP 通信が何らかの方法で疎通できれば基本的に耐えることができます。そのような環境下であれば、開発環境を一箇所に集約できるのは、特にクライアント端末に対して、いい意味で慎重にならなくて良くなるので、かなり便利に過ごせていると感じます!