1 背景介绍
中间件应用运行在Docker容器中能够感受到容器快速创建快速销毁确实带来了很大的便利性、灵活性。但由于Docker应用容器销毁不管人为操作,还是容器挂掉甚至容器应用导致其崩溃,它运行的数据都会随着它的生命周期结束而结束,这种情况是非常适合部署无状态服务。却不适合有状态的应用部署。但问题来了,假如运维同事需要对容器应用发生的故障进行下一步分析,而在容器中这分部有状态的应用日志也会随着容器销毁而销毁。日志都丢了还谈什么故障分析定位,运维同事面临盲目被动状态。然而在大的容器集群环境下如果直接将容器应用日志持久化到本地磁盘目录,那样日志会出现目录结构临乱和容器日志文件也会面临覆盖问题。
2 日志转存需求
1)将容器中的单个或多个业务应用新增日志内容按照一定目录结构存放在远程日志服务器。
2)存储日志的目录结构形式需要以下方式存储:
/logs/app_id/service_id/container_id/app_name/xxx.log
3 工具介绍
1) Filebeat是一个日志文件托运工具,在你的服务器上安装客户端后,filebeat会监控日志目录或者指定的日志文件,追踪读取这些文件(追踪文件的变化,不停的读),并且转发这些信息到logstarsh中存放。
2) Logstash是一款轻量级的日志搜集处理框架,可以方便的把分散的、多样化的日志搜集起来,并进行自定义的处理,然后传输到指定的位置。

