在windows上通过wsl来部署k8s

2020/09/27 k8s 共 10111 字,约 29 分钟

1. 写在前面

为什么要在windows上使用kubernetes?

在过去的几年里,Kubernetes成为了在分布式环境中运行容器化服务和应用的事实标准平台。虽然存在各种各样的发行版和安装程序来部署Kubernetes在云环境(公共的、私有的或混合的),或在裸机环境中,但仍然需要在本地部署和运行Kubernetes,例如,在开发者的工作站上。

Kubernetes最初被设计为在Linux环境中部署和使用。然而,有不少用户(不仅是应用开发者)使用Windows操作系统作为日常工具。当微软揭示了WSL–Windows Subsystem for Linux时,Windows和Linux环境之间的界限变得更加不明显。

同时,WSL还带来了在Windows上几乎无缝运行Kubernetes的能力!

下面,我们将简要介绍如何安装和使用各种解决方案在本地运行Kubernetes。

2. 前提条件

尽管我们将会安装Kind,但是,讲解太多关于如何安装的细节,如果您对这个比较关注,请关注我后续的文章。

首先,我们先看一下我们继续进行下面的操作前,我们的最小的软件版本的需求:

  • OS:Win10 version 2004, build 19041。
  • WSL2开启。安装完成后,可以使用wsl.exe --set-default-version 2设置使用WSL2。
  • WSL2可以通过win应用商店来安装,这里使用的是Ubuntu 18.04。
  • Docker-desktop-for-windows
  • (可选)Microsoft Terminal。可以从windows应用商店进行安装。

图0

如何查看win10的版本信息?

  • win+R
  • 输入winver

3. WSL2:首次接触

上面的软件都安装完成后,我们就可以从开始->Ubuntu来打开wsl2了。

图1

打开后,你完全可以把它看成是一个正常的Linux的发行,同样的,你也可以在里面设置用户等。

3.1 (可选)设置sudoers

由于我们是在本地计算机上工作,通常情况下,更新sudoers,并将%sudo组设置为无密码组,可能会更好。

# 用visudo打开sudoer文件
sudo visudo

# 设置sudo group免密登陆
%sudo   ALL=(ALL:ALL) NOPASSWD: ALL

# 按 CTRL+X 退出
# 按 Y 保存
# 按 Enter 确认

3.2 更新Ubuntu

在进行后面的操作前,我们先升级一下我们的系统。

# 更新apt-get源
sudo apt update
# 基于最新的源更新系统。automatically
sudo apt upgrade -y

4. Docker Desktop

Docker-Windows-Desktop与WSL2更配哦。

在我们进入设置之前,让我们做一个小测试,它将显示出与Docker Desktop的新集成是多么的酷。

# 看一下docker的版本及docker是否被安装
docker version
# 看一下kubectl的版本及kubectl是否被安装
kubectl version

你有遇到错误吗?有错误就对了,所以现在让我们继续进行设置。

4.1 设置docker desktop:开启对WSL2的支持

如果还没有打开Docker-For-Windows的话,首先我们来启动它。打开Windows的开始菜单,输入 “docker”,点击名称启动应用程序。

现在在你的任务栏中就能看到它的图标了。

下面我们在docker-for-windows的中设置一下,让他使用wsl2:

这个选项默认情况下并没有开启:

这个功能在幕后所做的就是在WSL2中创建了两个新的发行版,包含并运行所有需要的后端socket、守护进程以及CLI工具(如:docker和kubectl命令)。

但是,第一种设置仍然不足以在我们的发行版中运行命令。如果我们尝试,我们会遇到和之前一样的错误。

为了解决这个问题,并最终能够使用这些命令,我们需要告诉Docker桌面也要 “附加 “到我们的发行版上。

接下来,我们再看一下命令是否正常了呢:

# 看一下docker的版本及docker是否被安装
docker version
# 看一下kubectl的版本及kubectl是否被安装
kubectl version

说明:

  • 如果没有发生任何事情,重启Docker Desktop并在Powershell中重启WSL进程。重启服务LxssManager并启动一个新的Ubuntu会话。
  • 如果您的docker-desktop-for-win中没有Use the WSL2 based engine的,请重新安装它的edge版本。

