zhangnaiwen 2 gadi atpakaļ
revīzija
fd4746d33b

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 1 - 0
.idea/.name

@@ -0,0 +1 @@
+nginx_agent

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 4 - 0
.idea/misc.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 virtualenv at C:\Users\admin\Envs\flask" project-jdk-type="Python SDK" />
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/nginx_agent.iml" filepath="$PROJECT_DIR$/.idea/nginx_agent.iml" />
+    </modules>
+  </component>
+</project>

+ 16 - 0
.idea/nginx_agent.iml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="Flask">
+    <option name="enabled" value="true" />
+  </component>
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="jdk" jdkName="Python 3.10 virtualenv at C:\Users\admin\Envs\flask" jdkType="Python SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="TemplatesService">
+    <option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
+  </component>
+</module>

+ 5 - 0
Dockerfile

@@ -0,0 +1,5 @@
+FROM nginx_agent_base:latest
+
+COPY ./src /work/nginx_agent/src
+
+WORKDIR /work/nginx_agent/src

+ 23 - 0
base/Dockerfile

@@ -0,0 +1,23 @@
+FROM debian:latest
+
+COPY ./requirements.txt           /tmp/
+COPY ./conf/uwsgi.ini             /work/
+COPY ./scripts/bootstrap.sh       /opt/
+COPY ./conf/uwsgi.ini             /work/nginx_agent/conf/uwsgi.ini
+COPY ./conf/supervisord.conf      /etc/
+COPY ./conf/supervisor_nginx.conf /etc/supervisord.d/nginx_agent.conf
+
+RUN apt-get -y update \
+    && apt-get -y upgrade \
+    && apt-get install -y python3 \
+                          python3-pip \
+                          gcc  g++ \
+                          supervisor \
+    && pip install --upgrade pip \
+    && pip install -r /tmp/requirements.txt \
+    && rm -rf /tmp/requirements.txt \
+    && chmod +x /opt/bootstrap.sh
+
+ENTRYPOINT ["/opt/bootstrap.sh"]
+
+EXPOSE 5000

+ 9 - 0
conf/supervisor_nginx.conf

@@ -0,0 +1,9 @@
+[program:nginx_agent]
+command = uwsgi /work/nginx_agent/conf/uwsgi.ini
+
+autorestart = true
+redirect_stderr = true
+stopsignal = QUIT
+stderr_logfile = /data/logs/nginx_agent_error.log
+stdout_logfile = /data/logs/nginx_agent.log
+

+ 18 - 0
conf/supervisord.conf

