🐳

WSL2でSSHトンネルを構築してDockerで使用する方法:なぜこの最適解に辿り着いたのか

に公開

WSL2でSSHトンネルを構築してDockerで使用する方法:なぜこの最適解に辿り着いたのか

はじめに

WSL2環境でSSHトンネルを確立し、Dockerコンテナから利用する方法にお悩みではありませんか? 安定稼働させるまでに様々な試行錯誤を重ねてきました。この記事では、なぜ「WSL起動スクリプト + nohup」という現在の方法に落ち着いたのか、そして他の一般的な方法と比較して、なぜそれらでは不十分だったのかを詳しく解説します。特有の制約を乗り越え、Docker開発をより快適にするための実践的な知見を共有します。

前回は「新しい環境で活用!ZshとOh My Zshの設定ガイド(Dockerでのテスト導入も解説)」を投稿しました。


今回の方法に至るまでの試行錯誤:なぜ他の方法ではダメだったのか

SSHトンネルを自動で起動し、かつ安定して維持するために、いくつかの一般的な方法を試しましたが、WSL2の特性ゆえの課題に直面し、実用レベルでの安定稼働は困難でした。

試したけれど安定しなかった他の方法

  • systemdサービス化して実行: systemdは、Linuxシステムにおけるサービス管理の標準です。デーモンプロセスをバックグラウンドで起動し、システムの起動・停止、再起動時の自動復旧などを一元的に管理するのに非常に強力です。通常のLinuxサーバーであれば、SSHトンネルをサービスとして登録し、システム起動時に自動で立ち上げるのが最も堅牢な方法と言えるでしょう。

    WSL2でなぜダメだったか: WSL2は、Windows上で動作する仮想化されたLinux環境であり、完全なsystemdサポートがありませんsystemdは、Linuxカーネルと密接に連携して動作する部分が多いため、WSL2ではその機能が一部制限されています。そのため、SSHトンネルをsystemdサービスとして設定しても、WSL2の再起動後にサービスが自動で再開されないことが頻繁に発生しました。開発環境として、WSL2を再起動するたびに手動でサービスを立ち上げ直すのは非効率的で、安定運用とは言えませんでした。


  • cronの@rebootオプションを利用: cronは、指定した時刻や間隔でコマンドを自動実行するためのスケジューラです。@rebootオプションを使用すると、システム起動時に一度だけコマンドを実行できます。これは、バックグラウンドで起動したいシンプルなスクリプトやコマンドの自動実行によく利用されます。

    WSL2でなぜダメだったか: WSL2の仮想化環境では、cron@rebootによる自動起動が不安定でした。具体的には、WSL2の起動シーケンスにおいてcronデーモンが立ち上がるタイミングと、ネットワークインターフェースが完全に初期化されるタイミングに競合が発生することが原因と考えられます。SSHトンネルはネットワーク接続が必要不可欠なため、cronが実行される際にまだネットワークが準備できていない、あるいは不安定な状態だとトンネルの確立に失敗し、その後自動で再試行されることもありませんでした。結果として、再起動時にトンネルが立ち上がらないケースが多発し、信頼性に欠けました。


  • ネットワークマネージャーのスクリプトフック(例: NetworkManager): NetworkManagerなどのネットワーク管理ツールには、ネットワークインターフェースが稼働した際やIPアドレスが割り当てられた際などに、特定のスクリプトを実行するフック機能が用意されています。これにより、ネットワークが完全に利用可能になったことをトリガーとしてSSHトンネルを確立できます。

    WSL2でなぜダメだったか: WSL2のネットワークスタックは、Windowsのネットワーク機能と密接に連携しており、標準的なLinuxディストリビューションのようにNetworkManagerがデフォルトでインストールされていなかったり、そのフック機能が期待通りに動作しない場合があります。WSL2のネットワーク設定は起動時にWindows側から提供されるため、Linux側のネットワーク管理ツールが完全に機能しない、または設定が複雑になる傾向があります。このため、より直接的でWSL2の起動シーケンスに依存しない方法が必要でした。


最適解:WSL起動スクリプト + nohup の使用に辿り着いた理由

最終的に、これらの試行錯誤を経て、以下の構成がWSL2におけるSSHトンネル自動起動の最も安定した、かつシンプルな方法であると判断しました。

