k8s 中 configMap 的日常使用

在和 k8s 的日常玩耍中,经常需要变更某些服务容器的配置文件的啦,Kubernetes 就提供了非常灵活的模块化方式,即 configMap

介绍

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。

ConfigMap 将您的环境配置信息和容器镜像解耦,便于应用配置的修改。

当然 ConfigMap 不保证数据的隐私性,如果有重要数据请存放在 Secret 中

创建 ConfigMap

使用 kubectl create configmap 命令

来基于目录、文件、或者字面值来创建 ConfigMap:

1
kubectl create configmap <映射名称> <数据源>

其中,<映射名称> 是为 ConfigMap 指定的名称,<数据源> 是要从中提取数据的目录、 文件或者字面值。 ConfigMap 对象的名称必须是合法的 DNS 子域名

在你基于文件来创建 ConfigMap 时,<数据源> 中的键名默认取自文件的基本名, 而对应的值则默认为文件的内容

示例:创建 synthetic-monitoring(grafana 的一个插件)的配置文件的 configMap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#先创建这个配置文件
cat >> synthetic-monitoring-app-grafana.yaml << EOF
apiVersion: 1
apps:
- type: grafana-synthetic-monitoring-app
name: grafana-synthetic-monitoring-app
disabled: false
jsonData:
apiHost: https://synthetic-monitoring-api.grafana.net/
stackId: xxxxxx
logs:
grafanaName: grafanacloud-sunnyrian-logs
hostedId: xxxxxx
metrics:
grafanaName: grafanacloud-sunnyrian-prom
hostedId: xxxxxx
secureJsonData:
publisherToken: <your Token>

datasources:
- name: grafanacloud-sunnyrian-logs
type: loki
access: proxy
url: https://logs-prod-us-central1.grafana.net
basicAuth: true
basicAuthUser: xxxxxx
jsonData:
maxLines: 1000
secureJsonData:
basicAuthPassword: <your Token>
version: 1

- name: grafanacloud-sunnyrian-prom
type: prometheus
access: proxy
url: https://prometheus-us-central1.grafana.net/api/prom
basicAuth: true
basicAuthUser: xxxxxx
jsonData:
timeInterval: 1s
secureJsonData:
basicAuthPassword: <your Token>
version: 1
EOF

然后创建 configMap

1
kubectl create configmap synthetic-configmap --from-file=./synthetic-monitoring-app-grafana.yaml -n kube-system

(optional) 也可以同时将多个文件生成一个 configMap: –from-env-file=file1 –from-env-file=file2

其中 synthetic-configmap 为该 configMap 的名字,然后选择从文件生成,生成到 kube-system 的命名空间

这里指定命名空间很重要

基于现有 configMap 生成 yaml

下面的指令可以把刚刚生成的 configMap 打印成yaml格式

1
kubectl get configmap synthetic-monitoring-app-grafana -o yaml -n kube-system

然后再导成yaml就可以啦

直接写 configMap.yaml

格式参照

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-12-27T18:36:28Z
name: game-config-env-file
namespace: default
resourceVersion: "809965"
selfLink: /api/v1/namespaces/default/configmaps/game-config-env-file
uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
data:
allowed: '"true"'
enemies: aliens
lives: "3"

应用 configMap

1
kubectl apply -f configMap.yaml

使用存储在 ConfigMap 中的数据填充卷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# 提供包含要添加到容器中的文件的 ConfigMap 的名称
name: special-config
#将该键放在 /etc/config/keys 下
items:
- key: SPECIAL_LEVEL
path: keys
restartPolicy: Never

apply 之后,启动容器,就可以在相应目录看到配置文件啦

Alertmanager 部署指南

介绍一下,Altermanager 一般在 Grafana 中是外置告警器,在 Grafana 中配置好它之后,触发了 Alerting 规则之后,就会让 Altermanager 根据它的配置,用某种方式向接收方发送告警信息

本文示例为配置 Altermanager k8s 服务通过 SMTP 发送告警

准备配置文件

  1. configMap

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    cat >> Altermanager-configMap.yaml << EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: alertmanager-config
    namespace: kube-system
    labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: EnsureExists
    data:
    alertmanager.yml: |
    global:
    resolve_timeout: 5m
    smtp_smarthost: 'smtp.163.com:25'
    smtp_from: 'Sunnyrain233@163.com'
    smtp_auth_username: 'Sunnyrain233@163.com'
    smtp_auth_password: 'xxxxxx'
    smtp_require_tls: true

    receivers:
    - name: default-receiver
    email_configs:
    - to: "Sunnyrain233@163.com"

    route:
    group_interval: 1m
    group_wait: 10s
    receiver: default-receiver
    repeat_interval: 1m

    EOF

    详细配置文档

  2. deployment

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    cat >> Altermanager-deployment.yaml << EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: alertmanager
    namespace: kube-system
    labels:
    k8s-app: alertmanager
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    version: latest
    spec:
    replicas: 1
    selector:
    matchLabels:
    k8s-app: alertmanager
    version: latest
    template:
    metadata:
    labels:
    k8s-app: alertmanager
    version: latest
    annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ''
    spec:
    priorityClassName: system-cluster-critical
    containers:
    - name: prometheus-alertmanager
    image: "prom/alertmanager"
    imagePullPolicy: "IfNotPresent"
    args:
    - --config.file=/etc/config/alertmanager.yml
    - --storage.path=/data
    # - --web.external-url=/
    ports:
    - containerPort: 9093
    readinessProbe:
    httpGet:
    path: /#/status
    port: 9093
    initialDelaySeconds: 30
    timeoutSeconds: 30
    volumeMounts:
    - name: config-volume
    mountPath: /etc/config
    - name: storage-volume
    mountPath: "/data"
    subPath: ""
    resources:
    limits:
    cpu: 10m
    memory: 50Mi
    requests:
    cpu: 10m
    memory: 50Mi
    - name: prometheus-alertmanager-configmap-reload
    image: "jimmidyson/configmap-reload:v0.1"
    imagePullPolicy: "IfNotPresent"
    args:
    - --volume-dir=/etc/config
    - --webhook-url=http://localhost:9093/-/reload
    volumeMounts:
    - name: config-volume
    mountPath: /etc/config
    readOnly: true
    resources:
    limits:
    cpu: 10m
    memory: 10Mi
    requests:
    cpu: 10m
    memory: 10Mi
    volumes:
    - name: config-volume
    configMap:
    name: alertmanager-config
    - name: storage-volume
    persistentVolumeClaim:
    claimName: alertmanager
    EOF

    DockerHub

  3. PVC(PersistentVolumeClaim)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    cat >> Altermanager-pvc.yaml << EOF
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: alertmanager
    namespace: kube-system
    labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: EnsureExists
    spec:
    storageClassName: managed-nfs-storage
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: "2Gi"
    EOF
  4. Service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    cat >> Altermanager-service.yaml << EOF
    apiVersion: v1
    kind: Service
    metadata:
    name: alertmanager
    namespace: kube-system
    labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "Alertmanager"
    spec:
    ports:
    - name: http
    port: 80
    protocol: TCP
    targetPort: 9093
    selector:
    k8s-app: alertmanager
    type: "ClusterIP"
    EOF

