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 :

Elasticsearch versi 7.14.0
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

Leave a comment

Your email address will not be published. Required fields are marked *