使用 kube-prometheus 部署完整的 prometheus 监控

kube-prometheus 是一个开源项目,其目的是提供基于 prometheus-operator 的,容易部署到 Kubernetes 集群的监控方案。

1. 部署说明

操作系统及已部署程序信息

程序 版本
OS CentOS-Stream-9-20241007.0
Linuex Kernel 5.14.0-514.el9.x86_64
kubernetes v1.32.5.x86_64
docker-ce 24.0.9-1.el9.x86_64
containerd 1.7.22-3.1.el9.x86_64
cri-docker 0.3.20.el9.x86_64
flannel v0.24.2

主机信息

节点 ip 容器运行时
master1 192.167.16.116 docker
node1 192.167.16.117 docker
node2 192.167.16.118 containerd

注意:
kube-prometheus 的版本选择可以参考其兼容性说明,尽量选择与 kubernetes 相兼容的版本。兼容性表明当时在对应的kubenetes 版本上进行了测试。

部署情况说明:

  1. 本次部署 kubernetes 版本为 1.32.5,选择 kube-prometheus v0.16;
  2. 将 prometheus,grafana 和 alertmanager 通过 nodeport 暴漏;
  3. 因 prometheus 被扫出过未授权访问的漏洞,所以开启 prometheus basic-auth 认证,开启认证涉及到 prometheus 自身,grafana 的数据源配置调整;
  4. 开启 prometheus 多副本部署,加载 thanos sidecar 组件;
  5. etcd 是由 kubeadm 部署的静态 Pod,本次增加了静态 ectd 的监控(prometheusRule 和 serviceMonitor),在 grafana 中也增加了 etcd 的图表。
  6. kubernetes 是由 kubeadm 部署的,kube-controllerManager 和 kube-scheduler 都默认绑定 127.0.0.1,如果不处理对应的 target 就是是异常的,该问题需要调整两个的服务绑定 ip;

注意:

  1. etcd 的地址和证书路径需要按需修改为实际的地址
  2. 此处的密码都默认为 1234567,如需修改,已在每处密码信息都标注了对应的密码生成方案。

2. 参考链接

github - kube-prometheus
jsonnet - jsonnet
夸克网盘 - 所需镜像

3. 基础依赖安装

# 安装 git
yum install git

# 安装 gog
yum install go

# 设置 go 的源为国内源
go env -w GOPROXY=https://goproxy.cn,direct

# 修改环境变量,增加 gopath
export PATH=$PATH:/root/go/bin

# 安装 gojsontoyaml
go install github.com/brancz/gojsontoyaml@latest

# 安装 jsonnet
go install github.com/google/go-jsonnet/cmd/jsonnet@latest

# 安装 jb(jsonnet-bundler) 这个是 jsonnet 的包管理器
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest

4. 下载 kube-prometheus 的 jsonnet 包

先根据 kubernetes 版本确认 kube-prometheus 的版本。本例以 kubernetes v1.32.5 为例,对应 kube-prometheus release-0.16 版本。

# 创建目录
mkdir -p /root/kube-prometheus/release-0.16
cd /root/kube-prometheus/release-0.16

# 初始化
jb init

# 下载远程包
jb install github.com/prometheus-operator/kube-prometheus/jsonnet/kube-prometheus@release-0.16

5. 创建编译文件及编译脚本

创建编译文件:

