Kubernetes 初心者の JK です
今回はローカルで Kubernetes の環境を作成して本番環境と同じようにドメインでアクセスして動作するかを確認する方法をご紹介します
なお、DNS の設定は Mac のやり方となるため他の OS では異なる設定が必要になる場合があります
サンプルリポジトリ
下記のリポジトリを使用します
https://github.com/koyama-tagbangers/k8s-web-app-sample
- api ディレクトリには node.js の簡易 API サーバプロジェクトを用意しています
- web ディレクトリには next.js を使用したプロジェクトを用意しています
- k8s ディレクトリには Kubernetes で使用するマニフェストファイルを用意しています
開発環境で動作確認
node.js を事前にインストールしておいてください
brew install node
api ディレクトリと web ディレクトリそれぞれでサーバを起動します
cd api npm ci npm run start
cd web npm ci npm run dev
この状態で http://localhost:3000 にアクセスして動作確認をします
内容は http://localhost:8080/oranges を fetch してデータを表示しているだけです
API
Web
API の URL 設定は NODE_ENV 環境変数を見て切り替えています
const baseUrl = process.env.NODE_ENV === 'development' ? 'localhost:8080' : 'api.jk.test'
NODE_ENV は開発時は development ビルド後は production に自動設定される環境変数です
Buildpacks を使用して Docker Image を作成する
Kubernetes でアプリを使用するために Docker Image を用意する必要があります
brew install docker
Dockerfiles を作成する方法がありますが、自動で行ってくれる Buildpacks を今回使います
brew install buildpacks/tap/pack
pack に用いる Builder は heroku を指定します(Next.js においてこれ以外では正常に動作しませんでした)
(cd api && pack build jk/api --builder heroku/buildpacks --buildpack heroku/nodejs) (cd web && pack build jk/web --builder heroku/buildpacks --buildpack heroku/nodejs)
実行には少し時間がかかります、出来上がると Image の確認ができます
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE jk/api latest 97820836aac8 40 years ago 614MB jk/web latest 9ada7d1e8b20 40 years ago 713MB
作成日時がオーパーツと化してますが、Buildpacks の仕様です
https://github.com/buildpacks/pack/issues/931#issuecomment-719524493
試しに Docker Image を起動してみます
docker run --rm -p 8080:8080 jk/api docker run --rm -p 3000:3000 jk/web
Buildpack で作成した Docker Image は起動時に npm start コマンドを発火します
http://localhost:8080 の API は正常に稼働していますが、http://localhost:3000 の Web は NODE_ENV が production のために http://api.jk.test/oranges に fetch を試みて失敗しています
このため実際の動作確認は次のローカルの Kubernetes 環境の構築が必要です
ローカルの Kubernetes 環境を構築する
方法① Docker Desktop の Kubernetes を使用する
brew cask install docker
Docker Desktop には Kubernetes 機能も同封されています
デフォルトでオフになっているので設定画面から機能を有効にします(時間がかかります)
有効にすると Kubernetes に必要な Docker Image が幾つか Pull されています
クラスタ名は docker-desktop となっています
$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * docker-desktop docker-desktop docker-desktop
Dashboard の有効化
必須ではありませんが、GUI で Kubernetes の状況を確認するために Dashboard をデプロイします
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml
下記のコマンドを打ち込むとブラウザで確認することができます
kubectl proxy
トークンが必要となります、下記のコマンドで引っ張ってこれるのでこちらの値を入力してサインインします
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | awk '/^deployment-controller-token-/{print $1}') | awk '$1=="token:"{print $2}'
参考: https://stackoverflow.com/a/47761914
Ingress の有効化
NGINX Ingress Controller をデプロイすることで Ingress 機能を有効化します
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.41.2/deploy/static/provider/cloud/deploy.yaml
DNS の設定
今回は .test で終わる次の2つのドメインを用意します
- API → http://api.jk.test
- Web → http://jk.test
何も設定していない状況だと当然 test ドメインに ping を打っても Unknown host になります
$ ping test ping: cannot resolve test: Unknown host $ ping jk.test ping: cannot resolve jk.test: Unknown host
これらのドメインを localhost (127.0.0.1) に向けさせるため2つの設定が必要です
まず /etc/resolver ディレクトリに test ファイルを作成して下記を入力します
nameserver 127.0.0.1
これで test ドメインが localhost に向いたので ping でエラーは発生しなくなりましたがレスポンスは帰ってきません
次に開発用の DNS を設定するために Dnsmasq をセットアップします
brew install dnsmasq
/usr/local/etc/dnsmasq.conf に下記を追記します
address=/.test/127.0.0.1
サービスとして Dnsmasq を起動します(sudo のつけ忘れに気をつけてください)
sudo brew services start dnsmasq
これで test ドメインがワイルドカード付きで起動しました
$ ping test PING test (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.025 ms $ ping jk.test PING jk.test (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.027 ms
ワイルドカードのため、test でおわるドメインは全てレスポンスが帰ってきます
補足
一部の環境では 127.0.0.1 だと Pod 内で設定したドメインにつながらないケースがあったため、その場合は IP アドレスを代わりに入れてください
ワンライナーで取得するコマンドは下記です
ifconfig en0 | awk '/inet / { print $2 }'
マニフェストファイルのデプロイ
k8s ディレクトリにある全てのマニフェストファイル(.yml)を Kubernetes にデプロイします
kubectl apply -f k8s
ダッシュボードからワークロードの状態が全て緑色であれば問題ありません
問題がある場合は Pods から該当の Pod のログを確認します
問題ない場合は http://jk.test からアプリが正常に動作していることを確認できます
クラスターの一時停止・削除
使用しない場合は Docker Desktop の設定からチェックボックスを外すことで一時停止できます
また、Reset Kubernetes Cluster から Kubernetes をリセットすることができます
一時停止する際は Dnsmasq の停止もしておきます
sudo brew services stop dnsmasq
方法② Minikube with HyperKit を使用する
brew install minikube hyperkit
Minikube は VM モード(HyperKit)で起動する必要があります
minikube start --vm --driver=hyperkit
デフォルトプロファイルの minikube で Kubernetes クラスターが作成されます
$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop * minikube minikube minikube default
Minikube 内の docker daemon で docker image を作成
Minikube 内部の docker daemon は Docker Desktop 使用時の localhost の docker daemon とは別にあります
このため先ほど作成した Docker Image は Minikube で扱うことができません
Minikube 内部の docker daemon を docker コマンドで利用するために下記のコマンドを入力します
eval $(minikube docker-env)
このコマンド以降は docker コマンドでは Minikube 上の docker daemon を利用するため再度 Docker Image のビルドを行います
なお、上記のコマンドはターミナルを再起動するたびに必要です
eval $(minikube docker-env) (cd api && pack build jk/api --builder heroku/buildpacks --buildpack heroku/nodejs) (cd web && pack build jk/web --builder heroku/buildpacks --buildpack heroku/nodejs)
Dashboard の有効化
下記のコマンドを打つだけで Dashboard 機能が有効になり、ログインなしで Dashboard にアクセスできます
minikube dashboard
Ingress の有効化
下記のコマンドを打つだけです
minikube addons enable ingress
DNS の設定
下記のコマンドを打つことで、Dnsmasq を使用せずに DNS の設定を行ってくれます
minikube addons enable ingress-dns
/etc/resolver/test の nameserver を Minikube の IP アドレスに変える必要があります
IP アドレスは下記から取得できます
minikube ip
なお、この地点では ping を飛ばしても Unknown host になります
マニフェストファイルのデプロイ
kubectl apply -f k8s
同様の手順で http://jk.test からアプリが正常に動作していることを確認できます
なお、Minikube では ingress.yml で指定したドメイン以外は Unknown host となります
$ ping test ping: cannot resolve test: Unknown host $ ping jk.test PING jk.test (192.168.64.5): 56 data bytes 64 bytes from 192.168.64.5: icmp_seq=0 ttl=64 time=0.240 ms
クラスターの一時停止・削除
それぞれコマンド上で行います
minikube stop
minikube delete
HyperKit を使用しない場合の問題
minikube start 時にデフォルトでは docker driver を使用しますが、Ingress の設定の時に怒られてしまいます
$ minikube addons enable ingress ❌ Exiting due to MK_USAGE: Due to networking limitations of driver docker on darwin, ingress addon is not supported. Alternatively to use this addon you can use a vm-based driver: 'minikube start --vm=true' To track the update on this work in progress feature please check: https://github.com/kubernetes/minikube/issues/7332
それぞれのメリット・デメリット
Docker Desktop
メリット
- localhost で Kubernetes が起動されるため、普段ビルドした Docker Image をそのまま利用できる
- GUI ベースでリソースの設定、コンテナの可視化が行えるため確認が楽
デメリット
- DNS の設定が少し面倒、場合によっては /etc/hosts を直接編集する方が楽
Minikube
メリット
- Dashboard, DNS の設定が非常に楽
- プロファイル機能で複数のクラスターの管理が可能
- 複数のプロジェクトを横断する場合などに便利
- Kubernetes や Docker のバージョンなどを指定できる
デメリット
- ローカルの Docker Image が利用できないため Image をリポジトリにプッシュするか Minikube 上で再ビルドする必要がある
- eval $(minikube docker-env) の実行を忘れてビルドする事故が起きやすい
- リソースの設定もローカルの Docker とは別にする必要がある
- Minikube を使っている間に他の開発環境がおかしくなる時がある(環境が汚れているだけ?)
まとめ
Minikube は特に DNS の設定周りが非常に楽ですが、Docker Image ビルド前の eval $(minikube docker-env) を忘れることがたびたびあります
Docker Desktop は制限がありますが、リソースなどを共有できるのが便利です
どちらも気軽に使えるツールのため、状況に応じて使い分けていくと良いと思います