Thứ hai, 30/03/2020 | 00:00 GMT+7

Cách thiết lập ngăn ghi log Elasticsearch, Fluentd và Kibana (EFK) trên Kubernetes

Khi chạy nhiều dịch vụ và ứng dụng trên một cụm Kubernetes, ngăn xếp ghi log cấp cụm, tập trung có thể giúp bạn nhanh chóng sắp xếp và phân tích dung lượng lớn dữ liệu log do Pod của bạn tạo ra. Một giải pháp ghi log tập trung phổ biến là ngăn xếp E lasticsearch, F luentd và K ibana (EFK).

Elasticsearch là một công cụ tìm kiếm theo thời gian thực, phân tán và có thể mở rộng cho phép tìm kiếm toàn văn và có cấu trúc, cũng như phân tích. Nó thường được sử dụng để lập index và tìm kiếm thông qua dung lượng lớn dữ liệu log , nhưng cũng được dùng để tìm kiếm nhiều loại tài liệu khác nhau.

Elasticsearch thường được triển khai cùng với Kibana , một giao diện và console trực quan hóa dữ liệu mạnh mẽ cho Elasticsearch. Kibana cho phép bạn khám phá dữ liệu log Elasticsearch của bạn thông qua giao diện web, đồng thời xây dựng các trang tổng quan và truy vấn để nhanh chóng trả lời các câu hỏi cũng như hiểu rõ hơn về các ứng dụng Kubernetes của bạn.

Trong hướng dẫn này, ta sẽ sử dụng Fluentd để thu thập, chuyển đổi và chuyển dữ liệu log đến phần backend Elasticsearch. Fluentd là công cụ thu thập dữ liệu nguồn mở phổ biến mà ta sẽ cài đặt trên các node Kubernetes của bạn để điều chỉnh các file log containers , lọc và chuyển đổi dữ liệu log , đồng thời phân phối dữ liệu đó đến cụm Elasticsearch, nơi nó sẽ được lập index và lưu trữ.

Ta sẽ bắt đầu bằng cách cấu hình và chạy một cụm Elasticsearch có thể mở rộng, sau đó tạo Dịch vụ và Triển khai Kibana Kubernetes. Để kết luận, ta sẽ cài đặt Fluentd như một DaemonSet để nó chạy trên mọi nút công nhân Kubernetes.

Yêu cầu

Trước khi bạn bắt đầu với hướng dẫn này, hãy đảm bảo bạn có những thứ sau:

  • Một cụm Kubernetes 1.10+ với điều khiển truy cập dựa trên role (RBAC) được bật

    • Đảm bảo cụm của bạn có đủ tài nguyên để triển khai ngăn xếp EFK và nếu không mở rộng cụm của bạn bằng cách thêm các node công nhân. Ta sẽ triển khai cụm 3-Pod Elasticsearch (bạn có thể chia tỷ lệ này xuống 1 nếu cần), cũng như một Kibana Pod duy nhất. Mỗi nút công nhân cũng sẽ chạy Fluentd Pod. Cụm trong hướng dẫn này bao gồm 3 nút công nhân và một mặt phẳng điều khiển được quản lý.
  • Công cụ dòng lệnh kubectl được cài đặt trên máy local của bạn, được cấu hình để kết nối với cụm của bạn. Bạn có thể đọc thêm về cách cài đặt kubectl trong tài liệu chính thức .

Khi bạn đã cài đặt các thành phần này, bạn đã sẵn sàng để bắt đầu với hướng dẫn này.

Bước 1 - Tạo không gian tên

Trước khi ta triển khai cụm Elasticsearch, trước tiên ta sẽ tạo một Không gian tên để cài đặt tất cả các thiết bị ghi log của ta . Kubernetes cho phép bạn phân tách các đối tượng đang chạy trong cụm của bạn bằng cách sử dụng trừu tượng "cụm ảo" được gọi là Không gian tên. Trong hướng dẫn này, ta sẽ tạo một không gian tên kube-logging mà ta sẽ cài đặt các thành phần ngăn xếp EFK. Không gian tên này cũng sẽ cho phép ta nhanh chóng dọn dẹp và loại bỏ ngăn xếp ghi log mà không làm mất chức năng của cụm Kubernetes.

Để bắt đầu, trước tiên hãy điều tra các Không gian tên hiện có trong cụm của bạn bằng cách sử dụng kubectl :

  • kubectl get namespaces

Bạn sẽ thấy ba Không gian tên ban đầu sau đây, được cài đặt sẵn với cụm Kubernetes của bạn:

Output
NAME STATUS AGE default Active 5m kube-system Active 5m kube-public Active 5m

Không gian tên default chứa các đối tượng được tạo mà không chỉ định Không gian tên. Không gian tên kube-system chứa các đối tượng được tạo và sử dụng bởi hệ thống Kubernetes, như kube-dns , kube-proxykubernetes-dashboard . Thực hành tốt để giữ cho Không gian tên này sạch sẽ và không làm ô nhiễm nó với dung lượng công việc ứng dụng và thiết bị của bạn.

Không gian tên kube-public là một Không gian tên khác được tạo tự động được dùng để lưu trữ các đối tượng mà bạn muốn có thể đọc được và có thể truy cập được trong toàn bộ cụm, ngay cả với những user chưa được xác thực.

Để tạo Không gian tên kube-logging , trước tiên hãy mở và chỉnh sửa file có tên kube-logging.yaml bằng editor yêu thích của bạn, chẳng hạn như nano:

  • nano kube-logging.yaml

Bên trong editor , dán đối tượng Không gian tên sau YAML:

kube-logging.yaml
kind: Namespace apiVersion: v1 metadata:   name: kube-logging 

Sau đó, lưu file .

Ở đây, ta xác định đối tượng của Kubernetes kind như một Namespace đối tượng. Để tìm hiểu thêm về các đối tượng Namespace , hãy tham khảo Hướng dẫn về Không gian tên trong tài liệu chính thức của Kubernetes. Ta cũng chỉ định version Kubernetes API được sử dụng để tạo đối tượng ( v1 ) và name cho nó, kube-logging .

