Rootop 服务器运维与web架构

2019-10-10
发表者 Venus
The ‘INFORMATION_SCHEMA.SESSION_VARIABLES’ feature is disabled; see the documentation for ‘show_compatibility_56’已关闭评论

The ‘INFORMATION_SCHEMA.SESSION_VARIABLES’ feature is disabled; see the documentation for ‘show_compatibility_56’

在用MySQL-Front时报错。


The ‘INFORMATION_SCHEMA.SESSION_VARIABLES’ feature is disabled; see the documentation for ‘show_compatibility_56’

原因:
从mysql5.7.6开始 information_schema.global_status 已经开始被舍弃(表不存在),为了兼容性,此时需要打开show_compatibility_56

临时打开:
进入mysql命令行执行:

MySQL> set global show_compatibility_56=on;
MySQL> show variables like '%show_compatibility_56%';

永久打开:
修改mysql配置文件my.ini/my.cnf
在 [mysqld]段添加一行

show_compatibility_56 = 1

重启MySQL生效。

2019-08-30
发表者 Venus
nginx日志转为json格式已关闭评论

nginx日志转为json格式

# nginx配置文件

# 手动拼成json格式
log_format log_json
'{'
	'"remote_addr":"$remote_addr",'
	'"x-forwarded-for":"$http_x_forwarded_for",'
	'"remote_user":"$remote_user",'
	'"time_local":"$time_local",'
	'"request":"$request",'
	'"status":"$status",'
	'"body_bytes_sent":"$body_bytes_sent",'
	'"http_referer":"$http_referer",'
	'"user_agent":"$http_user_agent"'
'}';

# 通过内置参数实现,需要nginx版本 >= 1.11.8
# 官方文档:http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format
log_format log_json2 escape=json
'{'
	'"remote_addr":"$remote_addr",'
	'"x-forwarded-for":"$http_x_forwarded_for",'
	'"remote_user":"$remote_user",'
	'"time_local":"$time_local",'
	'"request":"$request",'
	'"status":"$status",'
	'"body_bytes_sent":"$body_bytes_sent",'
	'"http_referer":"$http_referer",'
	'"user_agent":"$http_user_agent"'
'}';

server
{
	listen 80;
	root html;
	access_log /tmp/access.log log_json2;
}

# 浏览器请求地址
http://192.168.10.17/index.php?method=\add&id=1

# 不加 escape=json 参数日志打印

{"remote_addr":"192.168.1.139","x-forwarded-for":"-","remote_user":"-","time_local":"30/Aug/2019:14:28:46 +0800","request":"GET /index.php?method=\x5Cadd&id=1 HTTP/1.1","status":"404","body_bytes_sent":"555","http_referer":"-","user_agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0"}

# 添加 escape=json 参数日志打印

{"remote_addr":"192.168.1.139","x-forwarded-for":"","remote_user":"","time_local":"30/Aug/2019:14:28:24 +0800","request":"GET /index.php?method=\\add&id=1 HTTP/1.1","status":"404","body_bytes_sent":"555","http_referer":"","user_agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0"}

可以看到x-forwarded-for和request两个字段是不同的。
日志如果获取不到调用变量的值,则用 横杠 “-” 做为值,添加了escape=json参数则变为空字符串。
反斜杠 “\” 变为 “\x5C”,添加了escape=json参数则自动转义,前面又添加了个反斜杠 “\\”

之前手动拼出来的json格式,在python里解析时候就报错,知道是转义问题,但是不知道怎么解决,今天发现支持内部转义。
这样json格式便于日志分析处理。

2019-08-29
发表者 Venus
nginx 四层代理已关闭评论

nginx 四层代理

官方文档:http://nginx.org/en/docs/stream/ngx_stream_core_module.html
nginx四层代理需要ngx_stream_core_module模块支持,这个模块需要在nginx1.9版本之后。
默认这个模块不会编译,需要加编译参数–with-stream

[root@localhost nginx-1.17.3]# ./configure --prefix=/usr/local/nginx --with-stream

# 主配置文件通过include指令引入其他目录下的配置文件,便于管理。

