这是一个k8s集群,搭建gluster fs系统提供存储服务,搭建heketi进行管理gluster fs,结合k8s的StorageClass进行动态pv建立。提供给生产环境的日志收集系统EFK存储数据。

准备环境

  • 操作系统:centos7
  • 硬盘:/dev/vdc 50Gi

GlusterFS

搭建glusterfs来作为可持续存储k8s的CSI

安装glusterfs

三台服务器都要执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 先安装 gluster 源
$ yum install centos-release-gluster -y

# 安装 glusterfs 组件(这里包含了server和client)
$ yum install -y glusterfs glusterfs-server glusterfs-fuse glusterfs-rdma glusterfs-geo-replication glusterfs-devel

# 创建 glusterfs服务运行目录
$ mkdir /opt/glusterd

# 修改 glusterd 目录,将/var/lib改成/opt
$ sed -i 's/var/lib/opt/g' /etc/glusterfs/glusterd.vol

# 启动 glusterfs(为挂载提供服务)
$ systemctl start glusterd.service

# 设置开机启动
$ systemctl enable glusterd.service

#查看状态
$ systemctl status glusterd.service

配置 glusterfs

三台服务器都要执行

配置本地解析文件hosts

1
2
3
4
5
echo """
192.168.1.49 api.328ym.com
192.168.1.55 node1.328ym.com
192.168.1.100 node2.328ym.com
""" >> /etc/hosts

开放端口(24007是gluster服务运行所需的端口号)如果关闭了防火墙就省略此步操作。其他防火墙设置自己解决

1
iptables -I INPUT -p tcp --dport 24007 -j ACCEPT

搭建完毕glusterFS

heketi

本项目参考github地址:
https://github.com/huisebug/heketi.git

安装客户端

下载地址:
https://github.com/heketi/heketi/releases/

1
2
tar zxf heketi-client-v9.0.0.linux.amd64.tar.gz
mv heketi-client/bin/heketi-cli /usr/local/bin/

创建ssh key并分发

在所有的glusterfs节点,创建hekeli的数据库存储目录、ssh免密码登录文件目录。

1
2
mkdir -p /data/heketi/{db,.ssh} && chmod 700 /data/heketi/.ssh
ssh-keygen -t rsa -b 2048 -f /data/heketi/.ssh/id_rsa

如果执行操作的节点可以免密登录到其他节点就可以执行下面命令,不行就手动分发

1
2
for NODE in node1 node2 node3; do scp -r /data/heketi/.ssh root@${NODE}:/data/heketi; done
for NODE in node1 node2 node3; do ssh-copy-id -i /data/heketi/.ssh/id_rsa.pub root@${NODE} ; done

手动分发

1
cat /data/heketi/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys

运行heketi

运行原理

Heketi服务使用建立的ssh key登录到gluster fs服务器的root账户,然后就可以执行gluster fs服务进行管理。