应用配置

1
2
3
4
5
kubectl apply -f Altermanager-deployment.yaml
kubectl apply -f Altermanager-configMap.yaml
kubectl apply -f Altermanager-pvc.yaml
kubectl apply -f Altermanager-service.yaml
kubectl get svc -n kube-system | grep alertmanager

等容器运行正常后,在 Grafana 中 Alerting 的 Admin 点击 Add AlertManager

微信截图_20220327162701.png

查看 alertManager Pod 的 IP address
1
kubectl describe pod $(kubectl get pod -n kube-system | awk '{print $1}' | grep alert) -n kube-system | grep IP

添加你的 AltermanagerURL 到 Grafana http://< pod-IP >:9093

然后在 Grafana 中添加 Alert rules 触发告警至 firing 之后,就会发邮件到你的收件邮箱啦

微信截图_20220327162217.png

什么时候才需要进行 NAT?

NAT(Network Address Translate) 在我们日常网络中太常见了,今天重新仔细审视 NAT,我想到了一些东西

什么时候要进行 NAT?-> 下面的话取反,则是需要 NAT 的时候 /doge

当需要通信的双方路由器之间,互相完全掌握所有的主机地址的路由的时候,NAT 是不必要的

如果两个 Router 之间用 BGP 建邻了,那么大部分内网地址的路由,双方都是知道的,在两个路由器之后的主机相互通信,并不需要进行 NAT,直接 src.address 填源主机地址,通信没有障碍。

但是有些时候,我们的 Router A 有一个 VPN 接口,但这个接口的地址和对端用来通信的地址,Router B 都是不知道的,那么这个时候,没有进行 NAT 的话,在 Router B 想要回包的时候,因为找不到对应的路由,并不能回复这个包,于是 drop 了,网络不可达:(

那么对于以上情况我们有两种处理方法:

  1. 在 Router A 上添加 srcNAT, masquerade 这个 VPN 接口,那么在发送 VPN 客户端主机想要发送报文给 Router B 后的主机时,会把 src.address 替换成 Router A 的地址 (Router B 认识的那个),这样的话 Router B 就可以回包给 Router A,在 Router A 重新收到这个包的时候,把 dst.address 换回客户端主机的地址,网络就可达了✌
  2. 在 Router A 上添加 BGP 的 network ,添加 VPN 网络,那么不需要 NAT 也行,或者直接在 Router B 上加静态路由

未命名绘图.drawio.png

NAT 带来了很多好处:

  1. 节省了 IP 地址空间,大家都可以用 RFC 中规定的保留地址,在和外部网络交流的时候 NAT 成外部 IP
  2. 增强了网络的安全性和隐私性,我们可以把网络中的主机藏在防火墙的 NAT 之后

也有缺点:

  1. 在需要 NAT 时增加了转发报文的开销,需要对报文首部进行处理
  2. 在没有 UPNP 的情况下,NAT 会很怪
  3. 需要维护

在我遇到的问题中,Openwrt 有时候并没有和 RouterA (那个管理隧道的 Router )在同一网段,也没有建立 BGP ,没有直连路由,所以我的方法是,直接在 Linux Host 中添加了内网路由,路由到 RouterA 上。

CentOS7 添加路由

1
ip route add x.x.x.x/x via <gateway>

重启之后上面这条会失效,所以,要加个开机之后会运行的脚本

1
2
3
vi /etc/sysconfig/network-scripts/route-eth0
x.x.x.x/x via <gateway>
:wq

百度

今天被朋友推了一个规则 中文文案排版指北

然后我就开始改我的博客了

是可以用正则匹配替换的,但是确实还有一定难度 /doge

所以我就直接手工替换,养成好习惯,同时还能审查一遍

有了 k8s 之后….

微信截图_20220323020847.png

为什么不试试用 Mikrotik_exporter 来监控你的 RouterOS 呢?

为了更方便我监控 RouterOS,嘿嘿嘿,我找到了这个,mikrotik-exporter

配置 Mikrotik

添加 Prometheus 用户

创建有 api 且 read only 的用户组

1
/user group add name=prometheus policy=api,read,winbox

(optional)如果有 lte 的话要再加一个 test

1
/user group add name=prometheus policy=api,read,winbox,test

创建用户,记得改密码

1
/user add name=prometheus group=prometheus password=changeme

监控单台设备

1
./mikrotik-exporter -address 10.10.0.1 -device my_router -password changeme -user prometheus

-address 后是你 RouterOS 的地址,-device 后是给它起的标签名,后面是密码和用户名

监控多台设备

使用配置文件启动

1
./mikrotik-exporter -config-file config.yml

样例 config.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
devices:
- name: my_router
address: 10.10.0.1
user: prometheus
password: changeme
- name: my_second_router
address: 10.10.0.2
port: 8999
user: prometheus2
password: password_to_second_router
- name: routers_srv_dns
srv:
record: _mikrotik._udp.example.com
user: prometheus
password: password_to_all_dns_routers
- name: routers_srv_custom_dns
srv:
record: _mikrotik2._udp.example.com
dns:
address: 1.1.1.1
port: 53
user: prometheus
password: password_to_all_dns_routers

features:
bgp: true
dhcp: true
dhcpv6: false
dhcpl: true
routes: true
pools: true
optics: true

然后配置 Prometheus

1
vi Prometheus-configmap.yaml

在 scrape_configs 后面加上

1
2
3
4
5
6
- job_name: 'RouterOS_exporter'
static_configs:
- targets: ['127.0.0.1:9436']
labels:
instance: 'RouterOS'
env: 'Prodction'

targets 后面加上 mikrotik_exporter 运行的机子的 ip

热加载更新: 为 Prometheus 服务的端口

1
curl -XPOST http://<your-address>:<port>/-/reload

在 Prometheus 的 Target 中看到它没什么问题的话

就可以在 Grafana 中添加仪表盘啦

Mikrotik Exporter 仪表盘代码:10950

Synology 群晖推荐 Dashboard: 14284

可能发生的问题

http 500 error 或者 UTF-8 invaild

在我遇到的情况,多半是 RouterOS 中的接口的 comment 有中文备注且混杂不是 UTF-8 的编码,只需要去把 RouterOS 上的中文去掉或者改成英文就 ok 了

同时要保证网络通畅

用 snmp-exporter 在 Grafana 中监控 RouterOS

在有了 Grafana 之后,总得监控些什么吧,那就让我们来监控 RouterOS 吧

配置 snmp-exporter

我刚开始被指点的就是使用 snmp_exporter ,让我们看看具体怎么做来监控一些支持 SNMP 协议的设备

可以下载该仓库 releases 中的最新版对应你机器类型的包,放在工作目录中来运行,有很多方式,比如直接在 Linux 环境中运行,用 docker 运行,在 k8s 中运行,都可以

然后就是配置 Prometheus 了

1
vi /prometheus-configmap.yaml

在 scrape_configs 后面加上 其中 为你运行 snmp-exporter 的机器IP地址

targets 后面加上你要监控的主机地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
scrape_configs:
- job_name: 'snmp'
static_configs:
- targets:
- 192.168.1.100 #SNMP device
metrics_path: /snmp
params:
module: [mikrotik]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: <your-address>:9116 # The SNMP exporter's real hostname:port.

注意这里 module 是 mikrotik,是用来监控 mikrotik 家的 ROS 的,如果需要监控别的东西,可以再加一条 job,配置 module 为其他的类型例如 synology(只要snmp.yaml 中有这个类型就可以)

完事之后更新一下 prometheus-configmap 就可以了

热加载: 为 Prometheus 服务的端口

1
curl -XPOST http://<your-address>:<port>/-/reload

加载完之后就可以在 Prometheus 的 targets 中看到 snmp 了

然后就可以在 Grafana 中配置仪表盘了

当然我得先会写 PromQL 才行

我们也可以自己生成 snmp.yml

这里安利大家使用 CloudShell 进行编译,比较方便,当然自己有环境更好啦

安装环境和依赖

1
sudo apt update
1
sudo apt install unzip build-essential libsnmp-dev p7zip-full -y

装上 gcc-g++

1
apt install golang-go -y

检查一下装上 go 了没有

1
go version

下载 snmp_exporter

1
go get github.com/prometheus/snmp_exporter/generator

cd 到该库的目录下

1
cd ${GOPATH-$HOME/go}/src/github.com/prometheus/snmp_exporter/generator

看看对不对

1
ls -lh

没问题就编译它

1
go build

然后下载各种厂商的 mibs

1
make mibs

导出 mibs 文件夹的目录以便于程序指向它

1
export MIBDIRS=mibs

可以开始生成 snmp.yml 了

1
./generator generate

然后就生成出来了

然后想办法传到你要运行 snmp_exporter 的机子上,放在相同目录下替换掉原来的就 ok

可能遇到的问题

=> Prometheus 的服务容器没有连通要监控的路由器,那么在我们需要 prometheus-deploy.yaml 中加上这条:hostNetwork: true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
namespace: kube-system
labels:
app: prometheus
spec:
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
#就下面这一行
hostNetwork: true
serviceAccountName: prometheus
containers:
- image: prom/prometheus:v2.4.3

独立硬盘冗余阵列RAID的学习笔记和心得

基本介绍

独立硬盘冗余阵列RAID, Redundant Array of Independent Disks),旧称廉价磁盘冗余阵列Redundant Array of Inexpensive Disks),简称磁盘阵列。利用虚拟化存储技术把多个硬盘组合起来,成为一个或多个硬盘阵列组,目的为提升性能或减少冗余,或是两者同时提升。

