在WSL2上部署标准k8s集群并使用Prometheus监控spring cloud服务

0 / 945

本篇文章将教会大家如何在 WSL2 部署一个标准版的 k8s 集群以及使用 Prometheusgrafana 监控 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 集群后,就没有剩余内存

安装开始:

  1. 在桌面左下角Windows 徽标上,右键选择Windows Powershell(管理员)(A),然后运行一下脚本
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
复制代码

如果这里遇到失败,多半是操作系统没有升到最新版本的 Windows 10 或者

  1. 安装 WSL 2 之前,必须启用“虚拟机平台”可选功能。
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
复制代码
  1. 重新启动计算机,以完成 WSL 安装并更新到 WSL 2。
  2. 将 WSL 2 设置为默认版本

安装新的 Linux 分发版时,请在 Powershell 中运行以下命令,以将 WSL 2 设置为默认版本:

wsl --set-default-version 2
复制代码
  1. 安装所选的 Linux 分发版

打开 Microsoft Store,并选择你偏好的 Linux 分发版。

单击以下链接会打开每个分发版的 Microsoft Store 页面:

  1. 在分发版的页面中,选择“获取”。
  2. 设置新分发版

首次启动新安装的 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

  1. 排查安装问题

下面是相关的错误和建议的修复措施。 有关其他常见错误及其解决方法,请参阅 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 安装说明。
  • 由于虚拟磁盘系统的某个限制,无法完成所请求的操作。虚拟硬盘文件必须是解压缩的且未加密的,并且不能是稀疏的。
    • 请检查WSL Github 主题 #4103,其中跟踪了此问题以提供更新的信息。
  • 无法将词语“wsl”识别为 cmdlet、函数、脚本文件或可运行程序的名称。
    • 请确保已安装“适用于 Linux 的 Windows 子系统”可选组件。 此外,如果你使用的是 Arm64 设备,并从 PowerShell 运行此命令,则会收到此错误。 请改为从 PowerShell Core 或从命令提示符运行 wsl.exe。
  1. 额外工作
  • 禁用 swap
    因为 kubelet 不支持 swap 内存,因此需要通过设置 wslconfig 禁用 swap 。在 用户根目录 创建 .wslconfig 文件,例如: 'C:\Users\openoker' ,添加以下内容:

    [wsl2]
    swap=0 # 关闭swap
    
    [network]
    generateResolvConf = false # 解决域名解析失败的问题
    复制代码
    

    然后在 powershellcmd 运行以下命令,关闭 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 运行,比如说 dockerkubelet。但是几乎所有 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

eurekaschoolteacherstudent 目录下都写好 Dockerfile,以 eureka 为例:

``