[root@localhost ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes  1;
events
{
	worker_connections  1024;
}

http {
	include       mime.types;
	default_type  application/octet-stream;
	sendfile        on;
	keepalive_timeout  65;
	server
	{
		listen       80;
		server_name  localhost;
		location /
		{
			root   html;
			index  index.html index.htm;
		}
	}
}
# 注意这个include是在http{}配置段外层,也就是说stream和http段是平级的。
include vhost/*.conf;

# 四层代理配置

[root@localhost conf]# cat vhost/a.conf 
stream {

	upstream ssh
	{
		server 192.168.10.74:22;
	}

	server
	{
		listen 8888;
		proxy_pass ssh;
	}
}

这样ssh登陆本机8888端口时,就会连接74这台机器的22端口。
upstream中可以写多个server,也支持会话保持。
会话保持参考官方文档:http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#hash

2019-08-28
发表者 Venus
fluentd接收docker日志转存到kafka (elasticsearch+fluentd+kafka+logstash+kibana)已关闭评论

fluentd接收docker日志转存到kafka (elasticsearch+fluentd+kafka+logstash+kibana)

系统版本:centos7
IP:192.168.10.74

组件版本:
logstash 6.6.2
elasticsearch 6.5.4
kibana 6.5.4
fluentd 1.3.2
kafka 2.12-2.3.0
都安装在本机。

目的:
docker容器(应用日志输出为json格式)日志通过log-driver直接输出到fluentd。
fluentd将接收的日志生产转存到kafka消息队列。
logstash从kafka中消费日志,经过处理后输出到elasticsearch中用于检索。
kibana展示。

# kafka消息队列
配置参考:http://www.rootop.org/pages/4508.html
此处略过

# 启动一个fluentd

[root@localhost]# docker pull fluentd
[root@localhost]# docker run -dit --name fluentd -p 24224:24224 -p 24224:24224/udp docker.io/fluent/fluentd

# 进入fluentd容器,配置转存kafka
fluentd docker版安装kafka插件 官网文档:https://docs.fluentd.org/output/kafka
1、安装插件

# fluent-gem install fluent-plugin-kafka

2、编辑配置文件

# vi /fluentd/etc/fluent.conf

<source>
  @type  forward
  @id    input1
  @label @mainstream
  port  24224
</source>

<filter **>
  @type stdout
</filter>

<label @mainstream>
  <match docker.**>
    @type file
    @id   output_docker1
    path         /fluentd/log/docker.*.log
    symlink_path /fluentd/log/docker.log
    append       true
    time_slice_format %Y%m%d
    time_slice_wait   1m
    time_format       %Y%m%dT%H%M%S%z
  </match>

  <match **>
    @type kafka2

    # list of seed brokers,这个地方可以通过逗号写多个地址比如 host1:9092,host2:9092
    brokers 192.168.10.74:9092
    use_event_time true

    # buffer settings
    <buffer topic>
	@type file
	# 下面的path可能需要手动创建目录,并给写入权限,我直接给了777
	path /var/log/td-agent/buffer/td
	flush_interval 3s
    </buffer>

    # data type settings
    <format>
	@type json
    </format>

    # kafka中创建的topic
    topic_key test
	# 默认topic
    default_topic test
    get_kafka_client_log true
    # producer settings
    required_acks -1
    compression_codec gzip
  </match>
</label>

保存退出,重启容器。

# docker容器通过log-driver输出到fluentd

[root@localhost]# docker run -dit --name name-api-2 -v /home/dockermount/api:/mnt --publish-all --log-driver=fluentd --log-opt fluentd-address=192.168.10.74:24224 --log-opt fluentd-async-connect java8t

docker fluentd官方资料:https://docs.docker.com/config/containers/logging/fluentd/
fluentd-async-connect # 此参数可以防止连不上fluentd导致容器退出。
Docker connects to Fluentd in the background. Messages are buffered until the connection is established. Defaults to false.
If container cannot connect to the Fluentd daemon, the container stops immediately unless the fluentd-async-connect option is used.
目前为止,容器日志已经可以写入kafka了。

# 安装es、kibana

[root@localhost log]# docker run -dit --name es -p 9200:9200 -p 9200:9200/udp elasticsearch:6.5.4
[root@localhost log]# docker run -dit --name kibana -e ELASTICSEARCH_HOST=http://192.168.10.74:9200 -e ELASTICSEARCH_URL=http://192.168.10.74:9200 -p 5601:5601 kibana:6.5.4

# 配置logstash配置文件,直接rpm安装,过程略。

[root@localhost ~]# cd /usr/share/logstash/
[root@localhost logstash]# cat kafka.conf 
input {

	kafka {
		bootstrap_servers => ["192.168.10.74:9092"]
		client_id => "test1"
		group_id => "test1"
		auto_offset_reset => "latest"
		consumer_threads => 1
		decorate_events => false
		topics => ["test"]
		type => "fromk"
	}
}

filter {
	
    json {
		# 将message字段的key及value(json格式)导入到es,在根部生成新字段。
        source => "message"
		# 添加新列,便于下面再执行source
		add_field => { "@javalog" => "%{log}" }
    }

	# 将json中的json字段、值导入到es中(json嵌套json)
	# {"xxx":"xxx","log":{"time":"xxx","path":"xxx"}}
	# 即导入json中的log


	# 第二次解析json串
    json {
		source => "@javalog"
		# 移除没用的字段
		remove_field => [ "log","@javalog" ]
    }
}

output
{

	elasticsearch {
		hosts => "192.168.10.74"
		index => "jar-log-%{+YYYY.MM.dd}"
	}

	stdout {
		codec => rubydebug
	}

}

# 启动logstash

[root@localhost logstash]# logstash -f kafka.conf

# 容器中java应用日志输出格式为:

{"@timestamp":"2019-08-22T15:09:26.801+08:00","@version":"1","message":"运行时报错:","logger_name":"com.sailei.modules.test.controller.TestController","threa"level":"INFO","level_value":20000}

# docker fluentd日志输出会将应用产生的日志再加入4个元数据发给fluentd(仍然是json格式):
container_id #The full 64-character container ID.
container_name #The container name at the time it was started. If you use docker rename to rename a container, the new name is not reflected in the journal entries.
source #stdout or stderr
log #The container log 应用日志会在log字段中做为value

所以要在logstash中处理json嵌套,获取log字段中数据(提取到根部,便于检索)。
(本来想用filebeat处理json问题,结果因为log字段和filebeat内部一个方法关键词冲突,导致log字段中的数据无法加到根部,才换的logstash)

2019-08-27
发表者 Venus
通过HSTS实现浏览器自动跳转https(非服务器响应跳转)已关闭评论

通过HSTS实现浏览器自动跳转https(非服务器响应跳转)

nginx中关于hsts资料:https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

全称 HTTP Strict Transport Security

HSTS目的是让浏览器在访问网站的时候浏览器内部自动实现https协议访问(不需要服务器告诉浏览器跳转https)。
在没有hsts功能时,需要自己在nginx里配置http跳转https。
但是这样每个请求(可能)都需要nginx告诉浏览器你访问的地址需要跳转到https,这样就浪费了时间。

hsts需要在第一次访问https时,服务器返回一个指定的响应头,用于告诉浏览器你可以用hsts功能。
然后后续的访问都会自动走https,而不需要跳转了(浏览器内部自己跳转,下面会说)。

nginx配置:

# 首先配置 http跳转https
if ($scheme = http) {
	return 301 https://$host$request_uri;
}

# 添加hsts响应头,可以在server{}段,或者location中。

add_header Strict-Transport-Security "max-age=86400; includeSubdomains; preload";

# 参数解释
max-age # 必选参数,告诉浏览器在多少秒内一直用https (关闭浏览器不会失效、刷新页面会延长失效时间)
includeSubdomains # 可选参数,包括子域名
preload # 可选参数,使用HSTS预加载列表,在nginx文档有说明

这里就不演示我自己的站了(HK的机器https不稳定)。
我们来看百度的首页

第一次访问http协议的百度首页,百度响应头里回应了需要跳转到https。

第二次访问https,响应头里有Strict-Transport-Security参数,生命周期是172800秒,也就是48小时。也就是在放着当前页面不动的情况下,48小时内刷新页面,或者关掉浏览器重新访问百度,都会自动访问https。

关掉浏览器,重新打开百度

第一次发起http协议访问,看到状态码是 307 internal redirect ,307内部跳转,这就是浏览器内部自己实现的,没有通过服务器来返回location头跳转。

第二个请求就直接https协议访问服务器了。

chrome浏览器里可以通过访问: chrome://net-internals/#hsts 搜索支持的域名。