在运作中,取决于 RAID 层级不同,资料会以多种模式分散于各个硬盘,RAID 层级的命名会以 RAID 开头并带数字,例如:RAID 0、RAID 1、RAID 5、RAID 6、RAID 7、RAID 01、RAID 10、RAID 50、RAID 60。每种等级都有其理论上的优缺点,不同的等级在两个目标间获取平衡,分别是增加资料可靠性以及增加存储器(群)读写性能。

RAID 最少硬盘 最大容错 可用容量 读取性能 写入性能 安全性 目的 应用
UNRAID 1 0 1 1 1 到处都有
JBOD 1 0 n 1 1 单纯增加容量 个人
0 2 0 n n n 一个硬盘寄了就全寄了 追求快 缓存
1 2 n-1 1 n 1 高,一块硬盘正常即可 追求稳 个人、企业备份
5 3 1 n-1 n-1 n-1 低,不能坏超过一块 追求快稳便宜 个人、小型企业备份
6 4 2 n-2 n-2 n-2 比RAID5高,不能坏超过两块 追求快加更稳 个人、企业备份
10 4 又稳又快 大型数据库、服务器
50 6 又稳又快但起步价小贵
60 8 又稳又快但起步价贵
  1. n 代表硬盘总数
  2. JBOD(Just a Bunch Of Disk) 指将数个物理硬盘,在操作系统中合并成一个逻辑硬盘,直接增加容量
  3. 10、50、60、依照组成公式不同,容量和性能也不同

RAID 0

RAID 0

RAID 0 亦称为带区集。它将两个以上的磁盘并联起来,成为一个大容量的磁盘。在存放数据时,分段后分散存储在这些磁盘中,因为读写时都可以并行处理,所以在所有的级别中,RAID 0 的速度是最快的。但是 RAID 0 既没有冗余功能,也不具备容错能力,如果一个磁盘(物理)损坏,所有数据都会丢失,危险程度与JBOD相当。

RAID 1

RAID 1

两组以上的 N 个磁盘相互作镜像,在一些多线程操作系统中能有很好的读取速度,理论上读取速度等于硬盘数量的倍数,与 RAID 0 相同。另外写入速度有微小的降低。只要一个磁盘正常即可维持运作,可靠性最高。其原理为在主硬盘上存放数据的同时也在镜像硬盘上写一样的数据。当主硬盘(物理)损坏时,镜像硬盘则代替主硬盘的工作。因为有镜像硬盘做数据备份,所以 RAID 1 的数据安全性在所有的 RAID 级别上来说是最好的。但无论用多少磁盘做 RAID 1,仅算一个磁盘的容量,是所有 RAID 中磁盘利用率最低的一个级别。

