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

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

2019年Windows Build大会上,微软发布 WSL2,意味着开发者们终于可以在Windows上开发和运行原汁原味 Linux 应用。

本篇文章将教会大家如何在 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

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

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

首次启动新安装的 Linux 分发版时,将打开一个控制台窗口,系统会要求你等待一分钟或两分钟,以便文件解压缩并存储到电脑上。 未来的所有启动时间应不到一秒。

然后,需要为新的 Linux 分发版创建用户帐户和密码

ubuntu-install

将分发版版本设置为 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\huang' ,添加以下内容:

    [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 脚本到 .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 到正常状态

```powsershell
wsl -e sudo mv /etc/bash.bashrc /opt/bash.bashrc
```

重新进入 `wsl` 后,打开 `/opt/bash.bashrc` ,将上一步添加的两行内容如下删除:

```sh
# 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/huang/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://github.com/zaoying/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/huang/Documents/github

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

FROM openjdk:8u242-jre-slim
COPY target/eureka-0.0.1-SNAPSHOT.jar ./app.jar
CMD java -jar app.jar

其他微服务模块的 Dockerfile 也类似,把 eureka-0.0.1-SNAPSHOT.jar 替换成 xxx-0.0.1-SNAPSHOT.jar 即可,xxx 就是微服务模块的名称。

Dockerfile 都编写完成后,运行以下命令打包 Docker 镜像

# 打包eureka镜像
docker build -t datacenter-eureka:latest /mnt/c/Users/huang/Documents/github/datacenter/eureka

# 打包school镜像
docker build -t datacenter-school:latest /mnt/c/Users/huang/Documents/github/datacenter/school

# 打包teacher镜像
docker build -t datacenter-teacher:latest /mnt/c/Users/huang/Documents/github/datacenter/teacher

# 打包student镜像
docker build -t datacenter-student:latest /mnt/c/Users/huang/Documents/github/datacenter/student

部署并初始化 mysql

为了方便管理,先创建一个新的 namespace,名字就叫 spring-cloud

kubectl create namespace spring-cloud

mysql 有官方镜像,直接拿过来使用即可,不用重新打包。另外因为 mysql 是个有状态应用,为了避免Pod重启导致数据丢失,所以在运行之前,需要先分配一个 Persistent VolumePersistent Volume Claim

kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv-volume
  namespace: spring-cloud
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/opt/data/mysql"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  namespace: spring-cloud
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

可以根据实际情况,把 /opt/data/mysql 换成其他目录,PVPVC 的大小也可以调整为其他大小,就目前的demo而已,2Gi 容量已经足够了。

将上述内容保存到 pvc.yml 文件,然后执行 kubectl apply -f 命令创建:

kubectl apply -f pvc.yml

接下来,创建 mysql.yml 文件,再将以下内容添加到文件内:

apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: spring-cloud
spec:
  type: NodePort
  ports:
  - name: mysql
    protocol: TCP
    nodePort: 30306
    port: 3306
    targetPort: 3306
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: spring-cloud
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: bocloud@2019
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

还是通过 kubectl apply -f 命令创建 mysqlservicedeployment, 然后同一个 namespacespring-cloud 命令空间的 Pod 就可以通过 mysql:3306 地址访问 mysql

kubectl apply -f mysql.yml

通过 kubectl get pod -n spring-cloud 命令,查看 pod 是否 running

NAME                              READY   STATUS    RESTARTS   AGE
mysql-85bcfd68f6-qxmcj            0/1     Pending   0          4m59s

使用 kubectl descibe pod mysql-85bcfd68f6-qxmcj -n spring-cloud 查看,发现以下原因:

Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  14s (x4 over 104s)  default-scheduler  0/1 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate.

说明 pod 不能在控制面 control panel 运行,可以通过以下命令解决:

kubectl taint nodes --all node-role.kubernetes.io/master-

编写 datacenter.yml 并部署

创建 datacenter.yml 文件,并把以下内容添加到文件内:

apiVersion: v1
kind: Service
metadata:
  name: datacenter
  namespace: spring-cloud
spec:
  ports:
    - name: eureka
      protocol: TCP
      port: 8761
      targetPort: 8761
      nodePort: 30761
    - name: school
      protocol: TCP
      port: 8084
      targetPort: 8084
      nodePort: 30084
    - name: teacher
      protocol: TCP
      port: 8082
      targetPort: 8082
      nodePort: 30082
    - name: student
      protocol: TCP
      port: 8083
      targetPort: 8083
      nodePort: 30083
  selector:
    app: datacenter
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: datacenter-dep
  namespace: spring-cloud
  labels:
    app: datacenter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: datacenter
  template:
    metadata:
      labels:
        app: datacenter
    spec:
      containers:
      - name: eureka
        image: datacenter-eureka:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8761
      - name: school
        image: datacenter-school:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019
        ports:
        - containerPort: 8084
      - name: teacher
        image: datacenter-teacher:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019
        ports:
        - containerPort: 8082
      - name: student
        image: datacenter-student:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019
        ports:
        - containerPort: 8083

运行以下命令,即可创建 datacenterservicedeployment,同一个 namespacePod 可以通过 datacenter:8761datacenter:8084datacenter:8082datacenter:8083 来分别访问 eurekaschoolteacherstudent 服务。

kubectl apply -f pvc.yml

部署 prometheusgrafana

为了方便管理,先创建 prometheus-k8snamespace

kubectl create namespace prometheus-k8s

然后,再创建一个 configmap 来保存 prometheus 的配置:

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
    - targets: ['localhost:9090']
  - job_name: 'school'
    metrics_path: "/actuator/prometheus"
    static_configs:
    - targets: ['datacenter.spring-cloud:8084']
  - job_name: 'teacher'
    metrics_path: "/actuator/prometheus"
    static_configs:
    - targets: ['datacenter.spring-cloud:8082']
  - job_name: 'student'
    metrics_path: "/actuator/prometheus"
    static_configs:
    - targets: ['datacenter.spring-cloud:8083']

然后把文件保存为 prometheus.yml,再运行以下命令:

kubectl create configmap prometheus-config -n prometheus-k8s --from-file prometheus.yml

接着,创建 prometheusservicedeployment

apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: prometheus-k8s
spec:
  type: NodePort
  ports:
  - name: http
    protocol: TCP
    nodePort: 30909
    port: 9090
    targetPort: 9090
  selector:
    app: prometheus
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: prometheus-k8s
spec:
  selector:
    matchLabels:
      app: prometheus
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - image: prom/prometheus
        name: prometheus
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9090
          name: http
        volumeMounts:
        - name: prometheus-config
          mountPath: /etc/prometheus/
      volumes:
      - name: prometheus-config
        configMap:
          name: prometheus-config
          items:
           - key: prometheus.yml
             path: prometheus.yml

把上述内容保存为 serviceAndDeployment.yml 文件,再运行以下命令:

kubectl apply -f serviceAndDeployment.yml

接着,创建 grafanaservicedeployment

apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: prometheus-k8s
spec:
  type: NodePort
  ports:
  - name: http
    protocol: TCP
    nodePort: 30009
    port: 3000
    targetPort: 3000
  selector:
    app: grafana
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: prometheus-k8s
spec:
  selector:
    matchLabels:
      app: grafana
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - image: grafana/grafana
        name: grafana
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
          name: http

把上述内容保存为 serviceAndDeployment-grafana.yml 文件,再运行以下命令:

kubectl apply -f serviceAndDeployment-grafana.yml

创建 ingress

创建 ingress-nginx-controller,这里用到 hostNetwork,所以会占用宿主机的 80443 端口

kubectl apply -f https://raw.githubusercontent.com/zaoying/k8s-learning/master/nginx/mandatory.yaml

创建 ingress-nginx 服务

kind: Service
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  externalTrafficPolicy: Local
  type: NodePort
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: http
    - name: https
      port: 443
      protocol: TCP
      targetPort: https

把以上内容保存为 service-node-port.yml,再运行 kubectl apply -f service-node-port.yml

接着为 grafana 创建 tls secret,信息可以随便填

openssl genrsa -aes128 -out server.key 2048

openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 3650 -out server.crt

kubectl create secret tls prometheus-secret-tls --cert=server.crt --key=server.key -n prometheus-k8s

把以下内容保存到 ingress.yml,再运行 kubectl apply -f ingress.yml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: grafana
  namespace: prometheus-k8s
  annotations:
    nginx.ingress.kubernetes.io/ingress.class: nginx
spec:
  tls:
  - hosts:
    - grafana.local
    secretName: prometheus-secret-tls
  rules:
  - host: grafana.local
    http:
      paths:
      - path: /
        backend:
          serviceName: grafana
          servicePort: 3000

127.0.0.1 grafana.local 追加到 C:\Windows\System32\drivers\etc\hosts 文件末。

配置 grafana

  1. 在浏览器打开 https://grafana.local 就可以看到 grafana 网页,因为是自签名 tls 证书,所以浏览器会警告,忽略警告。
grafana
  1. 输入 admin/admin 登录,然后修改密码
datasource
  1. 点击 Add your first data source,选择 prometheus ,填写 http://prometheus:9090 ,然后点击 Save & Test 保存。
import-dashboard
  1. 点击 +,选择 import,输入 4701,点击 Load
import
  1. prometheus 列选择 prometheus, 然后点击 import
jvm-micrometer
  1. 重复步骤 4-5,把 4701 换成 6756
spring-boot-statistic

至此,本教程结束!

参考文章:

安装适用于 Linux 的 Windows 子系统

Running Snaps on WSL2 (Insiders only for now)

Install Docker Engine on Ubuntu

Creating a single control-plane cluster with kubeadm

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345