Kubernetes上のアプリケーション開発を加速させるツール(2) Telepresence
![](https://thinkit.co.jp/sites/default/files/styles/main_image_730x/public/main_images/zlab_kube_cover_02_1_2.jpg?itok=F0wZ6tV0)
はじめに
非コンテナ環境と比べると、コンテナ化したアプリケーションは1開発サイクルを回すために、より多くの時間と手数が要求されます。この問題の解決策の1つとして、第4回ではSkaffoldを紹介しました。今回は、Skaffoldとは別のアプローチで開発を効率化するTelepresenceについて紹介します。
Telepresenceを使った開発
Telepresenceは、ローカルからKubernetes用のマイクロサービスを開発するためのツールです。Datawireによって開発が始まり、現在はCNCFのSandboxプロジェクトの1つとなっています。
開発効率改善のアプローチとしては、下図のようにコンテナイメージのビルド*1・アップロード・デプロイといった開発ステップを省略する方法を取っています。これは、Kubernetes上のTelepresence Podから、ローカルに起動したアプリケーションへ通信や各種データをプロキシすることで実現しています。
*1:--docker-runオプションを利用する場合は必要になります。これにより、ローカルで起動したアプリケーションはあたかもKubernetes上にデプロイされたかのように動作します。サポートされている機能は、主にコンテナにマウントされたボリュームデータ(ConfigMapやSecret等)へのアクセス、環境変数の読み込み、Service名を使った他のアプリケーションとの通信です。
また、ローカルへのプロキシ方法はinject-tcpと、デフォルトのvpn-tcpの2つが提供されています。それぞれの概要と、主な制約を表にまとめました*2。実行環境や、アプリケーションの言語等に制約がありますので、適切な方を選択してください。
2つのプロキシ方法とその制約
inject-tcp | vpn-tcp | 概要 | アプリケーションの共有ライブラリを上書きする方法*3 | sshuttleを使ったVPNライクな接続方法 | 主な制約事項 |
|
|
---|
*3:Linuxの
LD_PRELOAD
とmacOSのDYLD_INSERT_LIBRARIES
を利用した方法で、詳細はこちらのブログで詳しく解説されています。*4:
go build
ではなくgccgo
によるビルドやGODEBUG
環境変数でnetdnsのリゾルバをcgoに変更するなどのワークアラウンドは存在しますが、非推奨です。*5:
--also-proxy
フラグによる手動設定は可能です。
第4回と同じく、今回もk8s-sample-applicationを利用します。このアプリケーションはGo言語で書かれていますので、Go言語をサポートするvpn-tcpを使った開発方法を紹介します。
開発の下準備
Telepresenceコマンドのインストール
それでは、実際に検証してみます。macOSの場合はHomebrewを使って下記のようにインストールします。その他の環境へのインストール方法は公式ドキュメントを参照してください。
# telepresenceと依存ツールのインストール $ brew cask install osxfuse && brew install datawire/blackbird/telepresence # バージョンの確認 $ telepresence --version 0.108
サンプルアプリケーションのデプロイ
まずは、開発用アプリケーションを通常通りkubectl apply
で適用します。前回Gitクローンしたsample-k8s-appディレクトリに移動し、manifestsディレクトリ内のマニフェストを適用してください。念のためkubectl get
で正常に動作していることも確認しましょう。DeploymentのREADYカラムが1/1
になっていれば大丈夫です。
# (1) 該当ディレクトリに移動 $ cd sample-k8s-app # (2) アプリケーションマニフェストの適用 $ kubectl apply -f manifests deployment.apps/myapp created service/myapp created # (3) デプロイしたリソースの確認 $ kubectl get deploy,svc myapp NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/myapp 1/1 1 1 33s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/myapp NodePort 10.102.199.85 <none> 80:30216/TCP 33s
Telepresenceによるローカルへのプロキシ
次に、アプリケーションをローカルから開発できるようにtelepresence
コマンドを実行します。--swap-deployment
フラグには置き換え対象となるDeployment名、--expose
フラグにはDeploymentで公開しているポート番号、--run
フラグにはアプリケーションを起動するためのコマンドを指定します。
正常にTelepresenceのプロキシ設定が完了すると、Start server...
というmyappの起動ログが出力されます。
# (1) telepresence --swap-deployment <Deployment名> --expose <ポート番号> --run <アプリケーションの起動コマンド> $ telepresence --swap-deployment myapp --expose 8080 --run go run main.go T: Using a Pod instead of a Deployment for the Telepresence proxy. If you experience problems, please file an issue! T: Set the environment variable TELEPRESENCE_USE_DEPLOYMENT to any non-empty value to force the old behavior, e.g., T: env TELEPRESENCE_USE_DEPLOYMENT=1 telepresence --run curl hello T: How Telepresence uses sudo: https://www.telepresence.io/reference/install#dependencies T: Invoking sudo. Please enter your sudo password. Password: # (2) sudoパスワードの入力 T: Starting proxy with method 'vpn-tcp', which has the following limitations: All processes are affected, only one telepresence can run per T: machine, and you can't use other VPNs. You may need to add cloud hosts and headless services with --also-proxy. For a full list of method T: limitations see https://telepresence.io/reference/methods.html T: Volumes are rooted at $TELEPRESENCE_ROOT. See https://telepresence.io/howto/volumes.html for details. T: Starting network proxy to cluster by swapping out Deployment myapp with a proxy Pod T: Forwarding remote port 8080 to local port 8080. T: Connected. Flushing DNS cache. T: Setup complete. Launching your command. # (3) アプリケーションログが標準出力に表示される 2020/09/19 15:07:23 Start server...
では、実際に置き換わったことを別のターミナルから確認しましょう。myappのDeploymentを確認すると、(1)のようにPodのレプリカ数が0に変わっていました。しかし、(2)の通りmyappをプレフィックスに持つPodが起動しています。では、このPodはいったい何者でしょうか?
このPodのコンテナイメージを確認すると、(3)のようにdatawire/telepresence-k8s:0.108
が返ってきました。このことから、telepresence
コマンドを実行したタイミングで、指定したmyappがTelepresenceコンテナイメージを持つPodに置き換えられたことが分かります。
また、(4)のようにmyapp ServiceのEndpointもTelepresence Podを参照しています。よって、NodePort経由でアプリケーションにリクエストを送信すると、ローカルで起動しているmyappからレスポンスが返ってきます。
# (1) Deploymentのレプリカ数が0に変わっている $ kubectl get deploy myapp -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 0/0 0 0 2m49s sample-k8s-app ladicle/sample-k8s-app app=myapp # (2) myappの名を持つPodが新たに立ち上がっている $ kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-51b8df20eef24324959a3f3eb46e7d48 1/1 Running 0 94s 192.168.189.82 worker2 <none> <none> # (3) PodのコンテナイメージはTelepresenceに置き換わっている $ kubectl get po myapp-51b8df20eef24324959a3f3eb46e7d48 -o jsonpath='{.spec.containers[0].image}' datawire/telepresence-k8s:0.108 # (4) myappのService Endpointは、Telepresenceのコンテナイメージを持つPodのIPを参照している $ kubectl get ep myapp NAME ENDPOINTS AGE myapp 192.168.189.82:8080 3m17s # (5) myapp ServiceのNodePort経由で、ローカルに起動しているmyappからレスポンスを受け取る $ curl http://:30216/hello Hello World
開発フローを回す
サンプルアプリケーションの修正と確認
続いて、プログラムを修正して変更内容が適用されていることを確認します。下記のようにmain.go
のコメントアウトされている行をアンコメントしてください。
diff --git a/main.go b/main.go @@ -7,11 +7,11 @@ import ( - // "os" + "os" ) func main() { - // log.Printf("TELEPRESENCE_ROOT: %v, TELEPRESENCE_MOUNTS: %v", os.Getenv("TELEPRESENCE_ROOT"), os.Getenv("TELEPRESENCE_MOUNTS")) + log.Printf("TELEPRESENCE_ROOT: %v, TELEPRESENCE_MOUNTS: %v", os.Getenv("TELEPRESENCE_ROOT"), os.Getenv("TELEPRESENCE_MOUNTS"))
この変更の適用はtelepresence
コマンドを再実行するだけです。実行するとアンコメントしたログ出力が確認できます。このように、Telepresenceではコンテナイメージのビルド・アップロード・ダウンロードというステップを省略することで、修正と動作確認をすばやく繰り返すことができます。
今回はアプリケーションをビルドするため、変更適用時にtelepresence
コマンドを再実行しましたが、Node.jsのnodemon
のようなコード変更時に再起動するツールを利用すれば、コマンドの再実行は不要です。また、アプリケーション自体はローカルに立ち上がっていますので、IDE等でローカルデバッグも可能です。
$ telepresence --swap-deployment myapp --expose 8080 --run go run main.go (省略) 2020/09/20 13:14:12 TELEPRESENCE_ROOT: /tmp/tel-fcw5e_zg/Fs, TELEPRESENCE_MOUNTS: /var/run/secrets/kubernetes.io/serviceaccount 2020/09/20 13:14:12 Start server...
コンテナボリュームのデータ参照
はじめに紹介したように、Telepresenceではコンテナボリュームもローカルから参照できます。試しにdf
コマンドでローカルのファイルシステムを見ると、TELEPRESENCE_ROOT
環境変数が示すパスにマウントされていました。
それでは、ServiceAccountトークンが格納されているディレクトリも確認してみましょう。(2)のように/var/run/secrets/kubernetes.io/serviceaccount
ディレクトリを参照すると、コンテナ内と同じ3つのファイルが確認できました。
# (1) ローカルにコンテナボリュームがマウントされていることが確認できる $ df | grep telepresence telepresence@127.0.0.1:/ 479101704 13557996 446013480 3% /private/tmp/tel-fcw5e_zg/fs # (2) `/var/run/secrets/kubernetes.io/serviceaccount` を参照するとコンテナ内と同様にServiceAccountトークンなどが格納されている $ ls /tmp/tel-fcw5e_zg/fs/var/run/secrets/kubernetes.io/serviceaccount ca.crt namespace token
もちろん、コンテナ内のファイルパスとは異なりますので、TELEPRESENCE_ROOT
が設定されている場合は、その値をパスのルートとするような処理をアプリケーションに入れる必要があります。
おわりに
以上のように、Telepresenceはコンテナイメージのビルド・アップロード・デプロイを省略するため、非コンテナ環境と同じような流れで開発できることが分かりました。
今回は紹介しませんでしたが、コンテナ特有のバグなどを発見するための--docker-run
フラグも存在します。これを利用すれば、Dockerでローカル上にアプリケーションコンテナを立ち上げ、そのコンテナに対してプロキシを通すといったこともできます。もちろん、Telepresenceにも制約は色々ありますので、第4回で紹介したSkaffoldと合わせて、ご自身の環境にあった開発を加速させる方法を模索してみてください。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Kubernetesクラスターの遠隔操作による開発を支援するTelepresence
- Oracle Cloud Hangout Cafe Season7 #1「Kubnernetes 超入門」(2023年6月7日開催)
- KubernetesのDiscovery&LBリソース(その1)
- Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
- KubernetesのWorkloadsリソース(その1)
- Kubernetes上のアプリケーション開発を加速させるツール(1) Skaffold
- Kubernetes 1.18の新機能を学び、使ってみよう
- Kubernetesの基礎
- 「Inspektor Gadget」でKubernetesクラスタをデバッグする
- Kubernetes環境を構築して、実際にコンテナを動かしてみよう