クラウドエンジニアの @aoyagi9936 です。
Mac
での構築方法は同時に公開した記事を参照してください。
開発環境の構築はエンジニアにとって最初の登竜門ですが、コンテナ環境は特に Docker Desktop の有料化やローカルでの Kubernetes の実行などのハードルもあり、経験豊富なエンジニアにとっても一筋縄にはいかない難しさがあるように感じます。
今回は Windows(WSL)
Mac
Linux(Ubuntu)
ユーザーが同一の開発体験を得られることを目標にコンテナ開発環境の構築方法をご紹介します。
また、
-
Kubernetes
を学びたいがどうして良いかわからない -
本番環境に近いコンテナ実行環境
をローカルで実現したい -
CI/CD
を回して高速にコンテナアプリケーションを開発したい
という方も参考にしてみてください。
Skaffold とは
Google が開発しオープンソースで提供している、ローカルで Kubernetes ネイティブなアプリケーションを開発するためのコマンドラインツールです。
Golang で書かれておりシングルバイナリで動きます。
Google Cloud Deploy
を用いればローカルだけではなくクラウドでもデリバリーパイプラインを構築できますし、Kustomize
Helm
など Kubernetes をより効率的に扱う支援ツールにも対応しているので覚えておいて損はないと思います。
MicroK8s とは
MicroK8s
はローカルでも動作する軽量な Kubernetes ディストリビューションです。
他の候補としては Minikube
や K3s
等が挙げられますが、 MicroK8s はエンタープライズサポートや複数ノード対応など本番環境としての運用も可能で、開発や本番で有用なアドオンも充実しているのが特徴です。
詳しくは本家の比較表を参照してください。
ちなみに私は以前は Minikube を使っていましたが registry
hostpath-storage
linkerd
といった実用的なアドオンに惹かれて乗り換えました。
Windows (WSL) の準備
※ Ubuntu の方は Ubuntu に MicroK8s をインストールする
まで飛ばしてください。
WSL2 のセットアップ
Windows のバージョンによってセットアップ方法は微妙に異なるため詳細は割愛しますが、以下の手順で WSL が使えるようになります。
WSL には現在 WSL1
と WSL2
がありますが、より忠実に Linux 環境を再現できる WSL2
を利用します。1
- コントロールパネルから
Windowsの機能の有効化または無効化
を表示 -
Linux用Windowsサブシステム
仮想マシンプラットフォーム
にチェック - Windows を再起動
- コマンドプロンプトを開き
wsl --set-default-version 2
を実行
WSL2 requires an update to its kernel component. For information please visit https://aka.ms/wsl2kernel というエラーが表示される場合は指示に従ってリンク先のページから x64 マシン用 WSL2 Linux カーネル更新プログラム パッケージ
(wsl_update_x64.msi) をインストールしてください。
WSL2 で Ubuntu (18.04 or 20.04 or 22.04) を利用する
- コマンドプロンプトを開き
wsl --install -d Ubuntu-[18.04|20.04|22.04]
を実行 -
wsl -l -v
を実行しVERSION
が2
になっていることを確認 - 任意のID/PASSでログインし
sudo apt update
sudo apt -y upgrade
を実行
WSL での MicroK8s 文字化け対策
Cascadia Code をインストールします。
ページ内の Github リリースページ リンク
から zip をダウンロードして展開し、 .ttf
をダブルクリックして Windows にフォントをインストールします。
WSL ウィンドウを右クリックして Fontタブ > Font
のリストボックスに先ほどインストールした Cascadia ...
が表示されるので選択して OK を押してください。
ちなみに私は Powerline
を愛用しているので Cascadia Mono PL
を利用しています。
WSL で systemd を有効にする
2022年9月より WSL が systemd に正式に対応したため面倒なハックが不要となりました。
但し、デフォルトでは有効にはならないため以下の手順で有効化させてください。
まずはコマンドプロンプトか PowerShell で WSL を最新にします。
wsl --update
wsl --set-default-version 2
Ubuntu 上の etc/wsl.conf
で systemd
を有効にします。
echo -e "[boot]\nsystemd=true" | sudo tee /etc/wsl.conf
wsl.conf のその他の設定が知りたい方は Microsoft の公式ドキュメントを参照してください。
有効化できたら WSL を再起動してください。
wsl --shutdown
wsl
以前の記事で紹介したスタートアップスクリプトによる systemd 有効化のハックを使用した方は、スタートアップスクリプトを削除して systemd を有効化してください。
sudo rm /etc/profile.d/00-wsl2-systemd.sh
echo -e "[boot]\nsystemd=true" | sudo tee /etc/wsl.conf
WSL を再起動後にエラーで MicroK8s が起動できない場合は MicroK8s の再インストールが必要ですので以下のコマンドで一旦削除します。
sudo snap remove microk8s
以前の記事も記録として残しておきます。
## WSL で systemd を利用できるようにする
投稿して一週間も経たず内容が陳腐化するとは思ってもいませんでしたが、何と WSL が systemd
に正式に対応したそうです。
ですので下記対応は今後は不要となりそうですが未検証ですので記事は残しておきます。
↓↓↓↓↓
Ubuntu に MicroK8s をインストールするためにはパッケージマネージャーの snap
を使用しますが、 snap は systemd
を利用しており WSL は systemd が利用できない( PID 1
で起動しない)という罠にハマります(ハマりました)。
また、後ほど行うコンテナの Build には Docker Engine
を利用するためどちらにせよ WSL で sytemd を利用できるようにしておく必要があります。
最新の WSL2 + Ubuntu22.04
では標準で systemd を PID1 で起動できるようになったようですが、 Ubuntu-18.04
Ubuntu-20.04
では一工夫が必要です。
まずは fontconfig
と daemonize
をインストールします。
apt install -y fontconfig daemonize
次に /etc/wsl.conf
に WSL の設定ファイルを追加します。
<USER_NAME>
はご自身で作成したユーザー名を追加してください。
[automount]
enabled = true
options = "metadata,uid=1000,gid=1000,umask=22,fmask=11,case=off"
mountFsTab = true
crossDistro = true
[network]
generateHosts = false
generateResolvConf = true
[interop]
enabled = true
appendWindowsPath = true
[user]
default = <USER_NAME>
次に /etc/profile.d/00-wsl2-systemd.sh
にスタートアップスクリプトを作成します。
SYSTEMD_PID=$(ps -ef | grep '/lib/systemd/systemd --system-unit=basic.target$' | grep -v unshare | awk '{print $2}')
if [ -z "$SYSTEMD_PID" ]; then
sudo /usr/bin/daemonize /usr/bin/unshare --fork --pid --mount-proc /lib/systemd/systemd --system-unit=basic.target
SYSTEMD_PID=$(ps -ef | grep '/lib/systemd/systemd --system-unit=basic.target$' | grep -v unshare | awk '{print $2}')
fi
if [ -n "$SYSTEMD_PID" ] && [ "$SYSTEMD_PID" != "1" ]; then
exec sudo /usr/bin/nsenter -t $SYSTEMD_PID -a su - $LOGNAME
fi
上記は 20.04 の場合ですので 18.04 の場合は daemonize のパスを以下のように変更してください。
- /usr/bin/daemonize
+ /usr/sbin/daemonize
最後に localhost への接続をデフォルトのインターフェースに転送することで MicroK8s に到達できるようにします。
echo 'net.ipv4.conf.all.route_localnet = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
お疲れ様でした。これで WSL2 で MicroK8s を動かす下準備は終了です。
WSL を再起動したら通常の Ubuntu と同じようにコンテナ開発環境をセットアップしていきます。
Ubuntu に MicroK8s をインストールする
お待たせしました。Ubuntu の方はここから実行してください。
と言っても基本的にインストール方法は公式の通りです。2
メモリが少ないPCの場合は次のコマンドで失敗する可能性があるため念の為余計なプロセスは落としておきましょう(そもそも後続の開発に耐えられない可能性があるのでその環境は非推奨ですが)。
sudo snap install microk8s --classic
# リリースチャンネルを指定する場合
sudo snap install microk8s --classic --channel=1.24
Kubernetes の設定ファイルは .kube
に格納します(既存のものと分ける方法は後述)。
存在しない場合は作成し、存在する場合は既存のものとマージします。
cd $HOME
mkdir .kube
cd .kube
microk8s config > config
作成したフォルダに権限を付与します。
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
既存の環境と分けて設定を管理したい場合は先ほどの手順を .kube
ではなく .microk8s
フォルダで実行し KUBECONFIG
環境変数を利用するか --kubeconfig
フラグを利用してください(後述する Skaffold
にも --kubeconfig
は指定できます)。
export KUBECONFIG=$HOME/.microk8s/config
# または
kubectl --kubeconfig=$HOME/.microk8s/config
再起動し以下のコマンドで Microk8s が正常に動作していることを確認します。
(起動には少し時間がかかります)
microk8s status
MicroK8s には多くの便利なアドオンがありますが今回有効にするのは以下の2つです。
microk8s enable dns
microk8s enable registry
Kubernetes に慣れていない方はダッシュボードを使うことで状態をグラフィカルに確認できます。
アドオンを有効にするだけではなく追加でポートフォワード等の設定も必要なので脚注をご確認ください。3
ダッシュボードのインストールからアクセスに必要な設定までを一度にやってくれるコマンドがあります(version 1.19+)。
microk8s dashboard-proxy
ダッシュボードの起動後にターミナルに URL と トークンが表示されます。
指示の通りに https://127.0.0.1:10443
にアクセスするとトークンを入力できますのでコピー&ペーストしてサインインしてください。
Checking if Dashboard is running.
Infer repository core for addon dashboard
Infer repository core for addon metrics-server
Waiting for Dashboard to come up.
Trying to get token from microk8s-dashboard-token
Waiting for secret token (attempt 0)
Dashboard will be available at https://127.0.0.1:10443
Use the following token to login:
<TOKEN>
Ubuntu に Docker をインストールする
公式の手順に従ってください。
Install Docker Engine on Ubuntu
今回の趣旨は Skaffold + MicroK8s
による Kubernetes ネイティブな開発環境ですので Docker Compose
は不要です。
# GPG キーの設定やリポジトリの更新は公式通りのため省略
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin
Ubuntu に Skaffold をインストールする
最後に Skaffold をセットアップします。
快適な環境までもう一息ですので頑張りましょう。
Skaffold のインストールは公式の通りでも良いですし、 Homebrew on Linux
でもインストールできます。
Installing Skaffold - skaffold.dev
Homebrew-on-Linux - docs.brew.sh
インストールができたら MicroK8s の組み込みレジストリを登録します。
以下のコマンドで現在の Kubernetes コンテキスト(接続先クラスタ)で利用するレジストリを登録します。
skaffold config set insecure-registries localhost:32000
skaffold config set default-repo localhost:32000
今までの手順の通りであれば Skaffold に登録されるコンテキスト名は microk8s
となるはずです。
~/.skaffold/config
ファイルの中を見ると設定を確認できますが、異なる場合は kubectl config current-context
コマンドを実行して表示されるコンテキスト名を確認してください。
kubeContexts:
- kube-context: microk8s
default-repo: localhost:32000
insecure-registries:
- localhost:32000
最後に microk8s status
で registry
アドオンが enabled
であることを確認しておきましょう。
お疲れ様でした。これで環境は完成です!
Skaffold を構成してコンテナをローカルの MicroK8s にデプロイする
Dockerfile と Kubernetes のマニフェストファイルを作成し、 Skaffold で Docker Build と MicroK8s へのデプロイの一連の流れを構成します。
テストシナリオとして Postgres データベースを Pod で立ち上げてローカルから接続してみます。
サンプルソースも用意しておいたので git clone
してください。
ディレクトリ構成
.
└── skaffold-microk8s-example/
├── skaffold.yaml
├── kubernetes-manifests/
│ └── pod.yaml
└── src/
└── infra/
└── database/
├── Dockerfile
├── 0_create_database.sql
└── 1_insert_table.sql
Docker コンテナ設定ファイル
FROM postgres:14.4-alpine
COPY *.sql /docker-entrypoint-initdb.d/
DROP DATABASE IF EXISTS test_db;
CREATE DATABASE test_db;
\c test_db;
CREATE TABLE example_tbl (
id serial PRIMARY KEY,
name TEXT
);
INSERT INTO example_tbl (name) VALUES ('aoyagi');
Skaffold 設定ファイル
apiVersion: skaffold/v4beta2
kind: Config
build:
tagPolicy:
sha256: {}
local:
push: true
useBuildkit: true
artifacts:
- image: example-db
context: src/infra/database
deploy:
kubeContext: microk8s
profiles:
- name: local
portForward:
- resourceType: pod
resourceName: my-example-pod
port: 5432
manifests:
rawYaml: [
"./kubernetes-manifests/pod.yaml"
]
Kubernetes マニフェストファイル
apiVersion: v1
kind: Pod
metadata:
name: my-example-pod
spec:
containers:
- name: my-example-pod
image: example-db
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: postgres
- name: POSTGRES_DB
value: test_db
- name: TZ
value: Asia/Tokyo
全ての準備が整ったら Skaffold を実行してみましょう。
skaffold.yaml
のあるパスで以下のコマンドを実行します。
skaffold dev -p local
コンテナが MicroK8s へデプロイされたらお手元のDB接続ツールで接続してみましょう。
接続情報 | 設定値 |
---|---|
ホスト | localhost |
ポート | 5432 |
ユーザー名 | postgres |
パスワード | postgres |
データベース名 | test_db |
これだけでは Skaffold の良さが伝わりきらないので Skaffoldを実行したまま 1_insert_table.sql
にデータを追加してみましょう。
INSERT INTO example_tbl (name) VALUES ('aoyagi');
+ INSERT INTO example_tbl (name) VALUES ('your_name');
Skaffold が変更を自動で検知してコンテナを再作成し MicroK8s にデプロイします。
開発中は仕様が頻繁に変わりますが変更の都度環境を再作成してくれることで安全性が高まります。
環境をイミュータブルに作成することの良さはまたどこかでお伝えできればと思いますが、タイトルの目標は達成できましたので本記事はここまでとなります。
本投稿が皆様の快適なコンテナ開発ライフの一助になれば幸いです。