5. Kind: 让k8s方便的运行在容器中

现在,我们的Docker已经安装好了,配置好了,上次的测试也很正常。

但是,如果我们仔细观察kubectl命令,它找到了 “客户端版本”(1.15.5),但它没有找到任何服务器。

这很正常,因为我们没有启用Docker Kubernetes集群。所以让我们安装KinD并创建我们的第一个集群。

我们将按照KinD官方网站上的教程(部分)进行操作。

# 下载 KinD
curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(uname)-amd64
# 增加可执行权限
chmod +x ./kind
# 移动到系统PATH中
sudo mv ./kind /usr/local/bin/

5.1 创建单节点的集群

下面,我们将会创建我们的第一个集群:

# 检查 KUBECONFIG 是否存在
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

说明:对于执行的每一步,都会有一个小图标与之显示。

运行完上面的命令后,k8s集群就已经创建好了,因为我们使用是docker desktop,所以,里面的网络默认使用的是as is

我们可以在浏览器中打开kubernetes master的页面:

而这才是Docker Desktop for Windows与WSL2后台的真正优势。Docker真的做了一个惊人的整合

5.2 创建多节点的集群

上一节中,我们刚创建的那是一个单节点的集群。

# 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

5.3 查看k8s Dashboard

对于开发人员来说,在命令行上执行操作是可以接受,并且这样效率也比较高。然而,在处理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

虽然kind使用ClusterIP为集群创建了一个service,但是由于这个IP是一个内网的IP,所以我们现在还无法从页面上直接访问dashboard服务。

这个问题可以通过创建一个proxy来解决:

# 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/

最后要登录,我们可以输入一个我们没有创建的Token,或者从我们的Cluster中输入kubeconfig文件。

如果我们尝试用kubeconfig登录,我们会得到错误 “Internal error (500): Not enough data to create auth info structure”。没有足够的数据来创建Auth信息结构”。这是由于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"

6. minikube: 让k8s可任意部署

现在,我们的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/

6.1 更新Host

如果我们按照how-to,它提示我们应该使用–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

这次是不是没有出错呢。

6.2 启用systemd

为了能够使用systemd,我们需要按照这个脚本来配置一下。

说明:如果您想了解更多关于这个脚本背后的考虑,请参考

在终端中输入以下命令:


# 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的窗口,没有必要把前一个窗口关闭。

6.3 创建集群

下面我们创建我们的第一个集群:

# 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就能执行kubeletMinikube建议执行一下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,这样以来,我们不需要新配置proxy就可以直接访问dashboard了。

而WSL2集成的真正优势,8443端口一旦在WSL2发行版上打开,它其实是转发到Windows上的,所以我们不需要代理这个IP地址,也可以通过localhost访问到Kubernetes的dashboard URL。

6.4 访问dashboard

在命令行上工作总是好的,而且非常有见地。然而,当处理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

接下来,我们更改一下service的类型,让他以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相关的service,这次我们通过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>

7. 结论

很明显,我们还远远没有完成,因为我们可以实现一些LoadBalancing和/或其他服务(存储、入口、注册表等)。

关于WSL2上的Minikube,由于它需要启用SystemD,我们可以把它看作是一个中间层来实现。

那么,在两种解决方案中,什么才是 “最适合你 “的呢?两者都有各自的优势和不便,所以这里仅从我们的角度来概述一下。

对比项KindMinikube
与WSL2共同使用非常简单一般简单
多节点支持不支持
插件手动安装自动安装
持久化支持(但这并不是它的本初设计)支持
同类型的其它产品k3sMicroK8s

我们希望你能真正体验到不同组件之间的整合。WSL2 - Docker Desktop - KinD/Minikube。这给了你一些想法,甚至更好的是,给了你在Windows和WSL2上使用KinD和/或Minikube的Kubernetes工作流的一些答案。

8. 出处

WSL+Docker: Kubernetes on the Windows Desktop

Search

    Table of Contents