Kube Forwarderの不具合を修正してみた

# 概要

Kubernetesでのport-forwardには[Kube Forwarder](https://kube-forwarder.pixelpoint.io/)が便利で日常的に利用しているのですが、いくつかの不具合があり困っていました。[修正のPR](https://github.com/pixel-point/kube-forwarder/pull/64)を送ってみたりもしたのですが反応がなく、残念ながら最近は開発がアクティブではないようです。

そこで自分が困っている範囲を修正したバージョンのビルドを作成してみました。

- https://github.com/madogiwa/kube-forwarder/releases/tag/v1.5.2-snapshot-20200706

もしKube Forwarderで下記のような症状に困っている方がいたら[修正版](https://github.com/madogiwa/kube-forwarder/releases/tag/v1.5.2-snapshot-20200706)を利用すると幸せになれるかもしれません[^1]。

- MySQL等への接続に失敗する
- SSL(TLS)接続に時々失敗する

ちなみにKube Forwarderって何という方は下記の記事が参考になります。

- [kubectl port-forward 、僕はもう疲れたよ](https://qiita.com/high-u/items/93ce894b61aabe95a76c)

以降では具体的な修正内容などを簡単にメモしています。
同じ不具合で困っていて、とりあえず修正されていればOKという場合は見なくて大丈夫です。

[^1]: 未検証ですが修正内容的には1.4.2以前のバージョンを使うことでも回避できる可能性があります。そのため、もし野良ビルドを利用したくない（もしくはbrew caskでインストールしたい）などの場合はそちらの方法をお試し頂くと良いかもしれません。（ただし起動毎にバージョンアップしろと言われるという別の問題は残ります…）

# 修正内容
## MySQL等への接続に失敗する問題

[バージョン1.5.0](https://github.com/pixel-point/kube-forwarder/releases/tag/v1.5.0) でポートがHTTP(S)の場合にリンクが自動で表示されるという機能が追加されています。

これを実現するため、port-forwarding を開始した直後に HTTP の Option メソッドを送ってみて、返事があったらHTTP(S)と見なすという動作をしているようです。この動作が一部のアプリで問題を引き起こしている[^2]ようなので修正しました。

個人的にこの機能が不要だったのと、アップストリームに送る想定ではなかったので、今回はざっくりと該当機能を削除しています。

- https://github.com/madogiwa/kube-forwarder/commit/fd9776d34c80ac45fa2188783316fad8f4ed3f80

[^2]: HTTPではないサーバにとっては、TCPのConnectionを受け付けた後に途中までデータを受け取った、という中途半端な状態になってしまっているのだと思います。

## TLS接続に時々失敗する問題

[バージョン1.5.1](https://github.com/pixel-point/kube-forwarder/releases/tag/v1.5.1) でMariaDBへの接続に失敗する問題への対応として、port-fowardingを開始した直後に（実際のデータを送る前に）WebSocketのconnectionを作成するようになっています。

ところがconnectionが確立する前にデータの送信が発生してしまうと、新しいconnectionが作られてしまい、結果として2重にconnectionが作成されて問題が引き起こされてしまうようです[^3]。

そこで修正としては微妙ですが、二つのconnectionのうち最初に作成された方だけを生かして、もう一方をcloseするようにしました[^4]。

- https://github.com/madogiwa/kube-forwarder/commit/d6b847d47210f2cf86a63eb95b3cabfa0877be32

[^3]: バージョン1.5.0で開始時にOptionリクエストを送信するようになっているため実際は常にこの条件に該当するようです。
[^4]: MariaDBへの接続に失敗する問題は1.5.0で導入された機能によるものと思われるため、一つ前の修正によりこの仕組み自体が不要になっているという話もある気はします。

## bind先を指定しないと動かない問題

originのmasterに含まれる新機能として、デフォルトではlocalhostをlistenするところ、代わりに任意のアドレスに対するlistenが可能となる機能が追加されています。

ただこの機能は実装が不完全なようで、アドレスを指定しないとエラーが発生する状態になっていました。具体的には localAddress が `null` か `空文字列` かで状態を制御しようとしているのですが、`null` の場合に後続の処理でエラーになってしまうのが原因です。

ここは素直に状態管理用に別のフラグを導入して対処しました。

- https://github.com/madogiwa/kube-forwarder/commit/55e5b10c97f4d6d5fb3d4a3d85863185b2509b16

## Mac（10.15）でビルドできない問題

READMEに書かれた手順でビルドしてみると、下記のエラーが出てビルドできませんでした。

```
Can't locate Mac/Memory.pm in @INC (you may need to install the Mac::Memory module) (@INC contains: /Library/Perl/5.18/darwin-thread-multi-2level ...
```

これはアプリのビルドに利用されているelectron-builderの既知の問題らしく、基本的にはelectron-builderを最新版にすれば解消されるようです。ただそれだけでは.zipファイルが壊れてしまうという別の問題があるようなのですが、今回は原因の追及をせずにビルド生成物から.zipを外して.dmgだけにすることで対処しました。

- https://github.com/madogiwa/kube-forwarder/commit/0207b173e1eede3a012dca689b1e4513ec58713e

## 公証の取得

最近のMacでは公証（Notarize）を取得していないアプリは、ダウンロードしても警告が出て開けない状態となってしまいます。これを回避するには、Appleから公証を取得しないといけないのですが、具体的には下記を実施すれば良いようです。

- ビルドしたアプリに署名を付与する[^5]
- ビルドしたアプリをAppleのサーバに送付して公証をもらう

ビルド時の署名付与については electron-builder が自動で行ってくれるようです。

もう一方の公証の取得については、下記の記事などを参考にさせて頂きました。

- https://qiita.com/TomoyukiAota/items/6b81b4126058e7fd4099
- https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/

具体的には `electron-notarize` を利用してビルド後に自動的に公証を付与するようにしました。

- https://github.com/madogiwa/kube-forwarder/commit/1189cfdab943e6193cc84df1af94aafdd8e0a99f

[^5]: ビルド時に署名を付与すると公証に問題が出る的な情報もあったのですが特に問題なかったので詳細は未検証です。