squashでKubernetesのPod内のGoアプリをデバッグ実行する
はじめに
最近、アプリの実行プラットフォームとしてk8sを使うことが多いのですが、ローカルで動いているアプリがk8s上で動かないみたいな事象にハマることがありました(もちろん、なるべく環境は合わせるようにしていたのでですが、ローカルでは外部APIを一部モックしたりしている箇所がありそこの周りで)。
そんなとき、「Kubernetesで実践するクラウドネイティブDevOps」を読んでるときに
kubesquashというツールの名前と概要が紹介されていました。どうもこいつを使うと、k8s上で動いているアプリのデバッグを行なうことが可能になるとのことで、興味が湧いたので使ってみたいと思います。
.....と、思ったのですが、どうもkubesquashはsquashにマージされいました。なのでそちらを今回は使ってみたいと思います。
このブログのゴールは以下の通りです。
Squashとは
SquashはKubernetesで動作中のアプリに対して、ターミナルやIDEからデバッグ実行を可能とするOSSです。
Squashを利用することで以下のようなことが可能になります。
- 動作するマイクロサービスをDebuggingする
- contenier内のPodをDebuggingする
- ブレークポイントを置く
- ステップ単位でコードを実行する
squashは現在(2020/4/6)以下のDebuggerをサポートしているます。
また、プラットフォームは以下のものをサポートしているようです。
- Kubernetes
- OpenShift
- Istio
私は普段IntelliJ Ideaを使ってコーディングすることが多いのですが、dlvのサポートが無いらしいので、今回はVS Codeのプラグインを使います。
Goのアプリをデバッグする
Gin製のアプリをminikubeにデプロイして、デバッグをしてみます。
動作環境
インストールして動かす環境は以下です。
$ uname -srvmpio Linux 5.3.0-51-generic #44~18.04.2-Ubuntu SMP Thu Apr 23 14:27:18 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ docker -v Docker version 19.03.8, build afacb8b7f0 $ minikube version minikube version: v1.5.2 commit: 792dbf92a1de583fcee76f8791cff12e0c9440ad-dirty $ dlv version Delve Debugger Version: 1.4.0 Build: $Id: 67422e6f7148fa1efa0eac1423ab5594b223d93b
今回はk8sのクラスタはminikube上に構築します。
また、goのDebaggerであるdlvのインストールも必要なようなので事前にしておいてください。(Linuxでのdlvのインストるはここから)
下準備
もろもろのセットアップとかを行なうまえに以下のことをやっておきます。
- Ginでサンプルアプリを作成
- minikube 上にデプロイ(ServiceとDeploymentの作成)
- ローカルでの疎通確認
Ginでサンプルアプリを作成
さくっとアプリを作ってしまします。
$ mkdir sample-app $ cd sample-app $ go mod init sample-app $ go get -u github.com/gin-gonic/gin
作成するアプリはGin公式のquick-startを丸パクリします。
main.go
package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() }
実行してみます。
$ ls go.mod go.sum main.go sample-app $ go run main.go # 別ターミナルで $ curl http://localhost:8080/ping {"message":"pong"}
アプリは完成しました。
minikubeにデプロイ
作成したアプリをminikubeにデプロイしてみます。
まずは、作ったアプリをビルドします。
$ GOOS=linux CGO_ENABLED=0 go build -gcflags "-N -l" -o sample-app
-gcflags "-N -l"
ははDebuggerに必要な情報を出力するためのオプションです。
次にはイメージを作成します。 以下のDokcerfileを使用します。
FROM alpine COPY sample-app /sample-app ENTRYPOINT ["/sample-app"] EXPOSE 8080
ビルドします。
$ docker build -t sample-app:1.0.0 .
次にdeployment.yml
とservice.yml
を作成します。
$ kubectl create deployment sample-app --image=sample-app:1.0.0 --dry-run -o yaml > deployment.yml $ cat deployment.yml apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: sample-app name: sample-app spec: replicas: 1 selector: matchLabels: app: sample-app strategy: {} template: metadata: creationTimestamp: null labels: app: sample-app spec: containers: - image: sample-app:1.0.0 name: sample-app ports: - containerPort: 8080 resources: {} status: {} $ kubectl create service nodeport sample-app --tcp=8080:8080 --dry-run -o yaml > service.yml $ cat service.yml apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: sample-app name: sample-app spec: ports: - name: 8080-8080 port: 8080 protocol: TCP targetPort: 8080 selector: app: sample-app type: NodePort status: loadBalancer: {}
作成したymlを使ってリソースを作成します。
$ kubectl apply -f deployment.yml $ kubectl apply -f service.yml
また、localhostのアクセスでServiceにつながるようにするためにport-fowordをしておきます。
$ kubectl --context=minikube port-forward service/sample-app 8080:8080 $ curl localhost:8080/ping {"message":"pong"}
これで下準備は完了です。
squashのインストール
Mac OS用にはBrewでパッケージが用意されているようですがLinuxでは無いので、ここから最新のリリースを落として来て任意のディレクトリに起きPATHを通すようにします。
# ダウンロード $ wget https://github.com/solo-io/squash/releases/download/v0.5.18/squashctl-linux $ wget https://github.com/solo-io/squash/releases/download/v0.5.18/squashctl-linux.sha256 $ sha256sum squashctl-linux 071406a1eadcf78014c1b6c629c46e3145a1f150d40555a4be0410747160b82b squashctl-linu $ cat squashctl-linux.sha256 071406a1eadcf78014c1b6c629c46e3145a1f150d40555a4be0410747160b82b squashctl-linux # 今回はPATHの通っているところに配置 $ sudo mv squashctl-linux /usr/local/bin/squashctl $ sudo chmod +x /usr/local/bin/squashctl $ squashctl --version squashctl version 0.5.18
これでインストールは完了です。
VS codeからSquashを実行する
前述の通り、VS Codeのプラグインを用いて、Pluginの検索ボックスに"squash"と入力してプラグインをインストールします。
プラグインにはsquashctlのPathを設定してやる必要があります。
[Setting]の検索ボックスにsquash
と入力してSpuash: Path
の項目に/user/local/bin/squashctl
を指定してやります。
これで、インストールは完了です。
デバッグを実行する
それでは実際にデバッグをしてみましょう。
作成したmain.go
のソースファイルを開き、ctrl + shift + p
でコマンドパレットを開きます。
検索ボックスにsquash
と入力し、[debug pod]⇨[namespace]⇨[sample-app-デバッグしたいpodID]⇨[dlv]の順番でデバッグを実行したいNamespace、PodとDebeggerの種類を選択します。
そうすると、Debeggerが立ち上がります。
コードの左側(コードの行数が書かれている左側)をクリックするとブレークポイントを置くことができます。
この状態でcurlを叩くと置いたブレークポイントの位置で実行が停止します。
$ curl localhost:8080/ping
後は煮るなり焼くなりって感じですね。
感想
はじめは、アプリをマルチステージビルドでやっていたのですが、どうもビルドしたバイナリが、ローカルに無いとうまく動かないっぽいですね(この辺の理解がまだ甘いですが...)。それに気がつくまでにめっちゃ時間がかかりました。
それと、単一Podのデバッグ実行はできたのですが、ReplicaSetのスケールが1以上の場合は、少しやり方を考えないと行けないかもなと感じました。