Saat cluster kubernetes anda mulai banyak, mungkin kepikiran untuk centralize lognya, karena untuk melihat log satu persatu dari tiap pod/container akan makan waktu, belum lagi log dari container yang sudah di hapus/terminate akan hilang bersama dengan containternya. Semua log dari pod, namespace akan dikirim ke Elasticsearch.
Untuk kebutuhan centralize log ini kita akan menyimpan lognya di elasticsearch, yang di proses oleh fluentd. Fluentd sendiri adalah data colector yang memproses data agar lebih mudah dipahami, dengan fluentd kita bisa mengirim data ke berbagai tempat, contoh Elasticsearch, Sumo Logic, AWS S3, MySQL dan lain sebagainya. Untuk log yang lebih kompleks fluentd bisa menggunakan berbagai plugin yang tersedia, tetapi tidak akan kita bahas disini. Saya menggunakan Kubernetes Linode (bila anda daftar menggunakan affiliate link ini akan mendapatkan credit $100 selama 60 hari)
Untuk kebutuhan log ini akan kita gunakan :
Fluentd versi 1.13.0
Kubernetes 1.21.0 (bisa juga 1.19+)
Buat Namespace
Buat namespace baru, elasticsearch akan kita letakkan di namespace ini. Ini opsional, bila anda memilih menggunakan namespace yang lain atau default bawaan kubernetes tidak berpengaruh
kubectl create namespace log
1. Deployment Elasticsearch
Disini bisa saja kita menggunakan Elasticsearch yang ada di service yang berbeda, contoh cloud.elastic.co atau lainnya tetapi untuk lebih mendalami proses pembuatan log ini, sebaiknya kita buat Elasticsearch. Disini kita bisa menggunakan versi yang kita inginkan, selain itu juga menambahkan Kibana untuk mempermudah navigasi log Elasticsearch.
Buat file elastic.yaml
untuk deployment Elasticsearch yang berisi
apiVersion: apps/v1 kind: Deployment metadata: name: elasticsearch spec: selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0 env: - name: discovery.type value: single-node ports: - containerPort: 9200 resources: limits: cpu: 500m memory: 4Gi requests: cpu: 300m memory: 2Gi --- apiVersion: v1 kind: Service metadata: name: elasticsearch labels: service: elasticsearch spec: type: NodePort selector: app: elasticsearch ports: - port: 9200 targetPort: 9200
di deployment ini kita akan membuat service dengan nama elasticsearch
, service digunakan agar pod kubernetes bisa diakses menggunakan DNS/IP Address dari luar POD ataupun namespace nya. Untuk mengakses service kubernetes ini cukup menggunakan nama elasticsearch.log
tanpa perlu mengingat IP address, sehingga memudahkan proses deployment.
deploy elastic search dengan kubectl
kubectl apply -f elastic.yaml --namespace log
cek status deployment
kubectl get pods,services -n log # contoh output NAME READY STATUS RESTARTS AGE pod/elasticsearch-646cf66d79-h2899 1/1 Running 0 3h19m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch NodePort 10.128.215.140 <none> 9200:30547/TCP 3h19m
2. Fluentd RBAC
Role-based access control (RBAC) adalah metode yang digunakan untuk memberikan akses terhadap resource yang ada dikubernetes berdasarkan role. Contoh role disini adalah akses untuk melihat log dari setiap pod yang ada dikubernetes tanpa batasan namespace, akses penuh terhadap namespace tertentu.
Buat file fluentd-rbac.yaml
yang berisi
apiVersion: v1 kind: ServiceAccount metadata: name: fluentd namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: fluentd namespace: kube-system rules: - apiGroups: - "" resources: - pods - namespaces verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: fluentd subjects: - kind: ServiceAccount name: fluentd namespace: kube-system roleRef: kind: ClusterRole name: fluentd apiGroup: rbac.authorization.k8s.io
deploy dengan
kubectl apply -f fluentd-rbac.yaml
3. Fluentd POD Daemonset
Yang bertanggung jawab memproses log dari STDOUT docker adalah container fluentd yang ada disini. Container fluentd ini juga yang bertanggung jawab untuk mengirim log ke Elasticsearch.
buat file fluentd-daemonset.yaml
yang berisi
apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-logging namespace: kube-system labels: k8s-app: fluentd-logging spec: selector: matchLabels: name: fluentd-logging template: metadata: labels: name: fluentd-logging spec: serviceAccount: fluentd serviceAccountName: fluentd tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.13-debian-elasticsearch7-1 env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.log" - name: FLUENT_ELASTICSEARCH_PORT value: "9200" - name: FLUENT_ELASTICSEARCH_SCHEME value: "http" - name: FLUENT_UID value: "0" - name: FLUENTD_SYSTEMD_CONF value: "disable" resources: limits: memory: 200M requests: cpu: 100m memory: 100M volumeMounts: - name: systemlog mountPath: /var/log - name: dockercontainer mountPath: /var/lib/docker/containers readOnly: true terminationGracePeriodSeconds: 20 volumes: - name: systemlog hostPath: path: /var/log - name: dockercontainer hostPath: path: /var/lib/docker/containers
deploy dengan
kubectl apply -f fluentd-daemonset.yaml
cek status deployment daemonset
kubectl get daemonsets -n kube-system # output NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE calico-node 1 1 1 1 1 kubernetes.io/os=linux 3h53m csi-linode-node 1 1 1 1 1 <none> 3h53m fluentd-logging 1 1 1 1 1 <none> 79m kube-proxy 1 1 1 1 1 <none> 3h53m
4. Cek Log
Untuk testing apakah semua berjalan dengan normal, kita buat dua POD di namespace yang berbeda
kubectl run fedora --namespace log --image=fedora --restart=Never --command -- sh -c 'for i in $(seq 1 300); do echo "$(date) centrallogkubernetes jaranguda $i"; done' kubectl run fedora --namespace default --image=fedora --restart=Never --command -- sh -c 'for i in $(seq 1 300); do echo "$(date) centrallogkubernetes jaranguda $i"; done'
dari perintah diatas, akan menghasilan log seperti
Wed Aug 11 09:23:00 UTC 2021 centrallogkubernetes jaranguda 278 Wed Aug 11 09:23:00 UTC 2021 centrallogkubernetes jaranguda 279
Cek pod elasticsearch
kubectl get pods --namespace log | grep elasticsearch # output elasticsearch-646cf66d79-h2899 1/1 Running 0 4h16m
Buka shell dari pod tersebut
kubectl --namespace log exec --tty --stdin elasticsearch-646cf66d79-h2899 -- bash
ganti elasticsearch-646cf66d79-h2899
dengan nama pod diatas, cek lognya dengan menggunakan curl
curl -s "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "multi_match" : { "query": "centrallogkubernetes" } } } '
contoh outputnya
{ "_index" : "logstash-2021.08.11", "_type" : "_doc", "_id" : "l_2dNHsB2Tj_9CzcE18q", "_score" : 4.2414064, "_source" : { "log" : "Wed Aug 11 09:48:08 UTC 2021 centrallogkubernetes jaranguda 10\n", "stream" : "stdout", "docker" : { "container_id" : "da5431a42e8f249ce1d5057723906e8532f20fc227ec90b9d8ec1d03e2f39ae2" }, "kubernetes" : { "container_name" : "fedora", "namespace_name" : "log", "pod_name" : "fedora", "container_image" : "fedora:latest", "container_image_id" : "docker-pullable://fedora@sha256:d18bc88f640bc3e88bbfacaff698c3e1e83cae649019657a3880881f2549a1d0", "pod_id" : "721f3d07-d246-45ee-b6a2-0c44915b7953", "pod_ip" : "10.2.157.29", "host" : "lke34062-52617-611359b7a1bb", "labels" : { "run" : "fedora" }, "master_url" : "https://10.128.0.1:443/api", "namespace_id" : "4cd15297-1d31-4406-bcc0-8ff85826aec6", "namespace_labels" : { "kubernetes_io/metadata_name" : "log" } }, "@timestamp" : "2021-08-11T09:48:08.609137028+00:00", "tag" : "kubernetes.var.log.containers.fedora_log_fedora-da5431a42e8f249ce1d5057723906e8532f20fc227ec90b9d8ec1d03e2f39ae2.log" } }
bila menggunakan Kibana, cukup menggunakan query centrallogkubernetes