在 Kubernetes 集群部署 ECK
https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-eck.html
~]# kubectl create -f https://download.elastic.co/downloads/eck/2.9.0/crds.yaml
customresourcedefinition.apiextensions.k8s.io/agents.agent.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/apmservers.apm.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/beats.beat.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/elasticmapsservers.maps.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/elasticsearches.elasticsearch.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/enterprisesearches.enterprisesearch.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/kibanas.kibana.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/logstashes.logstash.k8s.elastic.co created
~]# kubectl apply -f https://download.elastic.co/downloads/eck/2.9.0/operator.yaml
~]# kubectl -n elastic-system logs -f statefulset.apps/elastic-operator
部署 ElasticSearch 集群
这里将 es、kibana、filebeat 部署在一个单独的 namespace,首先创建 namespace
~]# kubectl create ns efk-stack
namespace/efk-stack created
部署elasticsearch,这里使用 longhorn 存储持久化数据
~]# cat <<EOF | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elasticsearch
namespace: efk-stack
spec:
version: 8.9.0
nodeSets:
- name: default
count: 3
config:
node.store.allow_mmap: false
volumeClaimTemplates:
- metadata:
name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: longhorn
EOF
# elasticsearch集群创建成功
~]# kubectl get po -n efk-stack
NAME READY STATUS RESTARTS AGE
elasticsearch-es-default-0 1/1 Running 0 2m20s
elasticsearch-es-default-1 1/1 Running 0 2m20s
elasticsearch-es-default-2 1/1 Running 0 2m20s
~]# kubectl get svc -n efk-stack
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-es-default ClusterIP None <none> 9200/TCP 4m9s
elasticsearch-es-http ClusterIP 172.20.116.154 <none> 9200/TCP 4m11s
elasticsearch-es-internal-http ClusterIP 172.20.78.23 <none> 9200/TCP 4m11s
elasticsearch-es-transport ClusterIP None <none> 9300/TCP 4m11s
~]# kubectl get secrets -n efk-stack
NAME TYPE DATA AGE
elasticsearch-es-default-es-config Opaque 1 19m
elasticsearch-es-default-es-transport-certs Opaque 7 19m
elasticsearch-es-elastic-user Opaque 1 19m
elasticsearch-es-file-settings Opaque 1 19m
elasticsearch-es-http-ca-internal Opaque 2 19m
elasticsearch-es-http-certs-internal Opaque 3 19m
elasticsearch-es-http-certs-public Opaque 2 19m
elasticsearch-es-internal-users Opaque 4 19m
elasticsearch-es-remote-ca Opaque 1 19m
elasticsearch-es-transport-ca-internal Opaque 2 19m
elasticsearch-es-transport-certs-public Opaque 1 19m
elasticsearch-es-xpack-file-realm Opaque 4 19m
# 查看 elastic 密码
~]# PASSWORD=$(kubectl get secret elasticsearch-es-elastic-user -n efk-stack -o go-template='{{.data.elastic | base64decode}}')
~]# echo $PASSWORD
4xi5jtTwK8tV6Y2H54rq771A
~]# curl -u "elastic:4xi5jtTwK8tV6Y2H54rq771A" -k "https://172.20.116.154:9200"
{
"name" : "elasticsearch-es-default-0",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "Fs6JRC4KQROJpJ56XyAu2w",
"version" : {
"number" : "8.9.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "8aa461beb06aa0417a231c345a1b8c38fb498a0d",
"build_date" : "2023-07-19T14:43:58.555259655Z",
"build_snapshot" : false,
"lucene_version" : "9.7.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
部署kibana
https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-kibana.html
~]# cat <<EOF | kubectl apply -f -
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: kibana
namespace: efk-stack
spec:
version: 8.9.0
count: 1
elasticsearchRef:
name: elasticsearch
EOF
~]# kubectl get po -n efk-stack
NAME READY STATUS RESTARTS AGE
elasticsearch-es-default-0 1/1 Running 0 25m
elasticsearch-es-default-1 1/1 Running 0 25m
elasticsearch-es-default-2 1/1 Running 0 25m
kibana-kb-699bf98668-ptgvf 1/1 Running 0 68s
~]# kubectl get svc -n efk-stack
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-es-default ClusterIP None <none> 9200/TCP 25m
elasticsearch-es-http ClusterIP 172.20.116.154 <none> 9200/TCP 25m
elasticsearch-es-internal-http ClusterIP 172.20.78.23 <none> 9200/TCP 25m
elasticsearch-es-transport ClusterIP None <none> 9300/TCP 25m
kibana-kb-http ClusterIP 172.20.35.127 <none> 5601/TCP 58s
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kibana
namespace: efk-stack
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
labels:
app: kibana
spec:
ingressClassName: nginx
rules:
- host: kibana.example.io
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: kibana-kb-http
port:
number: 5601
EOF
~]# kubectl get ingress -n efk-stack
NAME CLASS HOSTS ADDRESS PORTS AGE
kibana nginx kibana.example.io 192.168.36.153,192.168.36.154,192.168.36.155 80 31s
部署 filebeat 采集 POD 日志
~]# cat filebeat_autodiscover.yaml
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: filebeat
namespace: efk-stack
spec:
type: filebeat
version: 8.9.0
elasticsearchRef:
name: elasticsearch
kibanaRef:
name: kibana
config:
filebeat:
autodiscover:
providers:
- type: kubernetes
node: ${NODE_NAME}
hints:
enabled: true
default_config:
type: container
paths:
- /var/log/containers/*${data.kubernetes.container.id}.log
processors:
- add_cloud_metadata: {}
- add_host_metadata: {}
daemonSet:
podTemplate:
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
serviceAccountName: filebeat
automountServiceAccountToken: true
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true # Allows to provide richer host metadata
containers:
- name: filebeat
securityContext:
runAsUser: 0
# If using Red Hat OpenShift uncomment this:
#privileged: true
volumeMounts:
- name: varlogcontainers
mountPath: /var/log/containers
- name: varlogpods
mountPath: /var/log/pods
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumes:
- name: varlogcontainers
hostPath:
path: /var/log/containers
- name: varlogpods
hostPath:
path: /var/log/pods
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
resources:
- namespaces
- pods
- nodes
verbs:
- get
- watch
- list
- apiGroups: ["apps"]
resources:
- replicasets
verbs:
- get
- list
- watch
- apiGroups: ["batch"]
resources:
- jobs
verbs:
- get
- list
- watch
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: default
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
---
~]# kubectl apply -f filebeat_autodiscover.yaml
beat.beat.k8s.elastic.co/filebeat created
clusterrole.rbac.authorization.k8s.io/filebeat created
serviceaccount/filebeat created
clusterrolebinding.rbac.authorization.k8s.io/filebeat created
~]# kubectl get po -n efk-stack
NAME READY STATUS RESTARTS AGE
elasticsearch-es-default-0 1/1 Running 0 48m
elasticsearch-es-default-1 1/1 Running 0 48m
elasticsearch-es-default-2 1/1 Running 0 48m
filebeat-beat-filebeat-2f9cx 1/1 Running 0 5s
filebeat-beat-filebeat-l5vr8 1/1 Running 0 5s
filebeat-beat-filebeat-ph4rg 1/1 Running 0 5s
filebeat-beat-filebeat-qgk6t 1/1 Running 0 5s
filebeat-beat-filebeat-rr6tn 1/1 Running 0 5s
kibana-kb-699bf98668-ptgvf 1/1 Running 0 23m