Octa Roboticsインターン体験記 Part2:ネットワーク検証編
ネットワーク検証編 ~ローカル vs クラウド、失敗からの学び~
1. はじめに:なぜネットワーク越しの検証が必要なのか?
前回の記事では、Python Tornadoを使ったログ永続化サーバーの開発について紹介しました。今回は、その続きとして、このサーバーをネットワーク越しに検証した記録をお伝えします。
これは単なる機能テストではなく、ネットワークの特性がアプリケーションに与える影響を理解するのに結果的に大きく役立ちました。
検証の目的
具体的な検証目的は以下の通りです:
-
ネットワーク特性の影響を測定する
- 遅延、パケットロス、スループット低下の実測
- 実環境を想定したパフォーマンス評価
-
ネットワーク機器/サービスの影響を可視化する
- ファイアウォール、NAT、VPNなどがもたらす制約の理解
- これらの制約に対する対策検討
-
セキュリティ面での検証
- 外部からの攻撃シナリオに対するサーバーの応答確認
- 認証・認可機能の検証
このような検証が重要な理由は、開発環境(localhost)と実運用環境では大きな差があるためです。ローカルホストでは見られなかった問題が、実際のネットワークでは露呈することがよくあります。例えば、ローカルでは数ミリ秒のレイテンシでも、インターネット経由だと数百ミリ秒になることがあり、これがタイムアウトやパフォーマンス問題を引き起こします。
この記事では、様々なネットワーク環境(VPN、仮想LAN、インターネット経由)を構築し、開発したログサーバーの性能とセキュリティを多角的に検証したプロセスをお伝えします。特に「失敗」から得た学びに焦点を当て、ネットワーク知識の深化過程を共有します。
2. 最初の壁:商用VPNでのクライアント間通信不可
検証計画
最初の検証計画は以下の通りでした:
- WSL(Ubuntu)をサーバー、VirtualBox(Rocky Linux)をクライアントとして設定
- 両者を同じVPNに接続し、同一VPNネットワーク内に配置
- RockyからWSL上のサーバーへアクセスし、VPNオーバーヘッドを測定
この計画の狙いは、公衆インターネットを使いながらも、VPNによるセキュアな通信環境を確保することでした。VPNは、エンドポイント間で暗号化トンネルを作り、ネットワーク層(OSI参照モデルのレイヤー3)で仮想的なプライベートネットワークを形成します。これにより、異なる物理ネットワーク上のデバイスが同じローカルネットワーク内にあるかのように通信できると考えていました。
環境構築と通信テスト
VPNクライアントのインストールと設定に成功した後、OpenVPNでの手動接続に切り替えて両環境で接続に成功しました。各環境でVPNインターフェースの確認と外部IPの変更を確認しました。この結果から、両環境ともにVPNに接続され、同じ10.xx.xx.0/16ネットワークに属していることが確認できました。
しかし、VPN接続に成功したにもかかわらず、RockyからWSLへの通信テストは失敗しました。pingやcurlコマンドでの接続が完全に失敗し、tracerouteではVPNゲートウェイ(10.xx.xx.1)までは到達しているものの、そこから先に進まないことがわかりました。
原因究明のプロセス
論理的に探究を進め、以下の可能性を順次検証しました:
- ファイアウォールの確認:Ubuntuのファイアウォール(ufw)は無効、ICMP応答も拒否していない
- ルーティングテーブルの確認:適切なルートが設定されている
- サーバー動作の確認:ローカルからのアクセスは正常に機能している
これらの確認から、問題はVPNサービス側にあることが示唆されました。調査を進めたところ、多くの商用VPNサービスではセキュリティ上の理由からクライアント間通信を意図的にブロックしていることが判明しました。
VPNの内部動作理解
この問題を通じて、VPNの内部動作について以下のような深い理解が得られました:
- カプセル化と暗号化:通信データは暗号化されVPNプロトコルでカプセル化される
- トンネリング:カプセル化パケットはVPNサーバーへの暗号化トンネルを通過
- クライアント分離:多くの商用VPNではプライバシーとセキュリティのため、意図的にクライアント間の直接通信を禁止
- トラフィック制御:VPNサーバーはインターネットへの出口として機能するが、クライアント間の内部ルーティングは行わない
この「失敗」から、商用VPNと企業VPNの設計思想の違い、ネットワークサービスの機能と制限、セキュリティとユーザビリティのトレードオフについて学ぶことができました。
3. 代替アプローチ①:ローカルネットワークシミュレーション
目的とアプローチ
VPNの制限を回避するため、WSLとVirtualBox VMを同一ネットワーク環境で接続する方法を模索しました。まず、VirtualBoxの「ブリッジアダプター」モードを試みましたが、Wi-Fi環境での制限やWSL2の仮想ネットワーク特性により失敗しました。
ホストオンリーアダプター方式の成功
次に、VirtualBoxに「ホストオンリーアダプター」を追加する方法に切り替えたところ、WSLからRocky Linuxへの通信に成功しました。ホストオンリーネットワークは、ホストマシン内部に閉じた仮想ネットワークを作成する方式です。これにより以下の通信経路が確立されました:
WSL (172.20.x.x) → Windows Host(NAT) → Host-only Network (192.168.56.x) → VirtualBox VM (192.168.56.10)
この方式が機能した理由は、ホストOSがWSL2とVirtualBoxの両方の仮想ネットワークにアクセスでき、中継点として機能するためです。
Windowsポートフォワーディングの設定
WSL上のサーバー(172.20.x.x:8888)にRocky Linuxからアクセスするために、Windowsのポートフォワーディング機能を活用しました。netsh interface portproxy
コマンドを使用して、ホストオンリーネットワークのIPアドレス(192.168.56.1)とWSLのIPアドレスの間でポート転送を設定しました。
この設定により、Windows OS内部でネットワークスタックのレイヤー4(トランスポート層)でポート転送が行われるようになりました。内部的には、Windows Filtering Platform(WFP)がパケットを検査し、適切な宛先に転送する仕組みです。
Nginxの設定調整
接続テスト時にupstream sent too big header
エラーが発生したため、Nginxの設定を調整しました。このエラーは、Nginxのバッファサイズとアップストリームサーバー(Tornadoアプリ)が送信するHTTPヘッダーサイズの不一致によるものです。バッファサイズを適切に増やすことで問題が解決しました。
技術的な学び
この過程を通じて、以下のような重要な技術知識を獲得しました:
- 仮想化ネットワークの種類と特性:各モードの違いと用途
- WSL2ネットワークアーキテクチャ:Hyper-V技術に基づく分離と統合
- Windowsネットワーク機能:ポートフォワーディングとファイアウォールの連携
- Nginxプロキシ設定:バッファ関連パラメータの役割と調整方法
特に、異なる仮想化技術(WSL2とVirtualBox)の相互連携方法を実践的に理解できたことは大きな収穫でした。
4. 代替アプローチ②:インターネット経由シミュレーション
構成選定の理由
より実際のインターネット越しの通信環境を再現するために、以下の構成を選びました:
- ローカルサーバー: WSL上のDocker環境
- トンネリングサービス: ngrok
- クライアント環境: AWS EC2インスタンス
この構成を選んだ理由は、インターネット経由の実レイテンシ、アクセス集中時の挙動、セキュリティ面の検証ができるためです。また、多くの実サービスがクラウドから他のサービスにアクセスする構成を採用しているため、現実的なテスト環境といえます。
ngrokによるトンネリング
ngrokは「リバーストンネル」の原理に基づくサービスで、以下のような仕組みで動作します:
- ローカルのngrokクライアントがngrokサーバーへアウトバウンド接続を確立
- この確立された接続を通じて、外部からのリクエストがローカルサーバーに転送される
- トンネルはTLSで暗号化され、セキュアな通信が可能
この方式には、NAT/ファイアウォール透過、HTTPS自動対応、リクエスト/レスポンスの可視化といった利点があります。
マルチインターフェース設定の工夫
Rocky Linuxからngrokサーバーへのアクセス時にDNS解決の問題が発生したため、VirtualBoxにNATアダプターを追加しました。これにより、以下のようなマルチホーミング構成が実現しました:
デフォルト → NATアダプター (外部インターネットアクセス用)
192.168.56.0/24 → ホストオンリーアダプター (ローカル通信用)
マルチホーミングとは、複数のネットワークインターフェースを持つコンピュータ構成のことです。このような環境では、宛先IPアドレスに応じて適切なインターフェースとルートが選択されるため、ルーティングテーブルが重要な役割を果たします。
5. パフォーマンス比較検証と考察
テスト設計の意図
異なるネットワーク環境での性能比較を行うために、Apache Benchmark(ab
)を使用した高負荷テストを設計しました。このテスト手法を選んだ理由は、実際の使用パターンの再現、定量的な比較、ボトルネックの特定、スケーラビリティの検証ができるためです。
テスト環境として以下の3種類を選定しました:
- ローカル環境 (WSL内): ネットワークのオーバーヘッドがない理想的なベースライン
- Rocky → WSL (ホストオンリー経由): 小規模LAN環境での特性評価
- EC2 → ngrok → WSL: インターネット経由アクセスの現実的な制約測定
これらを比較することで、各ネットワーク層が追加されるごとのオーバーヘッドを定量化できます。
結果分析と技術的考察
テスト結果を分析すると、以下のような興味深い傾向が明らかになりました:
-
スループット (RPS): ローカル(1102) > EC2経由(833) > ホストオンリー(546)
- ホストオンリーのオーバーヘッドはパケットカプセル化、ポートフォワーディング、二重ネットワークスタックによる
- EC2→ngrokのパフォーマンスが予想外に良好な理由は、ngrokのWebSocketベースの効率的プロトコルと高性能サーバーインフラの影響
-
応答時間パターン:
- ローカル環境: 平均応答時間は最速(0.91ms)だが高負荷時に大きなスパイク(最大3449ms)
- ホストオンリー環境: 平均応答時間は遅い(1.83ms)が安定している(最大608ms)
- EC2→ngrok環境: 地理的距離があるにもかかわらず、比較的良好な応答性能
-
安定性と失敗率:
- ローカル/ホストオンリー: 失敗なし
- EC2→ngrok: 高負荷時に一部SSL/TLSハンドシェイク失敗
これらの差異は、各環境での技術的な特性によって説明できます:
- ローカル環境のスパイク: リソース競合(CPU/メモリ)による処理遅延
- ホストオンリー環境の安定性: ネットワークレイテンシがボトルネックとなり、処理が分散される効果
- EC2環境のパフォーマンス: 地理的距離による遅延はあるが、EC2の高い処理能力で補完
6. ネットワーク検証プロセスから得た体系的知見
ネットワーク技術の層別理解
このインターンでの検証を通じて、ネットワーク技術を以下のような層に分けて体系的に理解することができました:
-
プロトコル階層と実装
- OSI参照モデルの各層での問題切り分け
- TCP/IPスタックの実装差異(Windows vs Linux)
- カプセル化とヘッダーオーバーヘッドの影響
-
仮想化ネットワーク
- コンテナネットワーク(Docker)の特性
- 仮想マシンの各種ネットワークモードの仕組み
- WSL2とHyper-Vの統合アーキテクチャ
-
通信セキュリティ
- VPNの暗号化と分離メカニズム
- ファイアウォールとアクセス制御の設計思想
- リバースプロキシとTLS終端の役割
-
パフォーマンス要素
- レイテンシとスループットの相互関係
- ボトルネックの種類と特定方法
- 負荷テスト設計と結果解釈のアプローチ
問題解決の体系的アプローチ
技術的知識と並行して、以下のような問題解決のフレームワークも体得できました:
-
仮説駆動型トラブルシューティング
- 観察された症状から複数の仮説を形成
- 最も可能性の高い仮説から順に検証
- 結果に基づいて新たな仮説を構築
-
階層的問題分離
- ネットワーク層、OS層、アプリケーション層などに問題を分解
- 各層での正常動作を確認しながらボトルネックを特定
- 複合的な問題を単一要素に分解して対処
-
比較分析と変数制御
- 「動く環境」と「動かない環境」の差分特定
- 一つの変数だけを変更して影響を観察
- パターンから根本原因を推測
この体系的なアプローチにより、初見の複雑な問題でも段階的に解決できるスキルが身についたと感じています。
7. 総括:インターンを通じて得た「エンジニアとしての強み」
技術的成長の多面性
このインターンを通じて、以下のような多面的な技術スキルを習得しました:
- バックエンド開発: 非同期プログラミング、APIデザイン、エラーハンドリング
- インフラストラクチャ: コンテナ化、リバースプロキシ、サービス連携
- ネットワーキング: 異種ネットワーク間接続、仮想ネットワーク構成、パフォーマンス最適化
- クラウドサービス: EC2の構築と操作、クラウドストレージAPI連携、ハイブリッド構成の検証
- セキュリティ: 認証フロー実装、ファイアウォール設定、安全なデータ転送
これらの技術は、単に表面的な使い方だけでなく、内部動作原理までを理解することに重点を置きました。そのため、今後新しい技術に出会った際も、基礎原理から応用まで体系的に学べる基盤ができたと感じています。
問題解決能力:失敗からの学びサイクル
技術以上に価値があったのは、以下のような問題解決アプローチを身につけたことです:
-
体系的なトラブルシューティング
- 問題の切り分けと原因の特定
- 仮説の構築と検証
- 根本原因に基づいた解決策の実装
-
失敗を学びに変える姿勢
- VPN接続失敗からVPNアーキテクチャの理解へ
- ネットワーク設定ミスからWSL2の仕組みの理解へ
- パフォーマンス問題からボトルネック分析手法の習得へ
-
継続的な改善と反復
- 初期実装から段階的な機能拡張
- フィードバックに基づく設計見直し
- 失敗から学んだ教訓の次回への適用
特に重要だったのは、「なぜうまくいかないのか」を深く掘り下げる姿勢です。表面的な解決ではなく、根本的な理解を追求することで、将来的に類似の問題に対応できる力が身についたと感じています。
「強いエンジニア」の定義の再考
このインターンでの経験から、私なりの「強いエンジニア」像が見えてきました:
-
技術的深さと幅のバランス
- 特定分野の専門知識を持ちつつ、関連する技術にも広く通じている
- 抽象化レイヤーを自在に行き来できる(高レベル設計から低レベル実装まで)
- 新技術を素早く学び、適切に評価できる
-
問題解決の体系的アプローチ
- 複雑な問題を構造化し、段階的に解決できる
- データと論理に基づいた意思決定ができる
- 効率的なトラブルシューティングができる
-
コミュニケーションと共有
- 技術的な内容を適切なレベルで説明できる
- 自分の知見を他者が活用できる形で共有できる
- チームやコミュニティに貢献する姿勢がある
-
継続的な学習と適応
- 失敗から学び、常に改善する
- 新しい課題に対して柔軟に対応できる
- 自己主導的に知識とスキルを更新し続ける
今回のインターンでは、これらの資質の基礎を築くことができたと感じています。
今後の展望と読者へのメッセージ
この経験を踏まえ、今後はより複雑なシステム開発やインフラ構築に挑戦し、オープンソースへの貢献や技術発信も積極的に行っていきたいと考えています。
最後に、この記事を読んでくださった方へのメッセージです。エンジニアリングの世界では、失敗は成功への階段です。完璧なコードや設計を目指すあまり、手を動かすことを躊躇するより、まずは試してみる姿勢が大切です。今回のインターンでの数々の「失敗」は、私にとって何物にも代えがたい学びとなりました。
特に印象的だったのは、問題に直面したときの「なぜ?」という問いの力です。表面的な症状に対処するだけでなく、根本原因を理解しようとすることで、単なる解決策ではなく、長期的に役立つ知識が得られます。
皆さんも、新しい技術や挑戦に恐れることなく取り組んでみてください。そして、一見無駄に思える「回り道」こそが、実は最も価値ある学びをもたらすことがあると覚えておいてください。
技術は日々進化しますが、問題を体系的に分析し、論理的に解決するというエンジニアリングの本質は変わりません。この記事が、皆さんの技術的な挑戦の一助となれば幸いです。
Discussion