本篇文章将教会大家如何在 WSL2
部署一个标准版的 k8s
集群以及使用 Prometheus
和 grafana
监控 spring cloud
服务。
和第一代 WSL
不同,WSL2
是运行在 hyper-v
上的一个 VM
,因此可以运行原汁原味的 Linux
发行版,例如 Ubuntu
,同样对 Linux ABI
接口兼容也更好,支持更多 Linux
应用,例如 docker
。
经过将近一年时间的开发与优化,微软团队终于发布了正式版 WSL2
,用户只需将操作系统升级到 2004
以后的 Windows 10
即可。
准备工作
安装 WSL
前置条件:
- 操作系统必须是
Windows 10 build 2004
以后的版本 C盘
剩余空间最好在64G
以上- 内存最好是
16G
以上,8g
内存运行k8s
集群后,就没有剩余内存
安装开始:
- 在桌面左下角
Windows
徽标上,右键选择Windows Powershell(管理员)(A)
,然后运行一下脚本
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
复制代码
如果这里遇到失败,多半是操作系统没有升到最新版本的
Windows 10
或者
- 安装 WSL 2 之前,必须启用“虚拟机平台”可选功能。
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
复制代码
- 重新启动计算机,以完成 WSL 安装并更新到 WSL 2。
- 将 WSL 2 设置为默认版本
安装新的 Linux 分发版时,请在 Powershell 中运行以下命令,以将 WSL 2 设置为默认版本:
wsl --set-default-version 2
复制代码
- 安装所选的 Linux 分发版
打开 Microsoft Store,并选择你偏好的 Linux 分发版。
单击以下链接会打开每个分发版的 Microsoft Store 页面:
- Ubuntu 16.04 LTS
- Ubuntu 18.04 LTS
- Ubuntu 20.04 LTS
- openSUSE Leap 15.1
- SUSE Linux Enterprise Server 12 SP5
- SUSE Linux Enterprise Server 15 SP1
- Kali Linux
- Debian GNU/Linux
- Alpine WSL
- 在分发版的页面中,选择“获取”。
- 设置新分发版
首次启动新安装的 Linux 分发版时,将打开一个控制台窗口,系统会要求你等待一分钟或两分钟,以便文件解压缩并存储到电脑上。 未来的所有启动时间应不到一秒。
然后,需要为新的 Linux 分发版创建用户帐户和密码。
将分发版版本设置为 WSL 1 或 WSL 2
可以打开 PowerShell 命令行并输入以下命令(仅在 Windows 内部版本 19041 或更高版本中可用),来检查分配给每个已安装的 Linux 分发版的 WSL 版本:wsl -l -v
wsl --list --verbose
复制代码
若要将分发版设置为受某一 WSL 版本支持,请运行:
wsl --set-version <distribution name> <versionNumber>
复制代码
请确保将 <distribution name>
替换为你的分发版的实际名称,并将 <versionNumber>
替换为数字“1”或“2”。 可以随时更改回 WSL 1
,方法是运行与上面相同的命令,但将“2”替换为“1”。
此外,如果要使 WSL 2
成为你的默认体系结构,可以通过此命令执行该操作:
wsl --set-default-version 2
复制代码
这会将安装的任何新分发版的版本设置为 WSL 2
。
- 排查安装问题
下面是相关的错误和建议的修复措施。 有关其他常见错误及其解决方法,请参阅 WSL 故障排除页。
- 安装失败并出现错误 0x80070003
- 适用于 Linux 的 Windows 子系统只能在系统驱动器(通常是 C: 驱动器)中运行。 请确保分发版存储在系统驱动器上:
- 打开“设置”->“存储”->“更多存储设置: 更改新内容的保存位置”
- WslRegisterDistribution 失败并出现错误
0x8007019e
- 未启用“适用于 Linux 的 Windows 子系统”可选组件:
- 打开“控制面板” -> “程序和功能” -> “打开或关闭 Windows 功能”-> 选中“适用于 Linux 的 Windows 子系统”,或使用本文开头所述的 PowerShell cmdlet。
- 安装失败,出现错误
0x80070003
或错误0x80370102
- 请确保在计算机的 BIOS 内已启用虚拟化。 有关如何执行此操作的说明因计算机而异,并且很可能在 CPU 相关选项下。
- 尝试升级时出错:
Invalid command line option: wsl --set-version Ubuntu 2
- 请确保已启用适用于 Linux 的 Windows 子系统,并且你使用的是 Windows 内部版本 19041 或更高版本。 若要启用 WSL,请在 Powershell 提示符下以具有管理员权限的身份运行此命令:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
。 可在此处找到完整的 WSL 安装说明。
- 请确保已启用适用于 Linux 的 Windows 子系统,并且你使用的是 Windows 内部版本 19041 或更高版本。 若要启用 WSL,请在 Powershell 提示符下以具有管理员权限的身份运行此命令:
- 由于虚拟磁盘系统的某个限制,无法完成所请求的操作。虚拟硬盘文件必须是解压缩的且未加密的,并且不能是稀疏的。
- 请检查WSL Github 主题 #4103,其中跟踪了此问题以提供更新的信息。
- 无法将词语“wsl”识别为 cmdlet、函数、脚本文件或可运行程序的名称。
- 请确保已安装“适用于 Linux 的 Windows 子系统”可选组件。 此外,如果你使用的是 Arm64 设备,并从 PowerShell 运行此命令,则会收到此错误。 请改为从 PowerShell Core 或从命令提示符运行 wsl.exe。
- 额外工作
-
禁用
swap
因为kubelet
不支持swap
内存,因此需要通过设置wslconfig
禁用swap
。在用户根目录
创建.wslconfig
文件,例如: 'C:\Users\openoker' ,添加以下内容:[wsl2] swap=0 # 关闭swap [network] generateResolvConf = false # 解决域名解析失败的问题 复制代码
然后在
powershell
或cmd
运行以下命令,关闭wsl
,再点击开始菜单Ubuntu
图标,即完成重启WSL
。wsl --shutdown 复制代码
-
设置
/etc/resolve.conf
因为每次WSL
启动会自动覆盖/etc/resolve.conf
文件,可能会导致域名解析失败的问题,必要时可以设置自定义的DNS服务器
,把以下内容追加到/etc/resolve.conf
文件末尾:(需要root
权限,记得加上sudo
)nameserver 8.8.8.8 nameserver 114.114.114.114 复制代码
-
替换
apt
源
Ubuntu
官方源在国内并不好用,因此我们需要替换源,提高软件安装和更新速度。编辑/etc/apt/sources.list
,为了安全可以先备份以下原文件# 备份source.list文件 sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak # 创建source.list文件 sudo vim /etc/apt/sources.list 复制代码
按
i
进入编辑模式,然后把以下内容复制粘贴到/etc/apt/sources.list
文件这是清华大学
Ubuntu 18.04 LTS
的镜像源,可根据用户安装的发行版自行替换# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # 预发布软件源,不建议启用 # deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable # deb-src [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable 复制代码
先按
esc
,再安装:
,输入wq
,回车就出退出并保存文件。然后更新本地缓存sudo apt update && sudo apt upgrade 复制代码
-
安装
daemonize
很多Linux
应用需要systemd
运行,比如说docker
和kubelet
。但是几乎所有WSL2
支持的镜像都不能运行systemd
,因此我们需要安装daemonize
。apt-get update && sudo apt-get install -yqq daemonize dbus-user-session fontconfig 复制代码
创建
/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 复制代码
接着,创建
/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 复制代码
运行
sudo visudo
命令,把以下内容复制粘贴到文件末尾:Defaults env_keep += WSLPATH Defaults env_keep += WSLENV Defaults env_keep += WSL_INTEROP Defaults env_keep += WSL_DISTRO_NAME Defaults env_keep += PRE_NAMESPACE_PATH %sudo ALL=(ALL) NOPASSWD: /usr/sbin/enter-systemd-namespace 复制代码
添加刚才的
shell
脚本到/etc/bash.bashrc
, 运行以下命令即可:(运行!不要复制粘贴!
)sudo sed -i 2a"# Start or enter a PID namespace in WSL2\nsource /usr/sbin/start-systemd-namespace\n" /etc/bash.bashrc 复制代码
最后,设置
Windows
环境变量,用管理员权限打开powershell
,运行以下命令:cmd.exe /C setx WSLENV BASH_ENV/u cmd.exe /C setx BASH_ENV /etc/bash.bashrc # 关闭WSL wsl --shutdown 复制代码
点击
开始菜单
上的Ubuntu
应用,重新打开WSL
,正常进入命令行界面说明操作成功。
若启动失败
在powershell
执行以下命令即可恢复wsl
到正常状态wsl -e sudo mv /etc/bash.bashrc /opt/bash.bashrc 复制代码
重新进入
wsl
后,打开/opt/bash.bashrc
,将上一步添加的两行内容如下删除:# Start or enter a PID namespace in WSL2 source /usr/sbin/start-systemd-namespace 复制代码
再把
/opt/bash.bashrc
放回/etc/
目录下,重走安装daemonize
流程
进入正题
安装 docker
移除旧版本docker
sudo apt-get remove docker docker-engine docker.io containerd runc
复制代码
安装docker
# 更新软件索引
sudo apt-get update
# 安装必备软件
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# 安装 apt-key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 添加 repository
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# 更新软件索引
sudo apt-get update
# 安装docker
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 检验docker是否安装成功
sudo docker run hello-world
复制代码
配置 docker
使用 root
权限创建 '/etc/docker/daemon.json' 文件,并填写以下内容:
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/"]
}
复制代码
重启 docker
sudo systemctl daemon-reload
sudo systemctl start docker
复制代码
安装 kubernetes
添加 apt-key.gpg
步骤可能需要梯=子,可以通过手动下载 apt-key.gpg,再用这个命令 cat /mnt/c/Users/openoker/Downloads/apt-key.gpg | sudo apt-key add -
,/mnt/c/
表示挂载 C盘
,后面加上 apt-key.gpg
所在目录
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
# 添加apt-key.gpg步骤可能需要梯=子
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
复制代码
启动 k8s集群
执行 kubeadm init
命令之前,先下载必要的镜像,运行以下命令:
kubeadm config images list
复制代码
得到以下结果:(冒号后面是镜像的版本,会根据kubeadm版本而变化)
k8s.gcr.io/kube-apiserver:v1.18.5
k8s.gcr.io/kube-controller-manager:v1.18.5
k8s.gcr.io/kube-scheduler:v1.18.5
k8s.gcr.io/kube-proxy:v1.18.5
k8s.gcr.io/pause:3.2
k8s.gcr.io/etcd:3.4.3-0
k8s.gcr.io/coredns:1.6.7
复制代码
k8s.gcr.io
镜像在国内多半是拉取失败的,所以要把 k8s.gcr.io
前缀换成 gotok8s
,再加上 'docker pull':
docker pull gotok8s/kube-apiserver:v1.18.5
docker pull gotok8s/kube-controller-manager:v1.18.5
docker pull gotok8s/kube-scheduler:v1.18.5
docker pull gotok8s/kube-proxy:v1.18.5
docker pull gotok8s/pause:3.2
docker pull gotok8s/etcd:3.4.3-0
docker pull gotok8s/coredns:1.6.7
复制代码
逐行执行以上命令,待全部完成后,再通过 docker tag
命令,把镜像标签改成 k8s.gcr.io
:
docker tag gotok8s/kube-apiserver:v1.18.5 k8s.gcr.io/kube-apiserver:v1.18.5
docker tag gotok8s/kube-controller-manager:v1.18.5 k8s.gcr.io/kube-controller-manager:v1.18.5
docker tag gotok8s/kube-scheduler:v1.18.5 k8s.gcr.io/kube-scheduler:v1.18.5
docker tag gotok8s/kube-proxy:v1.18.5 k8s.gcr.io/kube-proxy:v1.18.5
docker tag gotok8s/pause:3.2 k8s.gcr.io/pause:3.2
docker tag gotok8s/etcd:3.4.3-0 k8s.gcr.io/etcd:3.4.3-0
docker tag gotok8s/coredns:1.6.7 k8s.gcr.io/coredns:1.6.7
复制代码
再执行以下命令,等待数分钟后,即可搭建一个标准版 k8s
集群
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
复制代码
出现以下命令时,说明创建 k8s
集群成功,再按照提示执行以下命令:(如果创建集群失败,通过运行 sudo kubeadm reset
,然后输入 Y
即可清除 kubeadm init
命令的操作)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
复制代码
最后一步,通过 kubectl apply
命令,安装 CNI
插件,这里以 calico 为例:
kubectl apply -f https://docs.projectcalico.org/v3.14/manifests/calico.yaml
复制代码
通过 kubectl get node
命令获取 node
节点的状态是否 ready
:
NAME STATUS ROLES AGE VERSION
desktop-v6hkp49 Ready master 2m24s v1.18.5
复制代码
压轴环节
部署 spring cloud
集群
这里 spring cloud
示例源码是本人18年学习 spring cloud
的demo,相关代码已经上传到 Github
下载源码构建
git clone https://www.aiqianji.com/openoker/datacenter.git
复制代码
使用其他编程语言的项目也是可以的,只需要加上
prometheus
对应的sdk
以 Spring Boot
为例,pom.xml
文件添加 ``
<project
<properties>
...
<!-- 使用tomcat作为servlet容器,请确保版本在8.5.32 以上 -->
<tomcat.version>8.5.32</tomcat.version>
...
</properties>>
...
<dependencies>
...
<!-- Micrometer Prometheus registry -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
...
</dependencies>
</project>
复制代码
修改配置文件 application.yml
,增加以下内容:
management:
endpoints:
web:
exposure:
include: "*"
health:
show-details: always
metrics:
tags:
application: ${spring.application.name}
复制代码
建议把 eureka 以及其他微服务组件的镜像写到同一个 Pod 中运行,各组件直接就可以通过 localhost 直接进行通信
使用 maven
打包成jar
maven
环境的搭建不细说,以下命令可以在 Windows
上运行
# 切换到 datacenter 所在目录
cd datacenter
# 构建并打包eureka
cd eureka
mvn package -Dmaven.test.skip=true
# 构建并打包school
cd school
mvn package -Dmaven.test.skip=true
# 构建并打包teacher
cd teacher
mvn package -Dmaven.test.skip=true
# 构建并打包student
cd student
mvn package -Dmaven.test.skip=true
复制代码
使用 docker
打包镜像
这里使用 WSL2
里面安装的 docker
打包镜像。假设项目所在路径是 c:/Users/openoker/Documents/github
。
eureka
、school
、teacher
和 student
目录下都写好 Dockerfile
,以 eureka
为例:
``