﻿# 使用 MicroK8s 架設 Kubernetes 叢集時應注意的連線管理注意事項

使用 [MicroK8s](https://microk8s.io/) 架設 [Kubernetes](https://kubernetes.io/) 叢集，無論是本機的開發環境，或是實際運作的生產環境，都有一些應該注意的事情。本篇文章著重在「連線管理」部分，分享我過往的一些研究心得與筆記。

![Ubuntu + MicroK8s](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/48a6bc50734cce167ddc-185737144-f8758614-4cd5-4540-bf81-370bbd3d6363.png)

### 頻繁的更動節點 IP 怎麼辦

在 Windows 環境搭配 Hyper-V 安裝 [MicroK8s](https://microk8s.io/) 叢集時，預設會使用 Hyper-V 內建的 `Default Switch` 做為預設的**虛擬交換器**(vSwitch)，但由於 `Default Switch` 的特殊性，它有以下幾點限制：

1.  **連線類型**(Connection type)預設採用「內部網路」(`Internel network`)
    
    這意味著使用 `Default Switch` 的 VM 只能從「本機」進行連接，從外部網路是無法連上的，也無法實現 [Port forwarding](https://en.wikipedia.org/wiki/Port_forwarding) (通訊埠轉發)
    
2.  透過 [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) 伺服器自動配發 IP 地址
    
    由於 `Default Switch` 使用了 Windows 內建的 [Internet Connection Sharing](https://en.wikipedia.org/wiki/Internet_Connection_Sharing) (ICS) 機制，而正式這個機制配發了動態的私有 IP 地址給 VM 使用，並提供了相當基礎的 NAT 機制，讓你的 VM 可以連接到外部網路。
    
    透過 ICS 機制取得 IP 地址有好有壞。好的地方是，建立好的 VM 會自動配發 IP 地址，簡化網路管理。壞的地方是，這個 DHCP 伺服器**無法停用**，也**無法自行指定 IP 範圍**。更糟的地方是，你無法對 VM 設定「**靜態 IP 地址**」(Static IP Address)，而且只要電腦重開機後，這個 DHCP 伺服器就會配發全新的 IP 地址給 VM 使用，而且這個 IP 是無法事先設定或預測的。
    
3.  所有使用 `Default Switch` 的 VM 都會擁有一個本機可存取的**網域名稱**(Domain Name)
    
    因為 IP 無法固定的緣故，這個 ICS 機制還會自動維護一份本機的 `hosts.ics` 檔案，路徑如下：
    
    ```
    %systemroot%\system32\drivers\etc\hosts.ics
    ```
    
    這個檔案與我們常用的 `hosts` 檔案放在同一個資料夾下，但是你不用特別維護 `hosts.ics` 檔案。
    
    基本上，你只要在建立好 VM 之後的幾秒鐘內，系統就會自動更新 `hosts.ics` 檔案，提供你一個 `*.mshome.net` 的域名。例如你的 VM 名稱如果是 `microk8s-vm` 的話，那麼你就會有一個 `microk8s-vm.mshome.net` 域名可以直接取得這台 VM 的當時的 IP 地址 (請記得重開機 IP 就會變更)，這點倒是相當的便利。不過，這個域名是不能改的，改了也沒用，因為隨時可能會被 Hyper-V 覆寫。
    

上述限制，正是 [MicroK8s](https://microk8s.io/) 在最簡單的 `microk8s install` 安裝好環境後，其 VM 的 IP 會在每次重開機後變更的原因！ 🔥

其解決方案有兩個：

1.  調整 `KUBECONFIG` 設定檔，改用 `microk8s-vm.mshome.net` 做為預設的伺服器位址
    
    ```bash
    kubectl config set-cluster microk8s-cluster --server=https://microk8s-vm.mshome.net:16443
    
    microk8s kubectl config set-cluster microk8s-cluster --server=https://microk8s-vm.mshome.net:16443
    ```
    
2.  每次重開機後，自動執行以下命令，更新 `KUBECONFIG` 設定檔中的 `server` IP 地址
    
    ```powershell
    # 更新 microk8s kubectl 命令專用的 KUBECONFIG 內容
    microk8s config > $env:LOCALAPPDATA\MicroK8s\config
    
    # 更新 kubectl 命令專用的 KUBECONFIG 內容
    microk8s config > ~/.kube/config
    ```
    
3.  不要使用 `Default Switch` 虛擬交換器
    
    你可以參考我先前的 [利用 Multipass 在區域網路架設一套 MicroK8s 叢集環境](/post/2022/01/15/Build-your-own-MicroK8s-with-Multipass-with-Fixed-IP) 文章，額外建立一個 `External network` 虛擬交換器，直接讓 VM 取得外部網路的 IP 地址。
    

### 設定 k 別名

我在 Linux 的 Shell 環境下，幾乎都會用 `k` 來取代 `kubectl` 命令，簡化指令輸入的時間。若是在 Windows 環境下，你可以透過 PowerShell 的 [Set-Alias](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/set-alias) 來做到一樣的功能。

以下有 2 種不同用法：

1.  簡單的 `k` 對應到 `kubectl`
    
    這是在有事先安裝 `kubectl.exe` 工具並設定好 `PATH` 環境變數的前提下才能這樣設定：
    
    ```powershell
    Set-Alias -Name k -Value kubectl
    ```
    
2.  透過 `k` 去執行 `microk8s kubectl` 命令的話，也可以這樣寫：
    
    > 注意: 透過這種方式執行 `kubectl` 非常慢，建議不要這樣用。
    
    ```powershell
    function RunKubectl([Parameter(ValueFromRemainingArguments = $true)]$params) {
        & microk8s.exe kubectl $params
    }
    Set-Alias -Name k -Value RunKubectl
    ```
    
    同樣的技巧，也可以用在執行 `microk8s` 的時候，因為打這個命令實在太花時間，我可以簡化成 `mks` 就好 👍
    
    ```powershell
    function RunMicroK8s([Parameter(ValueFromRemainingArguments = $true)]$params) {
        & microk8s.exe $params
    }
    Set-Alias -Name mks -Value RunMicroK8s
    ```
    

### 常見的 KUBECONFIG 管理

以下是一些管理 `KUBECONFIG` 的常見命令：

-   預設的 `KUBECONFIG` 路徑
    
    ```
    ~/.kube/config
    ```
    
-   指定自訂的 `KUBECONFIG` 路徑
    
    ```
    $env:KUBECONFIG = '~/.kube/microk8s-config'
    ```
    
    清除 `KUBECONFIG` 環境變數設定：
    
    ```
    $env:KUBECONFIG = ''
    ```
    
-   取得目前 `KUBECONFIG` 中的叢集名稱
    
    ```powershell
    k config get-clusters
    ```
    
-   取得目前 `KUBECONFIG` 中的叢集設定
    
    ```powershell
    # 僅顯示重要參數並隱藏憑證的內容(因為內容很長)
    k config view
    
    # 顯示完整的原始內容
    k config view --raw
    ```
    
-   設定目前 `KUBECONFIG` 中的叢集相關參數
    
    ```powershell
    k config set-cluster -h
    # 重新指定叢集節點的 kube-apiserver 端點
    k config set-cluster microk8s-cluster --server=https://microk8s-vm.mshome.net:16443
    
    # 變更 CA 根憑證內容
    k config set-cluster microk8s-cluster --embed-certs --certificate-authority=~/.kube/e2e/kubernetes.ca.crt
    
    # 設定跳過 TLS 有效性驗證
    k config set-cluster microk8s-cluster --insecure-skip-tls-verify=true
    ```
    
-   設定目前 `KUBECONFIG` 中的 Context 設定
    
    所謂的 `Context` 就是一個連線到 K8s 叢集的**連線情境**，這個**情境**包含了 `NAME` (情境名稱)、`CLUSTER` (叢集名稱)、`AUTHINFO` (認證資訊) 與 `NAMESPACE` (命名空間) 等 4 個欄位。一個 `KUBECONFIG` 可以包含多種連線情境，而且可以任意切換。你可以一個叢集設定好幾組情境，也可以每個情境連到不同的叢集，你可以自由搭配。
    
    ```powershell
    # 列出目前所有的連線情境
    k config get-contexts
    
    # 切換到不同的連線情境
    kubectl config use-context myaks
    
    # 設定 microk8s 連線情境改用不同的使用者登入
    k config set-context microk8s --user=admin
    
    # 修改目前的連線情境改用 admin 來連線
    k config set-context --current --user=admin
    
    # 修改目前的連線情境改用 willh 為預設命名空間
    k config set-context --current --namespace=default
    
    # 列出 KUBECONFIG 中所有使用者
    k config get-users
    
    # 建立/更新 cluster-admin 使用者的 Bearer Token
    k config set-credentials cluster-admin --token=uXFGweU9l35q
    
    # 建立/更新 cluster-admin 使用者的 Private Key
    k config set-credentials cluster-admin --client-key=~/.kube/admin.key
    
    # 建立/更新 cluster-admin 使用者的 Client Certificate (用戶端憑證)
    k config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true
    ```
    

### 關於 MicroK8s 叢集重要的認證檔

進入到 MicroK8s 叢集主節點後，可以找到幾個重要的設定檔，這些設定檔決定了叢集要如何對使用者進行驗證，其主要目錄如下：

```
$ ll /var/snap/microk8s/current/credentials/
total 32
drwxrwx---  2 root microk8s 4096 Aug 15 13:56 ./
drwxr-xr-x 13 root root     4096 Aug 17 15:37 ../
-rw-rw----  1 root microk8s 1869 Aug 15 13:56 client.config
-rw-rw----  1 root microk8s 1879 Aug 15 13:56 controller.config
-rw-rw----  1 root microk8s  486 Aug 15 13:56 known_tokens.csv
-rw-rw----  1 root microk8s 1873 Aug 15 13:56 kubelet.config
-rw-rw----  1 root microk8s 1877 Aug 15 13:56 proxy.config
-rw-rw----  1 root microk8s 1877 Aug 15 13:56 scheduler.config
```

各檔案說明如下：

1.  `known_tokens.csv`
    
    這裡記錄了所有系統使用者的 Bearer Token 清單
    
    預設 MicroK8s 都是使用 Bearer Token 來驗證使用者，預設會從 `/var/snap/microk8s/3582/args/kube-apiserver` 啟動參數定義檔載入這個 `known_tokens.csv` 檔案。
    
    ```
    --cert-dir=${SNAP_DATA}/certs
    --service-cluster-ip-range=10.152.183.0/24
    --authorization-mode=AlwaysAllow
    --service-account-key-file=${SNAP_DATA}/certs/serviceaccount.key
    --client-ca-file=${SNAP_DATA}/certs/ca.crt
    --tls-cert-file=${SNAP_DATA}/certs/server.crt
    --tls-private-key-file=${SNAP_DATA}/certs/server.key
    --kubelet-client-certificate=${SNAP_DATA}/certs/server.crt
    --kubelet-client-key=${SNAP_DATA}/certs/server.key
    --secure-port=16443
    --token-auth-file=${SNAP_DATA}/credentials/known_tokens.csv
    --insecure-port=0
    --storage-backend=dqlite
    --storage-dir=${SNAP_DATA}/var/kubernetes/backend/
    --allow-privileged=true
    --service-account-issuer='https://kubernetes.default.svc'
    --service-account-signing-key-file=${SNAP_DATA}/certs/serviceaccount.key
    --feature-gates=RemoveSelfLink=false
    ```
    
2.  `client.config`
    
    系統管理員專用的預設 `KUBECONFIG` 設定檔，預設使用者名稱為 `admin`
    
3.  `controller.config`
    
    各 `controller` 預設使用的 `KUBECONFIG` 設定檔，預設使用者名稱為 `controller`
    
4.  `kubelet.config`
    
    各 `kubelet` 設使用的 `KUBECONFIG` 設定檔，預設使用者名稱為 `kubelet`
    
5.  `proxy.config`
    
    各 `kube-proxy` 設使用的 `KUBECONFIG` 設定檔，預設使用者名稱為 `kubeproxy`
    
6.  `scheduler.config`
    
    各 `scheduler` 設使用的 `KUBECONFIG` 設定檔，預設使用者名稱為 `admin`
    

### 相關連結

-   [MicroK8s - Services and ports](https://microk8s.io/docs/services-and-ports)
-   [MicroK8s - Troubleshooting](https://microk8s.io/docs/troubleshooting)
-   [MTT - Hyper-V Default Switch -- easy LAN/internet access for guest VMs](https://mytechiethoughts.com/windows/hyper-v-default-switch-easy-lan-internet-access-for-guest-vms/)
-   [Set up a NAT network | Microsoft Docs](https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/setup-nat-network?WT.mc_id=DT-MVP-4015686)
-   [How to Configure Hyper-V Virtual Switches? - Getlabsdone.com](https://getlabsdone.com/how-to-configure-hyper-v-virtual-switches/)
