本文发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
WSL+Docker:Windows 桌面上的 Kubernetes
简介
刚开始使用 Windows 10 和 WSL2,或者刚接触 Docker 和 Kubernetes?欢迎来到这篇博客文章,我们将从头开始在 Docker 中安装 Kubernetes KinD 和 Minikube。
为什么在 Windows 上使用 Kubernetes?
在过去的几年里,Kubernetes 已经成为在分布式环境中运行容器化服务和应用程序的事实上的标准平台。虽然存在各种各样的发行版和安装程序可以在云环境(公共、私有或混合)或裸机环境中部署 Kubernetes,但仍然需要在本地(例如,在开发人员的工作站上)部署和运行 Kubernetes。
Kubernetes 最初被设计为在 Linux 环境中部署和使用。然而,许多用户(不仅仅是应用程序开发人员)使用 Windows 操作系统作为他们的日常驱动程序。当微软推出 WSL - Windows Subsystem for Linux 时,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:计数 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 仪表板 项目。安装和首次连接测试非常快,因此让我们这样做
# 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://127.0.0.1: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 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 集成的真正优势在于,一旦在 WSL2 发行版上打开端口 8443
,它实际上会将其转发到 Windows,因此,无需记住 IP 地址,我们还可以通过 localhost
访问 Kubernetes master
URL
Minikube:我可以看到一个漂亮的仪表板吗?
在命令行上工作总是很好,而且很有见地。但是,在处理 Kubernetes 时,我们可能希望在某个时候拥有一个可视化概述。
为此,Minikube 嵌入了 Kubernetes 仪表板。借助它,运行和访问仪表板非常简单
# 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>
结论
很明显,我们还远远没有完成,因为我们可以实施一些负载平衡和/或其他服务(存储、入口、注册表等...)。
关于 WSL2 上的 Minikube,由于它需要启用 SystemD,我们可以将其视为要实现的中间级别。
因此,有了两个解决方案,哪一个“最适合您”?两者都有各自的优点和缺点,因此这里仅从我们的角度进行概述
标准 | KinD | Minikube |
---|---|---|
在 WSL2 上安装 | 非常简单 | 中等 |
多节点 | 是 | 否 |
插件 | 手动安装 | 是 |
持久性 | 是,但并非为此设计 | 是 |
替代方案 | K3d | Microk8s |
我们希望您能真正体验到不同组件之间的集成:WSL2 - Docker Desktop - KinD/Minikube。 这能为您在 Windows 和 WSL2 上使用 KinD 和/或 Minikube 进行 Kubernetes 工作流程提供一些思路,甚至更好的,一些答案。
下次 Kubernetes 海洋探险再见。