@@ -0,0 +1,18 @@
+[supervisord]
+pidfile = /run/supervisord.pid
+logfile = /data/logs/supervisord.log
+# Set loglevel=debug, only then all logs from child services are printed out
+# to container logs (and thus available via `docker logs [container]
+loglevel = debug
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
+
+[inet_http_server]
+port:127.0.0.1:9999
+
+[supervisorctl]
+serverurl=http://127.0.0.1:9999
+
+[include]
+files = /etc/supervisord.d/*.conf

+ 124 - 0
conf/uwsgi.ini

@@ -0,0 +1,124 @@
+[uwsgi]
+# 指定应用的用户(组)
+if-env=UWSGI_USER
+uid = $(UWSGI_USER)
+
+if-env = UWSGI_GROUP
+gid = $(UWSGI_GROUP)
+endif =
+
+# 监听的ip与端口
+http = :5000
+if-env = UWSGI_HTTP
+http = $(UWSGI_HTTP)
+endif =
+
+# PID文件
+pidfile = /var/run/nginx_agent.pid
+
+# 主入口模块
+module = app.webapp
+
+# 主入口函数
+callable = application
+
+# 需要关闭master,否则会导致进程中使用全局变量会出错
+master = true
+
+# 这个会导致不正常,待测试
+#async=128
+
+# 进程数
+processes = 2
+if-env = UWSGI_PROCESSES
+processes = $(UWSGI_PROCESSES)
+endif =
+
+# 运行多线程
+enable-threads = 0
+if-env = UWSGI_ENABLE_THREADS
+enable-threads = $(UWSGI_ENABLE_THREADS)
+endif =
+
+# http的线程数
+http-processes = 2
+if-env = UWSGI_HTTP_PROCESSES
+http-processes = $(UWSGI_HTTP_PROCESSES)
+endif =
+
+# 是否保持http连接
+http-keepalive = 0
+if-env = UWSGI_HTTP_KEEPALIVE
+http-keepalive = $(UWSGI_HTTP_KEEPALIVE)
+endif =
+
+# 超时关闭连接的时间(秒)
+harakiri = 20
+if-env = UWSGI_HARAKIRI
+harakiri = $(UWSGI_HARAKIRI)
+endif =
+
+# 打开http body缓冲
+if-env = UWSGI_POST_BUFFERING
+post-buffering = $(UWSGI_POST_BUFFERING)
+endif =
+
+# python解释器的优化,=0不优化
+if-env = UWSGI_PY_OPTIMIZE
+optimize = $(UWSGI_PY_OPTIMIZE)
+endif =
+
+# 关闭http请求的日志
+if-env = UWSGI_DISABLE_LOGGING
+disable-logging = $(UWSGI_DISABLE_LOGGING)
+endif =
+
+# 记录uwsgi自身的日志
+logto = /data/logs/nginx_agent_uwsgi.log
+# daemonize = /data/logs/nginx_agent.log
+
+
+# 等待其它进程重启(直到接收到的请求处理完才重启)/关闭的最大时间(秒)
+reload-mercy = 2
+
+# CPU亲和性
+cpu-affinity = 1
+
+# 进程的内存限制(address space/vsz)
+if-env = UWSGI_LIMIT_AS
+limit-as = $(UWSGI_LIMIT_AS)
+endif =
+
+# 占用内存(address space)大于指定值(MB),重启服务
+if-env = UWSGI_RELOAD_ON_AS
+reload-on-as = $(UWSGI_RELOAD_ON_AS)
+endif =
+
+# 占用内存(rss)大于指定值(MB),重启服务
+if-env = UWSGI_RELOAD_ON_RSS
+reload-on-rss = $(UWSGI_RELOAD_ON_RSS)
+endif =
+
+# 超过指定请求数,会创建新的进程
+if-env = UWSGI_MAX_REQUESTS
+max-requests = $(UWSGI_MAX_REQUESTS)
+endif =
+
+# 退出时清除环境(自动删除unix socket文件和pid文件)
+vacuum = true
+
+# python代码变化后自动重启服务,仅用用开发环境
+if-env = UWSGI_PY_AUTORELOAD
+py-autoreload = $(UWSGI_PY_AUTORELOAD)
+endif =
+
+# master进程关闭会自动杀死workers
+no-orphans = true
+
+# 设置socket的监听队列大小
+if-env = UWSGI_LISTEN
+listen = $(UWSGI_LISTEN)
+endif =
+
+# python包环境
+pythonpath=/work/nginx_agent/src

+ 22 - 0
docker-compose.yml

@@ -0,0 +1,22 @@
+service:
+  container_name: nginx_agent
+
+  image: nginx_agent:1.0.0
+
+  ports:
+    - "5000:5000"
+
+  environment:
+    - UWSGI_PROCESSES=4
+    - UWSGI_ENABLE_THREADS=true
+    - UWSGI_HTTP_PROCESSES=2
+    - UWSGI_HTTP_KEEPALIVE=false
+    - UWSGI_HARAKIRI=20
+    - UWSGI_PY_OPTIMIZE=0
+
+    - OAUTH_HOST=121.43.55.7:8888
+    - NGINX_HOST=192.168.1.37:80
+
+  privileged: true
+
+  restart: always

BIN
requirements.txt


+ 47 - 0
scripts/bootstrap.sh

@@ -0,0 +1,47 @@
+#!/bin/bash
+
+set -e
+set -u
+
+# supervisord 配置文件
+SUPERVISOR_PARAMS='-c /etc/supervisord.conf'
+
+
+# 创建一些需要的目录
+mkdir -p /data/conf /data/run /data/logs/
+chmod 711 /data/conf /data/run /data/logs
+
+#export WORKER_REDIS_PORT=${REDIS_PORT:6}
+#export WORKER_REDIS_DB=${REDIS_DB:-0}
+
+# 遍历 `/opt/init/*.sh`,然后执行它
+if [ "$(ls /opt/init/)" ]; then
+  for cmd in /opt/init/*.sh; do
+    . $cmd
+  done
+fi
+
+
+# 可能会使用一个交互式的容器.
+if test -t 0; then
+  # 运行 supervisord 到后台
+  supervisord $SUPERVISOR_PARAMS
+
+  # 运行一些命令并退出
+  # 没有命令时,运行bash
+  if [[ $@ ]]; then
+    eval $@
+  else
+    export PS1='[\u@\h : \w]\$ '
+    /bin/bash
+  fi
+
+# 运行 supervisord 在前台, 保持直到停止容器.
+else
+  # 有额外的参数,先执行它.
+  # 可能会有些问题
+  if [[ $@ ]]; then
+    eval $@
+  fi
+  supervisord -n $SUPERVISOR_PARAMS
+fi

+ 4 - 0
scripts/built.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+docker build -f base/Dockerfile -t nginx_agent_base:latest .
+docker build -t nginx_agent:1.0.0 .

+ 0 - 0
src/__init__.py


BIN
src/__pycache__/__init__.cpython-310.pyc


+ 1 - 0
src/app/__init__.py

@@ -0,0 +1 @@
+

+ 7 - 0
src/app/api/__init__.py

@@ -0,0 +1,7 @@
+from flask_restful import Api
+
+from app.api.apis import AgentApi
+
+api = Api()
+
+api.add_resource(AgentApi, '/<path:path>')

+ 31 - 0
src/app/api/apis.py

@@ -0,0 +1,31 @@
+import mimetypes
+
+import requests
+from flask import make_response, request, abort
+from flask_restful import Resource
+
+from app.configs import config
+
+
+class AgentApi(Resource):
+
+    def get(self, path):
+        token = request.args.get('token', None)
+        if token is None:
+            abort(418)
+
+        # 验证token
+        validate_token_rep = requests.get('http://%s/oauth/api/user/validateToken' % config.OAUTH_HOST,
+                                          headers={'token': token}).json()
+        if validate_token_rep.get('code') != 200:
+            return validate_token_rep
+        # 请求nginx
+        nginx_rep = requests.get('http://%s/%s' % (config.NGINX_HOST, path))
+        response = make_response(nginx_rep.content)
+        filename = path.split('/')[-1]
+        mime_type = mimetypes.guess_type(filename)[0]
+        if mime_type is None:
+            mime_type = 'application/octet-stream'
+        response.headers['Content-Type'] = mime_type
+        response.headers['Content-Disposition'] = 'attachment; filename={}'.format(filename.encode().decode('latin-1'))
+        return response

+ 0 - 0
src/app/configs/__init__.py


+ 4 - 0
src/app/configs/config.py

@@ -0,0 +1,4 @@
+import os
+
+OAUTH_HOST = os.environ.get('OAUTH_HOST', '121.43.55.7:8888')
+NGINX_HOST = os.environ.get('NGINX_HOST', '192.168.1.37:80')

+ 17 - 0
src/app/webapp.py

@@ -0,0 +1,17 @@
+from flask import Flask
+from flask_cors import CORS
+
+from app.api import api
+
+
+def create_app():
+    app = Flask(__name__)
+    api.init_app(app)
+    CORS(app)
+    return app
+
+
+application = create_app()
+
+if __name__ == '__main__':
+    application.run(debug=True, host='0.0.0.0')