4 Logstash日志服务器
部署日志服务器logstash配置要求如下。
系统 |
Centos7.0 X86_64 以上 |
CPU |
4核 |
内存 |
16G |
存储 |
外部存储500G以上 |
Logstash软件对JDK也是有要求的,建议在JDK1.8.0以上版本来运行logstash。
4.1 安装JDK软件
直接去oracle官方下载JDK版本1.8软件来安装
tar xvf jdk1.8.0_131.tar.gz –C /usr
然后配置JDK环境变量vi /etc/profile
JAVA_HOME=/usr/jdk1.8.0_131
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
用命令source /etc/profile生效环境变量
4.2 安装logstash软件
软件下载
https://artifacts.elastic.co/downloads/logstash/logstash-6.0.0.tar.gz
软件安装
执行命令tar -xvf /opt/ logstash-6.0.0.tar.gz 解压logstash
启动logstash
/opt/logstash/bin/logstash -f /opt/logstash/logstash.conf
在日志服务器上新建一个/logs目录用于存储大量应用容器日志。
5 Filebeat软件安装
直接将filebeat软件和nginx,php-fpm软件联合一起封装成一个新的基础镜像,事先我们需要知道哪些应用日志文件需要提取出来。注意以下是需要提取容器中的应用日志:
Nginx日志容器路径
/var/log/nginx
Php-fpm日志窗口路径:
/var/opt/remi/php70/log/php-fpm
下载filebeat软件
wget
https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.0.0-linux-x86_64.tar.gz
5.1 采用dockerfile脚本安装nginx,php-fpm, Filebeat软件
以下红色字体部署就是规范nginx与php-fpm应用日志,并将日志文件映射到/logs目录下。同时安装filebeat软件。
FROM centos
MAINTAINER jaymarco@shsnc.com
#Install system library
RUN rpm -ivh http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm && rpm -ivh http://rpms.remirepo.net/enterprise/remi-release-7.rpm && \
yum install -y php70-php-gd.x86_64 php70-php-mcrypt.x86_64 php70-php-fpm.x86_64 php70-php-pecl-redis.x86_64 python-setuptools \
php70-php-mbstring.x86_64 php70-php-snmp.x86_64 php70-php-pecl-zip.x86_64 php70-php-xml.x86_64 \
php70-php-mysqlnd.x86_64 php70-php-pecl-mysql.x86_64 gcc gcc-c++ automake libtool make cmake openssl openssl-devel pcre-devel && \
yum clean all
#Make install nginx
RUN rpm -ivh http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.10.3-1.el7.ngx.x86_64.rpm
COPY nginx.conf /etc/nginx/nginx.conf
#set php www.conf config
RUN sed -e 's/127.0.0.1:9000/9000/' \
-e '/allowed_clients/d' \
-e '/catch_workers_output/s/^;//' \
-e '/error_log/d' \
-e 's/;listen.backlog = 511/listen.backlog = 1024/' \
-e 's/pm.max_children = 50/pm.max_children = 300/' \
-e 's/pm.start_servers = 5/pm.start_servers = 30/' \
-e 's/pm.min_spare_servers = 5/pm.min_spare_servers = 30/' \
-e 's/pm.max_spare_servers = 35/pm.max_spare_servers = 60/' \
-e 's/;pm.max_requests = 500/pm.max_requests = 10240/' \
-e 's/;request_slowlog_timeout = 0/request_slowlog_timeout = 2/' \
-e 's/;request_terminate_timeout = 0/request_terminate_timeout = 20/' \
-e 's/;rlimit_files = 1024/rlimit_files = 65535/' \
-i /etc/opt/remi/php70/php-fpm.d/www.conf && \
sed -e 's/max_execution_time = 30/max_execution_time = 150/' \
-e 's/max_input_time = 60/max_input_time = 300/' \
-i /etc/opt/remi/php70/php.ini && \
sed -e 's/daemonize = yes/daemonize = no/' \
-e 's/;rlimit_files = 1024/rlimit_files = 65535/' -i /etc/opt/remi/php70/php-fpm.conf && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
echo 'Asia/Shanghai' >/etc/timezone
RUN easy_install supervisor && \
mkdir -p /var/log/supervisor && \
mkdir -p /var/run/sshd && \
mkdir -p /var/run/supervisord
#Add supervisord conf
ADD supervisord.conf /etc/supervisord.conf
#copy start script
ADD startserv.sh /startserv.sh
RUN chmod +x /startserv.sh
#Set port
EXPOSE 9000
# For collecting logs, install filebeat plugin
RUN mkdir /logs
RUN ln -s /var/log/nginx /logs/
RUN ln -s /var/opt/remi/php70/log/php-fpm /logs
ADD filebeat-6.0.0-linux-x86_64.tar.gz /var/log/
RUN chmod +x /var/log/filebeat/filebeat
#Start web server
#ENTRYPOINT ["/var/log/filebeat/init.sh"]
CMD ["/startserv.sh"] |
5.2 nginx参数配置优化
以下配置是对nginx服务的一些性能指标参数来优化,并一起打包到基础镜像中。
user nginx;
worker_processes 2;
worker_cpu_affinity auto;
error_log /var/log/nginx/error.log error;
worker_rlimit_nofile 10240;
worker_priority -2;
events {
use epoll;
accept_mutex on;
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'upstream_addr:"$upstream_addr" '
'upstream_cache_status:"$upstream_cache_status" '
'upstream_status:"$upstream_status" ';
access_log /var/log/nginx/access.log main;
sendfile on;
sendfile_max_chunk 512k;
aio threads;
directio 4m;
keepalive_timeout 65;
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
gzip on;
gzip_comp_level 4;
gzip_disable "MSIE [1-6].";
gzip_min_length 10k;
gzip_http_version 1.0;
gzip_types text/plain text/css text/xml text/javascript application/xml application/x-javascript application/xml+rss application/javascript application/json;
gzip_vary on;
client_max_body_size 2m;
include /etc/nginx/conf.d/*.conf;
} |
5.3 supervisord.conf配置参数
容器中只能运行一个进程,如果需要运行多个进程我们使用了supervisord后台管理进程工具,方便多进程启动监控。以下红色字体加入了filebeat启动命令。
[unix_http_server]
file=/tmp/supervisor.sock ; (the path to the socket file)
[supervisord]
logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=true ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
user=root ;
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
[program:php-fpm]
command=/opt/remi/php70/root/usr/sbin/php-fpm -F
[program:nginx]
command=/usr/sbin/nginx -c /etc/nginx/nginx.conf
[program:filebeat]
command=/var/log/filebeat/filebeat -c /var/log/filebeat/filebeat.yml |
5.4 startserv.sh启动脚本
以下红色字体部分的内容主要是为了生成一个filebeat.yml文件,让filebeat程序加载对应的app_id,service_id,host_name,logstash等参数值,并将服务接起来。
#!/bin/sh
ip=`ip a|grep -w inet|grep -v -w lo|awk '{print $2}'|awk -F'/' '{print $1}'`
LOGS="/logs/"
#FILE=`ls -l $LOGS |awk '/^d/ {print $NF}'`
FILE=`ls $LOGS`
HOME="/var/log/filebeat"
BAK="$HOME/bak"
CONF="$HOME/filebeat.yml"
HOST_NAME=`hostname`
cp $BAK $CONF
for name in $FILE
do
sed -i "/paths/a\ - $LOGS$name/*.log" $CONF
done
sed -i "s/#APP_ID#/$APP_ID/g" $CONF
sed -i "s/#ip#/$ip/g" $CONF
sed -i "s/#SERVICE_ID#/$SERVICE_ID/g" $CONF
sed -i "s/#HOST_NAME#/$HOST_NAME/g" $CONF
sed -i "s/#LOGSTASH_HOST#/$LOGSTASH_HOST/g" $CONF
/usr/bin/supervisord -n -c /etc/supervisord.conf |
filebeat.yml例子:
filebeat:
spool_size: 10240
idle_timeout: "10s"
prospectors:
-
paths:
- /logs/php-fpm/*.log
- /logs/nginx/*.log
fields:
app_id: "6db116df"
service_id: "_6db116df_64a00233"
host_name: "139b3e343614"
fields_under_root: true
tail_files: true
document_type: "172.17.0.2"
processors:
- drop_fields:
fields: ["input_type", "beat", "offset"]
output.logstash:
hosts: ["XX.XX.XX.XX:5044"]
worker: 2 |
打包应用镜像
docker build –t acitivty_front:6.0-201711221420 .
5.5 启动应用容器
以上操作已经封装成一个新的应用镜像acitivty_front:6.0-201711221420,然后通过docker运行指令来启动应用镜像。
docker run -itd -p 80:80 -e APP_ID=6db116df -e SERVICE_ID=_6db116df_64a00233 -e LOGSTASH_HOST=<日志服务器IP> acitivty_front:6.0-201711221420
6 提取日志结果
应用容器拉起来后同时会启动动应用和filebeat插件,容器就会自动对应用日志统一收集并推送到日志服务器。以下是日志服务器中看到的提取出来的容器中的应用日志。

Logstash日志目录解析
日志服务器logstash接收日志