需求: java应用访问qyapi.weixin.qq.com时根据不同组织对应不同公网出口ip
java实现部分:更新token的任务,先把token写到redis里TTL设置为4小时,再写到mysql
redis格式为
注意事项 在nginx/openresty中 企微接口proxy_pass不要直接写域名 ,否则会走系统解析(nginx -s reload 时解析 变化后还需要再次reload)
使用变量定义就会走resolver配置
参考文档: https://blog.csdn.net/ai2000ai/article/details/96329239
实现: configmap public-openresty-nginx-conf.yaml
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 kind: ConfigMap apiVersion: v1 metadata: name: public-openresty-nginx-conf namespace: suosi-pre data: nginx.conf: >- user root; processing. pcre_jit on; events { worker_connections 1024 ; } http { include mime.types; default_type application/octet-stream; resolver 10.252 .0 .10 valid=5 ipv6=off; lua_socket_pool_size 30 ; lua_socket_keepalive_timeout 60s; log_format nginxlog_json escape=json '{"timestamp":"$time_iso8601","status":"$status","upstream_status":"$upstream_status","wx_crop_id":"$wx_crop_id","request_uri":"$request","request_time":"$request_time""upstream_addr":"$upstream_addr","upstream_response_time":"$upstream_response_time","host":"$host"}' ; access_log /dev/stdout nginxlog_json; error_log /dev/stdout notice; client_body_temp_path /var/run/openresty/nginx-client-body; proxy_temp_path /var/run/openresty/nginx-proxy; fastcgi_temp_path /var/run/openresty/nginx-fastcgi; uwsgi_temp_path /var/run/openresty/nginx-uwsgi; scgi_temp_path /var/run/openresty/nginx-scgi; sendfile on; keepalive_timeout 65 ; client_header_buffer_size 16k; lua_shared_dict crop_id 10m; init_by_lua_file '/usr/local/openresty/nginx/lua/init_map.lua' ; include conf.d/*.conf; }
public-openresty-nginx-confd.yaml
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 kind: ConfigMap apiVersion: v1 metadata: name: public-openresty-nginx-confd namespace: suosi-pre data: cropid_map.map: '' server.crt: |- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIJANAXkECaGgIgMA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD VQQGEwJDTjELMAkGA1UECAwCU0QxCzAJBgNVBAcMAkpOMQ0wCwYDVQQKDARRRFpZ MRwwGgYDVQQLDBNxeWFwaS53ZWl4aW4ucXEuY29tMQswCQYDVQQDDAJDQTEdMBsG CSqGSIb3DQEJARYOYWRtaW5AdGVzdC5jb20wIBcNMjMwNTI0MDcxMzQ1WhgPMjIy ODA5MjYwNzEzNDVaMIGAMQswCQYDVQQGEwJDTjELMAkGA1UECAwCU0QxCzAJBgNV BAcMAkpOMQ0wCwYDVQQKDARRRFpZMRwwGgYDVQQLDBNxeWFwaS53ZWl4aW4ucXEu Y29tMQswCQYDVQQDDAJDQTEdMBsGCSqGSIb3DQEJARYOYWRtaW5AdGVzdC5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDgr+ktRZzDmV0FejtLJ6Jk B9FSu95yZSAmm8AWsPKXXU9BYQE0MTTmdEnqW+KnhOLPaTpxaD1xJwEXqSIrSKsX nYs2rfby4+duW9+7Xe4J9UxONHvAuctzOm0i5UoaMcfKi99Yny7WDNjYvFTEgTdn GBSCo8VYbyqZ7RTAbU17E76uCXf6KQb0e81ziANsxGaCzdx8F+nuENNfZca+RQRj xnXDcThi6NihZrQxRiHlPeIGqbUbG5ZQTS33AA85LW6O8kcRQEXNPAqItSZVELci ov1dqmRgdI2K9uyoj3ipFu64CJ2grY1FKLAXJkO1IYp08IAkCPvKLTYUh6xL1Ou7 AgMBAAGjKDAmMCQGA1UdEQQdMBuCE3F5YXBpLndlaXhpbi5xcS5jb22HBAAAAAAw DQYJKoZIhvcNAQELBQADggEBAIafbkCm+PSR3YBYl42lD+MbIkAEUps58WvqgdJO 7UT3lX7V7V3lqfaO8mx3+Q24ruH8+PaoA064PT3LYlzlG+2EIU3Jy9/cl+6Pp2LO xez+6GYcJxf/XpN5kwcm1HT4gYfhXyKWw1+Bhmujqauyz7tvIG+zxE3kEJzzzxRu sfIDol45ZY4aPVcpB/mzh+JWkRdhMuXtyntLXEeCcMAZJRcdiIQLnILb55MiwC/q MMwjZWBN6OpmraXLD7zQb7BYkJ4KK+II5HwMQZiEiZDrnqYmd2Zs8Hx1EF4XpKNO LsTa1Ebm2Sf4xXXw+v72l0LLErfmHf8yjsaVQe+wXW+OrnM= -----END CERTIFICATE----- server.key: |- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA4K/pLUWcw5ldBXo7SyeiZAfRUrvecmUgJpvAFrDyl11PQWEB NDE05nRJ6lvip4Tiz2k6cWg9cScBF6kiK0irF52LNq328uPnblvfu13uCfVMTjR7 wLnLczptIuVKGjHHyovfWJ8u1gzY2LxUxIE3ZxgUgqPFWG8qme0UwG1NexO+rgl3 +ikG9HvNc4gDbMRmgs3cfBfp7hDTX2XGvkUEY8Z1w3E4YujYoWa0MUYh5T3iBqm1 GxuWUE0t9wAPOS1ujvJHEUBFzTwKiLUmVRC3IqL9XapkYHSNivbsqI94qRbuuAid oK2NRSiwFyZDtSGKdPCAJAj7yi02FIesS9TruwIDAQABAoIBAEsDb93ld8j10tCZ VmJpARZUZdYxUrrueCVrql3pBZTzWhqBwF0kcHzgJi1QMAOtoeuNPi3Ol3THiN3V YcsBn91qg6flvKSq4gE+Oxva6DX651bUvtxBK2N1Biq4Ul0ccY9100NLId/kuiDh /4r7ePu6Vl6nPqOfuaFaPatg0pVcCfjpStPAf5YCpUeXpJfGFt5VGAKxf65vKCkh grbppM9yVzs2iiVK3U/STpbPXDC9e7/2aoqtNeKlCLPrUWKGFwZpBR+SxpUHHIZ1 3qb/JovEdeSN4Dl5xjwNHt7hd4SRAp/86NLEw5YVbvuRjkSzmMNrj4mfrMPPAZ6C NEH3ZcECgYEA+CLusJ0r1N1oGdQ99ALLIoXje7AqYFxwVTrcD5Y7d6m5npLr+hs7 yIWMz189MG1zWwv/s9RM9secsry+HhnltJ1qQZTOy7NZFMtnKKAa0NUy2xBQUslE AtgQgBGNIvVYK4upE2nngL0NAvNG7Sgwyv9UFtMyeprcqYH5xOtcIQ0CgYEA5869 ggoE7O+lBrbRu723MuaXj2mg8Y+UzxrIqgwX08HsMGub7P00SVyIwoybTQJNPGie 1kz82xDwXzrFq7H1tp1iEk103kHJq1rO0ggatrgD0VM0YpA9Xltv4/qA5xaVBo4B RhNrpjEj8pSn549CNfhqTMzeesd3bH8KXIRfPecCgYEA9VLEHgUmQqwrse2u2sKw Rw+MWstO+joqLXml/BsR7Dr3c5naiEnIj3XKQ3PrsSdk900jn410EkBD4krMxEHi YvGHDhOraKWGmxKGiRnRqUo/n2m/oDmwbgdkONohacCbTWIk5Ta9VQCUDqirJOmp Y+mQH4jqzWCybTw9zrzLNzkCgYEAsLCTHqXIb1mTLnT3lOTc2T2O1M+sz7Ojt+Ew hv1ExDISeC3t4kx2KF0SGUjXr3FLsfoE6FAyhEB7F/tSZLb3FcUM1eqYZDk9IRHM h6eJxTCqKEoFqgNL47pKpTlyO7Ko0SA4tFNlQH5Aak0JVqWJ0F2TmQqnomqcCuUi 3rY/ao0CgYBzZMeD/J6XTYzU7IU4xIpvcGPVGMXCgBgu99UOKG3IZNp8bRonupx7 77R6S8hzqup7b2mr19yb7nGYZVcEx1QLJrE6dghULqVaONMhRaEAnTBfJ44tmHy/ h1mlLqSyeiunl13ZY/rJ/NXwgn5hmpclLP+Z7dC4squwWyUU+TVIjA== -----END RSA PRIVATE KEY----- test.conf: |- upstream svc1 { server qywx-svc1.suosi-pre.svc.cluster.local:20000; } upstream svc2 { server whoami.pre.suosihulian.com; } server { listen 80 ; set $wx_crop_id "" ; set $wx_upstream "" ; set $wx_host "" ; location / { default_type text/html; access_by_lua_file '/usr/local/openresty/nginx/lua/getredis.lua' ; proxy_set_header Host $wx_host; proxy_pass $wx_upstream; } location /health { return 200 'ok' ; } } server { listen 443 ssl; ssl_certificate /usr/local/openresty/nginx/conf/conf.d/server.crt; ssl_certificate_key /usr/local/openresty/nginx/conf/conf.d/server.key; set $wx_crop_id "" ; set $wx_upstream "" ; set $wx_host "" ; location / { default_type text/html; access_by_lua_file '/usr/local/openresty/nginx/lua/getredis.lua' ; proxy_set_header Host $wx_host; proxy_pass $wx_upstream; } }
public-openresty-nginx-lua.yaml
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 kind: ConfigMap apiVersion: v1 metadata: name: public-openresty-nginx-lua namespace: suosi-pre data: getredis.lua: | local redis = require("resty.redis"); local cjson = require("cjson") local red = redis:new(); red:set_timeout(5000) local host = "xxxxx" local port = 6379 local password = "xxxx" local access_token = ngx.var.arg_access_token local function ret_def() ngx.var.wx_upstream = "https://qyapi.weixin.qq.com" ngx.var.wx_host = "qyapi.weixin.qq.com" ngx.var.wx_crop_id = "no" end if type(access_token) == "nil" then ret_def() return end local keys = 'qwtoken:' .. access_token -- 连接redis local ok, err = red:connect(host, port) if not ok then io.stderr:write('cant connect redis\n') ret_def() return end local res, err = red:auth(password) if not res then io.stderr:write('cant auth redis\n') return end -- 选择db ok, err = red:select(3) if not ok then io.stderr:write('failed to select db\n') ret_def() return end -- 获取redis key local res, err = red:get(keys) if not res then io.stderr:write('cant get redis\n') ret_def() return end ok, err = red:set_keepalive(10000, 300 ) --线程池 if not ok then io.stderr:write('cant close redis\n') ret_def() return end -- 将string转为map local keys = ngx.shared.crop_id:get("a") local my_table = cjson.decode(keys) local value = my_table[res] if value then ngx.var.wx_crop_id = res ngx.var.wx_upstream = "http://" .. value ngx.var.wx_host = "qyapi.weixin.qq.com" -- 后续的服务会加这个HOST else ret_def() end init_map.lua: >- local cjson = require("cjson") local function load_map(file_path) local map = {} local file = io.open(file_path, "r") if not file then ngx.log(ngx.ERR, "Failed to open map file: " , file_path) return map end for line in file:lines() do local key, value = string.match(line, [["(%S+)" %s+"(%S+)"; ]]) if key and value then map[key] = value end end file:close() return map end local map_file_path = "/usr/local/openresty/nginx/conf/conf.d/cropid_map.map" local tmp = load_map(map_file_path) ngx.shared.crop_id:set("a", cjson.encode(tmp)) local keys = ngx.shared.crop_id:get("a") io.stderr:write("\n---------------------------------\n") io.stderr:write("JSON: ", keys, " \n")
svc public-openresty.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 kind: Service apiVersion: v1 metadata: name: public-openresty namespace: suosi-pre spec: ports: - name: tcp-443 protocol: TCP port: 443 targetPort: 443 - name: tcp-80 protocol: TCP port: 80 targetPort: 80 selector: app: public-openresty type: ClusterIP sessionAffinity: None
qywx-svc1.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 kind: Service apiVersion: v1 metadata: name: qywx-svc1 namespace: suosi-pre spec: ports: - name: tcp-20000 protocol: TCP port: 20000 targetPort: 20000 selector: svc: qywx-svc1 type: ClusterIP sessionAffinity: None
deployment public-openresty.yaml
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 kind: Deployment apiVersion: apps/v1 metadata: name: public-openresty namespace: suosi-pre spec: replicas: 1 selector: matchLabels: app: public-openresty template: metadata: labels: app: public-openresty spec: volumes: - name: public-openresty-nginx-conf configMap: name: public-openresty-nginx-conf defaultMode: 420 - name: public-openresty-nginx-lua configMap: name: public-openresty-nginx-lua defaultMode: 420 - name: public-openresty-nginx-confd configMap: name: public-openresty-nginx-confd defaultMode: 420 containers: - name: openresty image: openresty ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP env: - name: TZ value: Asia/Shanghai resources: limits: cpu: '2' memory: 300Mi requests: cpu: 10m memory: 300Mi volumeMounts: - name: public-openresty-nginx-conf mountPath: /usr/local/openresty/nginx/conf/nginx.conf subPath: nginx.conf - name: public-openresty-nginx-lua mountPath: /usr/local/openresty/nginx/lua - name: public-openresty-nginx-confd mountPath: /usr/local/openresty/nginx/conf/conf.d readinessProbe: httpGet: path: /health port: 80 scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 3 periodSeconds: 20 successThreshold: 1 failureThreshold: 3 lifecycle: preStop: exec: command: - sleep 20 terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: Always restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst securityContext: {} affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - public-openresty topologyKey: kubernetes.io/hostname schedulerName: default-scheduler strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25 % maxSurge: 25 % revisionHistoryLimit: 10 progressDeadlineSeconds: 600
qywx-dep1.yaml
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 kind: Deployment apiVersion: apps/v1 metadata: name: qywx-dep1 namespace: suosi-pre spec: replicas: 1 selector: matchLabels: app: qywx-dep1 template: metadata: labels: app: qywx-dep1 svc: qywx-svc1 annotations: k8s.aliyun.com/pod-eip-instanceid: spec: volumes: - name: podinfo downwardAPI: items: - path: labels fieldRef: apiVersion: v1 fieldPath: metadata.labels - path: annotations fieldRef: apiVersion: v1 fieldPath: metadata.annotations defaultMode: 420 initContainers: - name: init image: harbor-core.suosihulian.com/devops/busybox:1.28 command: - timeout - '-t' - '60' - sh - '-c' - >- until grep -E '^k8s.aliyun.com\/allocated-eipAddress=\S?[0-9]+\S?' /etc/podinfo/annotations; do echo waiting for annotations; sleep 2; done resources: {} volumeMounts: - name: podinfo mountPath: /etc/podinfo terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: IfNotPresent containers: - name: qywx-dep1 image: proxy-qywx ports: - name: http containerPort: 20000 protocol: TCP env: - name: TZ value: Asia/Shanghai resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: Always restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst securityContext: {} affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - qywx-dep1 topologyKey: kubernetes.io/hostname schedulerName: default-scheduler strategy: type: Recreate revisionHistoryLimit: 10 progressDeadlineSeconds: 600
proxy-qywx镜像配置 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 user root; #worker_processes 1 ; pcre_jit on; events { worker_connections 1024 ; } http { include mime.types; default_type application/octet-stream; log_format nginxlog_json escape=json '{"timestamp":"$time_iso8601","status":"$status","upstream_status":"$upstream_status","request_uri":"$request","request_time":"$request_time""upstream_addr":"$upstream_addr","upstream_response_time":"$upstream_response_time","remote_addr":"$remote_addr"}' ; resolver 10.252 .0 .10 valid=10 s ipv6=off; access_log /dev/stdout nginxlog_json; error_log /dev/stdout notice; client_body_temp_path /var/run/openresty/nginx-client-body; proxy_temp_path /var/run/openresty/nginx-proxy; fastcgi_temp_path /var/run/openresty/nginx-fastcgi; uwsgi_temp_path /var/run/openresty/nginx-uwsgi; scgi_temp_path /var/run/openresty/nginx-scgi; sendfile on; keepalive_timeout 90 ; gzip on; server { listen 20000 ; server_name localhost; client_header_buffer_size 2046 k; large_client_header_buffers 4 2046 k; client_max_body_size 500 M; client_body_buffer_size 500 M; set $wx_upstream "https://qyapi.weixin.qq.com" ; set $wx_host "qyapi.weixin.qq.com" ; location / { proxy_set_header Host $wx_host; proxy_pass $wx_upstream; } } include /etc/nginx/conf.d/*.conf; }