cat << 'EOF' | tee /root/kube-prometheus/release-0.16/release-0.16.jsonnet
local kp =
  (import 'kube-prometheus/main.libsonnet') +
  // Uncomment the following imports to enable its patches
  (import 'kube-prometheus/addons/anti-affinity.libsonnet') +
  // (import 'kube-prometheus/addons/managed-cluster.libsonnet') +
  (import 'kube-prometheus/addons/node-ports.libsonnet') +
  (import 'kube-prometheus/addons/static-etcd.libsonnet') +
  // (import 'kube-prometheus/addons/custom-metrics.libsonnet') +
  // (import 'kube-prometheus/addons/external-metrics.libsonnet') +
  // (import 'kube-prometheus/addons/pyrra.libsonnet') +
  (import 'kube-prometheus/platforms/kubeadm.libsonnet') +
  {
    // 进行深度合并,同名字段如果都是对象,会继续合并而不是覆盖
    values+:: {
      // 进行浅合并,同名字段会覆盖原值
      common+: {
        namespace: 'monitoring',
      },
      
      prometheus+: {
        // 配置 thanos sidecar
        thanos: {
          version: 'v0.38.0',
          image: 'quay.io/thanos/thanos:v0.38.0',
        },
        // 此处需要增加下 prometheus 的标签,否则无法关联到 service
        commonLabels+:: {
          app: 'prometheus',
        }
      },

      // 启用静态 etcd 时,增加 etcd 配置
      etcd+: {
        ips: ['192.167.16.108'],
        clientCA: importstr '/etc/kubernetes/pki/etcd/ca.crt',
        clientCert: importstr '/etc/kubernetes/pki/etcd/server.crt',
        clientKey: importstr '/etc/kubernetes/pki/etcd/server.key',
        serverName: 'etcd.kube-system.svc.cluster.local',
        insecureSkipVerify: true,
      },

      // grafana 配置
      grafana+: {
        // 开启数据源修改,开启后可以在 Grafana UI 中修改数据源
        // 增加 Prometheus 数据源 basic auth 认证
        datasources: [
          {
            name: 'prometheus',
            type: 'prometheus',
            access: 'proxy',
            orgId: 1,
            url: 'http://prometheus-k8s.monitoring.svc:9090',
            version: 1,
            editable: true,
            basicAuth: true,
            basicAuthUser: 'admin',
            secureJsonData: {
              basicAuthPassword: '1234567',
            }
          }
        ],
        // 增加 Grafana 认证
        config: {
          // sections 是 Grafana 配置文件 ini 中的 sections
          sections: {
            data_formats: {
              default_timezone: 'CST',
            },
            security: {
              admin_user: 'admin',
              admin_password: '1234567',
            },
          }
        },
        // 启用静态 etcd 时,增加 etd 的 Grafana 仪表盘
        dashboards+:: kp.grafanaDashboards,
      },
    },
    // prometheus 配置
    prometheus+:: {
      prometheus+: {
        spec+: {
          // 数据保存时常
          retention: '30d',
          // 数据存储,在阿里云ssd云盘中
          // storage: {
          //   volumeClaimTemplate: {
          //     apiVersion: 'v1',
          //     kind: 'PersistentVolumeClaim',
          //     spec: {
          //       accessModes: ['ReadWriteOnce'],
          //       resources: {
          //         requests: {
          //           storage: '100Gi',
          //         },
          //       },
          //       storageClassName: 'alicloud-disk-ssd',
          //     },
          //   },
          // },

          // 资源限制
          resources: {
            limits: {
              cpu: '2',
              memory: '2Gi',
            },
            requests: {
              cpu: '1',
              memory: '400Mi',
            },
          },
          // 增加 prometheus basic auth 认证
          containers+: [
            // prometheus 增加 basic auth 的认证配置
            {
              name: 'prometheus',
              args+: [
                '--web.console.templates=/etc/prometheus/consoles',
                '--web.console.libraries=/etc/prometheus/console_libraries',
                '--config.file=/etc/prometheus/config_out/prometheus.env.yaml',
                '--storage.tsdb.path=/prometheus',
                '--storage.tsdb.retention.time=30d',
                '--web.enable-lifecycle',
                '--storage.tsdb.no-lockfile',
                '--web.route-prefix=/',
                '--web.config.file=/etc/prometheus/secrets/basic-auth/web-config.yaml',
              ],
              // 增加 basic auth 认证后,探针需要修改
              readinessProbe:{
                failureThreshold: 3,
                httpGet: {
                  path: '/-/ready',
                  port: 'web',
                  scheme: 'HTTP',
                  httpHeaders: [{
                    name: 'Authorization',
                    // echo -n 'admin:1234567' | base64
                    value: 'Basic YWRtaW46MTIzNDU2Nw==',
                  }],
                },
                periodSeconds: 5,
                successThreshold: 1,
                timeoutSeconds: 3,
              },
              startupProbe: {
                failureThreshold: 60,
                httpGet: {
                  path: '/-/ready',
                  port: 'web',
                  scheme: 'HTTP',
                  httpHeaders: [{
                    name: 'Authorization',
                    // echo -n 'admin:1234567' | base64
                    value: 'Basic YWRtaW46MTIzNDU2Nw==',
                  }],
                },
                periodSeconds: 15,
                successThreshold: 1,
                timeoutSeconds: 3,
              },
              livenessProbe: {
                failureThreshold: 6,
                httpGet: {
                  path: '/-/healthy',
                  port: 'web',
                  scheme: 'HTTP',
                  httpHeaders: [{
                    name: 'Authorization',
                    // echo -n 'admin:1234567' | base64
                    value: 'Basic YWRtaW46MTIzNDU2Nw==',
                  }],
                },
                periodSeconds: 5,
                successThreshold: 1,
                timeoutSeconds: 3,
              },
            }, 
            // config-reloader 访问 prometheus 时增加 basic auth 信息
            {
              args: [
                '--listen-address=:8080',
                '--reload-url=http://admin:1234567@localhost:9090/-/reload',
                '--config-file=/etc/prometheus/config/prometheus.yaml.gz',
                '--config-envsubst-file=/etc/prometheus/config_out/prometheus.env.yaml',
                '--watched-dir=/etc/prometheus/rules/prometheus-k8s-rulefiles-0'
              ],
              name: 'config-reloader'
            },
            // thanos-sidecar 访问 prometheus 时增加 basic auth 信息
            {
              args: [
                'sidecar',
                '--prometheus.url=http://admin:1234567@localhost:9090/',
                '--grpc-address=[$(POD_IP)]:10901',
                '--http-address=[$(POD_IP)]:10902',
              ],
              env: [
                {
                  name: 'POD_IP',
                  valueFrom:
                  {
                    fieldRef: 
                    {
                      apiVersion: 'v1',
                      fieldPath: 'status.podIP',
                    },
                  },
                },
              ],
              image: 'quay.io/thanos/thanos:v0.38.0',
              imagePullPolicy: 'IfNotPresent',
              name: 'thanos-sidecar',
              ports: [
                {
                  containerPort: 10902,
                  name: 'http',
                  protocol: 'TCP',
                },
                { 
                  containerPort: 10901,
                  name: 'grpc',
                  protocol: 'TCP',
                }
              ],
              terminationMessagePath: '/dev/termination-log',
              terminationMessagePolicy: 'FallbackToLogsOnError',
            },
          ],
          // 将 Baisc Auth 的配置文件挂载到容器中
          secrets+: [
            "basic-auth",
          ]
        }
      },
      // 因为 Prometheus 开启了 basic-auth 的认证,要修改抓取规则,从 secret 中读取认证信息
      serviceMonitor+: {
        spec+: {
          endpoints: [{
            port: 'web',
            interval: '30s',
            basicAuth: {
              username: {
                name: 'basic-auth',
                key: 'username',
              },
              password: {
                name: 'basic-auth',
                key: 'password',
              }
            },
          }]
        }
      },
    },
  };