Khi bạn đã tạo file đối tượng Không gian tên kube-logging.yaml , hãy tạo Không gian tên bằng cách sử dụng kubectl create với cờ -f tên file :

  • kubectl create -f kube-logging.yaml

Bạn sẽ thấy kết quả sau:

Output
namespace/kube-logging created

Sau đó, bạn có thể xác nhận Không gian tên đã được tạo thành công:

  • kubectl get namespaces

Đến đây, bạn sẽ thấy Không gian tên kube-logging :

Output
NAME STATUS AGE default Active 23m kube-logging Active 1m kube-public Active 23m kube-system Active 23m

Bây giờ ta có thể triển khai một cụm Elasticsearch vào Không gian tên ghi log cô lập này.

Bước 2 - Tạo Elasticsearch StatefulSet

Bây giờ ta đã tạo một Không gian tên để chứa ngăn xếp log của bạn , ta có thể bắt đầu triển khai các thành phần khác nhau của nó. Đầu tiên ta sẽ bắt đầu bằng cách triển khai cụm Elasticsearch 3 nút.

Trong hướng dẫn này, ta sử dụng 3 Elasticsearch Pod để tránh vấn đề "phân chia não" xảy ra trong các cụm nhiều nút, có độ khả dụng cao. Ở cấp độ cao, "bộ não phân chia" là điều phát sinh khi một hoặc nhiều nút không thể giao tiếp với các node khác và một số nút chủ "phân tách" được bầu chọn. Với 3 nút, nếu một nút tạm thời bị ngắt kết nối khỏi cụm, hai nút còn lại có thể chọn một nút chính mới và cụm có thể tiếp tục hoạt động trong khi nút cuối cùng cố gắng tham gia lại. Để tìm hiểu thêm, hãy tham khảo Kỷ nguyên mới cho điều phối cụm trong cấu hình ElasticsearchBỏ phiếu .

Tạo dịch vụ không đầu

Để bắt đầu, ta sẽ tạo một không đầu dịch vụ Kubernetes gọi elasticsearch mà sẽ xác định một domain DNS cho 3 Pods. Dịch vụ không có đầu không thực hiện cân bằng tải hoặc có IP tĩnh; để tìm hiểu thêm về các dịch vụ không đầu, hãy tham khảo tài liệu chính thức của Kubernetes .

Mở một file có tên elasticsearch_svc.yaml bằng editor yêu thích của bạn:

  • nano elasticsearch_svc.yaml

Dán vào YAML dịch vụ Kubernetes sau:

asticsearch_svc.yaml
kind: Service apiVersion: v1 metadata:   name: elasticsearch   namespace: kube-logging   labels:     app: elasticsearch spec:   selector:     app: elasticsearch   clusterIP: None   ports:     - port: 9200       name: rest     - port: 9300       name: inter-node 

Sau đó, lưu file .

Ta xác định một Service tên elasticsearch trong Không gian tên kube-logging và đặt cho nó nhãn app: elasticsearch . Sau đó, ta đặt .spec.selector thành app: elasticsearch .spec.selector để Dịch vụ chọn Group có nhãn app: elasticsearch . Khi ta liên kết Elasticsearch StatefulSet của bạn với Dịch vụ này, Dịch vụ sẽ trả về các bản ghi DNS A trỏ đến Elasticsearch Pods với nhãn app: elasticsearch .

Sau đó, ta đặt clusterIP: None , làm cho dịch vụ không có đầu. Cuối cùng, ta xác định các cổng 92009300 được sử dụng để tương tác với API REST và cho giao tiếp giữa các node tương ứng.

Tạo dịch vụ bằng kubectl :

  • kubectl create -f elasticsearch_svc.yaml

Bạn sẽ thấy kết quả sau:

Output
service/elasticsearch created

Cuối cùng, hãy kiểm tra kỹ xem dịch vụ đã được tạo thành công bằng cách sử dụng kubectl get :

kubectl get services --namespace=kube-logging 

Bạn sẽ thấy như sau:

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 26s

Bây giờ ta đã cài đặt dịch vụ không cần đầu và domain .elasticsearch.kube-logging.svc.cluster.local ổn định cho Pods của bạn , ta có thể tiếp tục và tạo StatefulSet.

Tạo StatefulSet

Kubernetes StatefulSet cho phép bạn gán danh tính ổn định cho Pod và cấp cho chúng khả năng lưu trữ ổn định, liên tục. Elasticsearch yêu cầu bộ nhớ ổn định để duy trì dữ liệu trên Pod lên lịch và khởi động lại. Để tìm hiểu thêm về dung lượng công việc StatefulSet, hãy tham khảo trang Statefulsets từ tài liệu Kubernetes.

Mở một file có tên elasticsearch_statefulset.yaml trong editor yêu thích của bạn:

  • nano elasticsearch_statefulset.yaml

Ta sẽ chuyển qua phần định nghĩa đối tượng StatefulSet theo từng phần, dán các khối vào file này.

Bắt đầu bằng cách paste vào khối sau:

asticsearch_statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata:   name: es-cluster   namespace: kube-logging spec:   serviceName: elasticsearch   replicas: 3   selector:     matchLabels:       app: elasticsearch   template:     metadata:       labels:         app: elasticsearch 

Trong khối này, ta xác định một StatefulSet được gọi là es-cluster trong không gian tên kube-logging . Sau đó ta liên kết nó với tạo trước đó của ta elasticsearch Dịch vụ sử dụng serviceName lĩnh vực. Điều này đảm bảo mỗi Pod trong StatefulSet sẽ có thể truy cập được bằng địa chỉ DNS sau: es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local , trong đó [0,1,2] tương ứng vào thứ tự số nguyên được chỉ định của Pod.