需要三个文件

  1. heketi-deployment.yaml:heketi服务运行yaml,其中需要声明登录到glusterfs的方式,

    需要指定ssh登录用户,此处我是root;ssh服务端口号,此处我未使用默认的22端口

    此处指定了node进行部署,所以记得修改你的节点特有的标签

    之前在所有运行gluster fs的服务器建立了/data/heketi/文件目录,这里指定其中节点运行就都可以使用hostPath方式volume,将生成的ssh key挂载到heketi服务中,让其可以远程发送命令操作gluster fs所在服务器,进行pv、vg管理(概念参考地址:https://www.cnblogs.com/zk47/p/4753987.html
  2. heketi-secret.yaml:这是设置登录到heketi服务的密码
  3. heketi-svc.yaml:因为我们需要使用客户端heketi-cli进行集群的创建,所以这里需要使用NodePort的方式进行访问

执行安装

1
kubectl apply -f heketi-deployment.yaml -f heketi-secret.yaml

验证

这里配置Heketi的service在NodeIP:30944上
通过命令检查heketi服务

1
curl -s <http://api.328ym.com:30944/hello>

导入glusterfs集群拓扑(topology)信息

文件内容heketi-topology-vdc.json

参考heketi-topology-vdc.json文件地址:
https://raw.githubusercontent.com/huisebug/heketi/master/heketi-topology-vdc.json

  • hostnames下的manage和storage配置为gluster的IP地址;
  • zone可以配置为非0值,这里配置为1,;
  • devices下制定gluster fs服务器下的文件驱动,例如:/dev/sdb,指定多个文件驱动!!!
  • destroydata:是否销毁文件驱动的数据,这里使用了true

有关glusterfs集群的topology的配置参考
https://github.com/heketi/heketi/blob/master/docs/admin/topology.md

执行

1
heketi-cli --user admin --secret password --server http://api.328ym.com:30944 topology load --json heketi-topology-vdc.json

查看heketi服务日志(kubectl logs -f heketi-7749795dc7-k6qnb)如果提示如下错误

1
2
3
4
5
6
[sshexec] ERROR 2019/04/28 07:41:01
/src/github.com/heketi/heketi/pkg/utils/ssh/ssh.go:172: Failed to run command[/bin/bash -c 'pvcreate --metadatasize=128M --dataalignment=256K '/dev/vdc''] on192.168.1.55:36888: Err[Process exited with status 5]: Stdout []: Stderr[WARNING: dos signature detected on /dev/vdc at offset 510. Wipe it? [y/n]: [n]

Aborted wiping of dos.

1 existing signature left on the device.

报错原因是无法手动向警告提示输入y或n,解决方法:

1
2
#那么就手动到所有gluster fs服务的命令行手动建立pv
pvcreate --metadatasize=128M --dataalignment=256K '/dev/vdc'

执行后,每个节点出现ok就说明成功建立,可以使用vgscan命令进行查看。

查看集群id

1
heketi-cli --user admin --secret password --server http://api.328ym.com:30944 cluster list

建立volume

非k8s使用

1
heketi-cli --user admin --secret password --server http://10.142.21.21:30088 volume create --size=100 --replica=3 --clusters=38c2729af0f42338cf66eed6b80f116f

k8s使用

此处使用动态PV的方式,建立storageclass和pvc进行关联,然后动态建立pv

建立StorageClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gluster-heketi
annotations:
#这里是将次storageclass设置为默认的class
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/glusterfs
parameters:
#注意这里下面的地址需要能解析的到,我之前写的是service名,是无法解析的
resturl: "http://api.328ym.com:30944"
#resturl: "http://heketi.default.svc.cluster.local:8080"
clusterid: "38c2729af0f42338cf66eed6b80f116f"
restuser: "admin"
secretNamespace: "default"
secretName: "heketi-secret"
volumetype: "none"

执行

1
kubectl apply -f heketi-storageclass.yaml

建立pvc

1
2
3
4
5
6
7
8
9
10
11
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: gluster-heketi
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi

执行

1
kubectl apply -f heketi-test-pvc.yaml

查看volume建立情况

1
heketi-cli --user admin --secret password --server http://api.328ym.com:30944 volume list

查看是否建立pvc和自动建立pv

查看gluster fs 卷信息和挂载情况

查看卷的使用情况和集群情况

1
heketi-cli --user admin --secret password --server http://api.328ym.com:30944 topology info

实践

###实践###

此处我们的gluster fs是使用了三块50Gi的硬盘组成的集群,验证当申请超过50Gi的时候会如何建立,能否建立成功?

  1. 我们复制之前的test-pvc 文件,将其修改为如下
    1
    cp -rf heketi-test-pvc.yaml heketi-test-pvc2.yaml
    heketi-test-pvc2.yaml

执行

查看挂载情况

难道说这里使用了30Gi,会平均从其他gluster节点划取空间?

查看gluster fs信息

获取到另一个来源是192.168.1.55这台服务器,切换到这台服务器进行查看

果然证实了我的猜测。

查看pvc和pv

删除pvc配置

pv也会自动删除

EFK

作为整个集群的日志系统,我们可以使用三台性能优越的服务器安装好kubelet、kube-proxy、docker后将其作为node加入到现有的集群中去,并将其打上efk的标签,不允许其他pod调度到服务器上面。

列如:

1
2
3
kubectl label node efk1.huisebug.com efknode=efk
kubectl label node efk2.huisebug.com efknode=efk
kubectl label node efk3.huisebug.com efknode=efk

我这里就不这样进行操作了,还是将efk服务安装到整个集群中

yaml文件下载地址

参考我的git地址

1
git clone https://github.com/huisebug/EFK.git

ElasticSearch

  • ES的官网推荐,不太推荐使用分布式文件系统(NFS/GlusterFS等)来进行数据的存储,对ES的性能会造成很大的影响。
  • 这里我就不使用之前搭建的GlusterFS系统了。使用 local-storage(1.9版本引入,将本地存储以PV形式提供给容器进行使用,实现存储空间的管理)作为storageClassName,PVC概念参考官方网址
    https://www.kubernetes.org.cn/pvpvcstorageclass

local-storage

三台服务器都要执行

新加硬盘

所以此处我们新加硬盘来建立local-storage

我这里是虚拟机,可以直接增加新硬盘SCSI接口硬盘进行热插拔,不重启系统,刷新出硬盘

1
2
3
4
5
$ ls /sys/class/scsi_host/
$ echo "- - -" > /sys/class/scsi_host/host0/scan
$ echo "- - -" > /sys/class/scsi_host/host1/scan
$ echo "- - -" > /sys/class/scsi_host/host2/scan
$ fdisk -l

上面的sdc硬盘20G就是我新加的硬盘

分区格式化并挂载到各宿主机的/data目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ fdisk -l /dev/sdc

# 建立分区并格式化为xfs类型
$ fdisk /dev/sdc
1. n 建立新分区
2. p 建立主分区
3. 1 分区号为1
4. 一直回车默认,将整块磁盘建立为一个分区,使用全部空间
5. w 保存退出

# 使分区生效
$ partprobe /dev/sdc

# 强制格式化为xfs
$ mkfs.xfs -f /dev/sdc1

# 手动将/dev/sdc1分区挂载到/data
$ mkdir /data && mount /dev/sdc1 /data

# 开机自动挂载
$ echo "/dev/sdc1 /data xfs defaults 0 0" >> /etc/fstab

# 查看挂载状态
$ df -hT

建立相应的PV

参考地址:
https://github.com/huisebug/EFK/blob/master/efkyaml/es-pv-api.yaml
https://github.com/huisebug/EFK/blob/master/efkyaml/es-pv-node1.yaml
https://github.com/huisebug/EFK/blob/master/efkyaml/es-pv-node2.yaml

注意:存储大小,别超过实际大小;指定正确的存储类型;指定正确的本地路径;指定连接的服务器主机名

  • accessModes:
    - ReadWriteOnce 注意这里定义的访问模式是单个节点读写。即一个pv只给一个pvc使用,像我们这里是3个pv,那么只能有3个pod调用pv,就算定义为ReadWriteMany也是如此。
    
  • 回收策略persistentVolumeReclaimPolicy: Retain保留
    该Retain回收政策允许资源的回收手册。当PersistentVolumeClaim删除时,PersistentVolume仍然存在,并且该卷被视为“已释放”。但它尚未提供另一项索赔,因为之前的索赔人的数据仍在数量上。管理员可以使用以下步骤手动回收卷。
  1. 删除PersistentVolume。删除PV后,外部基础架构(例如AWS EBS,GCEPD,Azure磁盘或Cinder卷)中的关联存储资产仍然存在。
  2. 相应地手动清理相关存储资产上的数据。
  3. 手动删除关联的存储资产,或者如果要重用同一存储资产,请PersistentVolume使用存储资产定义创建新的存储资产。

建立pv

1
kubectl apply -f es-pv-api.yaml -f es-pv-node1.yaml -f es-pv-node2.yaml

Elasticsearch安装

Elasticsearch最佳实践建议将节点分成三个角色:

  • Master 节点 - 仅用于集群管理,无数据,无HTTP API
  • Data 节点 - 用于客户端使用和数据
  • Ingest 节点 - 用于摄取期间的文档预处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Master节点		
    es-master-discovery-svc.yaml
    es-master-pdb.yaml
    es-master-stateful.yaml
    es-master-svc.yaml
    Data节点
    es-data-pdb.yaml
    es-data-stateful.yaml
    es-svc.yaml
    Ingest 节点
    es-ingest-deployment.yaml
    es-ingest-svc.yaml

(非常)重要说明

  • Elasticsearch pod需要init-container以特权模式运行,因此它可以设置一些VM选项。为此,kubelet应该使用args运行–allow-privileged,否则init-container将无法运行。
  • 默认情况下,ES_JAVA_OPTS设置为-Xms256m -Xmx256m。这是一个非常低的值,但许多用户,即minikube用户,由于主机内存不足而导致pod被杀的问题。可以在此存储库中可用的部署描述符中更改此设置。此处我的data就修改为了1024m,如果报错,请根据日志信息(kubectllogs es-data-0 -n efk)获取的日志信息来进行调整。
  • 目前,Kubernetes pod描述符emptyDir用于在每个数据节点容器中存储数据。这是为了简单起见,应根据一个人的存储需求进行调整。
  • statefulset包含部署数据豆荚作为一个例子StatefulSet。这些使用一个volumeClaimTemplates为每个pod配置持久存储。此处已经说明了pv建立时模式是单节点的,所以可根据自己需求来进行调整两个statefulset的replicas数量(此处我是data1个 master 2个。)
  • 默认情况下,PROCESSORS设置为1。对于某些部署,这可能是不够的,尤其是在启动时。根据需要调整resources.limits.cpu和或livenessProbe相应。请注意,resources.limits.cpu必须是整数。
  • elasticsearch的服务端和访问的客户端版本必须一致,不然会导致elasticsearch服务停掉。列如我这里对应版本为
    1
    2
    3
    4
    >   elasticsearch:6.3.2
    > fluentd-elasticsearch:2.4.0
    > fluent-bit:0.13.2
    > kibana:6.3.2
    常见问题

为什么NUMBER_OF_MASTERS与master-replicas的数量不同?

  • 之前master-replicas的数量是3,因为pv的模式问题,我修改为了2;
  • 此环境变量的默认值为2,表示群集至少需要2个主节点才能运行。如果一个集群有3个主服务器并且有一个管理器死亡,则集群仍可正常工通常是最小主节点n/2 +1,其中n是群集中主节点的数量。如果一个集群有5个主节点,则一个节点应该至少有3个节点,小于该节点并且集群停止。如果缩放主数量,请确保通过Elasticsearch API更新主节点的最小数量,因为设置环境变量仅适用于群集设置。

检查是否成功建立

pv和pvc

pod

Clean-up with Curator

主要用于清理elasticsearch超过天数的数据,更多高级用法参考官方网站
https://www.elastic.co/guide/en/elasticsearch/client/curator/current/index.html

创建curator

使用到的yaml

1
2
es-curator-configmap.yaml 
es-curator-cronJob.yaml

我们将其设置为一个定时任务,每天1点整进行清理超过3天的数据

Kibana

  • Kibana是一个开源的分析和可视化平台,设计用于和Elasticsearch一起工作。
  • 你用Kibana来搜索,查看,并和存储在Elasticsearch索引中的数据进行交互。
  • 你可以轻松地执行高级数据分析,并且以各种图标、表格和地图的形式可视化数据。
  • Kibana使得理解大量数据变得很容易。它简单的、基于浏览器的界面使你能够快速创建和共享动态仪表板,实时显示Elasticsearch查询的变化。

使用到的yaml文件

1
2
3
4
kibana-configmap.yaml 
kibana-deployment.yaml
kibana-ingress.yaml
kibana-svc.yaml

kibana的汉化

kibana的汉化方式,已经放到了Docker目录下,也可以使用我已经汉化好的镜像

验证效果

Fluent

组件 用途
Fluent Bit 拉起在每台宿主机上采集宿主机上的容器日志。(Fluent Bit 比较新一些,但是资源消耗比较低,性能比Fluentd好一些,但稳定性有待于进一步提升)
Fluentd 两个用途:1 以日志收集中转中心角色拉起,Deployment部署模式;2 在部分Fluent Bit无法正常运行的主机上,以Daemon Set模式运行采集宿主机上的日志,并发送给日志收集中转中心
ElasticSearch 用来接收日志收集中转中心发送过来的日志,并通过Kibana分析展示出来,鉴于硬件资源有限,仅保留一周左右的数据。
Amazon S3(fluentd server) 用来接收日志收集中转中心发送过来的日志,对日志进行压缩归档,也可后续使用Spark进行进一步大数据分析。

fluentd直接传递es建立

此处我们演示fluentd直接向elasticsearch传递数据建立使用,使用到的yaml分别如下
fluentd

1
2
fluentd-es-configmap.yaml 
fluentd-es-daemonset.yaml

给 Node 设置标签

定义fluentd-es-daemonset.yaml时设置了nodeSelector beta.kubernetes.io/fluentd-ds-ready=true,所以需要在期望运⾏fluentd 的 Node上设置该标签;

1
for i in api.huisebug.com node1.huisebug.com node2.huisebug.com; do kubectl label nodes $i beta.kubernetes.io/fluentd-ds-ready=true; done

我们这里是新建一个namespace:efk,所以建立fluentd-es-daemonset.yaml不能使用pod优先级priorityClassName:system-node-critical,需要注释掉。

查看是否成功建立

验证整个EFK效果

添加kibana检测到fluent传递给es的日志信息,并建立索引,如果整个集群没有建立成功,是不会自动出现如下界面的。




fluentd传递S3然后传递es

Amazon S3镜像建立

基于官方镜像添加对S3的支持,可在Docker目录下查找到Dockerfile,参考地址:
https://github.com/huisebug/EFK/blob/master/fluentd/Docker/Dockerfile

1
2
3
4
5
FROM huisebug/sec_re:fluentd-elasticsearch-2.4.0
RUN \
apt-get update -y && apt-get install ruby-dev -y && \
gem install fluent-plugin-s3 && \
apt-get clean

也可以直接使用我已经上传到dockerhub的镜像

使用到的yaml文件

fluentd

1
2
fluentd-es-f-configmap.yaml  
fluentd-es-f-daemonset.yaml

S3

1
2
fluentd-server-s3-configmap.yaml  
fluentd-server-s3-deployment.yaml

其中的fluentd-es-f-daemonset.yaml与之前的fluentd-es-daemonset.yaml内容相同,这里我为了便于区分。

fluentd-es-f-configmap.yaml 内容变更如下:

  • 调整output.conf。
  • 移除ES片段。
  • 添加forward片段。

注意!!!

为了不影响测试效果,我们需要删除es建立的数据,并重新建立,切换到es的yaml文件所在目录
api.huisebug.com主机:

1
kubectl delete -f . && rm -rf /data/*

其余节点主机:

1
rm -rf /data/*

并且删除之前直接传递建立的fluentd

1
kubectl delete -f fluentd-es-configmap.yaml -f fluentd-es-daemonset.yaml

查看效果

访问kibana验证

fluentd bit传递到S3然后传递es

使用到的yaml文件

fluentd-bit

1
2
fluentd-bit-es-f-configmap.yaml  
fluentd-bit-es-f-daemonset.yaml

S3

1
2
fluentd-bit-server-s3-configmap.yaml  
fluentd-bit-server-s3-deployment.yaml

其中的S3使用的yaml内容与之前的内容相同,这里我为了便于区分。

注意!!!

为了不影响测试效果,我们需要删除es建立的数据,并重新建立,切换到es的yaml文件所在目录

api.huisebug.com主机:

1
kubectl delete -f . && rm -rf /data/*

其余节点主机:

1
rm -rf /data/*

并且删除之前直接传递建立的fluentd-s3

1
kubectl delete -f fluentd-es-f-configmap.yaml -f fluentd-es-f-daemonset.yaml

查看效果

GlusterFS+Heketi+EFK

适用于生产环境

参考yaml文件

https://github.com/huisebug/GlusterFS-Heketi-EFK.git

三个文件夹,其他文件夹目录内容不变,这里主要需要修改ekheketi文件中的内容

ekheketi


将之前的ElasticSearch服务的三个角色分类文件目录存放,修改statefulset使用到的pvc的为storageClassName:
gluster-heketi,如下

即可完成!!!

此处整个efk集群使用到pvc的有es-master和es-data。

搭建完成后查看是否成功