// 生成 prometheus basic-auth 认证相关的 Secret
{
  'prometheus-secret-basicAuth': {
    apiVersion: 'v1',
    kind: 'Secret',
    metadata: {
      name: 'basic-auth',
      namespace: 'monitoring',
    },
    data: {
      // echo -n '1234567' | base64
      password: 'MTIzNDU2Nw==', 
      // echo -n 'admin' | base64
      username: 'YWRtaW4=',
      //# 生成 bcrypt 加密的密码
      //htpasswd -nBC 10 "" | tr -d ':\n'
      //# 创建文件 web-config.yaml
      //basic_auth_users:
      //  admin: 生成的密钥
      //# 生成 web-config.yaml secret 内容
      //cat web-config.yaml |base64 -w 0
      'web-config.yaml': 'YmFzaWNfYXV0aF91c2VyczoKICBhZG1pbjogJDJiJDEyJEprTmkuVWtYejdJRVBicFE0cmt1Nk9mVzlKRTlRZzNybHlhVHRzL0E2V2JsSjh3MHRUdmxtCg==',
    },
    type: 'Opaque'
  }
}+

// 启用静态 etcd 时,增加 etcd PrometheusRule 配置
{
  'kube-etcd-prometheusRule': {
    apiVersion: 'monitoring.coreos.com/v1',
    kind: 'PrometheusRule',
    metadata: {
      name: 'kube-etcd-rules',
      namespace: kp.values.common.namespace,
      labels: kp.values.common.ruleLabels,
    },
    spec: kp.prometheusAlerts,
  },
}+

