本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
WSL+Docker:Windows 桌面上的 Kubernetes
引言
剛接觸 Windows 10 和 WSL2,或剛接觸 Docker 和 Kubernetes?歡迎閱讀這篇部落格文章,我們將從頭開始在 Docker KinD 和 Minikube 中安裝 Kubernetes。
為什麼要在 Windows 上執行 Kubernetes?
在過去的幾年裡,Kubernetes 已成為在分散式環境中執行容器化服務和應用程式的實際標準平臺。雖然有各種各樣的發行版和安裝程式可以將 Kubernetes 部署到雲環境(公共、私有或混合)或裸機環境,但仍然需要本地部署和執行 Kubernetes,例如在開發人員的工作站上。
Kubernetes 最初設計用於部署和執行在 Linux 環境中。然而,相當多的使用者(不僅僅是應用程式開發人員)使用 Windows 作業系統作為他們的日常作業系統。當微軟釋出 WSL - 適用於 Linux 的 Windows 子系統時,Windows 和 Linux 環境之間的界限變得更加模糊。
此外,WSL 帶來了幾乎無縫地在 Windows 上執行 Kubernetes 的能力!
下面,我們將簡要介紹如何安裝和使用各種解決方案來本地執行 Kubernetes。
先決條件
由於我們將解釋如何安裝 KinD,因此不會詳細介紹 KinD 依賴項的安裝。
但是,這裡是所需的先決條件及其版本/通道的列表
- 作業系統:Windows 10 版本 2004,內部版本 19041
- 已啟用 WSL2
- 要預設將發行版安裝為 WSL2,一旦安裝了 WSL2,請在 Powershell 中執行命令
wsl.exe --set-default-version 2
- 要預設將發行版安裝為 WSL2,一旦安裝了 WSL2,請在 Powershell 中執行命令
- 從 Windows 應用商店安裝的 WSL2 發行版 - 使用的發行版是 Ubuntu-18.04
- 適用於 Windows 的 Docker Desktop,穩定通道 - 使用的版本是 2.2.0.4
- [可選] 從 Windows 應用商店安裝了 Microsoft Terminal
- 開啟 Windows 應用商店並在搜尋中輸入“Terminal”,它將是(通常)第一個選項
實際上就是這樣。對於適用於 Windows 的 Docker Desktop,無需配置任何內容,我們將在下一節中解釋。
WSL2:初次接觸
一切安裝完成後,我們可以從“開始”選單啟動 WSL2 終端,然後輸入“Ubuntu”搜尋應用程式和文件
找到後,單擊名稱,它將啟動預設的 Windows 控制檯,其中執行著 Ubuntu bash shell。
與任何正常的 Linux 發行版一樣,您需要建立一個使用者並設定密碼
[可選] 更新 sudoers
由於我們通常在本地計算機上工作,更新 sudoers
並將組 %sudo
設定為無需密碼可能會很好
# Edit the sudoers with the visudo command
sudo visudo
# Change the %sudo group to be password-less
%sudo ALL=(ALL:ALL) NOPASSWD: ALL
# Press CTRL+X to exit
# Press Y to save
# Press Enter to confirm
更新 Ubuntu
在進入 Docker Desktop 設定之前,讓我們更新我們的系統並確保我們在最佳條件下開始
# Update the repositories and list of the packages available
sudo apt update
# Update the system based on the packages installed > the "-y" will approve the change automatically
sudo apt upgrade -y
Docker Desktop:WSL2 更快
在進入設定之前,讓我們做一個小測試,它將真正展示與 Docker Desktop 的新整合有多酷
# Try to see if the docker cli and daemon are installed
docker version
# Same for kubectl
kubectl version
你收到錯誤了嗎?太棒了!這實際上是個好訊息,所以現在讓我們繼續設定。
Docker Desktop 設定:啟用 WSL2 整合
首先,如果尚未啟動,請啟動適用於 Windows 的 Docker Desktop。開啟 Windows “開始”選單並輸入“docker”,單擊名稱啟動應用程式
您現在應該會在時鐘附近看到帶有其他工作列圖示的 Docker 圖示
現在單擊 Docker 圖示並選擇設定。將出現一個新視窗
預設情況下,WSL2 整合未啟用,因此單擊“啟用基於 WSL 2 的實驗性引擎”並單擊“應用並重啟”
此功能在幕後建立了兩個新的 WSL2 發行版,包含並執行所有必要的後端套接字、守護程式以及 CLI 工具(即:docker 和 kubectl 命令)。
但是,此第一個設定仍不足以在我們的發行版中執行命令。如果我們嘗試,我們將收到與之前相同的錯誤。
為了解決這個問題,並最終能夠使用這些命令,我們還需要告訴 Docker Desktop “附加”到我們的發行版
現在讓我們切換回 WSL2 終端,看看我們是否可以(最終)啟動命令
# Try to see if the docker cli and daemon are installed
docker version
# Same for kubectl
kubectl version
提示:如果沒有發生任何事情,請重新啟動 Docker Desktop 並在 Powershell 中重新啟動 WSL 程序:
Restart-Service LxssManager
並啟動新的 Ubuntu 會話
成功了!基本設定現已完成,我們繼續安裝 KinD。
KinD:容器中的 Kubernetes 變得簡單
現在,我們已經安裝、配置了 Docker,並且上次測試執行良好。
但是,如果我們仔細檢視 kubectl
命令,它找到了“客戶端版本”(1.15.5),但沒有找到任何伺服器。
這是正常的,因為我們沒有啟用 Docker Kubernetes 叢集。所以讓我們安裝 KinD 並建立我們的第一個叢集。
由於來源總是重要的,我們將(部分)遵循 官方 KinD 網站 上的操作指南
# Download the latest version of KinD
curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-linux-amd64
# Make the binary executable
chmod +x ./kind
# Move the binary to your executable path
sudo mv ./kind /usr/local/bin/
KinD:第一個叢集
我們已準備好建立我們的第一個叢集
# Check if the KUBECONFIG is not set
echo $KUBECONFIG
# Check if the .kube directory is created > if not, no need to create it
ls $HOME/.kube
# Create the cluster and give it a name (optional)
kind create cluster --name wslkind
# Check if the .kube has been created and populated with files
ls $HOME/.kube
提示:如您所見,終端已更改,因此所有漂亮的圖示都已顯示
叢集已成功建立,並且由於我們使用的是 Docker Desktop,因此網路已為我們設定好,可以直接使用。
所以我們可以在 Windows 瀏覽器中開啟 Kubernetes master
URL
這就是適用於 Windows 的 Docker Desktop 與 WSL2 後端整合的真正優勢。Docker 確實做了一個令人驚歎的整合。
KinD:數一數二數三
我們的第一個叢集已建立,它是一個“正常”的單節點叢集
# Check how many nodes it created
kubectl get nodes
# Check the services for the whole cluster
kubectl get all --all-namespaces
雖然這對於大多數人來說已經足夠了,但讓我們利用其中一個最酷的功能,多節點叢集
# Delete the existing cluster
kind delete cluster --name wslkind
# Create a config file for a 3 nodes cluster
cat << EOF > kind-3nodes.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# Create a new cluster with the config file
kind create cluster --name wslkindmultinodes --config ./kind-3nodes.yaml
# Check how many nodes it created
kubectl get nodes
提示:根據我們執行“獲取節點”命令的速度,可能並非所有節點都已就緒,等待幾秒鐘並再次執行,一切都應該就緒
就是這樣,我們已經建立了一個三節點叢集,如果我們再次檢視服務,我們將看到現在有三個副本的服務
# Check the services for the whole cluster
kubectl get all --all-namespaces
KinD:我能看到一個漂亮的儀表板嗎?
命令列操作總是好的,並且非常富有洞察力。然而,在處理 Kubernetes 時,我們可能在某個時候需要一個視覺化的概述。
為此,Kubernetes Dashboard 專案應運而生。安裝和首次連線測試非常快,所以讓我們開始吧
# Install the Dashboard application into our cluster
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc6/aio/deploy/recommended.yaml
# Check the resources it created based on the new namespace created
kubectl get all -n kubernetes-dashboard
由於它建立了一個帶有 ClusterIP(即:內部網路地址)的服務,因此如果我們直接在 Windows 瀏覽器中輸入 URL,將無法訪問它
那是因為我們需要建立一個臨時代理
# Start a kubectl proxy
kubectl proxy
# Enter the URL on your browser: https://:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
最後,要登入,我們可以輸入一個我們沒有建立的令牌,或者輸入我們叢集的 kubeconfig
檔案。
如果我們嘗試使用 `kubeconfig` 登入,我們將收到錯誤“內部錯誤 (500):沒有足夠的資料來建立身份驗證資訊結構”。這是由於 `kubeconfig` 檔案中缺少憑據。
因此,為了避免您遇到同樣的錯誤,讓我們遵循推薦的 RBAC 方法。
讓我們開啟一個新的 WSL2 會話
# Create a new ServiceAccount
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
EOF
# Create a ClusterRoleBinding for the ServiceAccount
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
# Get the Token for the ServiceAccount
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
# Copy the token and copy it into the Dashboard login and press "Sign in"
成功!讓我們也看看我們列出的節點
一個漂亮閃亮的三節點出現了。
Minikube:無處不在的 Kubernetes
現在,我們已經安裝、配置了 Docker,並且上次測試執行良好。
但是,如果我們仔細檢視 kubectl
命令,它找到了“客戶端版本”(1.15.5),但沒有找到任何伺服器。
這是正常的,因為我們沒有啟用 Docker Kubernetes 叢集。所以讓我們安裝 Minikube 並建立我們的第一個叢集。
由於引用來源總是很重要,我們將(部分)遵循 Kubernetes.io 網站上的操作指南
# Download the latest version of Minikube
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
# Make the binary executable
chmod +x ./minikube
# Move the binary to your executable path
sudo mv ./minikube /usr/local/bin/
Minikube:更新主機
如果我們按照操作指南,它指出我們應該使用 --driver=none
標誌,以便直接在主機和 Docker 上執行 Minikube。
不幸的是,我們將收到一個關於執行 Kubernetes v1.18 需要“conntrack”的錯誤
# Create a minikube one node cluster
minikube start --driver=none
提示:如您所見,終端已更改,因此所有漂亮的圖示都已顯示
所以讓我們透過安裝缺失的軟體包來解決這個問題
# Install the conntrack package
sudo apt install -y conntrack
讓我們再試一次
# Create a minikube one node cluster
minikube start --driver=none
# We got a permissions error > try again with sudo
sudo minikube start --driver=none
好的,這個錯誤在過去可能會有問題……幸運的是,我們有解決方案
Minikube:啟用 SystemD
為了在 WSL2 上啟用 SystemD,我們將應用 Daniel Llewellyn 的指令碼。
我邀請您閱讀完整的博文,瞭解他是如何找到解決方案的,以及他為解決各種問題所做的多次迭代。
簡而言之,以下是命令
# Install the needed packages
sudo apt install -yqq daemonize dbus-user-session fontconfig
# Create the start-systemd-namespace script
sudo vi /usr/sbin/start-systemd-namespace
#!/bin/bash
SYSTEMD_PID=$(ps -ef | grep '/lib/systemd/systemd --system-unit=basic.target$' | grep -v unshare | awk '{print $2}')
if [ -z "$SYSTEMD_PID" ] || [ "$SYSTEMD_PID" != "1" ]; then
export PRE_NAMESPACE_PATH="$PATH"
(set -o posix; set) | \
grep -v "^BASH" | \
grep -v "^DIRSTACK=" | \
grep -v "^EUID=" | \
grep -v "^GROUPS=" | \
grep -v "^HOME=" | \
grep -v "^HOSTNAME=" | \
grep -v "^HOSTTYPE=" | \
grep -v "^IFS='.*"$'\n'"'" | \
grep -v "^LANG=" | \
grep -v "^LOGNAME=" | \
grep -v "^MACHTYPE=" | \
grep -v "^NAME=" | \
grep -v "^OPTERR=" | \
grep -v "^OPTIND=" | \
grep -v "^OSTYPE=" | \
grep -v "^PIPESTATUS=" | \
grep -v "^POSIXLY_CORRECT=" | \
grep -v "^PPID=" | \
grep -v "^PS1=" | \
grep -v "^PS4=" | \
grep -v "^SHELL=" | \
grep -v "^SHELLOPTS=" | \
grep -v "^SHLVL=" | \
grep -v "^SYSTEMD_PID=" | \
grep -v "^UID=" | \
grep -v "^USER=" | \
grep -v "^_=" | \
cat - > "$HOME/.systemd-env"
echo "PATH='$PATH'" >> "$HOME/.systemd-env"
exec sudo /usr/sbin/enter-systemd-namespace "$BASH_EXECUTION_STRING"
fi
if [ -n "$PRE_NAMESPACE_PATH" ]; then
export PATH="$PRE_NAMESPACE_PATH"
fi
# Create the enter-systemd-namespace
sudo vi /usr/sbin/enter-systemd-namespace
#!/bin/bash
if [ "$UID" != 0 ]; then
echo "You need to run $0 through sudo"
exit 1
fi
SYSTEMD_PID="$(ps -ef | grep '/lib/systemd/systemd --system-unit=basic.target$' | grep -v unshare | awk '{print $2}')"
if [ -z "$SYSTEMD_PID" ]; then
/usr/sbin/daemonize /usr/bin/unshare --fork --pid --mount-proc /lib/systemd/systemd --system-unit=basic.target
while [ -z "$SYSTEMD_PID" ]; do
SYSTEMD_PID="$(ps -ef | grep '/lib/systemd/systemd --system-unit=basic.target$' | grep -v unshare | awk '{print $2}')"
done
fi
if [ -n "$SYSTEMD_PID" ] && [ "$SYSTEMD_PID" != "1" ]; then
if [ -n "$1" ] && [ "$1" != "bash --login" ] && [ "$1" != "/bin/bash --login" ]; then
exec /usr/bin/nsenter -t "$SYSTEMD_PID" -a \
/usr/bin/sudo -H -u "$SUDO_USER" \
/bin/bash -c 'set -a; source "$HOME/.systemd-env"; set +a; exec bash -c '"$(printf "%q" "$@")"
else
exec /usr/bin/nsenter -t "$SYSTEMD_PID" -a \
/bin/login -p -f "$SUDO_USER" \
$(/bin/cat "$HOME/.systemd-env" | grep -v "^PATH=")
fi
echo "Existential crisis"
fi
# Edit the permissions of the enter-systemd-namespace script
sudo chmod +x /usr/sbin/enter-systemd-namespace
# Edit the bash.bashrc file
sudo sed -i 2a"# Start or enter a PID namespace in WSL2\nsource /usr/sbin/start-systemd-namespace\n" /etc/bash.bashrc
最後,退出並啟動一個新會話。您**無需**停止 WSL2,新會話就足夠了
Minikube:第一個叢集
我們已準備好建立我們的第一個叢集
# Check if the KUBECONFIG is not set
echo $KUBECONFIG
# Check if the .kube directory is created > if not, no need to create it
ls $HOME/.kube
# Check if the .minikube directory is created > if yes, delete it
ls $HOME/.minikube
# Create the cluster with sudo
sudo minikube start --driver=none
為了能夠讓我們的使用者使用 `kubectl`,而不是 `sudo`,Minikube 建議執行 `chown` 命令
# Change the owner of the .kube and .minikube directories
sudo chown -R $USER $HOME/.kube $HOME/.minikube
# Check the access and if the cluster is running
kubectl cluster-info
# Check the resources created
kubectl get all --all-namespaces
叢集已成功建立,Minikube 使用了 WSL2 IP,這出於多種原因非常棒,其中之一是我們可以在 Windows 瀏覽器中開啟 Kubernetes master
URL
WSL2 整合的真正優勢在於,埠 `8443` 一旦在 WSL2 發行版上開啟,它實際上會將其轉發到 Windows,因此無需記住 IP 地址,我們也可以透過 `localhost` 訪問 `Kubernetes master` URL
Minikube:我能看到漂亮的儀表板嗎?
命令列操作總是好的,並且非常富有洞察力。然而,在處理 Kubernetes 時,我們可能在某個時候需要一個視覺化的概述。
為此,Minikube 內建了 Kubernetes Dashboard。多虧了它,執行和訪問 Dashboard 非常簡單
# Enable the Dashboard service
sudo minikube dashboard
# Access the Dashboard from a browser on Windows side
該命令還會建立一個代理,這意味著一旦我們透過按 `CTRL+C` 結束命令,儀表板將不再可訪問。
但是,如果我們檢視 `kubernetes-dashboard` 名稱空間,我們會發現服務仍然存在
# Get all the services from the dashboard namespace
kubectl get all --namespace kubernetes-dashboard
讓我們編輯服務並將其型別更改為 `LoadBalancer`
# Edit the Dashoard service
kubectl edit service/kubernetes-dashboard --namespace kubernetes-dashboard
# Go to the very end and remove the last 2 lines
status:
loadBalancer: {}
# Change the type from ClusterIO to LoadBalancer
type: LoadBalancer
# Save the file
再次檢查儀表板服務,並透過 LoadBalancer 訪問儀表板
# Get all the services from the dashboard namespace
kubectl get all --namespace kubernetes-dashboard
# Access the Dashboard from a browser on Windows side with the URL: localhost:<port exposed>
結論
很明顯,我們離完成還很遠,因為我們可能還需要實現一些負載均衡和/或其他服務(儲存、Ingress、登錄檔等)。
關於 WSL2 上的 Minikube,由於它需要啟用 SystemD,我們可以認為它是一個需要實現的中間級別。
那麼有了兩種解決方案,哪種才是“最適合你的”呢?兩者都有各自的優點和缺點,所以這裡僅從我們的角度進行概述
標準 | KinD | Minikube |
---|---|---|
在 WSL2 上安裝 | 非常簡單 | 中等 |
多節點 | 是 | 否 |
外掛 | 手動安裝 | 是 |
永續性 | 是,但並非為此設計 | 是 |
替代方案 | K3d | Microk8s |
我們希望您能真正體驗到不同元件(WSL2 - Docker Desktop - KinD/Minikube)之間的整合。這為您在 Windows 和 WSL2 上使用 KinD 和/或 Minikube 的 Kubernetes 工作流程提供了一些想法,甚至更好的答案。
期待在 Kubernetes 的海洋中再次相遇,共探更多冒險。