如果用两个不同大小的磁盘建 RAID 1,可用空间为较小的那个磁盘,较大的磁盘多出来的空间也可以分割成一个区来使用,不会造成浪费。

{\begin{aligned}Size&=\min \left(S_{1},S_{2},S_{3}\dots \right)\end{aligned}}

RAID 1 没有校验机制。如果用两个磁盘组成 RAID 1 阵列,如果两个硬盘上的数据不知怎么的变得不一致,RAID 1 不知道应该相信哪一个硬盘,这就是大脑分裂的情况。事实上,RAID 1 的磁盘数量越多,越有可能其中某个磁盘的数据变得不一致(但仍然工作),RAID 1 只会从第一个工作的硬盘里提供数据,没有办法检测到底哪个硬盘的数据不对。

RAID1:发生 bit 反转才会寄,一般机械硬盘平均每读写 10^15 个比特才有可能反转一个 bit,否则只要有一块硬盘正常,就可以恢复数据

RAID 5

RAID 5

RAID Level 5 是一种储存性能、数据安全和存储成本兼顾的存储解决方案。它使用的是 Disk Striping(硬盘分割)技术。

RAID 5 至少需要三个硬盘,RAID 5 不是对存储的数据进行备份,而是把数据和相对应的奇偶校验信息存储到组成 RAID 5 的各个磁盘上,并且奇偶校验信息和相对应的数据分别存储于不同的磁盘上。当 RAID 5 的一个磁盘数据发生损坏后,可以利用剩下的数据和相应的奇偶校验信息去恢复被损坏的数据。RAID 5 可以理解为是 RAID 0 和 RAID 1 的折衷方案。RAID 5 可以为系统提供数据安全保障,但保障程度要比镜像低而磁盘空间利用率要比镜像高。RAID 5 具有和 RAID 0 相近似的数据读取速度,只是因为多了一个奇偶校验信息,

写入数据的速度相对单独写入一块硬盘的速度略慢,若使用“回写缓存”可以让性能改善不少。同时由于多个数据对应一个奇偶校验信息,RAID 5 的磁盘空间利用率要比 RAID 1 高,存储成本相对较便宜。

RAID 6

RAID 6

与 RAID 5 相比,RAID 6 增加第二个独立的奇偶校验信息块。两个独立的奇偶系统使用不同的算法,数据的可靠性非常高,任意两块磁盘同时失效时不会影响数据完整性。RAID 6 需要分配给奇偶校验信息更大的磁盘空间和额外的校验计算,相对于 RAID 5 有更大的 IO 操作量和计算量,其“写性能”强烈取决于具体的实现方案,因此 RAID 6 通常不会通过软件方式来实现,而更可能通过硬件方式实现。

同一数组中最多容许两个磁盘损坏。更换新磁盘后,资料将会重新算出并写入新的磁盘中。

依照设计理论,RAID 6 必须具备四个以上的磁盘才能生效。可使用的容量为硬盘总数减去 2 的差,乘以最小容量,公式为:

同理,数据保护区域容量则为最小容量乘以 2。

RAID 6 在硬件磁盘阵列卡的功能中,也是最常见的磁盘阵列等级。

实现

Storage Networking Industry Association (SNIA) 对于 RAID 6 的定义是:”在任意两块磁盘同时失效的情况下,仍然能够对RAID中的所有虚拟磁盘执行读写操作的RAID实现。迄今已经有:奇偶 和 里德-所罗门 双校验、正交双奇偶校验和对角奇偶校验等若干方法用于实现 RAID 6。”

为了达到容忍任意两块磁盘失效的目的,需要计算两种不同的综合解码。其中之一是 P,可以像 RAID 5 那样经过简单的异或计算获得,而另一个不同的综合编码则比较复杂,需要利用[域论]来解决。

反正就非常复杂

软件方式实现的 RAID 6 对于系统性能会有明显的影响,而硬件方案则相对复杂。

RAID 10/01

RAID 1+0

RAID 0+1

RAID 10 是先分割资料再镜像,再将所有硬盘分为两组,视为以 RAID 1 作为最低组合,然后将每组 RAID 1 视为一个“硬盘”组合为 RAID 0 运作。

RAID 01 则是跟 RAID 10 的程序相反,是先镜像再将资料到分割两组硬盘。它将所有的硬盘分为两组,每组各自构成为 RAID 0 作为最低组合,而将两组硬盘组合为 RAID 1 运作。

当 RAID 10 有一个硬盘受损,其余硬盘会继续运作。RAID 01 只要有一个硬盘受损,同组 RAID 0 的所有硬盘都会停止运作,只剩下其他组的硬盘运作,可靠性较低。如果以六个硬盘建 RAID 01,镜像再用三个建 RAID 0,那么坏一个硬盘便会有三个硬盘离线。因此,RAID 10 远较 RAID 01 常用,零售主板绝大部分支持RAID 0/1/5/10,但不支持 RAID 01。

RAID 50

RAID 50

RAID 5 与 RAID 0 的组合,先作 RAID 5,再作 RAID 0,也就是对多组 RAID 5 彼此构成 Stripe 访问。由于 RAID 50 是以 RAID 5 为基础,而 RAID 5 至少需要 3 颗硬盘,因此要以多组 RAID 5 构成 RAID 50,至少需要 6 颗硬盘。以 RAID 50 最小的 6 颗硬盘配置为例,先把 6 颗硬盘分为 2 组,每组 3 颗构成 RAID 5,如此就得到两组 RAID 5,然后再把两组 RAID 5 构成 RAID 0。

RAID 50 在底层的任一组或多组 RAID 5 中出现 1 颗硬盘损坏时,仍能维持运作,不过如果任一组 RAID 5 中出现 2 颗或 2 颗以上硬盘损毁,整组 RAID 50 就会失效。

RAID 50 由于在上层把多组 RAID 5 构成 Stripe,性能比起单纯的 RAID 5 高,容量利用率比 RAID5 要低。比如同样使用 9 颗硬盘,由各 3 颗 RAID 5 再组成 RAID 0 的 RAID 50,每组 RAID 5 浪费一颗硬盘,利用率为 (1-3/9),RAID 5 则为 (1-1/9)。

RAID 60

raid 60