Ta chỉ định 3 replicas (Pod) và đặt bộ chọn matchLabels thành app: elasticseach , sau đó ta phản chiếu trong phần .spec.template.metadata . Các trường .spec.selector.matchLabels.spec.template.metadata.labels phải trùng với nhau.

Bây giờ ta có thể chuyển sang đặc tả đối tượng. Dán vào khối YAML sau ngay bên dưới khối trước đó:

asticsearch_statefulset.yaml
. . .     spec:       containers:       - name: elasticsearch         image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0         resources:             limits:               cpu: 1000m             requests:               cpu: 100m         ports:         - containerPort: 9200           name: rest           protocol: TCP         - containerPort: 9300           name: inter-node           protocol: TCP         volumeMounts:         - name: data           mountPath: /usr/share/elasticsearch/data         env:           - name: cluster.name             value: k8s-logs           - name: node.name             valueFrom:               fieldRef:                 fieldPath: metadata.name           - name: discovery.seed_hosts             value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"           - name: cluster.initial_master_nodes             value: "es-cluster-0,es-cluster-1,es-cluster-2"           - name: ES_JAVA_OPTS             value: "-Xms512m -Xmx512m" 

Ở đây ta xác định các Pod trong StatefulSet. Ta đặt tên cho container elasticsearch và chọn docker.elastic.co/elasticsearch/elasticsearch:7.2.0 Docker hình ảnh. Đến đây, bạn có thể sửa đổi thẻ hình ảnh này để tương ứng với hình ảnh Elasticsearch nội bộ của bạn hoặc một version khác. Lưu ý đối với mục đích của hướng dẫn này, chỉ Elasticsearch 7.2.0 đã được thử nghiệm.

Sau đó, ta sử dụng trường resources để chỉ định rằng containers cần ít nhất 0,1 vCPU được đảm bảo cho nó và có thể bùng nổ tối đa 1 vCPU (giới hạn mức sử dụng tài nguyên của Pod khi thực hiện một lần nhập lớn ban đầu hoặc xử lý tăng đột biến tải). Bạn nên sửa đổi các giá trị này tùy thuộc vào tải dự kiến của bạn và các tài nguyên có sẵn. Để tìm hiểu thêm về các yêu cầu và giới hạn tài nguyên, hãy tham khảo Tài liệu Kubernetes chính thức.

Sau đó, ta mở và đặt tên các cổng 92009300 tương ứng cho REST API và giao tiếp giữa các node . Ta xác định một volumeMount gọi là data đó sẽ mount PersistentVolume tên data để container tại đường dẫn /usr/share/elasticsearch/data . Ta sẽ xác định Dung lượng yêu cầu cho StatefulSet này trong khối YAML sau này.

Cuối cùng, ta đặt một số biến môi trường trong containers :

  • cluster.name : Tên của cụm Elasticsearch, trong hướng dẫn này là k8s-logs .
  • node.name : Tên của nút mà ta đặt thành trường .metadata.name bằng cách sử dụng valueFrom . Điều này sẽ giải quyết thành es-cluster-[0,1,2] , tùy thuộc vào thứ tự được chỉ định của nút.
  • discovery.seed_hosts : Trường này cài đặt danh sách các node đủ điều kiện chính trong cụm sẽ khởi tạo quá trình khám phá nút. Trong hướng dẫn này, nhờ vào dịch vụ không đầu mà ta đã cấu hình trước đó, các Group của ta có các domain có dạng es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local , vì vậy ta đặt biến này cho phù hợp . Sử dụng phân giải DNS Kubernetes của không gian tên local , ta có thể rút ngắn nó thành es-cluster-[0,1,2].elasticsearch . Để tìm hiểu thêm về khám phá Elasticsearch, hãy tham khảo tài liệu chính thức của Elasticsearch .
  • cluster.initial_master_nodes : Trường này cũng chỉ định danh sách các node đủ điều kiện chính sẽ tham gia vào quy trình bầu cử chính. Lưu ý đối với trường này, bạn nên xác định các node bằng tên node.name của chúng chứ không phải tên server của chúng.
  • ES_JAVA_OPTS : Ở đây ta đặt giá trị này thành -Xms512m -Xmx512m yêu cầu JVM sử dụng kích thước heap tối thiểu và tối đa là 512 MB. Bạn nên điều chỉnh các thông số này tùy thuộc vào nhu cầu và khả năng cung cấp tài nguyên của cụm của bạn. Để tìm hiểu thêm, hãy tham khảo Đặt kích thước heap .

Khối tiếp theo mà ta sẽ paste vào trông như sau:

asticsearch_statefulset.yaml
. . .       initContainers:       - name: fix-permissions         image: busybox         command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]         securityContext:           privileged: true         volumeMounts:         - name: data           mountPath: /usr/share/elasticsearch/data       - name: increase-vm-max-map         image: busybox         command: ["sysctl", "-w", "vm.max_map_count=262144"]         securityContext:           privileged: true       - name: increase-fd-ulimit         image: busybox         command: ["sh", "-c", "ulimit -n 65536"]         securityContext:           privileged: true 

Trong khối này, ta định nghĩa một vài Init Container chạy trước khi chính elasticsearch chứa ứng dụng. Mỗi Init Container này đều chạy đến khi hoàn thành theo thứ tự chúng được xác định. Để tìm hiểu thêm về Init Containers, hãy tham khảo Tài liệu Kubernetes chính thức.

Quyền đầu tiên, được đặt tên là fix-permissions , chạy lệnh chown để thay đổi chủ sở hữu và group của folder dữ liệu Elasticsearch thành 1000:1000 , UID của user Elasticsearch. Theo mặc định, Kubernetes gắn folder dữ liệu dưới dạng folder root , điều này khiến Elasticsearch không thể truy cập được. Để tìm hiểu thêm về bước này, hãy tham khảo " Các lưu ý khi sử dụng production và mặc định " của Elasticsearch.

Thứ hai, được đặt tên là increase-vm-max-map , chạy lệnh để tăng giới hạn của hệ điều hành về số lượng mmap, theo mặc định có thể quá thấp, dẫn đến lỗi hết bộ nhớ. Để tìm hiểu thêm về bước này, hãy tham khảo tài liệu chính thức của Elasticsearch .

