在Docker环境下的kafka部署之三:ELK和filebeat
整体架构
现在可以基于Docker环境来构建一个完整的日志处理系统了,整体架构如下:
客户端 | 互联网 | 日志服务端 |
---|---|---|
logfile => filebeat | => SSL => | kafka => logstash => ES => kibana |
其中的日志处理部分就是以前说过的《用Docker+ELK集中处理日志》。
除去这部分,剩下的关键问题就是跨互联网的filebeat到kafka之间的连接。
生成证书
因为如架构所示,kafka是一个典型的同时需要支持内外网连接的情况:外网通过SSL接受来自filebeat的推送,内网对接logstash提供日志内容。
所以大致上可以基于前一篇的方式进行配置,但是因为filebeat的SSL配置与kafka客户端略有不同,所以证书的生成方面有少许不同,结合《 Setting Filebeat 5 with Kafka 0.10 over TLS》和《 TLS for Filebeat Kafka Output》及原来的证书脚本,重写了一个证书生成脚本如下:
#!/bin/bash
BASE_DIR=. # 保存路径
DAYS_VALID=3650 # 证书有效期
PASSWORD=12345678 # 证书密码
NAME=domain_name # 域名
DEPT=devops # 部门名
COMPANY=your_company # 公司名
CITY=Xiamen # 城市
PROVINCE=Fujian # 省份
COUNTRY=CN # 国家
CERT_DIR="$BASE_DIR/ca"
SERVER_DIR="$BASE_DIR/secrets"
CLIENT_DIR="$BASE_DIR/client"
CA_CERT_NAME="$CLIENT_DIR/ca.crt"
CA_KEY_NAME="$CERT_DIR/ca.key"
PWD_NAME="$SERVER_DIR/password"
SERVER_KEYSTORE="$SERVER_DIR/server.keystore.jks"
SERVER_TRUSTSTORE="$SERVER_DIR/server.truststore.jks"
SERVER_CSR="$CERT_DIR/server.csr"
SERVER_CERT="$CERT_DIR/server.crt"
CLIENT_KEY="$CLIENT_DIR/client.key"
CLIENT_CSR="$CERT_DIR/client.csr"
CLIENT_CERT="$CLIENT_DIR/client.crt"
SUBJ="/C=$COUNTRY/ST=$PROVINCE/L=$CITY/O=$COMPANY/OU=$DEPT/CN=$NAME"
DNAME="CN=$NAME, OU=$DEPT, O=$COMPANY, L=$CITY, ST=$PROVINCE, C=$COUNTRY"
mkdir -p $CERT_DIR
mkdir -p $SERVER_DIR
mkdir -p $CLIENT_DIR
rm $CERT_DIR/*
rm $SERVER_DIR/*
rm $CLIENT_DIR/*
echo "1. Generate CA certificate and key..."
openssl req -new -x509 -keyout $CA_KEY_NAME -out $CA_CERT_NAME -days $DAYS_VALID \
-passin pass:"$PASSWORD" -passout pass:"$PASSWORD" -subj "$SUBJ"
echo ""
echo "2. Generate server key store..."
keytool -genkey -keyalg RSA -keystore $SERVER_KEYSTORE -alias $NAME \
-keysize 2048 -validity $DAYS_VALID -storepass $PASSWORD -keypass $PASSWORD \
-dname "$DNAME"
echo ""
echo "3. Export server certificate signing request..."
keytool -certreq -keystore $SERVER_KEYSTORE -alias $NAME \
-file $SERVER_CSR -storepass $PASSWORD -keypass $PASSWORD -noprompt
echo ""
echo "4. Sign server certificate by CA..."
openssl x509 -req -CAcreateserial -CA $CA_CERT_NAME -CAkey $CA_KEY_NAME \
-in $SERVER_CSR -out $SERVER_CERT -days $DAYS_VALID -passin pass:$PASSWORD
echo ""
echo "5. Import CA to server key store..."
keytool -import -keystore $SERVER_KEYSTORE -alias CARoot -file $CA_CERT_NAME \
-storepass $PASSWORD -keypass $PASSWORD -noprompt
echo ""
echo "6. Import server certificate to server key store..."
keytool -import -keystore $SERVER_KEYSTORE -alias $NAME -file $SERVER_CERT \
-storepass $PASSWORD -keypass $PASSWORD -noprompt
echo ""
echo "7. Import CA to server trust store..."
keytool -import -keystore $SERVER_TRUSTSTORE -alias CARoot -file $CA_CERT_NAME \
-storepass $PASSWORD -keypass $PASSWORD -noprompt
echo ""
echo "8. Generate client key and certificate request..."
openssl req -nodes -new -keyout $CLIENT_KEY -out $CLIENT_CSR -days $DAYS_VALID \
-subj "$SUBJ"
echo ""
echo "9. Sign client certificate by CA..."
openssl x509 -req -CAcreateserial -CA $CA_CERT_NAME -CAkey $CA_KEY_NAME \
-in $CLIENT_CSR -out $CLIENT_CERT -days $DAYS_VALID -passin pass:$PASSWORD
echo ""
echo "10. Generate password file..."
echo "$PASSWORD" > $PWD_NAME
rm .srl
echo ""
echo "####### Done. #######"
echo "Following files were generated"
echo "Server password file: $PWD_NAME"
echo "Server java keystore: $SERVER_KEYSTORE"
echo "Server java truststore: $SERVER_TRUSTSTORE"
echo "Signed Client cert: $CLIENT_CERT"
echo "Client RSA private key: $CLIENT_KEY"
echo "Client PEM truststore: $CA_CERT_NAME"
按注释修改配置内容为你自己的相关信息,然后运行这个脚本即可生成所需要的所有证书。
需要注意的是:
OpenSSL 1.1.0f和1.1.0g生成的证书在ELK 6.4.1中使用会有问题,说是不是PKCS8格式,但OpenSSL又会提示说你现在用的是PKCS8,建议更新为PKCS12格式。按《SSL communication fails btw Filebeat (5.1.1) and Logstash (5.1.1)》所说,用如下命令转换后的结果与未转换是一样的,可见本来就是PKCS8。
openssl pkcs8 -in privatekey.key -topk8 -nocrypt -out privatekey.p8
所以保险起见还是用旧版一点的OpenSSL,比如1.0.2x。
如果不想重装系统中的OpenSSL,可以使用我的一个image:raptor/jdkssl,内置了所需要的keytool和openssl,生成的证书经实践是可用的。
用法如下:
docker pull raptor/jdkssl
docker run -it --rm -v /path_to_script:/root/bin raptor/jdkssl
# cd /root/bin
# ./setup_certs.sh
# exit
其中setup_certs.sh
就是上面那个证书生成脚本。
配置kafka
基本配置方式如前一篇文章所说,docker-compose.yml
如下:
version: '2'
services:
zookeeper:
image: confluentinc/cp-zookeeper
container_name: zookeeper
mem_limit: 1024M
environment:
ZOOKEEPER_CLIENT_PORT: 2181
kafka:
image: confluentinc/cp-kafka
container_name: kafka
mem_limit: 1024M
depends_on:
- zookeeper
ports:
- 9093:9093
volumes:
- /home/raptor/path_to/secrets:/etc/kafka/secrets
environment:
KAFKA_BROKER_ID: 1
KAFKA_LISTENERS: PLAINTEXT://:9092,SSL://:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,SSL://domain_name:9093
KAFKA_SSL_KEY_CREDENTIALS: password
KAFKA_SSL_KEYSTORE_FILENAME: server.keystore.jks
KAFKA_SSL_KEYSTORE_CREDENTIALS: password
KAFKA_SSL_CLIENT_AUTH: required
KAFKA_SSL_TRUSTSTORE_FILENAME: server.truststore.jks
KAFKA_SSL_TRUSTSTORE_CREDENTIALS: password
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_HEAP_OPTS: "-Xmx512M -Xms16M"
注意其中的配置项,文件名根据新的脚本生成证书修改,然后用docker-compose up -d kafka
启动即可。
启动完成后最好用consumer和producer测试一下,确保配置成功再进行下一步。
配置ELK
ELK的配置包括两个方面:一个是输入源配置为kafka,另一个是过滤时需要转换格式。
kafka的输入配置如下:
input {
kafka {
bootstrap_servers => "kafka:9092"
topics => ["logstash"]
consumer_threads => 1
auto_offset_reset => "latest"
}
}
很简单,通过内网不加密方式连接kafka,主题为logstash(这个可以自己任意命名),单线程,从最后开始取。
过滤配置则需要在filter的最前面加上一个转换:
filter {
json {
source => "message"
}
... # 原来的过滤配置
}
这是因为filebeat发来的数据会被编码为JSON再存到kafka里,logstash读出来就是一个放在message字段里的字符串,需要用json插件解析到root,恢复成原本的格式供logstash解析。
最后把ELK也加到前面那个docker-compose.yml
里:
...
elk:
image: sebp/elk
container_name: elk
depends_on:
- kafka
ports:
- 127.0.0.1:5601:5601
- 127.0.0.1:9200:9200
volumes:
- /home/raptor/path_to_logstash/conf.d:/etc/logstash/conf.d
- /home/raptor/path_to_elk/data:/var/lib/elasticsearch
然后用docker-compose up -d elk
启动。因为是通过内网连接kafka,也没有使用加密,一般没什么问题是很容易配通的。
配置filebeat
这个配置是关键点,搞了很久才搞通,当然,大部分坑在上面已经说过了,这里就说一下结论。
filebeat的配置中,主要就是output部分:
output.kafka:
hosts: ["domain_name:9093"]
topic: 'logstash'
worker: 1
ssl:
certificate_authorities: "/etc/pki/tls/ca.crt"
certificate: "/etc/pki/tls/client.crt"
key: "/etc/pki/tls/client.key"
其中域名domain_name必须与kafka证书保持一致,并且解析到kafka的外网IP(如果本地测试,可以修改hosts文件实现),logstash是主题名,保持与ELK中的配置一致。剩下的就是三个客户端证书文件,即前面那个脚本生成的client
文件夹里的三个文件,把它们放到/etc/pki/tls
(或你自己指定的其它文件夹,只要和这边的配置一致即可)下。
配置无误,service filebeat start
即可。
推送到[go4pro.org]