RAID 6 与 RAID 0 的组合:先作 RAID 6,再作 RAID 0。换句话说,就是对两组以上的 RAID 6 作 Stripe 访问。RAID 6 至少需具备 4 颗硬盘,所以 RAID 60 的最小需求是 8 颗硬盘。

由于底层是以 RAID 6 组成,所以 RAID 60 可以容许任一组 RAID 6 中损毁最多 2 颗硬盘,而系统仍能维持运作;不过只要底层任一组 RAID 6 中损毁 3 颗硬盘,整组 RAID 60 就会失效,当然这种情况的概率相当低。

比起单纯的 RAID 6,RAID 60 的上层透过结合多组 RAID 6 构成 Stripe 访问,因此性能较高。不过使用门槛高,而且容量利用率低是较大的问题。

由八块相同硬盘组成 RAID 60 的话,每组 RAID6 使用两块硬盘来存奇偶校验信息,硬盘利用率是 50%

git 学习笔记

Git 的完整性

​ Git 中的所有数据在存储前都会执行校验和计算,随后以校验和来引用对应的数据。这意味着不可能在 Git 不知情的情况下更改文件或目录的内容。这项功能根植于 Git 的最底层,是其设计理念中不可或缺的一环。只要有 Git 在,它就能检测出传输过程中丢失的信息或者受损的文件。

​ Git所采用的校验和机制叫做 SHA-1 散列。这是一个由 40 个十六进制字符所组成的字符串,它是根据文件内容或者 Git 的目录结构计算所得到的。一个 SHA-1 散列类似于如下的字符串

​ 24b9da6552252987aa493b52f8696cd6d3b00373

​ 由于用途极广,你在 Git 中到处都会看到这种散列值。实际上,Git 并不是通过文件名在数据库中存储信息,而是通过信息的散列值

Git 中文件的三种状态

​ Committed 已提交

​ Modified 已修改

​ Staged 已暂存

Git 的首次配置

1
2
3
4
#配置用户名
git config --global user.name "Sunnyrian"
#配置邮箱
git config --global user.email Sunnyrain233@gmail.com

配置自己喜欢的 editor,如果没有配置,Git 会使用默认的编辑器

1
git config --global core.editer nano

在 Windows X64 中配置 editor Notepad++

1
git config --global core.editor "'C:/Program Files(x86)/Notepad++/notepad++.exe' -multiInst"

检查个人配置

1
git config --list

在现有目录中初始化 Git 仓库

1
git init

这个命令会创建一个名为 .git 的子目录。这个子目录包含了构成 Git 仓库骨架的所有必需文件。但此刻 Git 尚未开始跟踪项目中的任何文件

如果要开始对现有文件进行版本控制,那么就应该开始跟踪这些文件并进行初次提交。对需要跟踪的文件执行 git add 命令,然后输入 git commit

1
2
git add .
git commit -m 'initial project version'

克隆现有仓库

1
git clone https://github.com/Sunnyrian/Blog

查看当前文件状态

1
git status

如果在克隆仓库后立即执行这个命令,我们可以看到

On branch master

nothing to commit, working directory clean

如果将新的文件添加进去,我们又没有 add 过这个文件,那么就会在 status 下看到这个未被跟踪的文件

如果使用 add 命令,可以将该文件放到暂存区,将会是一个 Changes to be committed 的状态

如果更改了某个 git 仓库原有的文件,那么该文件会是一个 Changes not staged for commit 的状态

git add 是一个多功能的命令,既可以用来跟踪新文件,也可以用来暂存文件,它还可以做其他的一些事,比如把存在合并冲突的文件标记为已解决。所以,把 git add 命令看成“添加内容到下一次提交中”而不是“把这个文件加入到项目中”,更有助于理解该命令。

如果说我们在修改一个文件后,git add 它之后又修改了它,那么他的 git status 状态将会是即在 Changes to be committed 中又会在 Changes not staged for commit 中,但 Changes to be committed 中存储的是第一次 add 的文件的样子

显示更简洁的状态信息
1
git status -s

忽略文件

大家很多时候,都会有希望某一类或者某几个文件不想被Git自动添加,甚至不想这些文件被显示在未跟踪的文件列表下面。

那么我们可以创建一个名为 .gitignore 的文件,然后在里面写入待匹配文件的模式

1
2
3
4
cat >>.gitignore <<EOF
*.[oa]
*~
EOF

其中第一行告诉 Git 忽略所有以 .o 或者 .a 结尾的文件,这些一般是编译代码生产的二进制文件。第二行是告诉 Git 忽略所有以波浪号(~)结尾的文件

可以写入 .gitignore 文件中的匹配模式的规则如下:

  • 空行或以 # 开始的行会被忽略
  • 支持标准的 glob 模式(正则表达式)
  • 以斜杠(/)开头的模式可用于禁止递归匹配
  • 以斜杠(/)结尾的模式表示目录
  • 以感叹号(!)开始的模式表示取反
1
2
3
4
5
6
*.a		#忽略.a类型的文件
!lib.a #仍然跟踪lib.a,即使上一行指令要忽略 .a 类型的文件
/TODO #只忽略当前目录的 TODO 文件,而不忽略子目录下的 TODO
build/ #忽略 build/ 目录下的所有文件
doc/*.txt #忽略 doc/note.txt,而不忽略 /doc/server/arch.txt
doc/**/*.pdf #忽略 doc/目录下的所有 .pdf文件

查看已暂存和未暂存的变更

1
git diff

查看暂存的变更与上一次提交的内容的比较

1
git diff -staged

查看已暂存的更改

1
git diff --cached

提交变更

1
git commit

会在编辑器中显示并可以编辑提交信息 -v 的话可以把这次提交的差异对比显示在文本编辑器中,可以看到更具体的的变更

1
2
#在命令行中
git commit -m

跳过暂存区,有时候会我们不用再添加文件,而只是修改了现有文件,要提交 commit,可以直接 commit -a,不需要再执行 add指令,可以自动把已经跟踪的所有文件添加到暂存区,然后再提交,就可以省掉 git add了

1
git commit -a -m 'added new benchmarks'

移除文件

​ 要从 Git 中移除某个文件,你需要把它先从已跟踪的文件列表中移除(确切地说,是从暂存区中移除),然后再提交。git rm 可以帮我们完成这些操作,同时会在工作目录中删除该文件

1
git rm <file>

​ 如果我们只是简单地删掉了我们的文件,没有使用 git rm,那么在执行 git status 的时候,还是会看到该文件出现在 “Changes not staged for commit” 区域(也就是未暂存区域)