{ 'setup/0namespace-namespace': kp.kubePrometheus.namespace } +
{
  ['setup/prometheus-operator-' + name]: kp.prometheusOperator[name]
  for name in std.filter((function(name) name != 'serviceMonitor' && name != 'prometheusRule'), std.objectFields(kp.prometheusOperator))
} +
// { 'setup/pyrra-slo-CustomResourceDefinition': kp.pyrra.crd } +
// serviceMonitor and prometheusRule are separated so that they can be created after the CRDs are ready
{ 'prometheus-operator-serviceMonitor': kp.prometheusOperator.serviceMonitor } +
{ 'prometheus-operator-prometheusRule': kp.prometheusOperator.prometheusRule } +
{ 'kube-prometheus-prometheusRule': kp.kubePrometheus.prometheusRule } +
{ ['alertmanager-' + name]: kp.alertmanager[name] for name in std.objectFields(kp.alertmanager) } +
{ ['blackbox-exporter-' + name]: kp.blackboxExporter[name] for name in std.objectFields(kp.blackboxExporter) } +
{ ['grafana-' + name]: kp.grafana[name] for name in std.objectFields(kp.grafana) } +
// { ['pyrra-' + name]: kp.pyrra[name] for name in std.objectFields(kp.pyrra) if name != 'crd' } +
{ ['kube-state-metrics-' + name]: kp.kubeStateMetrics[name] for name in std.objectFields(kp.kubeStateMetrics) } +
{ ['kubernetes-' + name]: kp.kubernetesControlPlane[name] for name in std.objectFields(kp.kubernetesControlPlane) } +
{ ['node-exporter-' + name]: kp.nodeExporter[name] for name in std.objectFields(kp.nodeExporter) } +
{ ['prometheus-' + name]: kp.prometheus[name] for name in std.objectFields(kp.prometheus) } +
{ ['prometheus-adapter-' + name]: kp.prometheusAdapter[name] for name in std.objectFields(kp.prometheusAdapter) }

EOF

创建编译脚本:

cat << 'EOF' | tee /root/kube-prometheus/release-0.16/build.sh
#!/usr/bin/env bash

# This script uses arg $1 (name of *.jsonnet file to use) to generate the manifests/*.yaml files.

set -e
set -x
# only exit with zero if all commands of the pipeline exit successfully
set -o pipefail

# Make sure to use project tooling
PATH="$(pwd)/tmp/bin:${PATH}"

# Make sure to start with a clean 'manifests' dir
rm -rf manifests
mkdir -p manifests/setup

# Calling gojsontoyaml is optional, but we would like to generate yaml, not json
jsonnet -J vendor -m manifests "${1-release-0.16.jsonnet}" | xargs -I{} sh -c 'cat {} | gojsontoyaml > {}.yaml' -- {}

# Make sure to remove json files
find manifests -type f ! -name '*.yaml' -delete
rm -f kustomization
EOF

6. 编译、部署

编译,生成 kubernetes yaml 清单

[root@master release-0.16]# sh build.sh 

部署 kube-prometheus

# 如果无法拉取镜像,可在所有节点上先导入准备好的镜像
tar -zxf kube-prometheus-release-0.16-images.tar.gz
cd release-0.16

# docker 导入
for i in $(ls); do docker load -i ${i}; done
# containerd 导入
for i in $(ls); do ctr -n k8s.io i import ${i}; done

# 部署
kubectl create -f manifests/setup
kubectl apply -f manifests/

访问地址:
Prometheus(admin/1234567):http://192.167.16.116:30900
Grafana(admin/1234567):http://192.167.16.116:30902
AlertManager:http://192.167.16.116:30903

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