（和訳）MacOS での Kubernetes 開発ワークフロー

Kubernetes の開発環境や周辺ツールについて、Google Cloud のエンジニアである Megan O'Keefe さん ([@askmeegs](https://twitter.com/askmeegs)) による記事 ["A Kubernetes Development Workflow for MacOS 💻"](https://medium.com/@mo_keefe/a-kubernetes-development-workflow-for-macos-8c41669a4518) が非常に参考になったので和訳しました （公開にあたっては著者の許可をいただいています）。

---

# 💻 MacOS での Kubernetes 開発ワークフロー

[Kubernetes](https://kubernetes.io/) 開発というのは「フリーサイズの服」ではありません。ローカルマシン上の [Minikube](https://github.com/kubernetes/minikube) で Kubernetes を勉強中という人もいれば、たくさんのクラスタを持つ大規模組織で働いている人もいるでしょう。クラスタはオンプレミスの実験環境かもしれませんし、クラウド上に構築されているかもしれません。

しかし、クラスタのポリシー管理をしているオペレータであれ、新規サービスをテストしているアプリケーション開発者であれ、あるいは [Kubeflow](https://www.kubeflow.org/docs/about/kubeflow) を動かしているデータサイエンティストであっても、おそらくは「クラスタに接続する」、「その状態を調べる」、「リソースを作成する」、「そのリソースをデバッグする」といったことのどれかは（あるいは全部を）行っていると思います。

Kubernetes のデベロッパーリレーションズエンジニアとして、私はたくさんのデモコードやサンプル、サンドボックス用クラスタを使っています。となるとこれは把握するだけでもおもしろい（読み方:「完全なカオス」）ことにもなりかねません。そこで、この記事では私の Kubernetes ライフを快適にしてくれるツールたちをお見せしたいと思います。

この環境はどんなスタイルで Kubernetes を使っている人にとっても役に立つはずです。そして、これらのツールはすべてオープンソースコミュニティの驚異的な力のおかげで生まれたものです。

* * *

## 💻 ターミナル

私は [iTerm2](https://www.iterm2.com/) を [palenight](https://github.com/JonathanSpeek/palenight-iterm2) カラースキーマで使っています。そして [zsh](http://www.zsh.org/) と [oh_my_zsh](https://github.com/robbyrussell/oh-my-zsh) をデフォルトの `robby-russell` テーマにして使っています。

このテーマには基本的な Git サポートが付いていますが、同時にミニマルでもあります。もし現在の Kubernetes コンテキストをシェルのプロンプトに表示してみたいと思う人は、 [kube-ps1](https://github.com/jonmosco/kube-ps1) や [spaceship](https://github.com/denysdovhan/spaceship-prompt#features) プロンプトについて調べてみてください。
![1_JSiYljTJt2LyffjZ9_Irag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/45fd8ef7-35bf-addc-ddc1-1544723d170b.png)
そして、重要なのは `~/.zshrc` ファイルの中に次の行を入れておくことです:

```sh
source <(kubectl completion zsh)
```

これによって kubectl コマンドのタブ補完が [可能になります](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion) 。これでもうポッド名のコピペは不要です！

## 🛶 クラスタ間の移動

どんな日でも私は３つのクラスタを使い分けています。みなさんも同様かもしれませんね！みなさんはいつも `kubeconfig` を開くのが面倒ではないですか？私もそうです！そこで朗報です。その用途にぴったりな [kubectx](https://github.com/ahmetb/kubectx) というものがあります:
![1_vt7On1gLVnZyFKDScL-GJw.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/0e4b0df5-4ca0-4c62-01f9-687c2fb04490.gif)
kubectx を使うと、複数クラスタの [コンテキスト](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#define-clusters-users-and-contexts) の間を簡単に移動することができます。私のお気に入りは `kubectx -` を実行すれば１つ前に使っていたクラスタに戻れることです。

## ⚡️ パワーアップした kubectl

それではクラスタにたどり着くことができたので、作業にとりかかりましょう。

みなさんは kubectl にはフラグがたくさん付いてとても長いコマンドになってしまうと感じたことがあるかもしれません。私は kubectl のタブ補完とエイリアス（コマンドのショートカット）集を組み合わせるのがとても便利だと思います。

こちらに [kubectl エイリアスの素晴らしいまとめ](https://github.com/ahmetb/kubectl-aliases) があります。これを使うと例えば
![1_8j4WgwFfK_9wOHq5K2TUtg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/a749a72f-68f5-edbd-e820-4bd2e354b7ba.png "get pods")
![1_trS4MZoird8kgIaM618eig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/a3b7855b-6f54-3a6d-3520-acc313da8702.png "describe pod")
のようなことができます。

最後に、私は [kubectl のプラグイン](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/) をいくつか入れています。しかし手動でこれをセットアップするのは面倒のもとです。そこで私は [krew](https://github.com/GoogleContainerTools/krew) という [オープンソースの kubectl 用プラグインマネージャ](https://medium.com/@ahmetb/kubectl-plugin-management-21dcd93e3721) を使っています:
![1_1TjlIdS2DfKVabZ5ldCLCg.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/72c89112-5311-56a8-b98f-77e75e00abe3.gif "krew")
krew で kubectl プラグインの検索とインストールを行えば、カスタムコマンドが使えるようになります。

## 📜 yaml の取り扱い

それではクラスタの準備が整いましたので、何かデプロイしてみましょう。

Kubernetes で開発を行うということはつまり、たくさんの YAML ファイルを書いて、管理して、更新して、デプロイするということです。私は自分の YAML ファイルをすべて [Git](https://github.com/m-okeefe/helloworld) で保存するようにしています。

（ローカルにファイルを保存しておくのではなく） [GitOps](https://www.weave.works/technologies/gitops/) を早めに取り入れることで、初めのうちにデバッグしていたころのリビジョン履歴がわかるようになり、後でアプリケーションのパイプライン (例: GitHub webhook による CI/CD パイプライン) を整えたくなったときに上手くいくよう備えておくことができます。

私はテキストエディタとして [VSCode](https://code.visualstudio.com/) を [Moonlight](https://marketplace.visualstudio.com/items?itemName=atomiks.moonlight) テーマで使っています。
そして、VSCode には元から素晴らしい機能がたくさんあるのですが、Red Hat の [YAML Support](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) プラグインを入れるとバリデーション・オートコンプリート・フォーマットができるようになってとても便利になります。
![1_ZGdvQwvn6_8WavC8L3XJ5Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/a7d8ae66-dfc0-7941-dc8e-df1f0cbe2baa.png)

いまのところ、私が Kubernetes の YAML ファイルを書くときのプロセスは完全に手動です。しかし、普段プロジェクトを新規作成するとき、私はいつも同じ Kubernetes スペック - ConfigMap, Secret, Volume, Deployment, Service - を書いています。

私はこのプロセスを効率化する方法をいろいろと調べているところです。テキストエディタの拡張機能や、 [テンプレートエンジン](https://github.com/kubernetes-sigs/kustomize) や、その他のツールなど種類を問わずです。もしみなさんが YAML を書いたり管理したりするのに使っているツールがあれば、下でコメントしてください！⬇

## ✨ デプロイ

YAML ファイルができたので、これでリソースをデプロイできるようになりました！パワーアップした `kubectl` 環境を手に入れたので、手動でデプロイする誘惑にかられそうなところです。

しかしこれは危ない橋で、そうすると `docker build`, `docker push`, `kubectl apply`, `kubectl delete pod` などの同じコマンドを何度も繰り返す羽目になってしまいます。これは嫌です。

[skaffold](https://skaffold.dev/) というツールでこの辛い作業を自動化することができます。skaffold は魔法のようです: skaffold はコードベースの変化を監視します。ローカルで変更が保存されると、skaffold は自動的に Docker イメージをビルドし、イメージを新規タグでプッシュし、クラスタへの再デプロイを行います。
![1_rF-csS89udEJ6w-O9KFEbg.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/0b3e9475-d316-862d-eb1c-59a7e503424d.gif)

skaffold の本当にクールなところの１つがイメージタグの自動生成です。このおかげで実際の YAML ファイルにはイメージのタグではなくリポジトリだけを書いておけば、skaffold がデプロイ時に新しいタグを埋め込んでくれます。
 
```yaml
spec:
  containers:
  - name: helloworld
    image:  gcr.io/megangcp/helloworld
    imagePullPolicy: Always
   ports:
     - containerPort: 8080
```

skaffold のために唯一必要なのは (やはり YAML の) 構成ファイルです:

```yaml
apiVersion: skaffold/v1beta3
kind: Config
build:
  artifacts:
  - image: gcr.io/megangcp/helloworld
deploy:
  kubectl:
    manifests:
      - kubernetes/*
```

この例は最小限の構成になっており、この中でイメージのリポジトリを指定しています（この場合は [Google Container Registry](https://cloud.google.com/container-registry/) にありますが、 DockerHub など他のレジストリでも同様に使えます）。またマニストファイルが置いてあるディレクトリもこの中で指定しています。

skaffold は [非常にカスタマイズ性が高く](https://github.com/GoogleContainerTools/skaffold/tree/master/examples) 、kubectl のほか Helm などのデプロイツールと一緒に使うことができます。

## 🐳 Docker イメージの調査

skaffold は Docker のビルドプロセスを抽象化してくれますが、新規にビルドされたイメージを詳しく調べたくなることもあります。例えば、イメージのサイズは前のバージョンに比べてどうか？とか、各イメージレイヤに含まれる内容はどうなっているか？といったことについてです。

[dive](https://github.com/wagoodman/dive) は Docker イメージの調査に使える強力なツールです。
![1_zLIgc-0sHlfLAH0eJ06S6g.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/00d5ee14-9119-0349-5d72-65c2343a349f.gif)
dive を使えば、異なるレイヤーの間でのファイルシステムの違いを調べることができます。これは Docker ビルドがどこかで失敗しているときにとても役に立ちます。

## 😱 デバッグ

Kubernetes 上でポッドを動作させるところまで来ました。次にやることは何でしょうか？

スペック指定やアプリケーションのコードの中で、時折（読み方:「いつも」）何かが間違っていることがあります。

私が普段 Kubernetes のデバッグをするときの流れはこんな感じです:

1. **ポッドを表示します** （エイリアスは `kdpo` ）。スペックが間違っている？（例: デプロイメントでマウントしようとしてるシークレットが誤って別の名前空間になっている？）そうでなければ...
2. **ポッドのログを取得します。**
[skaffold dev](https://skaffold.dev/docs/getting-started/#skaffold-dev-build-and-deploy-your-app-every-time-your-code-changes) 
コマンドを使うとすべてのデプロイ中のコンテナログを結合して標準出力に流すことができます。
しかしポッドが２つ以上あるとき、このログフォーマットは鬱陶しい感じがします。
また同様に、通常の `kubectl logs` コマンドでも永遠にポッド名のコピペを繰り返すことになります。<br><br>
その代わりに、ログをカスタマイズして tail できる強力な手段が [stern](https://github.com/wercker/stern) です。stern はポッドを選ぶのに正規表現を使います &mdash; そしてポッドの名前はすべてデプロイメント名で始まるので、正確なポッド名を知らなくても、あるデプロイメントに含まれるすべてのポッドのログを追うことができます。これはめちゃくちゃ便利です:
![1_WqZ3eEhhbt8Wau_G6DWDyQ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/4b19bb45-37cc-9598-c651-b6414d6d8ee0.png)
ログを見ても何が悪いのか手ががりがつかめなかったら、たいてい私は...
3. **ポッド内で Exec します** （エイリアス `kex` とタブ補完を組み合わせます）:
![1_RnF4LX330A4slnax3cvt3A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78813/a8a43856-1737-17d6-2d04-1424e442c344.png)

## おわりに

Kubernetes は大規模な設定構造を持つ大きく複雑なソフトウェア構成物です。さまざまな k8s 利用歴の方がいらっしゃると思いますが、どなたにとってもこのツール共有が多少のお役に立てば嬉しく思います。

この記事で紹介したツールやプラグインの一覧はこちらです:

* [iterm2](https://www.iterm2.com/) / [palenight](https://github.com/JonathanSpeek/palenight-iterm2) / [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh)
* [kubectl tab completion](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)
* [kubectx](https://github.com/ahmetb/kubectx)
* [kubectl エイリアス集](https://github.com/ahmetb/kubectl-aliases)
* [krew](https://github.com/GoogleContainerTools/krew)
* [VSCode](https://code.visualstudio.com/) と [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
* [skaffold](https://github.com/GoogleContainerTools/skaffold/tree/master/examples/getting-started)
* [dive](https://github.com/wagoodman/dive)
* [stern](https://github.com/wercker/stern)

✨ お読みいただきありがとうございました！ ✨

（謝辞: [Ahmet Alp Balkan](https://medium.com/@ahmetb?source=post_page) に感謝します）