​ 如果我们已经 add 添加某个文件到暂存区了,我们需要使用 -f 选项,可以防止没有被记录到快照中的数据被意外移除,因为这样的数据被意外移除后无法由 Git恢复

1
git rm -f <file>

​ 如果我们只是想让 git 不再追踪某个文件,比如说我们忘记在 .gitignore 中添加该文件而将它 add 到暂存区了,我们想在工作目录中保留该文件,那么我们可以只删除暂存区的该文件

1
2
git rm --cached <file>
# 此处的<file>也可以输入glob正则表达式选取文件

移动文件

1
2
3
4
5
git mv README.md README
#相当于执行了以下三条命令
mv README.md README
git rm README.md
git add README

相当于非常方便了

查看提交历史

1
2
3
4
5
6
7
8
9
10
11
git log
#查看最近两次提交
git log -p -2
#查看简要统计信息
git log --stat
#选择日志输出的默认格式 例如单行显示↓ 还有 short、full、fullter 格式可以选择
git log --pretty=oneline
#明确指定输出格式
git log --pretty=format:"%h - %an, %ar : %s"
#加上简单图标来显示 Git 分支和合并历史 --graph
git log --pretty format: "%h %s" --graph

git log –pretty=format 命令的一些有用的选项👇:

格式选项 输出的格式描述
%H 提交对象的散列值
%h 提交对象的简短散列值
%T 树对象的散列值
%t 树对象的简短散列值
%P 父对象的散列值
%p 父对象的简短散列值
%an 作者的名字
%ae 作者的电子邮箱地址
%ad 创作日期(可使用 -date= 选项指定日期格式)
%ar 相对于当前日期的创作日期
%cn 提交者的名字
%ce 提交者的电子邮箱地址
%cd 提交日期
%cr 相对于当前日期的提交日期
%s 提交信息的主题

git log 的常用选项

选项 描述
-p 按补丁格式显示每个提交引入的更改
–stat 显示每个提交中被更改的文件的统计信息
–shortstat 只显示上述 –state 输出中包含“已更改/新增/删除”行的统计信息
–name-only 在每个提交信息后显示被更改的文件列表
–name-status 在上一个选项输出基础上还显示出“已更改/新增/删除”统计信息
–abbrev-commit 只显示完整的 SHA-1 40 位校验和字符串中的前几个字符
–relative-date 显示相对日期(如两周前),而不是完整日期
–graph 在提交历史旁边显示 ASCII 图标,用于展示分支和合并的历史信息
–pretty 用一种可选格式显示提交。选项有 oneline、short、full、fuller、format

用于限制 git log 输出范围的选项

选项 描述
-(n) 只显示最新的 n 次提交
–since,–after 只输出指定日期之后的提交
–until,–before 只输出指定日期之前的提交
–author 只输出作者与指定字符串匹配的提交
–committer 只输出提交者与指定字符串匹配的提交
–grep 只输出提交信息包含指定字符串的提交
-S 只输出包含“添加或删除指定字符串”的更改的提交

从远程仓库拉取代码库

1
git fetch <repo>

告诉 Git 去获取我们没有的数据,然后我们可以

1
git merge [alias]/[branch]

以上命令会将服务器上的任何更新合并到我们的当前分支

分支管理

创建分支

1
git branch <branch-name>

查看现有分支

1
git branch

切换分支

1
git checkout <branch-name>

删除分支

1
git branch -d <branch-name>

合并分支到主分支

1
git merge <branch-name>

在 Kubernetes 集群中部署 Prometheus 来监控集群,并用 Grafana 数据可视化

在 Kubernetes 集群中部署 Prometheus来 监控集群,并用 Grafana 数据可视化

