๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Cloud/Kubernetes

[k8s] Kubernetes ๋กœ๊ทธ - EFK ๊ตฌ์ถ•

by The Future Engineer, Lucy 2024. 9. 28.
 

Kubernetes ๋กœ๊ทธ - EFK ๊ฐœ์š”

EFK๋ž€?Elasticsearch+Fluent Bit/Fluentd+Kibana์˜ ์กฐํ•ฉ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์•ž๊ธ€์ž๋ฅผ ๋”ฐ์„œ EFK๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘, ์ €์žฅ, ๋ถ„์„ํ•˜๊ณ  ์‹œ๊ฐํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ์Šคํƒ์ž…๋‹ˆ๋‹ค.Flunetd์™€ Fluent Bi

lucy-devblog.tistory.com

์ด์ „ ํฌ์ŠคํŠธ์—์„œ EFK์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ EFK๋ฅผ ์ง์ ‘ ๊ตฌ์ถ•ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Fluent Bit ๊ตฌ์„ฑ

fluent bit๋Š” helm์„ ํ†ตํ•ด ์„ค์น˜ํ–ˆ์Šต๋‹ˆ๋‹ค.
helm install์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ „ values.yaml์—์„œ config ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
fluent bit๋Š” Daemonset์œผ๋กœ ๊ฐ ๋…ธ๋“œ๋ณ„๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

