Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3665  7  0

Kubernetes Cookbook 编程指南 中文版教程

收集应用程日志

当您开始管理应用程序时,日志收集和分析是跟踪应用程序状态的两个重要例程。

但是,当应用程序由Docker / Kubernetes管理时,存在一些困难; 因为日志文件位于容器内部,所以从容器外部访问它们并不容易。 此外,如果应用程序由复制控制器具有许多pod,则难以跟踪或识别已发生问题的pod。

克服这种困难的一种方法是准备一个集中的日志收集平台,用于累积和保留应用程序日志。 本节描述了一个流行的日志收集平台ELK(Elasticsearch,Logstash和Kibana)。

准备

首先,我们需要在开始时准备Elasticsearch服务器。 然后,应用程序将使用Logstash将日志发送到Elasticsearch。 我们将使用Kibana可视化分析结果。

Elasticsearch

Elasticsearch(https://www.elastic.co/products/elasticsearch)是流行的文本索引和分析引擎之一。 有一些例子是由Kubernetes来源提供的YAML文件; 让我们使用curl命令下载它并设置Elasticsearch:

YAML fle的示例位于GitHub上,网址为https://github.com/kubernetes/kubernetes/tree/master/examples/elasticsearch

# curl -L -O https://github.com/kubernetes/kubernetes/releases/download/
v1.1.4/kubernetes.tar.gz
% Total % Received % Xferd Average Speed Time Time Time
Current
Dload Upload Total Spent Left
Speed
100 593 0 593 0 0 1798 0 --:--:-- --:--:-- --:--:-
- 1802
100 181M 100 181M 0 0 64.4M 0 0:00:02 0:00:02 --:--:--
75.5M
# tar zxf kubernetes.tar.gz
# cd kubernetes/examples/elasticsearch/
# ls
es-rc.yaml es-svc.yaml production_cluster README.md service-account.
yaml

先创建ServiceAccount(service-account.yaml),然后创建Elasticsearch副本控制器(es-rc.yaml)和服务(es-svc.yaml),如下所示:

# kubectl create -f service-account.yaml
serviceaccount "elasticsearch" created

//As of Kubernetes 1.1.4, it causes validation error
//therefore append --validate=false option

# kubectl create -f es-rc.yaml --validate=false
replicationcontroller "es" created

# kubectl create -f es-svc.yaml
service "elasticsearch" created

然后,您可以通过Kubernetes服务访问Elasticsearch接口,如下所示:

//Elasticsearch is open by 192.168.45.152 in this example
# kubectl get service
NAME CLUSTER_IP EXTERNAL_IP PORT(S)
SELECTOR AGE
elasticsearch 192.168.45.152 9200/TCP,9300/TCP
component=elasticsearch 9s
kubernetes 192.168.0.1 <none> 443/TCP <none>
110d

//access to TCP port 9200
# curl http://192.168.45.152:9200/
{
    "status" : 200,
    "name" : "Wallflower",
    "cluster_name" : "myesdb",
    "version" : {
        "number" : "1.7.1",
        "build_hash" : "b88f43fc40b0bcd7f173a1f9ee2e97816de80b19",
        "build_timestamp" : "2015-07-29T09:54:16Z",
        "build_snapshot" : false,
        "lucene_version" : "4.10.4"
    },
    "tagline" : "You Know, for Search"
}

现在,准备好将应用程序日志发送到Elasticsearch。

如何去做...

让我们使用一个示例应用程序,该应用程序在第5章“构建持续交付管线”中的从整体到微服务这一节中引入的。 准备Python Flask程序如下:

# cat entry.py

from flask import Flask, request
app = Flask(__name__)

@app.route("/")
def hello():
	return "Hello World!"

@app.route("/addition/<int:x>/<int:y>")
def add(x, y):
	return "%d" % (x+y)

if __name__ == "__main__":
	app.run(host='0.0.0.0')

使用此应用程序将日志发送到Elasticsearch。

Logstash

将应用程序日志发送到Elasticsearch; 使用Logstash(https://www.elastic.co/products/logstash)是最简单的方法,因为它从纯文本格式转换为Elasticsearch(JSON)格式。

Logstash需要一个指定Elasticsearch IP地址和端口号的配置文件。 在本节中,Elasticsearch由Kubernetes服务管理; 因此,可以使用环境变量找到IP地址和端口号,如下所示:

Item Environment Variable Example
Elasticsearch IP address ELASTICSEARCH_SERVICE_ HOST 192.168.45.152
Elasticsearch port number ELASTICSEARCH_SERVICE_ PORT 9200

但是,Logstash配置文件不直接支持环境变量。因此,Logstash配置文件将占位符用作 _ES_IP_ 和 _ES_PORT_,如下所示:

# cat logstash.conf.temp

input {
	stdin {}
}

filter {
    grok {
        match => {
            "message" => "%{IPORHOST:clientip} %{HTTPDUSER:ident} %{USER:auth} \[%{DATA:timestamp}\] \"(?:%{WORD:verb} %{NOTSPACE:request} (?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-)"
        }
    }
}

output {
    elasticsearch {
        hosts => ["_ES_IP_:_ES_PORT_"]
        index => "mycalc-access"
}

stdout { codec => rubydebug }
}

启动脚本

启动脚本将读取环境变量,然后替换占位符以设置实际IP和端口号,如下所示:

#!/bin/sh

TEMPLATE="logstash.conf.temp"
LOGSTASH="logstash-2.2.2/bin/logstash"

cat $TEMPLATE | sed "s/_ES_IP_/$ELASTICSEARCH_SERVICE_HOST/g" | sed "s/_ES_PORT_/$ELASTICSEARCH_SERVICE_PORT/g" > logstash.conf

python entry.py 2>&1 | $LOGSTASH -f logstash.conf

Dockerfile

最后,按如下方式准备Dockerfle以构建示例应用程序:

FROM ubuntu:14.04

# Update packages
RUN apt-get update -y

# Install Python Setuptools
RUN apt-get install -y python-setuptools git telnet curl openjdk-7-jre

# Install pip
RUN easy_install pip

# Bundle app source
ADD . /src
WORKDIR /src

# Download LogStash
RUN curl -L -O https://download.elastic.co/logstash/logstash/logstash-
2.2.2.tar.gz

RUN tar -zxf logstash-2.2.2.tar.gz

# Add and install Python modules
RUN pip install Flask

# Expose
EXPOSE 5000

# Run
CMD ["./startup.sh"]

Docker build

让我们使用docker build命令构建一个示例应用程序:

# ls
Dockerfile entry.py logstash.conf.temp startup.sh

# docker build -t hidetosaito/my-calc-elk .
Sending build context to Docker daemon 5.12 kB
Step 1 : FROM ubuntu:14.04
---> 1a094f2972de
Step 2 : RUN apt-get update -y
---> Using cache
---> 40ff7cc39c20
Step 3 : RUN apt-get install -y python-setuptools git telnet curl
openjdk-7-jre
---> Running in 72df97dcbb9a

(skip…)

Step 11 : CMD ./startup.sh
---> Running in 642de424ee7b
---> 09f693436005
Removing intermediate container 642de424ee7b
Successfully built 09f693436005

//upload to Docker Hub using your Docker account
# docker login
Username: hidetosaito
Password:
Email: hideto.saito@yahoo.com
WARNING: login credentials saved in /root/.docker/config.json
Login Succeeded

//push to Docker Hub
# docker push hidetosaito/my-calc-elk
The push refers to a repository [docker.io/hidetosaito/my-calc-elk] (len:
1)
09f693436005: Pushed
b4ea761f068a: Pushed

(skip…)

c3eb196f68a8: Image already exists
latest: digest: sha256:45c203d6c40398a988d250357f85f1b5ba7b14ae73d449b3ca
64b562544cf1d2 size: 22268

Kubernetes副本控制器和服务

现在,使用Kubernetes的此应用程序将日志发送到Elasticsearch。 首先,准备YAML文件以使用副本控制器和服务加载此应用程序,如下所示:

# cat my-calc-elk.yaml
apiVersion: v1
kind: ReplicationController
metadata:
	name: my-calc-elk-rc
spec:
    replicas: 2
    selector:
    	app: my-calc-elk
    template:
        metadata:
            labels:
            	app: my-calc-elk
    spec:
        containers:
        - name: my-calc-elk
          image: hidetosaito/my-calc-elk
---
apiVersion: v1
kind: Service
metadata:
	name: my-calc-elk-service
spec:
    ports:
        - protocol: TCP
        	port: 5000
    type: ClusterIP
        selector:
        app: my-calc-elk

使用kubectl命令创建副本控制器和服务,如下所示:

# kubectl create -f my-calc-elk.yaml
replicationcontroller "my-calc-elk-rc" created
service "my-calc-elk-service" created

检查Kubernetes服务以获取此应用程序的IP地址,如下所示。 它表示192.168.121.63:

# kubectl get service
NAME CLUSTER_IP EXTERNAL_IP PORT(S)
SELECTOR AGE
elasticsearch 192.168.101.143 9200/TCP,9300/TCP
component=elasticsearch 15h
kubernetes 192.168.0.1 <none> 443/TCP
<none> 19h
my-calc-elk-service 192.168.121.63 <none> 5000/TCP
app=my-calc-elk 39s

让我们使用curl命令访问此应用程序,如下所示:

# curl http://192.168.121.63:5000/
Hello World!

# curl http://192.168.121.63:5000/addition/3/5
8

Kibana

Kibana(https://www.elastic.co/products/kibana)是Elasticsearch的可视化工具。 下载Kibana,并指定Elasticsearch IP地址和端口号,以启动Kibana:

//Download Kibana 4.1.6
# curl -O https://download.elastic.co/kibana/kibana/kibana-4.1.6-
linux-x64.tar.gz
% Total % Received % Xferd Average Speed Time Time Time
Current
Dload Upload Total Spent Left
Speed
100 17.7M 100 17.7M 0 0 21.1M 0 --:--:-- --:--:-- --:--:--
21.1M

//unarchive
# tar -zxf kibana-4.1.6-linux-x64.tar.gz

//Find Elasticsearch IP address
# kubectl get services
NAME CLUSTER_IP EXTERNAL_IP PORT(S)
SELECTOR AGE
elasticsearch 192.168.101.143 9200/TCP,9300/TCP
component=elasticsearch 19h
kubernetes 192.168.0.1 <none> 443/TCP
<none> 23h

//specify Elasticsearch IP address
# sed -i -e "s/localhost/192.168.101.143/g" kibana-4.1.6-linux-x64/
config/kibana.yml

//launch Kibana
# kibana-4.1.6-linux-x64/bin/kibana

然后,您将看到应用程序日志。 创建图表如下:

本书不包括如何配置Kibana; 请访问官方网页,通过https://www.elastic.co/products/kibana了解Kibana配置。

它是如何工作的...

现在,Logstash捕获了应用程序日志; 它被转换为JSON格式,然后发送到Elasticsearch。

由于Logstash与应用程序容器捆绑在一起,因此副本控制器增加Pod的副本数量时没有问题。 它捕获所有应用程序日志而不进行配置更改。

所有日志都将存储在Elasticsearch中,如下所示:

还可以参考

本节介绍了如何集成到ELK堆栈。 集中式日志收集平台对于Kubernetes环境非常重要。 容器很容易启动,并且由调度程序来销毁,但要知道哪个节点运行哪个pod并不容易。 查看以下章节:

  • 使用Kubernetes日志

  • 使用etcd日志

  • 第5章构建持续交付管线,从整体到微服务这一节