为什么要在Windows上使用Kubernetes?
在过去的几年中,Kubernetes成为事实上的云原生平台,用于在分布式环境中运行容器化服务和应用程序。尽管可以在在云环境(公有云,私有云或混合云)或裸机环境中部署Kubernetes,但有时仍然需要在本地部署和运行Kubernetes。
Kubernetes最初被设计为在Linux环境中部署和使用。但是,大量用户是使用Windows OS作为其日常驱动程序。因此,当微软发布WSL- Linux的Windows子系统时,Windows和Linux环境之间的界线变得不那么明显。
此外,WSL可以满足在Windows上运行Kubernetes的功能!
WSL 不是跑在一个虚拟机里的 Linux。WSL 环境里安装和运行的都是标准的 Linux 程序。当我们运行一个 Linux 程序的时候,这个进程会调用一些 Linux 系统功能调用。WSL 真的提供了这些功能,只是它们被映射为 Windows 操作系统提供的系统功能调用了。所以,WSL 是在 Windows 操作系统内核之外包了一层,使其看上去长得像 Linux 操作系统内核,从而“蒙蔽”了 Linux 应用程序。
下面,我们将简要介绍如何通过结合WSL,安装和使用Kind或Minikube在本地运行Kubernetes集群。
前提条件
- 操作系统:Windows 10 version 2004,Build 19041
- Microsoft更新助手可以帮助你更新到 Windows 10 的最新版本
- 启用WSL2
- 一旦安装了WSL2,请在Powershell中运行命令wsl.exe –set-default-version 2,将WSL2设置为默认。
- 如果提示”WSL 2 需要更新其内核组件。有关信息,请访问 https://aka.ms/wsl2kernel” ,那你就需要 更新 WSL 2 Linux 内核
- 更新内核,再次在Powershell中运行命令wsl.exe –set-default-version 2,控制台输出“有关与 WSL 2 的主要区别的信息,请访问 https://aka.ms/wsl2”,说明已经将WSL2设置为默认。
- 打开Windows应用商店,下载安装Ubuntu-18.04
- 安装适用于Windows的Docker Desktop
- 对于Windows的Docker Desktop,现在无需进行任何配置,因为我们将在下文对其进行说明。
WSL2:与Ubuntu结合
安装完所有组件后,我们单击“ Ubuntu”,它将在运行Ubuntu bash shell的情况下,启动默认的Windows控制台。
像任何普通的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
这时候,我们如果输入以下命令:
# 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”,单击名称以启动应用程序:
选择设置,将会出现一个新窗口:
默认情况下,WSL2集成处于未启用状态,因此请单击“ Enable the experimental WSL 2 based engine ”,然后单击“ Apply & Restart ”:
“ Enable the experimental WSL 2 based engine ”功能的作用是在WSL2中创建两个新发行版,其中包含并运行所有必需的后端套接字,守护程序以及CLI工具(docker和kubectl命令)。
尽管如此,这时我们还不能运行docker和kubectl命令。
为了最终能够使用命令,我们还需要告诉Docker Desktop将其自身“ attach ”到我们的Ubuntu 上:
然后,我们回到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命令,它提示找不到服务器。
这是正常现象,因为我们没有启用Docker Kubernetes集群。因此,让我们安装Kind并创建我们的第一个集群。
# Download the latest version of Kind curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(uname)-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:
这就是WSL2集成Docker Desktop for Windows的真正优势。
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 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
其中https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc6/aio/deploy/recommended.yaml 需要翻墙才能获得,译者给出了文件内容
# Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: v1 kind: Namespace metadata: name: kubernetes-dashboard --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kubernetes-dashboard type: Opaque --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-csrf namespace: kubernetes-dashboard type: Opaque data: csrf: "" --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-key-holder namespace: kubernetes-dashboard type: Opaque --- kind: ConfigMap apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-settings namespace: kubernetes-dashboard --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard rules: # Allow Dashboard to get, update and delete Dashboard exclusive secrets. - apiGroups: [""] resources: ["secrets"] resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] verbs: ["get", "update", "delete"] # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. - apiGroups: [""] resources: ["configmaps"] resourceNames: ["kubernetes-dashboard-settings"] verbs: ["get", "update"] # Allow Dashboard to get metrics. - apiGroups: [""] resources: ["services"] resourceNames: ["heapster", "dashboard-metrics-scraper"] verbs: ["proxy"] - apiGroups: [""] resources: ["services/proxy"] resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] verbs: ["get"] --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard rules: # Allow Metrics Scraper to get metrics from the Metrics server - apiGroups: ["metrics.k8s.io"] resources: ["pods", "nodes"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: kubernetes-dashboard template: metadata: labels: k8s-app: kubernetes-dashboard spec: containers: - name: kubernetes-dashboard image: kubernetesui/dashboard:v2.0.0-rc6 imagePullPolicy: Always ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates - --namespace=kubernetes-dashboard # Uncomment the following line to manually specify Kubernetes API server Host # If not specified, Dashboard will attempt to auto discover the API server and connect # to it. Uncomment only if the default does not work. # - --apiserver-host=http://my-address:port volumeMounts: - name: kubernetes-dashboard-certs mountPath: /certs # Create on-disk volume to store exec logs - mountPath: /tmp name: tmp-volume livenessProbe: httpGet: scheme: HTTPS path: / port: 8443 initialDelaySeconds: 30 timeoutSeconds: 30 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 volumes: - name: kubernetes-dashboard-certs secret: secretName: kubernetes-dashboard-certs - name: tmp-volume emptyDir: {} serviceAccountName: kubernetes-dashboard nodeSelector: "beta.kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule --- kind: Service apiVersion: v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: ports: - port: 8000 targetPort: 8000 selector: k8s-app: dashboard-metrics-scraper --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: dashboard-metrics-scraper template: metadata: labels: k8s-app: dashboard-metrics-scraper annotations: seccomp.security.alpha.kubernetes.io/pod: 'runtime/default' spec: containers: - name: dashboard-metrics-scraper image: kubernetesui/metrics-scraper:v1.0.3 ports: - containerPort: 8000 protocol: TCP livenessProbe: httpGet: scheme: HTTP path: / port: 8000 initialDelaySeconds: 30 timeoutSeconds: 30 volumeMounts: - mountPath: /tmp name: tmp-volume securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 serviceAccountName: kubernetes-dashboard nodeSelector: "beta.kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule volumes: - name: tmp-volume emptyDir: {}
如果使用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登录,则将显示错误“ Internal error (500): Not enough data to create auth info structure ”。这是由于kubeconfig文件中缺少凭据。
因此,为避免出现以上的错误,请使用推荐的RBAC方法。
让我们打开一个新的WSL2会话:
# Create a new ServiceAccount kubectl apply -f - "$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 WSL2nsource /usr/sbin/start-systemd-namespacen" /etc/bash.bashrc
最后,退出并启动新minikube的会话。不需要停止WSL2,一个新的会话就足够了:
Minikube:单节点kubernetes集群
我们准备创建第一个集群:
# 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:
Minikube与WSL2集成的真正优势在于,端口8443一旦在WSL2上打开,便会实际上将其转发至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
再次检查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:
总结
标准 | Kind | Minikube |
---|---|---|
在WSL2上安装 | 很容易 | 有点复杂 |
多节点集群 | 支持 | 不支持 |
插件 | 手动安装 | 支持 |
持久化 | 支持(但没有针对WSL2设计) | 支持 |
替代方案 | K3d | Microk8s |
译文链接: https://kubernetes.io/blog/2020/05/21/wsl-docker-kubernetes-on-the-windows-desktop/