1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
|
local function init(env)
-- 判断是否是在root目录下
if env.is_root_path then
print('Warning! Running apisix under /root is only suitable for '
.. 'development environments and it is dangerous to do so. '
.. 'It is recommended to run APISIX in a directory '
.. 'other than /root.')
end
-- 判断获取到机器的打开文件句柄数量是否正确或者低于min_ulimit 1024
local min_ulimit = 1024
if env.ulimit ~= "unlimited" and env.ulimit <= min_ulimit then
print(str_format("Warning! Current maximum number of open file "
.. "descriptors [%d] is not greater than %d, please increase user limits by "
.. "execute \'ulimit -n <new user limits>\' , otherwise the performance"
.. " is low.", env.ulimit, min_ulimit))
end
-- 读取默认配置以及用户定义配置,并进行合并
local yaml_conf, err = file.read_yaml_conf(env.apisix_home)
if not yaml_conf then
util.die("failed to read local yaml config of apisix: ", err, "\n")
end
local ok, err = schema.validate(yaml_conf)
if not ok then
util.die(err, "\n")
end
-- 针对admin api做相关检测,白名单、token等
local checked_admin_key = false
local allow_admin = yaml_conf.deployment.admin and
yaml_conf.deployment.admin.allow_admin
if yaml_conf.apisix.enable_admin and allow_admin then
for _, allow_ip in ipairs(allow_admin) do
if allow_ip == "127.0.0.0/24" then
checked_admin_key = true
end
end
end
if yaml_conf.apisix.enable_admin and not checked_admin_key then
local help = [[
%s
Please modify "admin_key" in conf/config.yaml .
]]
local admin_key = yaml_conf.deployment.admin
if admin_key then
admin_key = admin_key.admin_key
end
if type(admin_key) ~= "table" or #admin_key == 0
then
util.die(help:format("ERROR: missing valid Admin API token."))
end
for _, admin in ipairs(admin_key) do
if type(admin.key) == "table" then
admin.key = ""
else
admin.key = tostring(admin.key)
end
if admin.key == "" then
util.die(help:format("ERROR: missing valid Admin API token."), "\n")
end
if admin.key == "edd1c9f034335f136f87ad84b625c8f1" then
stderr:write(
help:format([[WARNING: using fixed Admin API token has security risk.]]),
"\n"
)
end
end
end
-- admin证书相关校验配置
if yaml_conf.deployment.admin then
local admin_api_mtls = yaml_conf.deployment.admin.admin_api_mtls
local https_admin = yaml_conf.deployment.admin.https_admin
if https_admin and not (admin_api_mtls and
admin_api_mtls.admin_ssl_cert and
admin_api_mtls.admin_ssl_cert ~= "" and
admin_api_mtls.admin_ssl_cert_key and
admin_api_mtls.admin_ssl_cert_key ~= "")
then
util.die("missing ssl cert for https admin")
end
end
if yaml_conf.apisix.enable_admin and
yaml_conf.deployment.config_provider == "yaml"
then
util.die("ERROR: Admin API can only be used with etcd config_provider.\n")
end
-- 获取openresty版本,如果没有既说明找不到本机的openresty可执行文件
local or_ver = get_openresty_version()
if or_ver == nil then
util.die("can not find openresty\n")
end
-- 根据获取的openresty版本信息进行比较是否为指定版本范围内
local need_ver = "1.19.3"
if not version_greater_equal(or_ver, need_ver) then
util.die("openresty version must >=", need_ver, " current ", or_ver, "\n")
end
-- 检查openresty是否安装了http_stub_status_module
local or_info = env.openresty_info
if not or_info:find("http_stub_status_module", 1, true) then
util.die("'http_stub_status_module' module is missing in ",
"your openresty, please check it out.\n")
end
-- 判断是否启用http,以及是否只启用了stream
local enable_http = true
if not yaml_conf.apisix.enable_admin and yaml_conf.apisix.stream_proxy and
yaml_conf.apisix.stream_proxy.only ~= false
then
enable_http = false
end
-- 是否启动了自动发现
local enabled_discoveries = {}
for name in pairs(yaml_conf.discovery or {}) do
enabled_discoveries[name] = true
end
-- 启动的插件
local enabled_plugins = {}
for i, name in ipairs(yaml_conf.plugins or {}) do
enabled_plugins[name] = true
end
-- 启动的stream插件
local enabled_stream_plugins = {}
for i, name in ipairs(yaml_conf.stream_plugins or {}) do
enabled_stream_plugins[name] = true
end
-- 启动了插件proxy-cache,但是没有找到相关配置
if enabled_plugins["proxy-cache"] and not yaml_conf.apisix.proxy_cache then
util.die("missing apisix.proxy_cache for plugin proxy-cache\n")
end
-- 是否启动了插件batch-requests,批请求
if enabled_plugins["batch-requests"] then
local pass_real_client_ip = false
local real_ip_from = yaml_conf.nginx_config.http.real_ip_from
-- the real_ip_from is enabled by default, we just need to make sure it's
-- not disabled by the users
if real_ip_from then
for _, ip in ipairs(real_ip_from) do
local _ip = cli_ip:new(ip)
if _ip then
if _ip:is_loopback() or _ip:is_unspecified() then
pass_real_client_ip = true
end
end
end
end
if not pass_real_client_ip then
util.die("missing loopback or unspecified in the nginx_config.http.real_ip_from" ..
" for plugin batch-requests\n")
end
end
local ports_to_check = {}
local function validate_and_get_listen_addr(port_name, default_ip, configured_ip,
default_port, configured_port)
local ip = configured_ip or default_ip
local port = tonumber(configured_port) or default_port
if ports_to_check[port] ~= nil then
util.die(port_name .. " ", port, " conflicts with ", ports_to_check[port], "\n")
end
ports_to_check[port] = port_name
return ip .. ":" .. port
end
-- 监听在管理中使用单独端口,支持指定IP,兼容原有风格,并检测listen格式是否正确
local admin_server_addr
if yaml_conf.apisix.enable_admin then
local ip = yaml_conf.deployment.admin.admin_listen.ip
local port = yaml_conf.deployment.admin.admin_listen.port
admin_server_addr = validate_and_get_listen_addr("admin port", "0.0.0.0", ip,
9180, port)
end
-- 监听在control中使用单独端口,支持指定ip,并检测listen格式是否正确
local control_server_addr
if yaml_conf.apisix.enable_control then
if not yaml_conf.apisix.control then
control_server_addr = validate_and_get_listen_addr("control port", "127.0.0.1", nil,
9090, nil)
else
control_server_addr = validate_and_get_listen_addr("control port", "127.0.0.1",
yaml_conf.apisix.control.ip,
9090, yaml_conf.apisix.control.port)
end
end
-- 监听在prometheus中使用listen地址,并检测listen格式是否正确
local prometheus_server_addr
if yaml_conf.plugin_attr.prometheus then
local prometheus = yaml_conf.plugin_attr.prometheus
if prometheus.enable_export_server then
prometheus_server_addr = validate_and_get_listen_addr("prometheus port", "127.0.0.1",
prometheus.export_addr.ip,
9091, prometheus.export_addr.port)
end
end
if enabled_stream_plugins["prometheus"] and not prometheus_server_addr then
util.die("L4 prometheus metric should be exposed via export server\n")
end
local ip_port_to_check = {}
local function listen_table_insert(listen_table, scheme, ip, port, enable_http2, enable_ipv6)
if type(ip) ~= "string" then
util.die(scheme, " listen ip format error, must be string", "\n")
end
if type(port) ~= "number" then
util.die(scheme, " listen port format error, must be number", "\n")
end
if ports_to_check[port] ~= nil then
util.die(scheme, " listen port ", port, " conflicts with ",
ports_to_check[port], "\n")
end
local addr = ip .. ":" .. port
if ip_port_to_check[addr] == nil then
table_insert(listen_table,
{ip = ip, port = port, enable_http2 = enable_http2})
ip_port_to_check[addr] = scheme
end
if enable_ipv6 then
ip = "[::]"
addr = ip .. ":" .. port
if ip_port_to_check[addr] == nil then
table_insert(listen_table,
{ip = ip, port = port, enable_http2 = enable_http2})
ip_port_to_check[addr] = scheme
end
end
end
local node_listen = {}
-- 将http监听地址按照指定格式插入到node_listen,支持多个地址,并且将node_listen重新赋值给yaml_conf.apisix.node_listen
if type(yaml_conf.apisix.node_listen) == "number" then
listen_table_insert(node_listen, "http", "0.0.0.0", yaml_conf.apisix.node_listen,
false, yaml_conf.apisix.enable_ipv6)
elseif type(yaml_conf.apisix.node_listen) == "table" then
for _, value in ipairs(yaml_conf.apisix.node_listen) do
if type(value) == "number" then
listen_table_insert(node_listen, "http", "0.0.0.0", value,
false, yaml_conf.apisix.enable_ipv6)
elseif type(value) == "table" then
local ip = value.ip
local port = value.port
local enable_ipv6 = false
local enable_http2 = value.enable_http2
if ip == nil then
ip = "0.0.0.0"
if yaml_conf.apisix.enable_ipv6 then
enable_ipv6 = true
end
end
if port == nil then
port = 9080
end
if enable_http2 == nil then
enable_http2 = false
end
listen_table_insert(node_listen, "http", ip, port,
enable_http2, enable_ipv6)
end
end
end
yaml_conf.apisix.node_listen = node_listen
local ssl_listen = {}
-- 将https监听地址按照指定格式插入到ssl_listen,支持多个地址,并且将ssl_listen重新赋值给yaml_conf.apisix.ssl_listen
for _, value in ipairs(yaml_conf.apisix.ssl.listen) do
local ip = value.ip
local port = value.port
local enable_ipv6 = false
local enable_http2 = value.enable_http2
if ip == nil then
ip = "0.0.0.0"
if yaml_conf.apisix.enable_ipv6 then
enable_ipv6 = true
end
end
if port == nil then
port = 9443
end
if enable_http2 == nil then
enable_http2 = false
end
listen_table_insert(ssl_listen, "https", ip, port,
enable_http2, enable_ipv6)
end
yaml_conf.apisix.ssl.listen = ssl_listen
-- ssl证书相关设置
if yaml_conf.apisix.ssl.ssl_trusted_certificate ~= nil then
local cert_path = yaml_conf.apisix.ssl.ssl_trusted_certificate
-- During validation, the path is relative to PWD
-- When Nginx starts, the path is relative to conf
-- Therefore we need to check the absolute version instead
cert_path = pl_path.abspath(cert_path)
if not pl_path.exists(cert_path) then
util.die("certificate path", cert_path, "doesn't exist\n")
end
yaml_conf.apisix.ssl.ssl_trusted_certificate = cert_path
end
-- enable ssl with place holder crt&key
yaml_conf.apisix.ssl.ssl_cert = "cert/ssl_PLACE_HOLDER.crt"
yaml_conf.apisix.ssl.ssl_cert_key = "cert/ssl_PLACE_HOLDER.key"
local tcp_enable_ssl
-- stream_proxy相关配置
if yaml_conf.apisix.stream_proxy and yaml_conf.apisix.stream_proxy.tcp then
local tcp = yaml_conf.apisix.stream_proxy.tcp
for i, item in ipairs(tcp) do
if type(item) ~= "table" then
tcp[i] = {addr = item}
else
if item.tls then
tcp_enable_ssl = true
end
end
end
end
-- dubbo-proxy相关配置
local dubbo_upstream_multiplex_count = 32
if yaml_conf.plugin_attr and yaml_conf.plugin_attr["dubbo-proxy"] then
local dubbo_conf = yaml_conf.plugin_attr["dubbo-proxy"]
if tonumber(dubbo_conf.upstream_multiplex_count) >= 1 then
dubbo_upstream_multiplex_count = dubbo_conf.upstream_multiplex_count
end
end
-- dns_resolver相关配置
if yaml_conf.apisix.dns_resolver_valid then
if tonumber(yaml_conf.apisix.dns_resolver_valid) == nil then
util.die("apisix->dns_resolver_valid should be a number")
end
end
-- proxy_mirror相关配置
local proxy_mirror_timeouts
if yaml_conf.plugin_attr["proxy-mirror"] then
proxy_mirror_timeouts = yaml_conf.plugin_attr["proxy-mirror"].timeout
end
local conf_server, err = snippet.generate_conf_server(env, yaml_conf)
if err then
util.die(err, "\n")
end
-- 如果是控制平面并且没有adminserver地址配置,就根据现有地址拼接adminserver地址
if yaml_conf.deployment and yaml_conf.deployment.role then
local role = yaml_conf.deployment.role
env.deployment_role = role
if role == "control_plane" and not admin_server_addr then
local listen = node_listen[1]
admin_server_addr = str_format("%s:%s", listen.ip, listen.port)
end
end
-- 模板渲染所需要的变量
local sys_conf = {
lua_path = env.pkg_path_org,
lua_cpath = env.pkg_cpath_org,
os_name = util.trim(util.execute_cmd("uname")),
apisix_lua_home = env.apisix_home,
deployment_role = env.deployment_role,
use_apisix_base = env.use_apisix_base,
error_log = {level = "warn"},
enable_http = enable_http,
enabled_discoveries = enabled_discoveries,
enabled_plugins = enabled_plugins,
enabled_stream_plugins = enabled_stream_plugins,
dubbo_upstream_multiplex_count = dubbo_upstream_multiplex_count,
tcp_enable_ssl = tcp_enable_ssl,
admin_server_addr = admin_server_addr,
control_server_addr = control_server_addr,
prometheus_server_addr = prometheus_server_addr,
proxy_mirror_timeouts = proxy_mirror_timeouts,
conf_server = conf_server,
}
-- 渲染前的检测
if not yaml_conf.apisix then
util.die("failed to read `apisix` field from yaml file")
end
if not yaml_conf.nginx_config then
util.die("failed to read `nginx_config` field from yaml file")
end
-- 使用命令getconf LONG_BIT获取系统位数,根据系统位数给nginx配置worker_rlimit_core进行赋值
if util.is_32bit_arch() then
sys_conf["worker_rlimit_core"] = "4G"
else
sys_conf["worker_rlimit_core"] = "16G"
end
-- 将配置文件中apisix段下的配置赋值到sys_conf中
for k,v in pairs(yaml_conf.apisix) do
sys_conf[k] = v
end
-- 将配置文件中nginx_config段下的配置赋值到sys_conf中,此段是nginx相关的配置更改
for k,v in pairs(yaml_conf.nginx_config) do
sys_conf[k] = v
end
-- 将将配置文件中deployment.admin下相关配置赋值到sys_conf中
if yaml_conf.deployment.admin then
for k,v in pairs(yaml_conf.deployment.admin) do
sys_conf[k] = v
end
end
sys_conf["wasm"] = yaml_conf.wasm
-- 如果worker_rlimit_nofile配置不存在或者worker_rlimit_nofile值小于worker_connections,就将worker_rlimit_nofile=worker_connections+128
local wrn = sys_conf["worker_rlimit_nofile"]
local wc = sys_conf["event"]["worker_connections"]
if not wrn or wrn <= wc then
-- ensure the number of fds is slightly larger than the number of conn
sys_conf["worker_rlimit_nofile"] = wc + 128
end
-- 如果是开发模式,就将进程设置为1,将防止惊群的配置设置为false,否则,如果worker_processes没有设置的话,就将worker_processes设置为auto
if sys_conf["enable_dev_mode"] == true then
sys_conf["worker_processes"] = 1
sys_conf["enable_reuseport"] = false
elseif tonumber(sys_conf["worker_processes"]) == nil then
sys_conf["worker_processes"] = "auto"
end
-- 如果dns_resolver没有设置,就从/etc/resolv.conf文件中将nameserver取出来赋值给sys_conf["dns_resolver"]
local dns_resolver = sys_conf["dns_resolver"]
if not dns_resolver or #dns_resolver == 0 then
local dns_addrs, err = local_dns_resolver("/etc/resolv.conf")
if not dns_addrs then
util.die("failed to import local DNS: ", err, "\n")
end
if #dns_addrs == 0 then
util.die("local DNS is empty\n")
end
sys_conf["dns_resolver"] = dns_addrs
end
-- 从dns_resolver中重新编码ipv6的格式,不支持的格式从列表中剔除
for i, r in ipairs(sys_conf["dns_resolver"]) do
if r:match(":[^:]*:") then
-- more than one colon, is IPv6
if r:byte(1) ~= str_byte('[') then
-- ensure IPv6 address is always wrapped in []
sys_conf["dns_resolver"][i] = "[" .. r .. "]"
end
end
-- check if the dns_resolver is ipv6 address with zone_id
-- Nginx does not support this form
if r:find("%%") then
stderr:write("unsupported DNS resolver: " .. r ..
", would ignore this item\n")
table_remove(sys_conf["dns_resolver"], i)
end
end
-- 从系统环境变量中获取APISIX_WORKER_PROCESSES,如果存在就将此值赋值给worker_processes
local env_worker_processes = getenv("APISIX_WORKER_PROCESSES")
if env_worker_processes then
sys_conf["worker_processes"] = floor(tonumber(env_worker_processes))
end
-- 针对exported变量做相关处理赋值
local exported_vars = file.get_exported_vars()
if exported_vars then
if not sys_conf["envs"] then
sys_conf["envs"]= {}
end
for _, cfg_env in ipairs(sys_conf["envs"]) do
local cfg_name
local from = str_find(cfg_env, "=", 1, true)
if from then
cfg_name = str_sub(cfg_env, 1, from - 1)
else
cfg_name = cfg_env
end
exported_vars[cfg_name] = false
end
for name, value in pairs(exported_vars) do
if value then
table_insert(sys_conf["envs"], name .. "=" .. value)
end
end
end
-- 如果启用了kubernetes的discoveries则注入kubernetes发现shard dict和环境变量
if enabled_discoveries["kubernetes"] then
if not sys_conf["discovery_shared_dicts"] then
sys_conf["discovery_shared_dicts"] = {}
end
local kubernetes_conf = yaml_conf.discovery["kubernetes"]
local inject_environment = function(conf, envs)
local keys = {
conf.service.host,
conf.service.port,
}
if conf.client.token then
table_insert(keys, conf.client.token)
end
if conf.client.token_file then
table_insert(keys, conf.client.token_file)
end
for _, key in ipairs(keys) do
if #key > 3 then
local first, second = str_byte(key, 1, 2)
if first == str_byte('$') and second == str_byte('{') then
local last = str_byte(key, #key)
if last == str_byte('}') then
envs[str_sub(key, 3, #key - 1)] = ""
end
end
end
end
end
local envs = {}
if #kubernetes_conf == 0 then
sys_conf["discovery_shared_dicts"]["kubernetes"] = kubernetes_conf.shared_size
inject_environment(kubernetes_conf, envs)
else
for _, item in ipairs(kubernetes_conf) do
sys_conf["discovery_shared_dicts"]["kubernetes-" .. item.id] = item.shared_size
inject_environment(item, envs)
end
end
if not sys_conf["envs"] then
sys_conf["envs"] = {}
end
for item in pairs(envs) do
table_insert(sys_conf["envs"], item)
end
end
-- 规范lua_path、lua_cpath路径,如果结尾不是;的加上;
sys_conf["extra_lua_path"] = get_lua_path(yaml_conf.apisix.extra_lua_path)
sys_conf["extra_lua_cpath"] = get_lua_path(yaml_conf.apisix.extra_lua_cpath)
-- 根据模版以及sys_conf生成nginx.conf配置文件
local conf_render = template.compile(ngx_tpl)
local ngxconf = conf_render(sys_conf)
local ok, err = util.write_file(env.apisix_home .. "/conf/nginx.conf",
ngxconf)
if not ok then
util.die("failed to update nginx.conf: ", err, "\n")
end
end
|