Elastic:运用Elastic Stack对Kubernetes进行监控 (一)

在本文中,我们将学习如何为您的Kubernetes环境(简称k8s)设置监视堆栈。 这种解决方案使您的团队可以在几乎不影响现有资源的情况下获得对基础架构和每个应用程序的可见性。

可观测性的目的是向负责生产的操作员提供工具,以检测不良行为(服务停机,错误,响应速度慢),并提供可操作的信息以查找问题的根本原因。 它通常分为三个支柱:

  • 指标:提供有关系统每个组件的时间序列信息,例如CPU,内存,磁盘和网络消耗,并且通常显示整体前景以及在特定时间检测异常行为的第一步。
  • 日志:为操作员提供了一种工具,可以将机器,服务和应用程序日志集中在同一可搜索数据库中,以分析和了解系统上的意外行为。
  • 跟踪或APM(应用程序监视性能):提供了对应用程序的更深入的了解,其中记录了服务执行中的每个请求和步骤(http调用,数据库查询等)。 使用跟踪,我们可以检测到性能低下或调试低级别的特定用户,并相应地改进或修复我们的系统。

出处:Peter Bourgon

360可观察性的概念与devop和敏捷原则完全一致,可以随着时间的推移不断观察,检测和改进系统。

在本文中,我们将在Kubernetes环境中使用由Elasticsearch,Kibana,Filebeat,Metricbeat和APM-Server组成的Elastic堆栈(版本7.6.2)监视和记录生产环境。 本系列文章将逐步介绍标准的Kubernetes部署,在我看来,它可以更好地全面了解安装和配置的每个步骤。 当然,还存在其他方法来在Kubernetes上使用Helm或Elastic Cloud之类的工具来安装和配置某些服务,但是本文的目的是使读者充分了解这种``相当''复杂的体系结构中的每个组件,以帮助他们进行调整 适用于自己的系统,有时会受到自动安装程序的限制。

前提条件

本教程使用minikube创建本地k8s环境,并部署一个简单的应用程序,该应用程序由Spring-Boot服务和MongoDB数据库组成,将用作示例来监视和跟踪系统及应用程序的行为。

因此,为了开始使用,需要以下工具:

  • Docker:容器引擎
  • minikube:用于开发和测试的本地kubernetes
  • kubectl:Kubernetes命令行工具
  • Elasticsearch要求增加主机上的nmapfs(虚拟内存)(请参阅详细信息)针对Linux系统我们需要运行如下的命令:
$ sudo sysctl -w vm.max_map_count=262144

关于如何在不同的操作系统上设置这个,请参阅链接Using docker images in production

如果你还没没有安装好自己的Minikube的话,那么请参照我之前的文章“Elastic Cloud Kubernetes (ECK) 部署”。

配置minikube 内存大小

首先,我们将分配给minikube主机的默认内存大小(2GB)增加到8GB。 在终端中运行以下命令:

minikube config set memory 8192
$ minikube config set memory 8192
❗  These changes will take effect upon a minikube delete and then a minikube start

启动minikube

现在,使用以下命令启动minikube。 可能要花几分钟...。针对中国的情况,我们使用如下命令来启动minikube:

minikube start --driver=docker --cpus 3 --memory 8196  --image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
$ minikube start --driver=virtualbox --cpus 3 --memory 8196  --image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
😄  minikube v1.9.2 on Darwin 10.15.4
✨  Using the virtualbox driver based on existing profile
✅  Using image repository registry.cn-hangzhou.aliyuncs.com/google_containers
👍  Starting control plane node m01 in cluster minikube
🏃  Updating the running virtualbox "minikube" VM ...
🐳  Preparing Kubernetes v1.18.0 on Docker 19.03.8 ...
🌟  Enabling addons: default-storageclass, storage-provisioner
🏄  Done! kubectl is now configured to use "minikube"

❗  /usr/local/bin/kubectl is v1.15.5, which may be incompatible with Kubernetes v1.18.0.
💡  You can also use 'minikube kubectl -- get pods' to invoke a matching versio

检查Minikube的状态

我们可以检查minikube的状态:

 minikube status
$ minikube status
m01
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
kubectl get nodes
$ kubectl get nodes
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   23m   v1.18.0

我们可以看到我们有一个master,并且Kubernetes的版本是1.18。

部署样本应用程序

现在,我们将部署一个简单的应用程序(Spring-Boot)及其数据库(MongoDB)。

MongoDB

我们首先在k8s环境中部署MongoDB,并公开端口27017。

mongo.yml

---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: mongo
  labels:
    app: mongo
spec:
  ports:
  - port: 27017
    protocol: TCP
  selector:
    app: mongo
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: default
  name: mongo
  labels:
    app: mongo
spec:
  serviceName: "mongo"
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongo
        image: mongo
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongo-persistent-storage
          mountPath: /data/db
  volumeClaimTemplates:
  - metadata:
      name: mongo-persistent-storage
      annotations:
        volume.beta.kubernetes.io/storage-class: "standard"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: standard
      resources:
        requests:
          storage: 1Gi