Prometheus 部署
  1. 先创建一个目录来存放管理配置文件

    1
    mkdir prometheus

    本次 prometheus 采用 nfs 挂载方式来存储数据,同时使用 configMap 管理配置文件。并且我们将所有的 prometheus 存储在 kube-system

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    #生成配置文件 

    cat >> prometheus-configmap.yaml <<EOF
    # Prometheus configuration format https://prometheus.io/docs/prometheus/latest/configuration/configuration/
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: prometheus-config
    namespace: prometheus
    labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: EnsureExists
    data:
    prometheus.yml: |
    rule_files:
    - /etc/config/rules/*.rules

    scrape_configs:
    - job_name: prometheus
    static_configs:
    - targets:
    - localhost:9090

    - job_name: kubernetes-apiservers
    kubernetes_sd_configs:
    - role: endpoints
    relabel_configs:
    - action: keep
    regex: default;kubernetes;https
    source_labels:
    - __meta_kubernetes_namespace
    - __meta_kubernetes_service_name
    - __meta_kubernetes_endpoint_port_name
    scheme: https
    tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

    - job_name: kubernetes-nodes-kubelet
    kubernetes_sd_configs:
    - role: node
    relabel_configs:
    - action: labelmap
    regex: __meta_kubernetes_node_label_(.+)
    scheme: https
    tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

    - job_name: kubernetes-nodes-cadvisor
    kubernetes_sd_configs:
    - role: node
    relabel_configs:
    - action: labelmap
    regex: __meta_kubernetes_node_label_(.+)
    - target_label: __metrics_path__
    replacement: /metrics/cadvisor
    scheme: https
    tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

    - job_name: kubernetes-service-endpoints
    kubernetes_sd_configs:
    - role: endpoints
    relabel_configs:
    - action: keep
    regex: true
    source_labels:
    - __meta_kubernetes_service_annotation_prometheus_io_scrape
    - action: replace
    regex: (https?)
    source_labels:
    - __meta_kubernetes_service_annotation_prometheus_io_scheme
    target_label: __scheme__
    - action: replace
    regex: (.+)
    source_labels:
    - __meta_kubernetes_service_annotation_prometheus_io_path
    target_label: __metrics_path__
    - action: replace
    regex: ([^:]+)(?::\d+)?;(\d+)
    replacement: $1:$2
    source_labels:
    - __address__
    - __meta_kubernetes_service_annotation_prometheus_io_port
    target_label: __address__
    - action: labelmap
    regex: __meta_kubernetes_service_label_(.+)
    - action: replace
    source_labels:
    - __meta_kubernetes_namespace
    target_label: kubernetes_namespace
    - action: replace
    source_labels:
    - __meta_kubernetes_service_name
    target_label: kubernetes_name

    - job_name: kubernetes-services
    kubernetes_sd_configs:
    - role: service
    metrics_path: /probe
    params:
    module:
    - http_2xx
    relabel_configs:
    - action: keep
    regex: true
    source_labels:
    - __meta_kubernetes_service_annotation_prometheus_io_probe
    - source_labels:
    - __address__
    target_label: __param_target
    - replacement: blackbox
    target_label: __address__
    - source_labels:
    - __param_target
    target_label: instance
    - action: labelmap
    regex: __meta_kubernetes_service_label_(.+)
    - source_labels:
    - __meta_kubernetes_namespace
    target_label: kubernetes_namespace
    - source_labels:
    - __meta_kubernetes_service_name
    target_label: kubernetes_name

    - job_name: kubernetes-pods
    kubernetes_sd_configs:
    - role: pod
    relabel_configs:
    - action: keep
    regex: true
    source_labels:
    - __meta_kubernetes_pod_annotation_prometheus_io_scrape
    - action: replace
    regex: (.+)
    source_labels:
    - __meta_kubernetes_pod_annotation_prometheus_io_path
    target_label: __metrics_path__
    - action: replace
    regex: ([^:]+)(?::\d+)?;(\d+)
    replacement: $1:$2
    source_labels:
    - __address__
    - __meta_kubernetes_pod_annotation_prometheus_io_port
    target_label: __address__
    - action: labelmap
    regex: __meta_kubernetes_pod_label_(.+)
    - action: replace
    source_labels:
    - __meta_kubernetes_namespace
    target_label: kubernetes_namespace
    - action: replace
    source_labels:
    - __meta_kubernetes_pod_name
    target_label: kubernetes_pod_name
    alerting:
    alertmanagers:
    - static_configs:
    - targets: ["alertmanager:80"]
    EOF

    配置文件解释(这里的 configmap 实际上就是 prometheus 的配置)

    上面包含了 3 个模块 global、rule_files 和 scrape_configs

    • 其中 global 模块控制 Prometheus Server 的全局配置
    • scrape_interval: 表示 prometheus抓取指标数据的频率,默认是 15 s,我们可以覆盖这个值
    • evaluation_interval: 用来控制评估规则的频率,prometheus 使用规则产生新的时间序列数据或者产生警报
    • rule_files 模块制定了规则所在的位置,prometheus 可以根据这个配置加载规则,用于生产新的时间序列数据或者报警信息,当前我们没有配置任何规则,后期会添加
    • scrape_configs 用于控制 prometheus 监控哪些资源。由于 prometheus 通过 http 的方式来暴露它本身的监控数据,prometheus 也能够监控本身的健康情况。在默认的配置有一个单独的 job,叫做 prometheus,它采集 prometheus 服务本身的时间序列数据。这个 job 包含了一个单独的、静态配置的目标;监听 localhost 上的 9090 端口
    • prometheus 默认会通过目标的 /metrics 路径采集 metrics。所以,默认的 job 通过 URL:http://localhost:9090/metrics 采集metrics。收集到时间序列包含 prometheus 服务本身的状态和性能。如果我们还有其他的资源需要监控,可以直接配置在该模块下即可

    监控 Prometheus

    1
    kubectl create -f prometheus-configmap.yaml

    更新 Configmap

    1
    curl -XPOST http://<Prometheus Service IP>:<port>/-/reload

    检查一下有没有创建成功

    1
    kubectl get configmaps -n kube-system |grep prometheus

    配置文件创建完成,如果以后我们有新的资源需要被监控,我们只需要将 ConfigMap 对象更新即可

  2. 创建 prometheus 的 Pod 资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    cat >>prometheus-deploy.yaml <<EOF
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: prometheus
    namespace: kube-system
    labels:
    app: prometheus
    spec:
    template:
    metadata:
    labels:
    app: prometheus
    spec:
    serviceAccountName: prometheus
    containers:
    - image: prom/prometheus:v2.4.3
    name: prometheus
    command:
    - "/bin/prometheus"
    args:
    - "--config.file=/etc/prometheus/prometheus.yml"
    - "--storage.tsdb.path=/prometheus"
    - "--storage.tsdb.retention=30d"
    - "--web.enable-admin-api" # 控制对 admin HTTP API 的访问,其中包括删除时间序列等功能
    - "--web.enable-lifecycle" # 支持热更新,直接执行 localhost:9090/-/reload 立即生效
    ports:
    - containerPort: 9090
    protocol: TCP
    name: http
    volumeMounts:
    - mountPath: "/prometheus"
    subPath: prometheus
    name: data
    - mountPath: "/etc/prometheus"
    name: config-volume
    resources:
    requests:
    cpu: 100m
    memory: 512Mi
    limits:
    cpu: 100m
    memory: 512Mi
    securityContext:
    runAsUser: 0
    volumes:
    - name: data
    persistentVolumeClaim:
    claimName: prometheus
    - configMap:
    name: prometheus-config
    name: config-volume
    EOF

    稍微解释一下配置参数

    我们在启动程序的时候,除了指定 prometheus.yaml(configmap) 以外,还通过 storage.tsdb.path 指定了 TSDB 数据的存储路径、通过storage.tsdb.rentention 设置了保留多长时间的数据,还有下面的 web.enable-admin-api 参数可以用来开启对 admin api 的访问权限,参数 web.enable-lifecyle 用来开启支持热更新,有了这个参数之后, prometheus.yaml(configmap) 文件只要更新了,通过执行localhost:9090/-/reload就会立即生效

    我们添加了一行 securityContext,其中 runAsUser 设置为 0,这是因为 prometheus 运行过程中使用的用户是 nobody,如果不配置可能会出现权限问题

    prometheus.yaml 文件对应的 ConfigMap 对象通过 volume 的形式挂载进 Pod,这样 ConfigMap 更新后,对应的 pod 也会热更新,然后我们在执行上面的 reload 请求,prometheus 配置就生效了。除此之外,对了将时间数据进行持久化,我们将数据目录和一个 pvc 对象进行了绑定,所以我们需要提前创建 pvc 对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    cat >>prometheus-volume.yaml <<EOF
    apiVersion: v1
    kind: PersistentVolume
    metadata:
    name: prometheus
    spec:
    capacity:
    storage: 10Gi
    accessModes:
    - ReadWriteOnce
    persistentVolumeReclaimPolicy: Recycle
    nfs:
    server: 10.4.82.138
    path: /data/k8s

    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: prometheus
    namespace: kube-system
    spec:
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: 10Gi
    EOF

    修改上面的 nfs server 和 path

    1
    kubectl create -f prometheus-volume.yaml

    检查一下有没有挂载好

    1
    2
    kubectl get pvc --all-namespaces
    kubectl get pv prometheus

    配置 rbac 认证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    cat >>prometheus-rbac.yaml <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: prometheus
    namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    name: prometheus
    rules:
    - apiGroups:
    - ""
    resources:
    - nodes
    - services
    - endpoints
    - pods
    - nodes/proxy
    verbs:
    - get
    - list
    - watch
    - apiGroups:
    - ""
    resources:
    - configmaps
    - nodes/metrics
    verbs:
    - get
    - nonResourceURLs:
    - /metrics
    verbs:
    - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
    name: prometheus
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: prometheus
    subjects:
    - kind: ServiceAccount
    name: prometheus
    namespace: kube-system
    EOF

    创建 rbac

    1
    kubectl create -f prometheus-rbac.yaml

    创建 prometheus 服务

    1
    kubectl create -f prometheus-deploy.yaml

    检查服务有没有起来

    1
    2
    kubectl get pod -n kube-system |grep prometheus
    # 是 running 就 ok

    现在我们 prometheus 服务状态是已经正常了,但是我们还无法访问 prometheus 的 webui 服务,我们还需要创建一个 service

    name 是 prometheus-svc

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    cat >>prometeheus-svc.yaml <<EOF
    apiVersion: v1
    kind: Service
    metadata:
    name: prometheus-svc
    namespace: kube-system
    labels:
    app: prometheus
    spec:
    selector:
    app: prometheus
    type: NodePort
    ports:
    - name: web
    port: 9090
    targetPort: http
    EOF

    创建这个服务

    1
    kubectl create -f prometheus-svc.yaml

    看一下分配的端口,用 IP+ 端口访问

    1
    kubectl get svc -n kube-system |grep prometheus
  3. 创建 grafana 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    cat >>grafana.yaml <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: grafana
    namespace: prometheus
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: grafana
    template:
    metadata:
    labels:
    app: grafana
    spec:
    containers:
    - name: grafana
    image: grafana/grafana
    ports:
    - containerPort: 3000
    protocol: TCP
    resources:
    limits:
    cpu: 100m
    memory: 256Mi
    requests:
    cpu: 100m
    memory: 256Mi
    volumeMounts:
    - name: grafana-data
    mountPath: /var/lib/grafana
    subPath: grafana
    securityContext:
    fsGroup: 472
    runAsUser: 472
    volumes:
    - name: grafana-data
    persistentVolumeClaim:
    claimName: grafana

    ---

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: grafana
    namespace: prometheus
    spec:
    storageClassName: "managed-nfs-storage"
    accessModes:
    - ReadWriteMany
    resources:
    requests:
    storage: 5Gi

    ---

    apiVersion: v1
    kind: Service
    metadata:
    name: grafana
    namespace: prometheus
    spec:
    type: NodePort
    ports:
    - port : 80
    targetPort: 3000
    nodePort: 30007
    selector:
    app: grafana
    EOF

    创建grafana-ingress.yaml

    #–optional可选的,没有外网访问需求可以直接跳过这一步

    ingress 文档: https://kubernetes.io/zh/docs/concepts/services-networking/ingress/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
       cat >>grafana-ingress.yaml <<EOF
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
    name: grafana
    namespace: prometheus
    spec:
    rules:
    - host: k8s.grafana
    http:
    paths:
    - path: /
    backend:
    serviceName: grafana
    servicePort: 80
    EOF

    应用 grafana

    1
    kubectl apply -f grafana.yaml -f grafana-ingress.yaml

    可以在 KubeSphere 中查看分配到的 ip 地址和端口,配置好 Grafana,就可以导入模板看到可视化界面啦

    容器监控模板:315 8588 3146 8685
    主机监控模板:8919 9276 10467 10171 9965

监控类型 模板ID
Kubernetes node_exporter 14249、8919、10262、5228
Mikrotik RouterOS 10950、14933(SWOS)
Synology 14284、14364
SNMP 14857(Mikrotik)、
Windows 9837
Proxmox PVE 13307
Openwrt 11147
Linux 12633
WireGuard 12177

DashBoard 看起来好看但是还没调教好的:8727、9733、9916、12798、11414、12095

funny DashBoard:3287(PUBG)、11993、11994(Minecraft)、12237(COVID-19)、14199(网络延迟)

一些我的仪表盘的效果

微信截图_20220323214600.png

微信截图_20220323231243.png

微信截图_20220323230620.png

微信截图_20220323214702.png

微信截图_20220324002923.png

微信截图_20220323231021.png

安装 Prometheus 和 Grafana(懒人版)

别人三年前写的东西了,不建议使用
建议不要在完全翻墙的环境下去拉镜像,很有可能拉不成功,有时候拉失败,要考虑一下是不是网络环境的问题

Prometheus and Grafana

快速安装

1
2
kubectl apply \
--filename https://raw.githubusercontent.com/giantswarm/prometheus/master/manifests-all.yaml

不建议使用,有点 bug

需要改 state-metrics image: bitnami/kube-state-metrics:latest

Linux时区设置以及 NTP 设置自动同步

查看当前时区

1
date -R

检查一下有没有 ntp 服务

1
systemctl status ntp

如果没有则安装 ntp 服务,安装了就直接下一步

1
2
3
yum install -y ntp
systemctl enable ntpd
systemctl start ntpd

更改时区

1
2
3
#先备份一下当前时区文件 然后把正确的时区文件链接过来
mv /etc/localtime /etc/localtime.old
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

同步硬件时间:
在 /etc/sysconfig/ntpd 最后一行加
SYNC_HWCLOCK=yes

Linux 内核升级指南

显示当前 Linux 系统内核
1
uname -sr

在 CentOS 7 上升级内核

启用 ELRepo 仓库
1
2
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
列出可以使用的内核相关包
1
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
安装最新的主线稳定内核
1
yum --enablerepo=elrepo-kernel install kernel-ml
设置 GRUB 默认启动的内核版本
1
2
vi /etc/default/grub
#设置 GRUB_DEFAULT=0
重新创建内核配置
1
grub2-mkconfig -o /boot/grub2/grub.cfg

这样重启之后就是新内核的系统了,记得改 hostname,关闭 selinux

有时候部署东西经常出问题,不如试试看更新一下 LinuxKernel,说不定是有内核版本要求呢?