この方法の優れている点

  • WSL2の起動シーケンスへの確実なフック: .bashrc.zshrcといったシェル設定ファイルは、WSL2の各シェルセッションが起動する際に必ず実行されます。これにより、WSL2環境が十分に立ち上がり、ネットワークも利用可能な状態になった後にスクリプトが実行されるため、安定した起動が可能です。他の方法のようにシステムの深い部分に依存せず、ユーザーランドで完結するのが強みです。


  • nohupによるバックグラウンド実行とセッション独立性: nohupを使用することで、SSHトンネルプロセスをシェルセッションから切り離し、完全にバックグラウンドで実行できます。これにより、ターミナルを閉じてもトンネルは維持され、また、シェル操作も妨げられません。systemdを使えないWSL2において、サービスに近い挙動を実現する現実的な代替手段となります。


  • autosshによる自動再接続: autosshを用いることで、SSH接続が何らかの原因で切断された際に自動的に再接続を試行します。AUTOSSH_MAXSTART=3という設定で、無限ループを防ぎつつ、一時的なネットワークの問題などによる切断から自動的に復旧できるため、トンネルの維持管理が大幅に楽になります


  • シンプルさと管理のしやすさ: 独立したスクリプトファイルを作成し、.bashrcなどから呼び出すことで、設定がシンプルになり、変更やデバッグが容易です。WSL2特有の複雑な設定をすることなく、標準的なLinuxコマンドの組み合わせで実現できるため、汎用性も高いです。

構成の詳細

  1. ~/.wsl_autossh_startファイルを作成し、以下を記述します。

    #!/bin/bash
    export AUTOSSH_MAXSTART=3
    nohup autossh -M 0 -f -N xxx-db-tunnel &>/dev/null &
    
    • AUTOSSH_MAXSTART=3: autosshが接続の初回試行を最大3回に制限し、無限ループを防ぎます。
    • -M 0: モニタリングポートを無効化します。
    • -f: autosshをバックグラウンドで実行します。
    • -N: リモートコマンドを実行せず、ポートフォワーディングのみを行います。
    • xxx-db-tunnel: .ssh/configで定義したホスト名です。
    • &>/dev/null &: 標準出力と標準エラー出力を破棄し、完全にバックグラウンドで実行します。
  2. 実行権限を付与します。

    chmod +x ~/.wsl_autossh_start
    
  3. .bashrcまたは.zshrcに以下の行を追加し、WSL起動時にスクリプトを実行します。

    if grep -iq Microsoft <<< "$(uname -r)"; then
        /home/your_username/.wsl_autossh_start &
    fi
    
    • if grep -iq Microsoft <<< "$(uname -r)": この条件分岐により、スクリプトがWSL環境でのみ実行されるようにします。これにより、同じ設定ファイルを他のLinux環境で共有している場合でも問題なく動作します。
    • /home/your_username/.wsl_autossh_start &: 作成したスクリプトをバックグラウンドで実行します。&を付けることで、シェルの起動を待たずにSSHトンネルの確立処理が開始され、ユーザーはすぐにシェル操作が可能になります。

DockerコンテナからMySQLへの接続

SSHトンネルが確立されたら、DockerコンテナからローカルのMySQLサーバーに接続できます。この際、host.docker.internal を使用すると、ローカルホストと同様にアクセスできます。これはDocker Desktopが提供する特別なDNS名で、ホストOS(この場合はWSL2上のWindowsサブシステム)のIPアドレスを解決します。

以下のように接続コマンドを実行します。

mysql -h host.docker.internal -P 3307 -u mysql_user -p
  • -h host.docker.internal: DockerホストのIPアドレスを指します。これにより、WSL2上で確立されたSSHトンネル(localhost:3307)にDockerコンテナからアクセスできます。
  • -P 3307: .ssh/configで設定したローカルフォワーディングのポートを指定します。

まとめ

WSL2上でのSSHトンネルの維持とDockerからの接続は、この記事で紹介した「WSL起動スクリプト + nohup + autossh」の構成で最も安定して動作します。systemdcronといった一般的なLinuxの自動起動方法がWSL2特有の制約により機能不全に陥る中、この方法はWSL2の特性に合わせた現実的かつ堅牢な解決策を提供します。確実な自動起動と再接続を実現することで、WSL2とDockerを活用した開発をよりスムーズに進めることができるでしょう。

この情報が、あなたのWSL2環境での開発効率向上の一助となれば幸いです。もし、さらに詳しい情報や別のユースケースについて知りたいことがあれば、ぜひお気軽にお尋ねください。

GitHubで編集を提案
CareNet Engineers

Discussion