使用以下命令部署MongoDB:

kubectl apply -f mongo.yml

我们等一下直到它运行起来:

 kubectl get pods
$ kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
mongo-0   1/1     Running   0          114s
kubectl get all -l app=mongo
$ kubectl get all -l app=mongo
NAME          READY   STATUS    RESTARTS   AGE
pod/mongo-0   1/1     Running   0          2m31s


NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
service/mongo   ClusterIP   10.104.205.22   <none>        27017/TCP   14m


NAME                     READY   AGE
statefulset.apps/mongo   1/1     2m31s

spring-boot-simple

现在让我们部署我们的Spring-Boot API。 它将API内部部署在端口8080上,但是type = NodePort也可以从节点静态IP在另一个端口上进行访问。

spring-boot-simple.yml

# spring-boot-simple.yml
---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: spring-boot-simple
  labels:
    app: spring-boot-simple
spec:
  type: NodePort
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: spring-boot-simple
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: spring-boot-simple
  labels:
    app: spring-boot-simple
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-boot-simple
  template:
    metadata:
      labels:
        app: spring-boot-simple
    spec:
      containers:
      - image: gjeanmart/spring-boot-simple:0.0.1-SNAPSHOT
        imagePullPolicy: Always
        name: spring-boot-simple
        env:
          - name: SPRING_DATA_MONGODB_HOST
            value: mongo
        ports:
        - containerPort: 8080

运行命令以部署spring-boot-simple:

kubectl apply -f spring-boot-simple.yml

然后等它部署好:

kubectl get all -l app=spring-boot-simple
$ kubectl get all -l app=spring-boot-simple
NAME                                      READY   STATUS    RESTARTS   AGE
pod/spring-boot-simple-84c965c78c-xmkcq   1/1     Running   0          14m


NAME                         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/spring-boot-simple   NodePort   10.101.241.38   <none>        8080:30202/TCP   14m


NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/spring-boot-simple   1/1     1            1           14m

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/spring-boot-simple-84c965c78c   1         1         1       14m

注意节点上API的外部端口:30202,并使用$ minikube ip获得节点静态IP。

$ minikube ip
127.0.0.1

我们也可以通过如下的方法来找到service的port号:

export NODE_PORT=$(kubectl get service/spring-boot-simple -o go-template='{{(index .spec.ports 0).nodePort}}')

echo $NODE_PORT
$ echo $NODE_PORT
30894

获得所需的所有信息后,只需运行以下命令以测试我们的示例API(将<IP>:<PORT>替换为您的值)。

对于使用Docker来说,在实际的操作中我发现这个端口号并不是直接可以在host中之间使用的。我们可以通过如下的方法来找到在host中可以使用的端口号:

minikube service spring-boot-simple --url
$ minikube service spring-boot-simple --url
🏃  Starting tunnel for service spring-boot-simple.
|-----------|--------------------|-------------|------------------------|
| NAMESPACE |        NAME        | TARGET PORT |          URL           |
|-----------|--------------------|-------------|------------------------|
| default   | spring-boot-simple |             | http://127.0.0.1:56611 |
|-----------|--------------------|-------------|------------------------|
http://127.0.0.1:56611
❗  Because you are using docker driver on Mac, the terminal needs to be open to run it.

请注意上面显示的端口号56611。这个端口号将在如下的API中进行使用。请使用这个值替换如下的端口号。

Greetings

curl $(minikube ip):port
$ curl $(minikube ip):56611
Greetings from Spring Boot!liuxg:minikube

Post 一个信息

curl -X POST $(minikube ip):56611/message -d 'hello world'
$ curl -X POST $(minikube ip):30894/message -d 'hello world'
{"id":"5eac196bcff47e0001297d16","message":"hello+world=","postedAt":"2020-05-01T12:43:23.944+0000"}

Get 所有信息

curl -X GET $(minikube ip):56611/message
$ curl -X GET $(minikube ip):56611/message
[{"id":"5eac196bcff47e0001297d16","message":"hello+world=","postedAt":"2020-05-01T12:43:23.944+0000"}]

创建 monitoring 的命名空间

最后,为了在逻辑上将监视堆栈与应用程序分开(namespace default),我们将所有内容部署在称为monitoring的命名空间下。

要创建namespace,只需运行以下命令:

kubectl create namespace monitoring

你也可以通过如下的方式来创建。先创建一个yaml文件。

monitoring.namespace.yml

# monitoring.namespace.yml
---
apiVersion: v1
kind: Namespace
metadata:
   name: monitoring
---

让后,使用如下的命令来创建:

kubectl apply -f monitoring.namespace.yml

在下一步,我们将安装Elasticsearch及Kibana。请阅读我的另外一篇文章“运用Elastic Stack对Kubernetes进行监控 (二)”。在那篇文章中,我们将详细介绍如何安装Elasticsearch Stack。

参考:

【1】https://github.com/kubernetes/kubernetes/issues/39823