helm repo add fluent https://fluent.github.io/helm-charts
helm fetch fluent/fluent-bit --untar
helm install fluent-bit fluent/fluent-bit -f values.yaml # values.yaml ํŒŒ์ผ ์ˆ˜์ • ํ›„ ์‹คํ–‰
config:
  service: |
    [SERVICE]
        Daemon Off
        Flush {{ .Values.flush }}
        Log_Level {{ .Values.logLevel }}
        Parsers_File /fluent-bit/etc/conf/custom_parsers.conf
        HTTP_Server On
        HTTP_Listen 0.0.0.0
        HTTP_Port {{ .Values.metricsPort }}
        Health_Check On

  inputs: |
    [INPUT]
        Name              tail
        Path              /var/log/containers/*.log
        Parser            cri
        Tag               kube.*
        Mem_Buf_Limit     5MB
        Skip_Long_Lines   Off

    [INPUT]
        Name            systemd
        Tag             host.*
        Systemd_Filter  _SYSTEMD_UNIT=kubelet.service
        Read_From_Tail  On

  filters: |
    [FILTER]
        Name                kubernetes
        Match               kube.*
        Merge_Log           On
        Keep_Log            Off
        K8S-Logging.Parser  On
        K8S-Logging.Exclude On

  outputs: |
    [OUTPUT]
        Name          es
        Match         *
        Host          elasticsearch.logging
        Port          9200
        Logstash_Format Off

 

Elasticsearch ๊ตฌ์„ฑ

Elasticsearch๋Š” 8.0 ์ดํ›„ ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” security๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ enabled ์ƒํƒœ์ž…๋‹ˆ๋‹ค. security๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ 7.17.0 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Elasticsearch์™€ Kibana ์—ฐ๋™ ์‹œ ๊ฐ™์€ ๋ฒ„์ „์œผ๋กœ ์ง„ํ–‰ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์•„๋ž˜ ์ฝ”๋“œ๋Š” ํ˜„์žฌ Minimal Security๊นŒ์ง€๋งŒ ๋˜์–ด์žˆ์œผ๋ฉฐ, Alert ๊ธฐ๋Šฅ๊นŒ์ง€๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: elasticsearch-service-account
  namespace: logging

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: elasticsearch-cluster-role
  namespace: logging
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/exec", "services", "endpoints"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments", "statefulsets", "replicasets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["extensions"]
    resources: ["ingresses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["monitoring.coreos.com"]
    resources: ["servicemonitors", "prometheuses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["logging.k8s.io"]
    resources: ["logs"]
    verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: elasticsearch-cluster-role-binding
  namespace: logging
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: elasticsearch-cluster-role
subjects:
  - kind: ServiceAccount
    name: elasticsearch-service-account
    namespace: logging
apiVersion: v1
kind: ConfigMap
metadata:
  name: elasticsearch-config
  namespace: logging
data:
  elasticsearch.yml: |
    network.host: 0.0.0.0
    http.port: 9200
    discovery.seed_hosts: ["elasticsearch-discovery"]
    xpack.security.enabled: true
    xpack.license.self_generated.type: basic
    xpack.security.authc.api_key.enabled: true
apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
  namespace: logging
  labels:
    app: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      serviceAccountName: elasticsearch-service-account
      containers:
        - name: elasticsearch
          image: elasticsearch:7.17.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9200
            - containerPort: 9300
          env:
            - name: discovery.type
              value: "single-node"
            - name: ES_JAVA_OPTS
              value: "-Xms500m -Xmx1000m"
          volumeMounts:
            - name: elasticsearch-config
              mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
              subPath: elasticsearch.yml
            - name: elasticsearch-data
              mountPath: /usr/share/elasticsearch/data
      volumes:
        - name: elasticsearch-config
          configMap:
            name: elasticsearch-config
        - name: elasticsearch-data
          emptyDir: {}

---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: logging
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  ports:
    - name: elasticsearch
      port: 9200
      protocol: TCP
      targetPort: 9200
    - name: elasticsearch-ssl
      port: 9300
      protocol: TCP
      targetPort: 9300

Kibana ๊ตฌ์„ฑ

Kibana๋ฅผ ํ†ตํ•ด Slack ์•Œ๋ฆผ๊นŒ์ง€ ์—ฐ๋™ํ•˜๊ณ  ์‹ถ์—ˆ์œผ๋‚˜ ์ด ๊ธฐ๋Šฅ์€ ์œ ๋ฃŒ์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
Elasticsearch์˜ Security๋ฅผ Basic security +  SSL/TLS๋กœ ์„ค์ •ํ•˜๋ฉด 14์ผ trial ๋ฒ„์ „์œผ๋กœ ์‚ฌ์šฉํ•ด ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

apiVersion: v1
kind: ConfigMap
metadata:
  name: kibana-config
  namespace: logging
  labels:
    app: kibana
data:
  kibana.yml: |
    server.host: "0.0.0.0"
    elasticsearch.hosts: [ "http://elasticsearch.logging:9200" ]
    server.publicBaseUrl: ${{ secrets.SERVER_NAME }}
    elasticsearch.username: "${ ELASTICSEARCH_USERNAME }"
    elasticsearch.password: "${ ELASTICSEARCH_PASSWORD }"
    xpack.encryptedSavedObjects.encryptionKey: ${{ vars.ENCRYPTEDSAVEDOBJECTS }}
    xpack.reporting.encryptionKey: ${{ vars.REPORTING }}
    xpack.security.encryptionKey: ${{ vars.SECURITY }}
    xpack.security.enabled: true
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      name: kibana
      labels:
        app: kibana
    spec:
      containers:
        - name: kibana
          image: kibana:7.17.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 5601
              protocol: TCP
          volumeMounts:
            - mountPath: /usr/share/kibana/config/kibana.yml
              name: config
              subPath: kibana.yml
          env:
            - name: ELASTICSEARCH_URL
              value: http://elasticsearch.logging:9200
            - name: discovery.type
              value: single-node
            - name: ELASTICSEARCH_USERNAME
              value: ${{ secrets.ELASTICSEARCH_USERNAME }}
            - name: ELASTICSEARCH_PASSWORD
              value: ${{ secrets.ELASTICSEARCH_PASSWORD }}
            - name: SERVER_NAME
              value: ${{ secrets.SERVER_NAME }}
      volumes:
        - name: config
          configMap:
            name: kibana-config

---
apiVersion: v1
kind: Service
metadata:
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  selector:
    app: kibana
  ports:
    - nodePort: 30651
      port: 5601
      protocol: TCP
      targetPort: 5601
  type: NodePort
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kibana-ingress
  namespace: logging
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
  labels:
    name: kibana-ingress
spec:
  ingressClassName: "alb-ingress-class"
  rules:
    - host: ${{ secrets.SERVER_NAME }}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kibana
                port:
                  number: 5601

AWSํ™˜๊ฒฝ์ด ์•„๋‹Œ ๊ฒฝ์šฐ Ingress Class๋ฅผ ์„ค์น˜ ํ›„ ์ง„ํ–‰ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ €๋Š” ํ˜„์žฌ AWS์˜ EKS ํ™˜๊ฒฝ์—์„œ ๊ตฌ์ถ•ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— annotations๋ถ€๋ถ„์„ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
SSL๊ณผ TLS ์„ค์ •์€ ๊ณ„์† ๋ง‰ํ˜€์„œ ์ถ”ํ›„ ์„ฑ๊ณตํ•˜๋ฉด ์˜ฌ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.๐Ÿฅฒ
๋‹ค์Œ์€ PLG ๊ฐœ์š” ๋ฐ ๊ตฌ์ถ•๊ณผ slack ์•Œ๋ฆผ ์—ฐ๋™์— ๋Œ€ํ•ด์„œ ์˜ฌ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

'Cloud > Kubernetes' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Kubernetes] kind๋กœ ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑํ•˜๊ธฐ  (0) 2024.10.21
[k8s] Kubernetes ๋กœ๊ทธ - EFK ๊ฐœ์š”  (1) 2024.09.28