本文已发布一年多。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已不再准确。
WSL+Docker:在 Windows 桌面上运行 Kubernetes
引言
你是 Windows 10 和 WSL2 的新手,还是 Docker 和 Kubernetes 的新手?欢迎来到这篇博文,我们将从零开始在 Docker KinD 和 Minikube 中安装 Kubernetes。
为什么要在 Windows 上运行 Kubernetes?
近几年来,Kubernetes 已成为在分布式环境中运行容器化服务和应用的实际标准平台。虽然存在各种各样的分发版本和安装程序用于在云环境(公有、私有或混合)或裸金属环境中部署 Kubernetes,但仍然需要在本地部署和运行 Kubernetes,例如在开发者的工作站上。
Kubernetes 最初设计用于在 Linux 环境中部署和使用。然而,相当多的用户(不仅是应用开发者)将 Windows 操作系统作为他们的日常主力系统。当微软发布 WSL - Windows Subsystem for Linux 时,Windows 和 Linux 环境之间的界限变得更加模糊。
此外,WSL 带来了几乎无缝地在 Windows 上运行 Kubernetes 的能力!
下面,我们将简要介绍如何安装和使用各种解决方案来在本地运行 Kubernetes。
先决条件
由于我们将解释如何安装 KinD,因此不会详细介绍 KinD 依赖项的安装过程。
但是,这里列出了所需的先决条件及其版本/通道
- 操作系统:Windows 10 版本 2004,Build 19041
- 启用 WSL2
- 为了默认将分发版安装为 WSL2,一旦安装了 WSL2,请在 Powershell 中运行命令
wsl.exe --set-default-version 2
- 为了默认将分发版安装为 WSL2,一旦安装了 WSL2,请在 Powershell 中运行命令
- 从 Windows 应用商店安装的 WSL2 分发版 - 使用的分发版是 Ubuntu-18.04
- Docker Desktop for Windows,稳定通道 - 使用的版本是 2.2.0.4
- [可选] 从 Windows 应用商店安装 Microsoft Terminal
- 打开 Windows 应用商店并在搜索中输入“Terminal”,它(通常)会是第一个选项
实际上就是这些。对于 Docker Desktop for Windows,暂时无需配置任何东西,我们将在下一节中解释。
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 集成
如果 Docker Desktop for Windows 尚未启动,请先启动它。打开 Windows 开始菜单,输入“docker”,点击名称启动应用
现在你应该会在时钟附近的任务栏图标中看到 Docker 图标
现在点击 Docker 图标并选择设置。一个新的窗口将出现
默认情况下,WSL2 集成未激活,因此请点击“启用基于 WSL 2 的实验性引擎”(Enable the experimental WSL 2 based engine)并点击“应用并重启”(Apply & Restart)
这个功能在幕后做了什么?它在 WSL2 中创建了两个新的分发版,其中包含并运行所有必需的后端 socket、守护进程以及 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
命令,它找到了“Client Version”(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
这就是 Docker Desktop for Windows 配合 WSL2 后端的真正优势。Docker 确实做到了令人惊叹的集成。
KinD:数到 1 - 2 - 3
我们的第一个集群已创建,它是“正常”的单节点集群
# 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
提示:取决于我们运行 "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: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
最后登录时,我们可以输入一个令牌(我们没有创建),或者输入集群的 kubeconfig
文件。
如果我们尝试使用 kubeconfig
登录,会收到错误信息“内部错误 (500):没有足够的数据创建 auth info 结构”。这是由于 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
命令,它找到了“Client Version”(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 v 1.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
为了能够使用我们的用户而不是 sudo
使用 kubectl
,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
结束该命令,Dashboard 将不再可访问。
不过,如果我们查看命名空间 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
再次检查 Dashboard 服务,然后通过 LoadBalancer 访问 Dashboard。
# 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>
结论
显然,我们还有很多事情要做,例如可以实现一些负载均衡和/或其他服务(存储、入口、注册表等)。
关于 WSL2 上的 Minikube,由于它需要启用 SystemD,我们可以将其视为一个需要实现的中间层。
那么,面对这两种方案,哪种是“最适合你的”呢?两者都有各自的优点和缺点,所以这里仅从我们的角度提供一个概览。
标准 | KinD | Minikube |
---|---|---|
在 WSL2 上安装 | 非常容易 | 中等 |
多节点 | 是 | 否 |
插件 | 手动安装 | 是 |
持久性 | 是,但不为此设计 | 是 |
替代方案 | K3d | Microk8s |
我们希望您能真正体会到不同组件之间的集成:WSL2 - Docker Desktop - KinD/Minikube。希望这能给您一些想法,或者更好地,为您在 Windows 和 WSL2 上使用 KinD 和/或 Minikube 的 Kubernetes 工作流程提供一些答案。
期待很快再次在 Kubernetes 的海洋中与您相遇,进行其他冒险。