podman + kind で macOS のディレクトリをマウントする

## 概要
以下の記事にて macOS で podman + kind を動かすことは確認出来たので、その続きをやってみた

https://qiita.com/tigerroll/items/74049070496144ae262f

## 以下のことを確認する

* nginx を deploy して画面を見るというシンプルな確認をする
* podman + kind で macOS で編集したものを、そのまま表示してみる
* podman machine は ４系から QEMU の volume マウントをサポートしているので、 kind の pod から macOS のディレクトリをマウントしてみる

https://podman.io/releases/2022/02/22/podman-release-v4.0.0.html

## 検証した環境
```bash
$ sw_vers
ProductName:	macOS
ProductVersion:	12.3.1
BuildVersion:	21E258

$ podman version
Client:       Podman Engine
Version:      4.0.3
API Version:  4.0.3
Go Version:   go1.18
Built:        Sat Apr  2 00:28:59 2022
OS/Arch:      darwin/amd64

Server:       Podman Engine
Version:      4.0.3
API Version:  4.0.3
Go Version:   go1.18
Built:        Sat Apr  2 03:21:54 2022
OS/Arch:      linux/amd64
```

## podman の導入

導入方法は以前書いた以下記事を参照ください :pray:

https://qiita.com/tigerroll/items/b511d7e2812b690df4c2


## podman + kind の構成

* macOS のディレクトリを QEMU インスタンスに Shared ディレクトリとしてマウントさせる
* kind が QEMU 上のディレクトリを worker にマウントする
* worker のディレクトリを pod  がマウントする形で macOS のディレクトリを参照させる
* ディレクトリのマウントの関係は以下の様になる
	`macOS` --> `/mnt/qemu` --> `/mnt/kind` --> `/mnt/kind/html` --> `/usr/share/nginx/html`

<img width="512" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214973/8c3d47e3-c87e-d92e-82b7-6ad3cf029e8d.png">


## network 構成

* kind からコンテナまでのPort転送の関係は以下の様になる
	`hostPort[8080]` --> `NodePort[30080]` --> `targetPort[80]` --> `containerPort[80]`
* hostPort に `80` や `443` を割り当てたい場合は　rootful モードに切り替えをすれば割当可能

#### rootrul モードに切り替えるコマンド

```bash:rootful モードに切り替える場合のみ利用する
$ podman machine set --rootful
```

## ディレクトリの構成

※ ファイルについては後述する

```bash
$ tree $(pwd)
/path/to/macOS
├── container.yaml
├── html
│   └── index.html
└── kind-1m1w-mnt.yaml

1 directory, 3 files
```


## QEMU インスタンスをセットアップする

ディレクトリをマウントするために `-v`  オプションを使う
`/Host側のパス:/Guest側のパス` で表現するで、適宜使いやすい様に試して頂ければ良いだろう

```bash
$ podman machine init --cpus 2 --memory 8192 -v /path/to/macOS:/mnt/qemu
```

docker 互換のツールと接続するために `DOCKER_HOST` に socket のパスを設定する  
もちろん、この設定を `.bash_profile` に追加しても良いだろう

```bash
$ export DOCKER_HOST="unix:///Users/${LOGNAME}/.local/share/containers/podman/machine/podman-machine-default/podman.sock"
```

## podman で kind を起動する
kind の provider を docker から  `KIND_EXPERIMENTAL_PROVIDER=podman` にて変更する
この設定を `.bash_profile` に追加しておくことをお勧めする

```bash
$ export KIND_EXPERIMENTAL_PROVIDER=podman
```

### kind の設定ファイルを用意する
* 2 node 起動して worker 側で hostPath をマウントする
* hostPort[8080] を LISTEN して NodePort に合わせて containerPort[30080] を指定する

```bash
$ cat <<'EOF'> kind-1m1w-mnt.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: false
nodes:
  - role: control-plane
  - role: worker
    extraPortMappings:
      - hostPort: 8080
        listenAddress: "0.0.0.0"
        containerPort: 30080
        protocol: TCP
    extraMounts:
      - containerPath: /mnt/kind
        hostPath: /mnt/qemu
EOF
```

用意したファイルを引数に渡してクラスタを起動する

```bash
$ kind create cluster --config kind-1m1w-mnt.yaml
using podman due to KIND_EXPERIMENTAL_PROVIDER
enabling experimental podman provider
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.23.4) 🖼
 ✓ Preparing nodes 📦 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Have a nice day! 👋
```

hostPort で指定した Port が LISTEN 状態になっていることが確認できる

```bash
$ lsof -n -P -iTCP -sTCP:LISTEN
COMMAND     PID        USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
gvproxy   83110   tigerroll   19u  IPv6 0x91e7d4b676058c2b      0t0  TCP *:8080 (LISTEN)
```

以上で cluster の構築は完了


## kubectl で pod を操作する

nignx コンテナを service を通してマウントした html を開いてみる

### ディレクトリをマウントした nginx  を定義する

```bash
cat <<'EOF'> nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: worker-volume
      volumes:
        - name: worker-volume
          hostPath:
            path: /mnt/kind/html
            type: Directory
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
      nodePort: 30080
  selector:
    app: nginx
  type: NodePort
EOF
```

## nginx で読み込む index.html を準備する

```bash
cat <<'EOF'> html/index.html
<h1>Hello hostPath mount contents !</h1>
EOF
```

## manifest を kind に反映する

```bash
$ kubectl apply -f nginx.yaml
deployment.apps/nginx created
service/nginx created
```

deployment が正常に反映されていることが確認できる

```bash
$ kubectl get deployment nginx
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           20m
```

searvice が正常に反映されていることが確認できる

```bash
$ kubectl get service nginx
NAME    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.96.79.111   <none>        80:30080/TCP   20m
```

## nginx にブラウザで接続してみる

上手く表示されることが確認できた :star2: 

<img width="512" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214973/7d7cd06a-ce97-7099-c83e-56aa1e7fc8b9.png">

## podman + kind で macOS のディレクトリをマウントした感想

* 検証はには kind の知識が必要だが、無事に nginx から macOS 側で編集したものを表示出来た :smile:
* rootful モードなら 80, 443 で LISTEN 可能なのでブラウザからのポート指定は不要になり便利 :rocket:  
* macOS で podman + kind を使ったアプリケーション開発もイケそうだなと思う :thumbsup: 
* 脱 Docker :whale: を求めてる人には、とても相性が良いと思う