# 使用 WSL 2 與 Docker Desktop 架設 Kubernetes 多節點叢集環境 (KinD)

在學習 Kubernetes 的時候，單一節點的 Kubernetes 測試環境已經可以讓你理解許多物件的建立與操作，對於「應用程式的開發人員」來說已經足夠。由於 Kubernetes 提供不同層級的「抽象」，照理說在不特別理解 Kubernetes 配置的情況下，應用程式都應該能正常運行才對。但如果想測試一些只有多台節點才能測試的功能，就需要相對完整的叢集才能測試了。本篇文章將分享 [KinD](https://kind.sigs.k8s.io/) (Kubernetes in Docker) 這套工具，可以幫助你在幾秒內成功架設擁有多節點的 Kubernetes 叢集環境。

### 前置條件 (Prerequisites)

要進行本篇文章的設定步驟時，必須符合以下條件：

-   作業系統：Windows 10 版本 2004 (Build 19041) 以上
-   啟用 WSL 2 功能
    -   請記得透過 `wsl.exe --set-default-version 2` 將之後安裝的 Distro 預設都調整為 WSL 2 版本
    -   官方文件: [Windows Subsystem for Linux Installation Guide for Windows 10](https://learn.microsoft.com/en-us/windows/wsl/install-win10)
    -   請看 [使用 WSL 2 打造優質的多重 Linux 開發環境](/post/2020/07/26/Multiple-Linux-Dev-Environment-build-on-WSL-2) 文章
-   到 Microsoft Store 安裝 [Ubuntu 20.04 LTS](https://www.microsoft.com/zh-tw/p/ubuntu-2004-lts/9n6svws3rx71) 應用程式
-   安裝 [Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows) 穩定版本 (Stable)

### 調整 WSL 2 (Ubuntu 20.04 LTS) 系統設定

-   進入 `Ubuntu-20.04` 的 bash 環境
    
    ```bash
    wsl -d Ubuntu-20.04
    cd ~
    ```
    
-   更新 Ubuntu 到最新版
    
    ```bash
    sudo apt update
    sudo apt upgrade -y
    ```
    
-   設定更清楚的命令提示字串(Prompt) (請加入到 `.profile` 檔案中)
    
    ```bash
    export PS1="\[\033[33m\]\D{%Y-%m-%d %I:%M%p}\[\033[00m\] \[\033[32m\]\u@$WSL_DISTRO_NAME\[\033[00m\]:\[\033[36m\]\w\[\033[00m\]$ "
    ```
    
-   建議調整 bash 環境參數 (請加入到 `.profile` 檔案中)
    
    ```bash
    shopt -u progcomp
    shopt -s no_empty_cmd_completion
    ```
    
-   我個人偏好使用 `vim` 當成預設編輯器
    
    ```bash
    sudo update-alternatives --set editor /usr/bin/vim.basic
    ```
    
-   安裝 [NERDTree](https://github.com/preservim/nerdtree) 檔案總管套件 (Vim)
    
    ```bash
    git clone https://github.com/preservim/nerdtree.git ~/.vim/pack/vendor/start/nerdtree
    vim -u NONE -c "helptags ~/.vim/pack/vendor/start/nerdtree/doc" -c q
    ```
    
-   新增 `~/.vimrc` 檔案
    
    ```
    set background=dark
    
    syntax enable
    "set number
    set noruler
    set ignorecase
    set smartcase
    
    "set cursorline
    "set cursorcolumn
    
    let &t_ti.="\e[1 q"
    let &t_SI.="\e[5 q"
    let &t_EI.="\e[1 q"
    let &t_te.="\e[0 q"
    
    map <A-Left> <Esc>:b#<CR>
    map <A-Right> <Esc>:bn<CR>
    map <C-W> <Esc>:q<CR>
    
    "------------Plugin: nerdtree------------
    map <C-p> :NERDTreeToggle<CR>
    map <C-l> :tabn<CR>
    map <C-h> :tabp<CR>
    
    " Map Ctrl-Left & Ctrl-Right to switching tabs Ctrl-n to open new tab
    map <C-Left> <Esc>:tabprev<CR>
    map <C-Right> <Esc>:tabnext<CR>
    map <C-n> <Esc>:tabnew<CR>
    ```
    
-   安裝 [kubectx 與 kubens](https://github.com/ahmetb/kubectx) 工具
    
    ```bash
    sudo apt install pkg-config -y
    
    wget https://github.com/ahmetb/kubectx/releases/download/v0.9.1/kubectx_v0.9.1_linux_x86_64.tar.gz
    wget https://github.com/ahmetb/kubectx/releases/download/v0.9.1/kubens_v0.9.1_linux_x86_64.tar.gz
    
    sudo tar zxvf kubectx_v0.9.1_linux_x86_64.tar.gz -C /usr/local/bin kubectx
    sudo tar zxvf kubens_v0.9.1_linux_x86_64.tar.gz -C /usr/local/bin kubens
    
    sudo git clone https://github.com/ahmetb/kubectx.git /etc/kubectx
    COMPDIR=$(pkg-config --variable=completionsdir bash-completion)
    sudo ln -sf /etc/kubectx/completion/kubens.bash $COMPDIR/kubens
    sudo ln -sf /etc/kubectx/completion/kubectx.bash $COMPDIR/kubectx
    
    rm kubectx_v0.9.1_linux_x86_64.tar.gz kubens_v0.9.1_linux_x86_64.tar.gz
    ```
    
-   安裝 [k9s](https://github.com/derailed/k9s) 工具
    
    ```bash
    sudo wget https://github.com/derailed/k9s/releases/download/v0.21.7/k9s_Linux_x86_64.tar.gz
    sudo tar -zxvf k9s_Linux_x86_64.tar.gz -C /usr/local/bin k9s
    
    k9s info
    ```
    

### 啟用 [Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows) 的 WSL Integration

1.  開啟 Docker Desktop for Windows 的 Settings 設定視窗
    
    ![開啟 Docker Desktop for Windows 的 Settings 設定視窗](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/3e13b7a97784899d694c-90830391-28e48d80-e374-11ea-9cd0-224cc9fe5687.png)
    
    > 請務必切換到 Linux container 模式！
    
2.  調整以下兩個設定
    
    General > 勾選 `Use the WSL 2 based engine`
    
    Resources > WSL INTEGRATION > 啟用 `Ubuntu-20.04`
    
    ![WSL Integration](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/17478b3c9ec8e40f29f3-90830516-61846700-e374-11ea-9ba6-69774318e060.png)
    

### 檢查 docker 與 kubectl 版本

-   檢查 Docker 版本資訊
    
    ```bash
    $ docker version
    Client: Docker Engine - Community
    Version:           19.03.12
    API version:       1.40
    Go version:        go1.13.10
    Git commit:        48a66213fe
    Built:             Mon Jun 22 15:45:36 2020
    OS/Arch:           linux/amd64
    Experimental:      false
    
    Server: Docker Engine - Community
    Engine:
      Version:          19.03.12
      API version:      1.40 (minimum version 1.12)
      Go version:       go1.13.10
      Git commit:       48a66213fe
      Built:            Mon Jun 22 15:49:27 2020
      OS/Arch:          linux/amd64
      Experimental:     false
    containerd:
      Version:          v1.2.13
      GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
    runc:
      Version:          1.0.0-rc10
      GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
    docker-init:
      Version:          0.18.0
      GitCommit:        fec3683
    ```
    
    > 如果你無法成功執行 `docker version` 的話，請嘗試在 Windows PowerShell 中執行 `Restart-Service LxssManager` 命令重啟 `LxssManager` 服務，並 Restart Docker 應用程式。
    
-   檢查 kubectl 版本資訊
    
    ```bash
    $ kubectl version
    Client Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", GitTreeState:"clean", BuildDate:"2020-01-15T08:26:26Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}
    The connection to the server localhost:8080 was refused - did you specify the right host or port?
    
    $ kubectl version --client --short
    Client Version: v1.16.6-beta.0
    ```
    
    > 此時連不上 Kubernetes 是正常的！
    

### 安裝 KinD 工具並建立 k8s 叢集

1.  安裝 [KinD](https://kind.sigs.k8s.io/) 工具
    
    ```bash
    curl -Lo ./kind https://kind.sigs.k8s.io/dl/$(curl -sSL 'https://api.github.com/repos/kubernetes-sigs/kind/releases/latest' | jq '.tag_name' -r)/kind-linux-amd64
    chmod +x ./kind
    sudo mv ./kind /usr/local/bin/
    ```
    
2.  建立單一節點的 K8S 叢集
    
    ```bash
    kind create cluster --name myk8s
    ```
    
    > 安裝過程大概只要 35 秒左右即可完成！
    
    ![kind create cluster --name myk8s](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/bfcf7033c48dfd08e18a-90831883-3b13fb00-e377-11ea-94ae-63caf1d513e1.png)
    
    > 如果不加上 `--name myk8s` 參數，也可以成功建立叢集，只是叢集名稱預設為 `kind`
    
    > 如果要安裝舊版的 k8s 叢集，kube可以嘗試以下命令：
    > 
    > ```bash
    > kind create cluster --name myk8s --image kindest/node:v1.17.5
    > ```
    > 
    > 完整可用的 node image 清單在此: https://hub.docker.com/r/kindest/node/tags
    > 
    > 若要自訂 node image 可參考 Base Image 的 [Dockerfile](https://github.com/kubernetes-sigs/kind/blob/master/images/base/Dockerfile) 進行調整。
    
    建立完成後，可以透過以下命令查詢目前已經透過 kind 建立幾套叢集：
    
    ```bash
    kind get clusters
    ```
    
3.  驗證安裝結果
    
    安裝好叢集之後，預設會在 `$HOME/.kube` 目錄下建立好一個 `config` 設定檔，你可以透過以下命令查詢叢集資訊：
    
    ```bash
    $ kubectl cluster-info
    Kubernetes master is running at https://127.0.0.1:43663
    KubeDNS is running at https://127.0.0.1:43663/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    ```
    
    如果你有超過一套叢集被建立，則必須指定 context name 才能正確取得叢集資訊：
    
    ```bash
    kubectl cluster-info --context kind-kind
    kubectl cluster-info --context kind-kind-2
    ```
    
    取得節點清單 (預設 [kind](https://kind.sigs.k8s.io/) 只會建立一個節點同時肩負 Control Plane Node 與 Worker Node 任務)
    
    ```bash
    $ kubectl get nodes
    NAME                  STATUS   ROLES    AGE   VERSION
    myk8s-control-plane   Ready    master   10m   v1.18.2
    ```
    
    > 注意：早期的 Master Node 都已經改名為 Control Plane Node 了！([#BlackLivesMatter](https://en.wikipedia.org/wiki/Black_Lives_Matter))
    
    取得所有命名空間下的所有物件清單
    
    > 請注意：在我的部落格可以按下鍵盤的 `F` 鍵切換瀏覽模式為全螢幕。
    
    ```bash
    $ kubectl get all --all-namespaces
    NAMESPACE            NAME                                              READY   STATUS    RESTARTS   AGE
    kube-system          pod/coredns-66bff467f8-4nf59                      1/1     Running   0          11m
    kube-system          pod/coredns-66bff467f8-k625z                      1/1     Running   0          11m
    kube-system          pod/etcd-myk8s-control-plane                      1/1     Running   0          11m
    kube-system          pod/kindnet-z4wx9                                 1/1     Running   0          11m
    kube-system          pod/kube-apiserver-myk8s-control-plane            1/1     Running   0          11m
    kube-system          pod/kube-controller-manager-myk8s-control-plane   1/1     Running   0          11m
    kube-system          pod/kube-proxy-2s2m7                              1/1     Running   0          11m
    kube-system          pod/kube-scheduler-myk8s-control-plane            1/1     Running   0          11m
    local-path-storage   pod/local-path-provisioner-bd4bb6b75-bglr2        1/1     Running   0          11m
    
    NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
    default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  11m
    kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   11m
    
    NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
    kube-system   daemonset.apps/kindnet      1         1         1       1            1           <none>                   11m
    kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   11m
    
    NAMESPACE            NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
    kube-system          deployment.apps/coredns                  2/2     2            2           11m
    local-path-storage   deployment.apps/local-path-provisioner   1/1     1            1           11m
    
    NAMESPACE            NAME                                               DESIRED   CURRENT   READY   AGE
    kube-system          replicaset.apps/coredns-66bff467f8                 2         2         2       11m
    local-path-storage   replicaset.apps/local-path-provisioner-bd4bb6b75   1         1         1       11m
    ```
    
    也可以透過以下命令查詢 Client 與 Server 版本：
    
    ```bash
    $ kubectl version --short
    Client Version: v1.16.6-beta.0
    Server Version: v1.18.2
    ```
    
    當預設 Client 與 Server 版本不同時，建議你安裝跟 Server 相同版本的 Client 工具 (`kubectl`)
    
    ```bash
    curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.2/bin/linux/amd64/kubectl
    chmod +x ./kubectl
    sudo mv ./kubectl /usr/local/bin/kubectl
    ```
    
    > 請注意上述網址中有個 `v1.18.2` 版本號碼，請換成跟你目前的 Server 版本一致。
    
    再檢查一次 `kubectl` 版本：
    
    ```bash
    $ kubectl version --short
    Client Version: v1.18.2
    Server Version: v1.18.2
    ```
    
    > 參考連結: [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
    
    除此之外，也建議設定 kubectl 的 bash 自動完成設定：
    
    ```bash
    kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
    
    echo 'alias k=kubectl' >>~/.profile
    echo 'complete -F __start_kubectl k' >>~/.profile
    ```
    
4.  刪除 K8S 叢集
    
    ```bash
    kind delete cluster --name myk8s
    ```
    
    > 刪除過程大概只要 1 秒左右即可完成！
    

### 建立多節點的 k8s 叢集

如果你想建立一個有 3 個 control-plane nodes 與 2 個 worker nodes 的叢集，那就可以先建立好一個設定檔：

```yml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
```

你也可以用以下命令快速產生 `kind-5nodes.yaml` 檔案：

```bash
# Create a config file for a 3 nodes cluster
cat << EOF > kind-5nodes.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
EOF
```

然後透過以下命令載入設定檔並建立叢集，過程大約 2 ~ 3 分鐘即可完成，相當便利！

```bash
kind create cluster --name myk8s --config ./kind-5nodes.yaml
```

剛裝好之後，還需要等十幾秒左右的時候，讓每個 Node 的 STATUS 進入 Ready 狀態！

```bash
$ kubectl get nodes -o wide
NAME                 STATUS   ROLES    AGE    VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION                CONTAINER-RUNTIME
k8s-control-plane    Ready    master   2m3s   v1.18.2   172.18.0.3    <none>        Ubuntu 19.10   4.19.104-microsoft-standard   containerd://1.3.3-14-g449e9269
k8s-control-plane2   Ready    master   96s    v1.18.2   172.18.0.6    <none>        Ubuntu 19.10   4.19.104-microsoft-standard   containerd://1.3.3-14-g449e9269
k8s-control-plane3   Ready    master   51s    v1.18.2   172.18.0.2    <none>        Ubuntu 19.10   4.19.104-microsoft-standard   containerd://1.3.3-14-g449e9269
k8s-worker           Ready    <none>   32s    v1.18.2   172.18.0.5    <none>        Ubuntu 19.10   4.19.104-microsoft-standard   containerd://1.3.3-14-g449e9269
k8s-worker2          Ready    <none>   32s    v1.18.2   172.18.0.4    <none>        Ubuntu 19.10   4.19.104-microsoft-standard   containerd://1.3.3-14-g449e9269
```

### 建立多節點的 k8s 叢集並設定對應 PORTS 到 Host 主機

預設透過 kind 建立的多節點叢集環境會有點小問題，那就是只因為 kind 是將每個「節點」跑在一個「容器」中，而預設執行容器時，只有將每個容器的 `api-server` 服務對外，你可以從以下命令看出 `PORTS` 的設定狀況，預設 `control-plane` 節點有對外提供連線，但 `worker` 則是都沒有辦法直接從本機連線過去！

```bash
$ docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                       NAMES
db64eb84d956        kindest/haproxy:2.1.1-alpine   "/docker-entrypoint.…"   23 minutes ago      Up 23 minutes       127.0.0.1:37527->6443/tcp   k8s-external-load-balancer
30259d7adfaf        kindest/node:v1.18.2           "/usr/local/bin/entr…"   23 minutes ago      Up 23 minutes                                   k8s-worker2
492ef5c6a816        kindest/node:v1.18.2           "/usr/local/bin/entr…"   23 minutes ago      Up 23 minutes                                   k8s-worker
68e329d37aca        kindest/node:v1.18.2           "/usr/local/bin/entr…"   23 minutes ago      Up 23 minutes       127.0.0.1:43579->6443/tcp   k8s-control-plane3
f60e32459b9a        kindest/node:v1.18.2           "/usr/local/bin/entr…"   23 minutes ago      Up 23 minutes       127.0.0.1:35647->6443/tcp   k8s-control-plane2
28793e631168        kindest/node:v1.18.2           "/usr/local/bin/entr…"   23 minutes ago      Up 23 minutes       127.0.0.1:39199->6443/tcp   k8s-control-plane
```

另一方面，在建立 Service 物件的時候，也沒辦法使用 `type: LoadBalancer` 取得服務對外的 IP，只能用 `type: NodePort` 才能對外提供連線。

我們也知道 Kubernetes 的 Service 物件當設定為 `type: LoadBalancer` 時，指定的 Port 埠號只能介於 `30000` ~ `32767` 而已，且每個 Node 的這個 Ports 範圍都可以接聽要求。所以我們現在可以先用以下命令快速產生 `kind-5nodes-mapping-ports.yaml` 檔案，隨便指定其中一個 Node 的 `extraPortMappings` 額外設定，並將這個 Node 容器的對外 IP `30080` 對應到本機的 `80` Port，如此一來你從 Windows 10 本機電腦就可以透過 [http://localhost](http://localhost) 連線到某個節點的 Port 30080，然後就可以直接存取叢集中的服務了！

> 注意：kind 的每個節點都是跑在 container 下！

```bash
# Create a config file for a 3 nodes cluster
cat << EOF > kind-5nodes-mapping-ports.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
  extraPortMappings:
  - containerPort: 30080
    hostPort: 80
  - containerPort: 30443
    hostPort: 443
EOF
```

然後透過以下命令載入設定檔並建立叢集：

```bash
kind create cluster --name myk8s --config ./kind-5nodes-mapping-ports.yaml
```

建立完成後，我們可以測試一下網路連線是否會通！

1.  建立 Pod 與 Service 物件所需的 YAML 檔 (`mynginx.yaml`)
    
    ```bash
    cat <<EOF > mynginx.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: web-nginx
      labels:
        app.kubernetes.io/name: nginx
    spec:
      type: NodePort
      ports:
        - name: http
          port: 80
          targetPort: http
          nodePort: 30080
      selector:
        app.kubernetes.io/name: nginx
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web-nginx
      labels:
        app.kubernetes.io/name: nginx
    spec:
      selector:
        matchLabels:
          app.kubernetes.io/name: nginx
      replicas: 2
      template:
        metadata:
          labels:
            app.kubernetes.io/name: nginx
        spec:
          containers:
            - name: nginx
              image: docker.io/bitnami/nginx:1.19.1-debian-10-r23
              ports:
                - name: http
                  containerPort: 8080
    EOF
    ```
    
2.  套用 YAML 設定建立 Deployment 與 Service 物件
    
    ```bash
    kubectl apply -f mynginx.yaml
    ```
    
    ```bash
    $ kubectl get all -o wide
    NAME                            READY   STATUS    RESTARTS   AGE     IP           NODE            NOMINATED NODE   READINESS GATES
    pod/web-nginx-57ff6845c-2m28n   1/1     Running   0          5m32s   10.244.4.4   myk8s-worker2   <none>           <none>
    pod/web-nginx-57ff6845c-gds75   1/1     Running   0          5m32s   10.244.3.5   myk8s-worker    <none>           <none>
    
    NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
    service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        24m     <none>
    service/web-nginx    NodePort    10.100.138.97   <none>        80:30080/TCP   5m32s   app.kubernetes.io/name=nginx
    
    NAME                        READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES                                         SELECTOR
    deployment.apps/web-nginx   2/2     2            2           5m32s   nginx        docker.io/bitnami/nginx:1.19.1-debian-10-r23   app.kubernetes.io/name=nginx
    
    NAME                                  DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                                         SELECTOR
    replicaset.apps/web-nginx-57ff6845c   2         2         2       5m32s   nginx        docker.io/bitnami/nginx:1.19.1-debian-10-r23   app.kubernetes.io/name=nginx,pod-temp
    ```
    
3.  開啟瀏覽器並打開 [http://localhost](http://localhost) 網頁
    
    如果這時你看見 Nginx 預設首頁畫面，就代表網路設定一切正常！
    
4.  刪除 YAML 中定義的所有物件
    
    ```bash
    kubectl delete -f mynginx.yaml
    ```
    

### 使用 Kubernetes Dashboard 管理主控台

1.  安裝 [Kubernetes Dashboard](https://github.com/kubernetes/dashboard)
    
    ```bash
    kubectl apply -f  https://raw.githubusercontent.com/kubernetes/dashboard/$(curl -s https://api.github.com/repos/kubernetes/dashboard/r
    eleases/latest | jq -r '.name')/aio/deploy/recommended.yaml
    kubectl get all -n kubernetes-dashboard
    ```
    
2.  設定 Dashboard 權限
    
    建立 k8s 服務帳戶 (`ServiceAccount`)
    
    ```bash
    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: admin-user
      namespace: kubernetes-dashboard
    EOF
    ```
    
    替上述 ServiceAccount 建立 ClusterRoleBinding 權限
    
    ```bash
    kubectl apply -f - <<EOF
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: admin-user
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - kind: ServiceAccount
      name: admin-user
      namespace: kubernetes-dashboard
    EOF
    ```
    
3.  取得登入 Token
    
    ```bash
    kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') --template={{.data.token}} | base64 -d
    ```
    
    由於 WSL 2 跟 Windows 10 無縫整合，你可以透過以下命令，直接將 Token 儲存到 Windows 剪貼簿中：
    
    ```bash
    kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') --template={{.data.token}} | base64 -d | clip.exe
    ```
    
4.  啟動 Proxy 連接介面
    
    ```bash
    kubectl proxy
    ```
    
5.  連接到 Kubernetes Dashboard 登入頁面並輸入 Token
    
    [http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/)
    
    ![連接到 Kubernetes Dashboard 登入頁面並輸入 Token](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/8c5e5b45b5a989e08247-90840264-1b3b0200-e38c-11ea-8181-35b3034fb692.png)
    
    > 由於 Kubernetes Dashboard 支援多國語系顯示，他會自動判斷你的瀏覽器可接受語言來進行自動顯示，而且沒有可以切換語言的地方。如果想以「英文」為主要語系，建議安裝 [Advanced Page Language Switcher](https://chrome.google.com/webstore/detail/advanced-page-language-sw/mhgjlbolkmcookadjpolimbddngjgbol) 擴充套件 (Google Chrome)，並切換到 English (`en`) 語系。設定完成後，再回到 Kubernetes Dashboard 按下 `Ctrl+F5` 重新整理，如果還是看到「中文」介面，請清空瀏覽器快取後再試一次即可！
    

### 使用 Istio 作為服務對外的閘道

1.  下載 Istio
    
    ```bash
    curl -L https://istio.io/downloadIstio | sh -
    cd istio-1.*
    export PATH=$PWD/bin:$PATH
    ```
    
2.  安裝 Istio
    
    測試環境可以用 `demo` 這個 Profile 來進行安裝，但正式環境不建議使用 `demo` Profile 喔！
    
    ```bash
    istioctl install --set profile=demo
    ```
    
    > [Installation Configuration Profiles](https://istio.io/latest/docs/setup/additional-setup/config-profiles/)
    
3.  設定 `default` 這個 namespace 啟用自動注入 Sidecar 的 Label
    
    ```bash
    kubectl label namespace default istio-injection=enabled
    ```
    
    列出目前所有 namespace 的 `istio-injection` 狀態
    
    ```bash
    kubectl get namespace -L istio-injection
    ```
    
4.  部署範例應用程式
    
    ```bash
    kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
    
    kubectl get services
    
    kubectl get pods
    
    kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
    ```
    
5.  開放應用程式給外部網路連線
    
    ```bash
    kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
    ```
    
    驗證 Istio 設定是否「正確」(因為太常設定錯誤了，特別寫了一個工具專門用來檢查)
    
    ```bash
    istioctl analyze
    ```
    
6.  決定 ingress 的 IP 與 Ports
    
    先取得 `istio-system` 負責對外的 `istio-ingressgateway` 服務資訊
    
    ```bash
    kubectl get svc istio-ingressgateway -n istio-system
    ```
    
    由於 KinD 內的服務沒辦法透過 `type: LoadBalancer` 取得 IP 地址，因此必須手動改成 `type: NodePort` 才行！
    
    請修改 `spec.type` 為 `NodePort`，並調整 `.spec.ports[*].nodePort` 的 Port 埠號。
    
    > `name: http2` 的 `nodePort` 調整為 `30080` `name: https` 的 `nodePort` 調整為 `30443`
    
    > [Service | Kubernetes > Type NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport)
    
7.  在 Windows 10 開啟瀏覽器，透過 Istio Gateway 瀏覽網頁！
    
    當你連到 [http://localhost/](http://localhost/) 將會看到 HTTP 404 錯誤頁面。
    
    當你連到 [http://localhost/productpage](http://localhost/productpage) 就會看到 BookInfo Sample 的首頁！
    
8.  開啟 Kiali dashboard 查看 Istio 的所有流量資訊
    
    透過以下命令可以啟動一個 Proxy 端點，讓你可以透過本機進行瀏覽
    
    > 請注意：每次執行 `istioctl dashboard kiali` 都會產生不同的 Ports
    
    ```bash
    $ istioctl dashboard kiali
    http://localhost:41515/kiali
    Failed to open browser; open http://localhost:41515/kiali in your browser.
    ```
    
    由於我們使用 `demo` Profile 安裝 Istio，所以預設已經啟用 Kiali 擴充套件，預設的登入帳號密碼為 `admin` / `admin`
    
    參考下圖進行報表顯示設定，對網站進行壓力測試後，就會看見流量的即時動畫！
    
    ![Kiali Console - Graph](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/4bdf0628268e7b311c83-90917039-aeb81580-e414-11ea-9bb2-210c762abc26.png)
    

### 其他 kind 設定

-   啟用 [Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) 功能
    
    Kubernetes 每當推出新版功能時，都會事先加上 [Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) 選項，讓你在安裝叢集的時候可以依據想啟用的功能進行開啟，這部分也可以直接透過 kind 的設定檔進行設定，設定方式如下：
    
    ```bash
    kind: Cluster
    apiVersion: kind.x-k8s.io/v1alpha4
    featureGates:
      FeatureGateName: true
    ```
    
    > 完整的 `FeatureGateName` 可以參考 [Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) 文件說明。
    
-   匯出叢集所有節點的完整紀錄 (Export Cluster Logs)
    
    ```bash
    kind export logs --name myk8s
    ```
    
    > 預設會輸出到 `/tmp/XXXXXX` 暫存目錄下！
    
    ```log
    .
    ├── docker-info.txt
    └── kind-control-plane/
        ├── containers
        ├── docker.log
        ├── inspect.json
        ├── journal.log
        ├── kubelet.log
        ├── kubernetes-version.txt
        └── pods/
    ```
    

### 相關連結

-   [kind](https://kind.sigs.k8s.io/)
    -   [User Guide > Quick Start](https://kind.sigs.k8s.io/docs/user/quick-start)
-   [Istio](https://istio.io/latest/)
    -   [Istio / Getting Started](https://istio.io/latest/docs/setup/getting-started/)
-   [Feature Gates | Kubernetes](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/)
-   [WSL+Docker: Kubernetes on the Windows Desktop | Kubernetes](https://kubernetes.io/blog/2020/05/21/wsl-docker-kubernetes-on-the-windows-desktop/)
-   [kubectx + kubens: Power tools for kubectl](https://github.com/ahmetb/kubectx)
-   [K9s - Kubernetes CLI To Manage Your Clusters In Style!](https://github.com/derailed/k9s)
