本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
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 的海洋中再次相遇,共探更多冒险。