memo "Kubernetes in Docker" 🫙

こんにちは。Enabling team の山本です。

今回は、[Kubernetes in Docker](https://kind.sigs.k8s.io/)（ `kind` ）についてです。

3年ぶりに `kind` をやり直す動機は、研修のためです。

研修で `kind` の実習を行うため、手順を再確認します。

## TL;DR
- Install 手順は、変わっていない。
- Artifact Registry の認証さえ通れば、GKE と同じ。

## 構築
### Compute Instance の作成
- machinie の spec に意味はありません。最適なものを選びます。
```bash
gcloud compute instances create kind-danny --machine-type=e2-standard-2 --zone=asia-northeast1-a
```
### Install
```bash
# docker
sudo apt-get update
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo docker run hello-world
sudo apt-get install -y wget

# Go
cd /usr/local/
sudo wget https://go.dev/dl/go1.20.3.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.20.3.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

# kind
sudo curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.18.0/kind-linux-amd64
sudo chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# kubectl
cd /usr/local/
sudo curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
```
### kind cluster 作成
```bash
# root の password を変更
sudo passwd root
# root に switch
su -
# cluster 作成
kind create cluster --name hoge
```

```bash
# cluster の作成を確認
kind get clusters
# cluster への接続情報を作成
kubectl cluster-info --context kind-hoge
```

## テスト
### Pod、Deployment の動作を確認
```bash
# Node の状態を確認
kubectl get node
# Nginx の Pod を作成
kubectl run nginx --image=nginx --restart=Never
# command を別名登録
alias k=kubectl
# Pod の状態を確認
k get po
```

```bash
# deployment を作成
cat << EOF  | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF
```

```bash
# Pod 間通信を確認するため、2つ目の deployment を作成
cat << EOF  | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-b
spec:
  selector:
    matchLabels:
      run: my-nginx-b
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx-b
    spec:
      containers:
      - name: my-nginx-b
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-b
  labels:
    run: my-nginx-b
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx-b
EOF
```

- どちらかの Pod に入る
- DNS に `curl` を送信して「Welcome Nginx」が表示されることを確認します。
```bash
# nslookup を install
apt-get install dnsutils
# service の DNS を確認
nslookup my-nginx-b
nslookup my-nginx
```

- config の mount を確認します。
- `index.html` を変更します。
```
cat << EOF  | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-index
data:
  index.html: |-
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to hoge!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
EOF
```

```bash
cat << EOF  | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-b
spec:
  selector:
    matchLabels:
      run: my-nginx-b
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx-b
    spec:
      containers:
      - name: my-nginx-b
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: index
          mountPath: /usr/share/nginx/html/
      volumes:
        - name: index
          configMap:
            name: nginx-index
EOF
```
### Image を Private Image リポジトリに push、pull
- DockerHub の Image を Private Image リポジトリに push します。
- Cloud Shell で実行します。
```bash
# pull
docker pull nginx
# auth
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
docker images
# tag 付け
docker tag nginx:latest asia-northeast1-docker.pkg.dev/junior-engineers-gym-2023/danny/nginx:1.24.0
# push
docker push asia-northeast1-docker.pkg.dev/junior-engineers-gym-2023/danny/nginx:1.24.0
```

- console で作成した credentials.json を `key.json` として保存します。
```bash
vi key.json
```

- Private Image リポジトリを認証します。
```bash
cat key.json | docker login -u _json_key --password-stdin asia-northeast1-docker.pkg.dev
```

- secret を作成します。
```bash
kubectl create secret docker-registry my-secret-b \
--docker-server=https://asia-northeast1-docker.pkg.dev \
--docker-username=_json_key \
--docker-email=kind-danny@hoge.iam.gserviceaccount.com \ --docker-password="$(cat key.json)"
```

- Private Image で Pod を apply します。
    - `imagePullSecrets` に secret を指定します。
```bash
cat << EOF  | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: asia-northeast1-docker.pkg.dev/hoge/danny/nginx:1.24.0
  imagePullSecrets:
  - name: my-secret-b
EOF
```

## まとめ
`kind` について書きました。
managed service を使用していると、「この option 何だっけ？」というのは、高頻度であります。そこが面倒に感じます。特に、managed service は、機能追加が継続的に行われるため。
一方、`kind` は、自分の client で手軽に動かせるメリットはあると思います。

## 参考
- [サービス アカウント キー](https://cloud.google.com/artifact-registry/docs/docker/authentication?hl=ja#json-key)
- [イメージを push および pull する](https://cloud.google.com/artifact-registry/docs/docker/pushing-and-pulling?hl=ja)