Init Container tiếp theo sẽ chạy là increase-fd-ulimit , chạy lệnh ulimit để tăng số lượng bộ mô tả file đang mở tối đa. Để tìm hiểu thêm về bước này, hãy tham khảo " Ghi chú cho việc sử dụng production và mặc định " từ tài liệu Elasticsearch chính thức.

Lưu ý: Ghi chú Elasticsearch cho việc sử dụng production cũng đề cập đến việc tắt swap vì lý do hiệu suất. Tùy thuộc vào nhà cung cấp hoặc cài đặt Kubernetes của bạn, swap có thể đã bị vô hiệu hóa. Để kiểm tra điều này, exec thành chạy container và chạy cat /proc/swaps vào danh sách các thiết bị trao đổi tích cực. Nếu bạn không thấy gì ở đó, swap sẽ bị vô hiệu hóa.

Bây giờ ta đã xác định containers ứng dụng chính của bạn và Vùng chứa Init chạy trước nó để điều chỉnh hệ điều hành containers , ta có thể thêm phần cuối cùng vào file định nghĩa đối tượng StatefulSet của ta : volumeClaimTemplates .

Dán vào khối volumeClaimTemplate sau:

asticsearch_statefulset.yaml
. . .   volumeClaimTemplates:   - metadata:       name: data       labels:         app: elasticsearch     spec:       accessModes: [ "ReadWriteOnce" ]       storageClassName: do-block-storage       resources:         requests:           storage: 100Gi 

Trong khối này, ta xác định volumeClaimTemplates của StatefulSet. Kubernetes sẽ sử dụng điều này để tạo PersisteVolumes cho các Pod. Trong khối trên, ta đặt tên cho nó là data (là name mà ta đề cập đến trong volumeMount được định nghĩa đó) và đặt cho nó cùng một nhãn app: elasticsearch như StatefulSet của ta .

Sau đó, ta chỉ định chế độ truy cập của nó là ReadWriteOnce , nghĩa là nó chỉ có thể được mount dưới dạng đọc-ghi bởi một nút duy nhất. Ta định nghĩa lớp lưu trữ là do-block-storage trong hướng dẫn này vì ta sử dụng cụm DigitalOcean Kubernetes cho mục đích demo . Bạn nên thay đổi giá trị này tùy thuộc vào nơi bạn đang chạy cụm Kubernetes của bạn . Để tìm hiểu thêm, hãy tham khảo tài liệu Dung lượng liên tục .

Cuối cùng, ta chỉ định rằng ta muốn mỗi PersentlyVolume có kích thước 100GiB. Bạn nên điều chỉnh giá trị này tùy thuộc vào nhu cầu production của bạn .

Thông số StatefulSet hoàn chỉnh sẽ trông giống như sau:

asticsearch_statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata:   name: es-cluster   namespace: kube-logging spec:   serviceName: elasticsearch   replicas: 3   selector:     matchLabels:       app: elasticsearch   template:     metadata:       labels:         app: elasticsearch     spec:       containers:       - name: elasticsearch         image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0         resources:             limits:               cpu: 1000m             requests:               cpu: 100m         ports:         - containerPort: 9200           name: rest           protocol: TCP         - containerPort: 9300           name: inter-node           protocol: TCP         volumeMounts:         - name: data           mountPath: /usr/share/elasticsearch/data         env:           - name: cluster.name             value: k8s-logs           - name: node.name             valueFrom:               fieldRef:                 fieldPath: metadata.name           - name: discovery.seed_hosts             value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"           - name: cluster.initial_master_nodes             value: "es-cluster-0,es-cluster-1,es-cluster-2"           - name: ES_JAVA_OPTS             value: "-Xms512m -Xmx512m"       initContainers:       - name: fix-permissions         image: busybox         command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]         securityContext:           privileged: true         volumeMounts:         - name: data           mountPath: /usr/share/elasticsearch/data       - name: increase-vm-max-map         image: busybox         command: ["sysctl", "-w", "vm.max_map_count=262144"]         securityContext:           privileged: true       - name: increase-fd-ulimit         image: busybox         command: ["sh", "-c", "ulimit -n 65536"]         securityContext:           privileged: true   volumeClaimTemplates:   - metadata:       name: data       labels:         app: elasticsearch     spec:       accessModes: [ "ReadWriteOnce" ]       storageClassName: do-block-storage       resources:         requests:           storage: 100Gi 

Khi bạn đã hài lòng với cấu hình Elasticsearch của bạn , hãy lưu file .

Bây giờ, hãy triển khai StatefulSet bằng kubectl :

  • kubectl create -f elasticsearch_statefulset.yaml

Bạn sẽ thấy kết quả sau:

Output
statefulset.apps/es-cluster created

Bạn có thể theo dõi StatefulSet khi nó được triển khai bằng cách sử dụng kubectl rollout status :

  • kubectl rollout status sts/es-cluster --namespace=kube-logging

Bạn sẽ thấy kết quả sau khi cụm được triển khai:

Output
Waiting for 3 pods to be ready... Waiting for 2 pods to be ready... Waiting for 1 pods to be ready... partitioned roll out complete: 3 new pods have been updated...

Khi tất cả các Group đã được triển khai, bạn có thể kiểm tra xem cụm Elasticsearch của bạn có hoạt động chính xác hay không bằng cách thực hiện yêu cầu đối với REST API.

Để làm như vậy, trước tiên hãy chuyển tiếp cổng local 9200 đến cổng 9200 trên một trong các node Elasticsearch ( es-cluster-0 ) bằng cách sử dụng kubectl port-forward :

  • kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging

Sau đó, trong một cửa sổ terminal riêng biệt, thực hiện yêu cầu curl đối với API REST:

  • curl http://localhost:9200/_cluster/state?pretty

Bạn sẽ thấy kết quả sau:

Output
{ "cluster_name" : "k8s-logs", "compressed_size_in_bytes" : 348, "cluster_uuid" : "QD06dK7CQgids-GQZooNVw", "version" : 3, "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg", "master_node" : "IdM5B7cUQWqFgIHXBp0JDg", "blocks" : { }, "nodes" : { "u7DoTpMmSCixOoictzHItA" : { "name" : "es-cluster-1", "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg", "transport_address" : "10.244.8.2:9300", "attributes" : { } }, "IdM5B7cUQWqFgIHXBp0JDg" : { "name" : "es-cluster-0", "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ", "transport_address" : "10.244.44.3:9300", "attributes" : { } }, "R8E7xcSUSbGbgrhAdyAKmQ" : { "name" : "es-cluster-2", "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA", "transport_address" : "10.244.40.4:9300", "attributes" : { } } }, ...

Điều này cho thấy rằng Elasticsearch cluster k8s-logs của ta đã được tạo thành công với 3 nút: es-cluster-0 , es-cluster-1es-cluster-2 . Nút chính hiện tại là es-cluster-0 .

Bây giờ cụm Elasticsearch của bạn đã được cài đặt và chạy, bạn có thể chuyển sang cài đặt giao diện user Kibana cho nó.

Bước 3 - Tạo Triển khai và Dịch vụ Kibana

Để chạy Kibana trên Kubernetes, ta sẽ tạo một Dịch vụ có tên là kibana và một Triển khai bao gồm một bản sao Pod. Bạn có thể chia tỷ lệ số lượng bản sao tùy thuộc vào nhu cầu production của bạn và tùy chọn chỉ định loại LoadBalancer cho Dịch vụ để yêu cầu cân bằng tải trên các group Triển khai.

Lần này, ta sẽ tạo Dịch vụ và Triển khai trong cùng một file . Mở file có tên kibana.yaml trong editor yêu thích của bạn:

  • nano kibana.yaml

Dán thông số dịch vụ sau:

kibana.yaml
apiVersion: v1 kind: Service metadata:   name: kibana   namespace: kube-logging   labels:     app: kibana spec:   ports:   - port: 5601   selector:     app: kibana --- apiVersion: apps/v1 kind: Deployment metadata:   name: kibana   namespace: kube-logging   labels:     app: kibana spec:   replicas: 1   selector:     matchLabels:       app: kibana   template:     metadata:       labels:         app: kibana     spec:       containers:       - name: kibana         image: docker.elastic.co/kibana/kibana:7.2.0         resources:           limits:             cpu: 1000m           requests:             cpu: 100m         env:           - name: ELASTICSEARCH_URL             value: http://elasticsearch:9200         ports:         - containerPort: 5601 

Sau đó, lưu file .

Trong thông số kỹ thuật này, ta đã xác định một dịch vụ được gọi là kibana trong không gian tên kube-logging và cấp cho nó nhãn app: kibana .

Ta cũng đã chỉ định rằng nó phải có thể truy cập được trên cổng 5601 và sử dụng nhãn app: kibana để chọn các Group mục tiêu của Dịch vụ.

Trong thông số Deployment , ta xác định một Triển khai có tên là kibana và chỉ định rằng ta muốn có 1 bản sao Pod.

Ta sử dụng hình ảnh docker.elastic.co/kibana/kibana:7.2.0 . Đến đây, bạn có thể thay thế hình ảnh Kibana riêng tư hoặc công khai của bạn để sử dụng.

Ta chỉ rõ rằng ta muốn có ít nhất 0,1 vCPU được đảm bảo cho Pod, tăng lên đến giới hạn 1 vCPU. Bạn có thể thay đổi các thông số này tùy thuộc vào tải dự kiến của bạn và các tài nguyên có sẵn.

Tiếp theo, ta sử dụng biến môi trường ELASTICSEARCH_URL để đặt điểm cuối và cổng cho cụm Elasticsearch. Sử dụng Kubernetes DNS, điều này tương ứng với terminal để đặt tên dịch vụ của nó elasticsearch . Miền này sẽ phân giải thành danh sách địa chỉ IP cho 3 Group Elasticsearch. Để tìm hiểu thêm về Kubernetes DNS, hãy tham khảo DNS cho Dịch vụ và Group .

Cuối cùng, ta đặt cổng container của Kibana thành 5601 , nơi mà Dịch vụ kibana sẽ chuyển tiếp các yêu cầu.

Khi hài lòng với cấu hình Kibana của bạn , bạn có thể triển khai Dịch vụ và Triển khai bằng kubectl :

  • kubectl create -f kibana.yaml

Bạn sẽ thấy kết quả sau:

Output
service/kibana created deployment.apps/kibana created

Bạn có thể kiểm tra xem triển khai có thành công hay không bằng cách chạy lệnh sau:

  • kubectl rollout status deployment/kibana --namespace=kube-logging

Bạn sẽ thấy kết quả sau:

Output
deployment "kibana" successfully rolled out

Để truy cập giao diện Kibana, ta sẽ chuyển tiếp một cổng local đến nút Kubernetes đang chạy Kibana. Lấy chi tiết Kibana Pod bằng cách sử dụng kubectl get :

  • kubectl get pods --namespace=kube-logging
Output
NAME READY STATUS RESTARTS AGE es-cluster-0 1/1 Running 0 55m es-cluster-1 1/1 Running 0 54m es-cluster-2 1/1 Running 0 54m kibana-6c9fb4b5b7-plbg2 1/1 Running 0 4m27s

Ở đây ta quan sát thấy rằng Kibana Pod của ta được gọi là kibana-6c9fb4b5b7-plbg2 .

Chuyển tiếp cổng local 5601 đến cổng 5601 trên Pod này:

  • kubectl port-forward kibana-6c9fb4b5b7-plbg2 5601:5601 --namespace=kube-logging

Bạn sẽ thấy kết quả sau:

Output
Forwarding from 127.0.0.1:5601 -> 5601 Forwarding from [::1]:5601 -> 5601

Bây giờ, trong trình duyệt web , hãy truy cập URL sau:

http://localhost:5601 

Nếu bạn thấy trang chào mừng Kibana sau đây, bạn đã triển khai thành công Kibana vào cụm Kubernetes của bạn :

Màn hình chào mừng Kibana

Đến đây bạn có thể chuyển sang triển khai thành phần cuối cùng của ngăn xếp EFK: trình thu thập log , Fluentd.

Bước 4 - Tạo Fluentd DaemonSet

Trong hướng dẫn này, ta sẽ cài đặt Fluentd dưới dạng DaemonSet, đây là loại dung lượng công việc Kubernetes chạy bản sao của một Pod nhất định trên mỗi Node trong cụm Kubernetes. Sử dụng bộ điều khiển DaemonSet này, ta sẽ triển khai một Pod tác nhân ghi log Fluentd trên mọi nút trong cụm của ta . Để tìm hiểu thêm về kiến trúc ghi log này, hãy tham khảo “ Sử dụng tác nhân ghi log nút ” từ tài liệu chính thức của Kubernetes.

Trong Kubernetes, các ứng dụng được container đăng nhập vào stdoutstderr có các stream log của chúng được ghi lại và chuyển hướng đến các file JSON trên các node . Fluentd Pod sẽ điều chỉnh các file log này, lọc các sự kiện log , chuyển đổi dữ liệu log và chuyển nó đến phần backend ghi log Elasticsearch mà ta đã triển khai ở Bước 2 .

Ngoài log containers , tác nhân Fluentd sẽ điều chỉnh các log thành phần hệ thống Kubernetes như log kubelet, kube-proxy và Docker. Để xem danh sách đầy đủ các nguồn do tác nhân ghi log Fluentd gắn thẻ, hãy tham khảo file kubernetes.conf được sử dụng để cấu hình tác nhân ghi log . Để tìm hiểu thêm về cách đăng nhập vào các cụm Kubernetes, hãy tham khảo “ Ghi log ở cấp độ nút ” từ tài liệu Kubernetes chính thức.

Bắt đầu bằng cách mở một file có tên thông fluentd.yaml trong editor yêu thích của bạn:

  • nano fluentd.yaml

, ta sẽ dán các định nghĩa đối tượng Kubernetes theo từng khối, cung cấp ngữ cảnh khi ta tiếp tục. Trong hướng dẫn này, ta sử dụng thông số kỹ thuật Fluentd DaemonSet do những người bảo trì Fluentd cung cấp. Một tài nguyên hữu ích khác được cung cấp bởi những người bảo trì FluentdKuberentes Fluentd .

Đầu tiên, hãy dán định nghĩa ServiceAccount sau:

thông thạod.yaml
apiVersion: v1 kind: ServiceAccount metadata:   name: fluentd   namespace: kube-logging   labels:     app: fluentd 

Tại đây, ta tạo một Tài khoản dịch vụ có tên là fluentd mà Fluentd Pods sẽ sử dụng để truy cập API Kubernetes. Ta tạo nó trong Không gian tên kube-logging và cung cấp cho nó app: fluentd nhãn app: fluentd . Để tìm hiểu thêm về Tài khoản Dịch vụ trong Kubernetes, hãy tham khảo Định cấu hình Tài khoản Dịch vụ cho Group trong tài liệu Kubernetes chính thức.

Tiếp theo, paste vào khối ClusterRole sau:

thông thạod.yaml
. . . --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata:   name: fluentd   labels:     app: fluentd rules: - apiGroups:   - ""   resources:   - pods   - namespaces   verbs:   - get   - list   - watch 

Ở đây ta định nghĩa một ClusterRole gọi fluentd mà ta cấp get , list , và watch điều khoản trên podsnamespaces đối tượng. ClusterRoles cho phép bạn cấp quyền truy cập vào các tài nguyên Kubernetes phạm vi cụm như Nodes. Để tìm hiểu thêm về Kiểm soát Truy cập Dựa trên Role và Role Cụm, hãy tham khảo Sử dụng Ủy quyền RBAC từ tài liệu Kubernetes chính thức.

Bây giờ, hãy paste vào khối ClusterRoleBinding sau:

thông thạod.yaml
. . . --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata:   name: fluentd roleRef:   kind: ClusterRole   name: fluentd   apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount   name: fluentd   namespace: kube-logging 

Trong khối này, ta xác định một ClusterRoleBinding được gọi là thông fluentd liên kết fluentd thạo với Tài khoản dịch vụ thông fluentd . Việc này cấp cho Dịch vụ fluentd Dịch vụ Tài khoản các quyền được liệt kê trong Role Cụm thông fluentd .

Đến đây, ta có thể bắt đầu dán thông số DaemonSet thực tế:

thông thạod.yaml
. . . --- apiVersion: apps/v1 kind: DaemonSet metadata:   name: fluentd   namespace: kube-logging   labels:     app: fluentd 

Ở đây, ta định nghĩa một DaemonSet có tên là thông fluentd trong Không gian tên kube-logging và đặt cho nó nhãn app: fluentd .

Tiếp theo, paste vào phần sau:

thông thạod.yaml
. . . spec:   selector:     matchLabels:       app: fluentd   template:     metadata:       labels:         app: fluentd     spec:       serviceAccount: fluentd       serviceAccountName: fluentd       tolerations:       - key: node-role.kubernetes.io/master         effect: NoSchedule       containers:       - name: fluentd         image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1         env:           - name:  FLUENT_ELASTICSEARCH_HOST             value: "elasticsearch.kube-logging.svc.cluster.local"           - name:  FLUENT_ELASTICSEARCH_PORT             value: "9200"           - name: FLUENT_ELASTICSEARCH_SCHEME             value: "http"           - name: FLUENTD_SYSTEMD_CONF             value: disable 

Ở đây, ta trùng với nhãn app: fluentd được định nghĩa trong .metadata.labels và sau đó gán fluentd Tài khoản dịch vụ thông fluentd . Ta cũng chọn app: fluentd làm Pods do DaemonSet này quản lý.

Tiếp theo, ta xác định dung NoSchedule để trùng với vết bẩn tương đương trên các node chính của Kubernetes. Điều này sẽ đảm bảo DaemonSet cũng được triển khai cho các bậc thầy Kubernetes. Nếu bạn không muốn chạy Fluentd Pod trên các node chính của bạn , hãy loại bỏ dung sai này. Để tìm hiểu thêm về các đặc điểm và dung sai của Kubernetes, hãy tham khảo “ Taints và Tolerations ” từ các tài liệu chính thức của Kubernetes.

Tiếp theo, ta bắt đầu xác định Pod container, ta gọi là thông fluentd .

Ta sử dụng hình ảnh Debian v1.4.2 chính thức do những người bảo trì Fluentd cung cấp. Nếu bạn muốn sử dụng hình ảnh Fluentd riêng tư hoặc công khai của riêng mình hoặc sử dụng version hình ảnh khác, hãy sửa đổi thẻ image trong thông số containers . Dockerfile và nội dung của hình ảnh này có sẵn trong repository lưu trữ Github của Fluentd 's fluentd-kubernetes-daemonset .

Tiếp theo, ta cấu hình Fluentd bằng một số biến môi trường:

  • FLUENT_ELASTICSEARCH_HOST : Ta đặt điều này thành địa chỉ Dịch vụ không đầu Elasticsearch được định nghĩa đó : elasticsearch.kube-logging.svc.cluster.local . Điều này sẽ giải quyết danh sách địa chỉ IP cho 3 Elasticsearch Pod. Server Elasticsearch thực tế rất có thể sẽ là địa chỉ IP đầu tiên được trả về trong danh sách này. Để phân phối log trên toàn cụm, bạn cần sửa đổi cấu hình cho plugin Đầu ra Elasticsearch của Fluentd. Để tìm hiểu thêm về plugin này, hãy tham khảo Elasticsearch Output Plugin .
  • FLUENT_ELASTICSEARCH_PORT : Ta đặt điều này thành cổng Elasticsearch mà ta đã cấu hình trước đó, 9200 .
  • FLUENT_ELASTICSEARCH_SCHEME : Ta đặt mục này thành http .
  • FLUENTD_SYSTEMD_CONF : Ta đặt cài đặt này thành disable để ngăn chặn kết quả liên quan đến systemd không được cài đặt trong containers .

Cuối cùng, paste vào phần sau:

thông thạod.yaml
. . .         resources:           limits:             memory: 512Mi           requests:             cpu: 100m             memory: 200Mi         volumeMounts:         - name: varlog           mountPath: /var/log         - name: varlibdockercontainers           mountPath: /var/lib/docker/containers           readOnly: true       terminationGracePeriodSeconds: 30       volumes:       - name: varlog         hostPath:           path: /var/log       - name: varlibdockercontainers         hostPath:           path: /var/lib/docker/containers 

Ở đây ta chỉ định giới hạn bộ nhớ 512 MiB trên FluentD Pod và đảm bảo nó là 0,1vCPU và 200MiB bộ nhớ. Bạn có thể điều chỉnh các giới hạn và yêu cầu tài nguyên này tùy thuộc vào dung lượng log dự kiến của bạn và các tài nguyên có sẵn.

Tiếp theo, ta gắn các đường dẫn server /var/log/var/lib/docker/containers vào containers bằng cách sử dụng varlogvarlibdockercontainers volumeMounts . Các volumes này được xác định ở cuối khối.

Thông số cuối cùng ta định nghĩa trong khối này là terminationGracePeriodSeconds , mang đến cho Fluentd 30 giây để đóng cửa một cách duyên dáng khi nhận được một SIGTERM tín hiệu. Sau 30 giây, các container được gửi tín hiệu SIGKILL . Giá trị mặc định cho terminationGracePeriodSeconds là 30 giây, vì vậy trong hầu hết các trường hợp, tham số này có thể bị bỏ qua. Để tìm hiểu thêm về cách chấm dứt dung lượng công việc Kubernetes một cách khéo léo, hãy tham khảo “ Các phương pháp hay nhất về Kubernetes: chấm dứt có thời hạn ” của Google.

Toàn bộ thông số kỹ thuật của Fluentd sẽ trông giống như sau:

thông thạod.yaml
apiVersion: v1 kind: ServiceAccount metadata:   name: fluentd   namespace: kube-logging   labels:     app: fluentd --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata:   name: fluentd   labels:     app: fluentd rules: - apiGroups:   - ""   resources:   - pods   - namespaces   verbs:   - get   - list   - watch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata:   name: fluentd roleRef:   kind: ClusterRole   name: fluentd   apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount   name: fluentd   namespace: kube-logging --- apiVersion: apps/v1 kind: DaemonSet metadata:   name: fluentd   namespace: kube-logging   labels:     app: fluentd spec:   selector:     matchLabels:       app: fluentd   template:     metadata:       labels:         app: fluentd     spec:       serviceAccount: fluentd       serviceAccountName: fluentd       tolerations:       - key: node-role.kubernetes.io/master         effect: NoSchedule       containers:       - name: fluentd         image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1         env:           - name:  FLUENT_ELASTICSEARCH_HOST             value: "elasticsearch.kube-logging.svc.cluster.local"           - name:  FLUENT_ELASTICSEARCH_PORT             value: "9200"           - name: FLUENT_ELASTICSEARCH_SCHEME             value: "http"           - name: FLUENTD_SYSTEMD_CONF             value: disable         resources:           limits:             memory: 512Mi           requests:             cpu: 100m             memory: 200Mi         volumeMounts:         - name: varlog           mountPath: /var/log         - name: varlibdockercontainers           mountPath: /var/lib/docker/containers           readOnly: true       terminationGracePeriodSeconds: 30       volumes:       - name: varlog         hostPath:           path: /var/log       - name: varlibdockercontainers         hostPath:           path: /var/lib/docker/containers 

Khi bạn đã hoàn tất cấu hình Fluentd DaemonSet, hãy lưu file .

Bây giờ, triển khai DaemonSet bằng kubectl :

  • kubectl create -f fluentd.yaml

Bạn sẽ thấy kết quả sau:

Output
serviceaccount/fluentd created clusterrole.rbac.authorization.k8s.io/fluentd created clusterrolebinding.rbac.authorization.k8s.io/fluentd created daemonset.extensions/fluentd created

Xác minh DaemonSet của bạn đã được triển khai thành công bằng kubectl :

  • kubectl get ds --namespace=kube-logging

Bạn sẽ thấy kết quả trạng thái sau:

Output
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd 3 3 3 3 3 <none> 58s

Điều này cho biết có 3 fluentd đang chạy, tương ứng với số lượng nút trong cụm Kubernetes của ta .

Bây giờ ta có thể kiểm tra Kibana để xác minh dữ liệu log đang được thu thập đúng cách và chuyển đến Elasticsearch.

Khi kubectl port-forward vẫn đang mở, hãy chuyển đến http://localhost:5601 .

Nhấp vào Khám phá trong menu chuyển bên trái:

Kibana Discover

Bạn sẽ thấy cửa sổ cấu hình sau:

Cấu hình mẫu index  Kibana

Điều này cho phép bạn xác định các chỉ số Elasticsearch mà bạn muốn khám phá trong Kibana. Để tìm hiểu thêm, hãy tham khảo Xác định các mẫu index của bạn trong các tài liệu chính thức của Kibana. Hiện tại, ta sẽ chỉ sử dụng mẫu ký tự đại diện logstash-* để nắm bắt tất cả dữ liệu log trong cụm Elasticsearch của ta . Nhập logstash-* vào hộp văn bản và nhấp vào Bước tiếp theo .

Sau đó, bạn sẽ được đưa đến trang sau:

Cài đặt mẫu index  Kibana

Điều này cho phép bạn cấu hình trường nào Kibana sẽ sử dụng để lọc dữ liệu log theo thời gian. Trong menu thả xuống, hãy chọn trường @timestamp và nhấn Tạo mẫu index .

Bây giờ, nhấn Khám phá trong menu chuyển bên trái.

Bạn sẽ thấy biểu đồ biểu đồ và một số mục log gần đây:

Nhật ký đến của Kibana

Đến đây, bạn đã cấu hình thành công và triển khai ngăn xếp EFK trên cụm Kubernetes của bạn . Để tìm hiểu cách sử dụng Kibana để phân tích dữ liệu log của bạn, hãy tham khảo Hướng dẫn sử dụng Kibana .

Trong phần tùy chọn tiếp theo, ta sẽ triển khai một Pod bộ đếm đơn giản in các số vào stdout và tìm log của nó trong Kibana.

Bước 5 (Tùy chọn) - Kiểm tra ghi log containers

Để chứng minh một trường hợp sử dụng Kibana cơ bản về việc khám phá các bản ghi mới nhất cho một Pod nhất định, ta sẽ triển khai một Pod bộ đếm tối thiểu in các số tuần tự vào stdout.

Hãy bắt đầu bằng cách tạo Pod. Mở file có tên counter.yaml trong trình soạn thảo yêu thích của bạn:

  • nano counter.yaml

Sau đó, dán thông số Pod sau:

counter.yaml
apiVersion: v1 kind: Pod metadata:   name: counter spec:   containers:   - name: count     image: busybox     args: [/bin/sh, -c,             'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] 

Lưu và đóng file .

Đây là một tối thiểu Pod gọi là counter bằng cách chạy một while vòng lặp, in số tuần tự.

Triển khai Pod bộ counter bằng kubectl :

  • kubectl create -f counter.yaml

Khi Pod đã được tạo và đang chạy, hãy chuyển trở lại console Kibana của bạn.

Từ trang Khám phá , trong thanh tìm kiếm, nhập kubernetes.pod_name:counter . Thao tác này lọc dữ liệu log cho bộ counter có tên Group .

Sau đó, bạn sẽ thấy danh sách các mục log cho Pod bộ counter :

Nhật ký truy cập trong Kibana

Bạn có thể nhấp vào bất kỳ mục log nào để xem metadata bổ sung như tên containers , nút Kubernetes, Không gian tên, v.v.

Kết luận

Trong hướng dẫn này, ta đã trình bày cách cài đặt và cấu hình Elasticsearch, Fluentd và Kibana trên một cụm Kubernetes. Ta đã sử dụng một kiến trúc ghi log tối thiểu bao gồm một Pod tác nhân ghi log duy nhất chạy trên mỗi nút công nhân Kubernetes.

Trước khi triển khai ngăn xếp ghi log này vào cụm Kubernetes production của bạn, tốt nhất bạn nên điều chỉnh các yêu cầu và giới hạn tài nguyên như được chỉ ra trong suốt hướng dẫn này. Bạn cũng có thể cần cài đặt X-Pack để kích hoạt các tính năng giám sát và bảo mật tích hợp.

Kiến trúc ghi log mà ta đã sử dụng ở đây bao gồm 3 Elasticsearch Pod, một Kibana Pod (không cân bằng tải) và một bộ Fluentd Pod được triển khai dưới dạng DaemonSet. Bạn có thể cần mở rộng cài đặt này tùy thuộc vào trường hợp sử dụng production của bạn. Để tìm hiểu thêm về cách mở rộng ngăn xếp Elasticsearch và Kibana của bạn, hãy tham khảo Scaling Elasticsearch .

Kubernetes cũng cho phép các kiến trúc tác nhân ghi log phức tạp hơn có thể phù hợp hơn với trường hợp sử dụng của bạn. Để tìm hiểu thêm, hãy tham khảo Kiến trúc ghi log từ tài liệu Kubernetes.


Tags:

Các tin liên quan