# vitr **Repository Path**: nativehacker/vitr ## Basic Information - **Project Name**: vitr - **Description**: No description available - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-04-15 - **Last Updated**: 2022-05-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 说明 ### 依赖说明 ```python3.7.x``` ### 开发环境搭建 1、[安装python3.7](https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe) 2、安装pip 3、安装virtualenv ``` pip install virtualenv ``` 4、创建并进入虚拟环境,在项目根目录下运行: ``` virtualenv venv (Windows)venv/Scripts/activate ``` 5、安装项目依赖 ``` pip install setuptools==57.5.0 -i https://pypi.tuna.tsinghua.edu.cn/simple (部分依赖库会因为setuptool版本过高,安装报错,所以降级setuptool) pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple ``` 6、运行 ``` python manage.py runserver ``` ### 持续集成持续部署 当触发git的push动作,将会触发webhook,请求服务器http服务,服务将会运行一段脚本,触发构建Docker镜像,杀掉之前的容器,并运行新的容器(这里理论上应该先开启新的容器再把之前的容器杀掉,但是服务器规格限制2核2G,会触发oom) #### webhook说明 ```python import time import hmac import hashlib import base64 import urllib import os from flask import Flask, request, jsonify app = Flask(__name__) def encryption(timestamp): secret = '18759799353gjb!' secret_enc = secret.encode('utf-8') string_to_sign = '{}\n{}'.format(timestamp, secret) string_to_sign_enc = string_to_sign.encode('utf-8') hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest() sign = urllib.parse.urlparse(base64.b64encode(hmac_code)).path return sign.decode("utf8") @app.route('/hook', methods=['POST']) def post_data(): timestamp = request.headers.get('X-Gitee-Timestamp', '') token = encryption(timestamp) signature = request.headers.get('X-Gitee-Token', '') print(request.headers.get("X-Gitee-Token"), token) if signature != token: return "token auth failed", 401 os.system('sh script.sh') return jsonify({"status": 200}) if __name__ == '__main__': app.run(port=8888, host="0.0.0.0") ``` 可以看到,这里主要就是做了两件事情: - 验证请求的头部携带的签名信息 - 运行script.sh脚本 再看看script.sh脚本的内容: ```shell #!/bin/bash cd /home/vitr/test_vitr wget https://gitee.com/nativehacker/vitr/repository/archive/master.zip -O /home/vitr/test_vitr/vitr.zip unzip -o -d /home/vitr/test_vitr vitr.zip cd /home/vitr/test_vitr/vitr-master/ docker build -t vitr:latest . current_run=`docker ps | grep 8000 | cut -d' ' -f 1` docker stop $current_run docker run -d -p 8000:80 vitr:latest ``` 这个脚本主要做了: - 下载代码到服务器的/home/vitr/test_vitr/vitr.zip路径下 - 解压代码并运行到代码的目录下 - 构建docker镜像 - 停止原有的docker容器 - 运行刚刚构建的docker容器 实际上这就是一个简单的flask应用,使用supervisor进行托管 配置文件如下: ```ini [program:webhook] command=python3 webhook.py environment=PYTHONPATH=/root/webhook/vitr/env/lib/python3.7/site-packages directory=/root/webhook/vitr/ process_name=%(program_name)s ; process_name expr (default %(program_name)s) numprocs=1 ; number of processes copies to start (def 1) startsecs=1 ; number of secs prog must stay running (def. 1) startretries=3 ; max # of serial start failures (default 3) user=root ; setuid to this UNIX account to run the program redirect_stderr=true ; redirect proc stderr to stdout (default false) stdout_logfile=/root/webhook/vitr/vitr.log stdout_logfile_maxbytes=50MB ; max # logfile bytes b4 rotation (default 50MB) stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) stdout_events_enabled=false ; emit events on stdout writes (default false) stderr_logfile=/root/webhook/vitr/vitr.err stderr_logfile_maxbytes=10MB ; max # logfile bytes b4 rotation (default 50MB) stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) stderr_events_enabled=false ; emit events on stderr writes (default false) ``` 这里依然是使用python的虚拟环境进行隔离,避免相互影响 supervisor的命令如下: ```shell supervisorctl start webhook (启动) supervisorctl stop webhook (停止) supervisorctl status (查看当前已注册的服务的状态) supervisorctl update (从配置文件更新已注册的服务) ``` #### 代理服务 整个服务采用nginx作为前端代理,flask服务以及docker容器用nginx进行托管,nginx监听80端口将请求转发到8000(Django容器映射到宿主机的端口),将2222端口监听到的请求转发到8888端口(flask服务运行的端口) ### Docker容器说明 - 基础镜像:ubuntu - 容器内部使用nginx作为容器内部的代理,转发请求到django服务的同时托管静态文件 - 使用tini作为容器内部的init进程,tini进程可以对容器内部的进程进行管理,避免更多僵尸进程的产生 - django应用使用uwsgi进行部署,开启两个django进程(受限于python全局解释锁,应该使用多进程模型,进程数量应该与cpu核数一致,过多的进程会造成频繁的上下文切换,进程数太少会造成服务器资源的浪费)