takutakahashi.dev

Global IP のない環境から k8s Ingress を使う

Global IP を持たない環境で,自宅 k8s からアプリケーションを公開するためのミドルウェアを作りました.

経緯

このお話の経緯を以下に説明します.
結論のみ興味ある方は,「構成概要」にお進みください.

アプリケーションのパブリックアクセス

開発したアプリケーションをパブリックで利用できるようにするためには,
グローバルにアクセスできる IP が必要となります.
固定回線を契約している環境下だと,インターネットに到達するための IP が付与されます.
その IP を利用して,インターネットに家庭内のアプリケーションを配信することができます.

マンション共有回線

しかし,インターネット回線がマンションの共有回線の場合ですと話は別です.
この場合ですと,マンションに1つのグローバル IP が付与され,管理施設にあるルータで各部屋にプライベートIPが付与される形式が一般的です.
よく,「インターネット無料!」と言われているものはだいたいグローバル IP を降ろしていません.

我が家がもれなくこの環境でして,外部到達を必要とするアプリケーションは GKE にデプロイしていました.

リソースが無駄に...

我が家には結構いいスペックの自宅サーバが設置してあります.
できればこのマシンでアプリを動かしたいのですが,外部到達できない.
外部到達のために低スペックの GKE を契約し,月数千円を払っている...もったいない状況でした.

外部からアクセスするぞ!

少し頑張って外部への穴を開けるぞ!というプロジェクトをはじめました.
結果,けっこういいものができたので紹介します.

構成概要

  • svc を緑, Pod を青で表示しています
  • 作図の都合上,物理構成と k8s の論理構成を混ぜています
  • 作図の都合上,svc は1ノードに載っているなど,一部正しくない表現が混ざっています

Global IP を持つ構成

Global IP を持つ構成では,簡易的には以下の構成となると思います.

  • NodePort をルータの 80, 443 にフォワーディングする
  • ルータの Global IP で受けたリクエストを ingress-controller がハンドリングする

NodePort とルータの経路を MetalLB で冗長化することはできます.

Global IP を持たない構成

構成は以下のようになります.

  • public → private へのトンネルとして pagekite.net を利用する
  • pagekite.net から受けたリクエストを pagekite-ingress-proxy が受ける
  • pagekite-ingress-proxy がリクエストを ingress controller に流す
  • ingress controller が適切な svc にリクエストを流す

pagekite.net

https://pagekite.net/

ローカルのアプリケーションをグローバルに晒すことができるサービスです.
アプリケーション開発者の間では,競合の ngrok が有名です.
pagekite を採用した理由として

  • 固定 subdomain (ex: hogehoge.pagekite.me) が無料で利用できる
  • subdomain に複数の CNAME を設定できる

という特徴があり,Ingress のハンドリングに最適であると判断しました.

pagekite-ingress-proxy

pagekite とトンネルを張る Proxy が内部に必要です.
Ingress などのリソースを監視し,設定を反映する Proxy を作成しました.

https://github.com/takutakahashi/pagekite-ingress-proxy

Proxy の動作

この Proxy は以下の動作を行います.

  • ingress-controller の svc を監視し pagekite config 書き換え process を reload
  • Ingress resource を監視し pagekite config 書き換え process を reload
  • Ingress resource から Host を取得し pagekite に CNAME を設定
  • pagekite → ingress-controller の L7 Proxy

つまりは,リソースを監視し自身のコンフィグを書き換え L7 Proxy するためのミドルウェアです.

ingress-controller に proxy するメリット

pagekite-ingress-controller として,自身から直接 application svc に L7 Proxy することもできるのですが,
ingress-controller に処理をバイパスすることで以下のメリットを享受することができます.

  • nginx-ingress-controller など,高機能の ingress-controller が利用できる
  • 独自ドメインでの TLS 終端ができる
    • hogehoge.pagekite.me や,app-hogehoge.pagekite.me のみ TLS 終端が可能

どっちも非常に魅力的なメリットですので,この形式としました.
独自ドメインのアプリケーションを cert-manager で作成した Let's Encrypt の証明書で配信できています.

その他のメリット

さらに,Deployment で proxy をデプロイすることにより,
NodePort をルータに登録する手法よりもノード障害への耐障害性が高まっています.
(pagekite の障害へのリスクはありますが...)

課題

この構成での課題がいくつかあります.

1. tls を配信する svc への proxy ができない

pagekite は CONNECT メソッドを利用できないため,例えば kubernetes svc のような,自身が https を配信する svc には繋げません.
internal の通信は http に限られます.
あくまで自宅用なので大きな支障はないですが,kubernetes api endpoint を外部公開できないのでちょっと不便です.
似たような仕組みで loadbalancer cloud provider を実装しようかな...

まとめ

外部のサービスを利用することで,k8s を更に活用できる環境を構築できました.
pagekite-ingress-proxy 自体にも,さらにメトリクス配信や監視プラクティスの構築など,
いろいろと機能を追加していければと思います.