项目部署 nginx + uwsgi
Posted addit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目部署 nginx + uwsgi相关的知识,希望对你有一定的参考价值。
1.项目部署的相关概念
关于部署流程,主要包含以下两个方面:部署方案、部署环境:
1. 分析项目的产品需求文档,定好部署方案的方向 2. 分析项目开发文档,按照功能边界,设计部署的结点 3. 分析项目功能软件,合理的取舍,选符合当前业务场景的 4. 梳理项目部署涉及到的部署软件实现方案,根据上面第2点确定的结点,确定初版部署方案 5. 根据项目实际情况,调整优化并确定项目部署方案
1.2部署环境
工作人员:自己
工作平台:个人笔记本、公司配的电脑
平台特点:环境是自己配的,团队中不同的个人开发环境可以不一样
工作内容:项目的子模块,子功能
完成标准:完成领导安排的内容[项目的功能子模块开发]
1.2.2
工作人员:开发团队
工作平台:公司内部服务器
平台特点:服务器环境和线上的服务器环境完全一致
工作内容:项目子模块间的功能联调
完成标准:项目阶段开发、调试完成
1.2.3项目测试环境:
工作人员:测试团队 工作平台:公司内部服务器 平台特点:服务器环境和线上的服务器环境完全一致 工作内容:项目功能/非功能/探索等测试 完成标准:项目阶段功能正常运行
1.2.4项目预发布环境:
工作人员:运维团队
工作平台:公司线上服务器组中的一台
平台特点:服务器环境和线上的服务器环境完全一致
工作内容:特殊功能测试(比如支付)、数据压力测试、其他安全测试等
完成标准:项目阶段功能正常运行,最后一道防线
1.2.5
工作人员:运维团队
工作平台:公司线上服务器组
平台特点:标准线上的服务器环境
工作内容:代码部署和维护、记录内部架构文档
完成标准:项目正常运行
服务器部署
服务器数量: 1000QPS 每秒请求数
服务器类型:物理服务器,云服务器
并发瓶颈:
1. 带宽:200M/10K 2. 处理并发的能力 3. 数据库查询能力:mysql 1000次/S
可以使用apache ab工具进行压测
将前后端项目上传码云
2.1第一步:编译。在本机电脑上找到前端项目位置
自动化程序会将打包的文件自动生成到项目的dist文件夹中。
npm run build
因为根据我们上面的部署方案,我们需要安装nginx来运行这个项目。
nginx部署有两种:
1).部署到云服务器中
2).部署到晕服务中的docker容器里面
此项目直接将nginx部署到服务器中
2.2部署nginx
2.2.1 .安装nginx
sudo apt-get install nginx
2.2.2 修改nginx配置文件 default
upstream luffy # 反向代理池 server 106.52.122.145:8000;
# nginx 反向代理uwsgi server listen 80; server_name 106.52.122.145 api.additwujiahua.com; # location /
# 通过uwsgi_pass 设置服务器地址和协议,将动态请求转发给uwsgi处理 include uwsgi_params; uwsgi_pass luffy; location ~ .*\\.(css|js)$ root /home/luffy/; server listen 80; server_name additwujiahua.com www.additwujiahua.com; location / #root /opt/luffyweb/dist/; root /home/luffy-cli/dist; index index.html; try_files $uri $uri /index.html;
# nginx 处理静态叶页面资源
# 当用户请求的是additwujiahua.com/static这个页面时,会进入这个location匹配
# alias 参数进行路径别名 让nginx去/opt/staic底下去找静态资源
# location / static
# alias /opt/static;
#
重启nginx
service nginx restart
nignx -s reload
启动nginx服务器
service nginx start
停止nginx服务器
service nginx stop
3.后端部署
将mysql和redis部署到 docker容易里面
3.1 安装docker
更新ubuntu的apt源索引
sudo apt-get update
安装包允许apt通过HTTPS使用仓库
sudo dpkg --configure -a sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
添加Docker官方GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
设置Docker稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
添加仓库后,更新apt源索引
sudo apt-get update
安装最新版Docker CE(社区版)
sudo apt-get install docker-ce
检查Docker CE是否安装正确
sudo docker run hello-world
3.2 docker的相关命令
安装完成Docker后,默认已经启动了docker服务,如需手动控制docker服务的启停,可执行如下命令
# 启动docker sudo service docker start # 停止docker sudo service docker stop # 重启docker sudo service docker restart # 列出镜像 docker image ls # 拉取镜像 docker image pull library/hello-world # 删除镜像 docker image rm 镜像id/镜像ID # 创建容器 docker run [选项参数] 镜像名 [命令] # 停止一个已经在运行的容器 docker container stop 容器名或容器id # 启动一个已经停止的容器 docker container start 容器名或容器id # kill掉一个已经在运行的容器 docker container kill 容器名或容器id # 删除容器 docker container rm 容器名或容器id
3.3 接下来尝试将nginx部署到docker容器里
# 在docker中下载nginx镜像 docker image pull nginx # 使用git把码云上面的编译过的vue项目克隆到服务器/home # 阿里云服务器中,我们从码云克隆下来的前端项目: /home/luffyproject_pc/dist git clone 项目git地址 # 创建nginx容器,并以80端口对外提供服务 docker run -itd -p 80:80 -v /home/luffyproject_pc/dist:/usr/share/nginx/html nginx # 启动nginx容器中的nginx【容器ID通过docker container ls --all可以查看到】 docker container exec -itd [容器ID] nginx """ /etc/nginx # nginx容器中nginx的配置目录 /usr/share/nginx/html # nginx容器中www目录 """
3.4 将后端项目部署到服务器
3.4.1
在项目中复制开发配置文件dev.py 到生产配置prod.py
修改配置中的地址相关即可。蓝色部分为修改部分
import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) import sys sys.path.insert(0, os.path.join(BASE_DIR, "apps")) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = ‘!!t0^(#[email protected][email protected]^!0u5lyq+4ctyui)sxmsc4*[email protected]([email protected]‘ # SECURITY WARNING: don‘t run with debug turned on in production! DEBUG = False ALLOWED_HOSTS = [ # "api.luffycity.cn", # "additwujiahua.com", ‘api.additwujiahua.com‘, ] # CORS组的配置信息 CORS_ORIGIN_WHITELIST = ( ‘www.additwujiahua.com‘ ‘additwujiahua.com:80‘ ) CORS_ALLOW_CREDENTIALS = True # 允许ajax跨域请求时携带cookie # Application definition INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, # 跨域 ‘corsheaders‘, # drf ‘rest_framework‘, # xadmin ‘xadmin‘, ‘crispy_forms‘, ‘reversion‘, # 富文本编辑器 ‘ckeditor‘, # 富文本编辑器 ‘ckeditor_uploader‘, # 富文本编辑器上传图片模块 # 子应用 ‘home‘, "users", "courses", "cart", ‘orders‘, "coupon", "payments" ] MIDDLEWARE = [ ‘corsheaders.middleware.CorsMiddleware‘, ‘django.middleware.security.SecurityMiddleware‘, ‘django.contrib.sessions.middleware.SessionMiddleware‘, ‘django.middleware.common.CommonMiddleware‘, ‘django.middleware.csrf.CsrfViewMiddleware‘, ‘django.contrib.auth.middleware.AuthenticationMiddleware‘, ‘django.contrib.messages.middleware.MessageMiddleware‘, ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘, ] ROOT_URLCONF = ‘luffy.urls‘ TEMPLATES = [ ‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘, ‘DIRS‘: [], ‘APP_DIRS‘: True, ‘OPTIONS‘: ‘context_processors‘: [ ‘django.template.context_processors.debug‘, ‘django.template.context_processors.request‘, ‘django.contrib.auth.context_processors.auth‘, ‘django.contrib.messages.context_processors.messages‘, ], , , ] WSGI_APPLICATION = ‘luffy.wsgi.application‘ # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = "default": "ENGINE": "django.db.backends.mysql", "HOST": "127.0.0.1", "PORT": 3306, "USER": "luffy_user", "PASSWORD": "luffy", "NAME": "luffycity", # Password validation # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ ‘NAME‘: ‘django.contrib.auth.password_validation.UserAttributeSimilarityValidator‘, , ‘NAME‘: ‘django.contrib.auth.password_validation.MinimumLengthValidator‘, , ‘NAME‘: ‘django.contrib.auth.password_validation.CommonPasswordValidator‘, , ‘NAME‘: ‘django.contrib.auth.password_validation.NumericPasswordValidator‘, , ] # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ LANGUAGE_CODE = ‘zh-hans‘ TIME_ZONE = ‘Asia/Shanghai‘ USE_I18N = True USE_L10N = True USE_TZ = False # Static files (CSS, javascript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ # 访问静态文件的url地址前缀 STATIC_URL = ‘/static/‘ # 设置django的静态文件目录 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "luffy/statics") ] # 项目中存储上传文件的根目录[暂时配置],注意,static目录需要手动创建否则上传文件时报错 MEDIA_ROOT = os.path.join(BASE_DIR, "luffy/statics") # 访问上传文件的url地址前缀 MEDIA_URL = "/media/" # 缓存配置 CACHES = "default": "BACKEND": "django_redis.cache.RedisCache", # 项目上线时,需要调整这里的路径 "LOCATION": "redis://127.0.0.1:6379/0", "OPTIONS": "CLIENT_CLASS": "django_redis.client.DefaultClient", , "session": "BACKEND": "django_redis.cache.RedisCache", # 项目上线时,需要调整这里的路径 "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": "CLIENT_CLASS": "django_redis.client.DefaultClient", , # 提供存储短信验证码 "sms_code": "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/2", "OPTIONS": "CLIENT_CLASS": "django_redis.client.DefaultClient", , # 储存购物车信息 "cart": "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/3", "OPTIONS": "CLIENT_CLASS": "django_redis.client.DefaultClient", , # 设置xadmin用户登录时,登录信息session保存到redis SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "session" # 日志配置 LOGGING = ‘version‘: 1, ‘disable_existing_loggers‘: False, ‘formatters‘: ‘verbose‘: ‘format‘: ‘%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s‘ , ‘simple‘: ‘format‘: ‘%(levelname)s %(module)s %(lineno)d %(message)s‘ , , ‘filters‘: ‘require_debug_true‘: ‘()‘: ‘django.utils.log.RequireDebugTrue‘, , , ‘handlers‘: ‘console‘: ‘level‘: ‘DEBUG‘, ‘filters‘: [‘require_debug_true‘], ‘class‘: ‘logging.StreamHandler‘, ‘formatter‘: ‘simple‘ , ‘file‘: ‘level‘: ‘DEBUG‘, ‘class‘: ‘logging.handlers.RotatingFileHandler‘, # 日志位置,日志文件名,日志保存目录必须手动创建 ‘filename‘: os.path.join(os.path.dirname(BASE_DIR), "logs/luffy.log"), # 日志文件的最大值,这里我们设置300M ‘maxBytes‘: 300 * 1024 * 1024, # 日志文件的数量,设置最大日志数量为10 ‘backupCount‘: 10, # 日志格式:详细格式 ‘formatter‘: ‘verbose‘ , , # 日志对象 ‘loggers‘: ‘django‘: ‘handlers‘: [‘console‘, ‘file‘], ‘propagate‘: True, # 是否让日志信息继续冒泡给其他的日志处理系统 , REST_FRAMEWORK = # 异常处理 ‘EXCEPTION_HANDLER‘: ‘luffy,utils.exceptions.custom_exception_handler‘, # 登录认证 ‘DEFAULT_AUTHENTICATION_CLASSES‘: ( ‘rest_framework_jwt.authentication.JSONWebTokenAuthentication‘, ‘rest_framework.authentication.SessionAuthentication‘, ‘rest_framework.authentication.BasicAuthentication‘, ), # 保存时间1天 import datetime JWT_AUTH = ‘JWT_EXPIRATION_DELTA‘: datetime.timedelta(days=1), # 设置jwt登录视图的返回值 ‘JWT_RESPONSE_PAYLOAD_HANDLER‘: ‘users.utils.jwt_response_payload_handler‘, # 告诉django我们使用自己的用户认证组件 AUTH_USER_MODEL = ‘users.User‘ # 配置django的认证类功能,增加手机号登录 AUTHENTICATION_BACKENDS = [ ‘users.utils.UsernameMobileAuthBackend‘, ] PC_GEETEST_ID = ‘81c4fd5a59bfd9da92796db7a45cce3e‘ PC_GEETEST_KEY = ‘1e4a137ed379d88ef171c0ac8d7b927f‘ # 短信配置 # 主账号 SMS_ACCOUNTSID = "8aaf07086ab0c082016ab3eda41a00bd" # 主账号Token SMS_ACCOUNTTOKEN = "29c414dd7446457d8f4a0678c6a2de86" # 创建应用的APPID SMS_APPID = "8aaf07086ab0c082016ab3eda47100c3" # 说明:请求地址,生产环境配置成app.cloopen.com SMS_SERVERIP = "sandboxapp.cloopen.com" # 富文本编辑器ckeditor配置 CKEDITOR_CONFIGS = ‘default‘: ‘toolbar‘: ‘full‘, # 工具条功能 ‘height‘: 300, # 编辑器高度 # ‘width‘: 300, # 编辑器宽 , CKEDITOR_UPLOAD_PATH = ‘‘ # 上传图片保存路径,留空则调用django的文件上传功能 # 保利威视频加密服务 POLYV_CONFIG = "userId": "00573fd073", "secretkey": "m2Xc6C6Fb0", "servicesUrl": "https://hls.videocc.net/service/v1/token", # 支付宝 ALIPAY_APPID = "2016093000628031" # 应用ID APP_NOTIFY_URL = None # 应用回调地址[支付成功以后,支付宝返回结果到哪一个地址下面] ALIPAY_DEBUG = True # APIPAY_GATEWAY="https://openapi.alipay.com/gateway.do" APIPAY_GATEWAY = "https://openapi.alipaydev.com/gateway.do" ALIPAY_RETURN_URL = "http://www.additwujiahua.com/success" # 支付宝会根据API中商户传入的notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统 ALIPAY_NOTIFY_URL = "http://api.additwujiahua.com:8000/payments/success"
3.4.2 上线前先收集静态文件static
我们先收集所有静态文件。项目中的静态文件除了我们使用的上传文件之外,django本身还有自己的静态文件,如rest_framework、xadmin、admin、ckeditor等。我们需要收集这些静态文件,集中一起放到静态文件服务器中。
我们要将收集的静态文件放到项目的static目录中,所以先创建目录static。
Django提供了收集静态文件的方法。先在配置文件中配置收集之后存放的目录
settings/prop.py,代码:
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), ‘static‘)
然后执行收集命令
python manage.py collectstatic
将 static文件 上传到码云
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE‘, ‘luffy.settings.prop‘)
我们可以在本地环境中先安装uwsgi模块进行使用,然后成功了再上传到服务器中。
pip install uwsgi uwsgi --version # 查看 uwsgi 版本
在项目根目录下创建uwsgi配置文件uwsgi.ini
[uwsgi] #使用nginx连接时使用,Django程序所在服务器地址 ;socket=127.0.0.1:8000 #直接做web服务器使用,Django程序所在服务器地址 http=127.0.0.1:8000 #项目目录 chdir=/home/moluo/Desktop/luffy #项目中wsgi.py文件的目录,相对于项目目录 wsgi-file=luffy/wsgi.py # 进程数 processes=2 # 线程数 threads=2 # uwsgi服务器的角色 master=True # 存放进程编号的文件 pidfile=uwsgi.pid # 日志文件,因为uwsgi可以脱离终端在后台运行,日志看不见。我们以前的runserver是依赖终端的 daemonize=uwsgi.log # 指定依赖的虚拟环境 virtualenv=/home/moluo/.virtualenvs/luffy
注意:云服务器里面注意修改路径!!!!
启动uwsgi服务器,必须在uwsgi配置文件中运行下面的命令
注意,在本地环境中必须先把runserver关闭
uwsgi --ini uwsgi.ini
停止uwsgi服务器,还可以通过使用kill命令停止
uwsgi --stop uwsgi.pid
uwsgi -9 进程号
pip freeze > requirements.txt
cd /home/luffyproject
git pull
3.6.3 安装基本虚拟环境[直接把项目运行在服务器中,不在容器里面]
# 安装python3的pip工具 apt install python3-pip # 使用pip安装虚拟环境 pip3 install virtualenv pip3 install virtualenvwrapper # 配置虚拟环境的环境变量 # 执行命令 mkdir $HOME/.virtualenvs # 执行命令,打开并编辑 ~/.bashrc vim ~/.bashrc # 文件末尾添加以下几行代码,:wq 保存退出。 export WORKON_HOME=$HOME/.virtualenvs export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 source /usr/local/bin/virtualenvwrapper.sh # 刷新配置文件 source ~/.bashrc # 创建虚拟环境 mkvirtualenv luffyproject -p python3 # 在虚拟环境中同步之前的个人开发环境中安装包列表 requirements.txt cd /home/luffy/docs pip install -r requirements.txt -i https://pypi.douban.com/simple # 项目中 pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 # 安装完成这些手动安装的包以后,我们再次执行上面的命令 pip install -r requirements.txt -i https://pypi.douban.com/simple # 经过上面的步骤,我们直接切到uwsgi.ini所在目录下,运行项目 uwsgi --ini uwsgi.ini # 我们会发现上面命令运行不起来,原因是我们的本地模块包是从新安装的,之前有修改过,所以需要调整。同时因为我们之前已经在项目中使用到了redis和mysql # 因此我们需要在docker中下载redis和mysql的容器 docker pull redis docker pull mysql # 创建redis容器并运行redis docker container run -itd -p6379:6379 redis # 创建mysql容器并启动mysql docker container run -itd -p3306:3306 -e MYSQL_ROOT_PASSWORD=luffy mysql:5.7 # 接下来远程在本地环境中导出当前项目的数据库,并导入到服务器中的数据库中 # 1. 本地导出数据 cd ~/Desktop/luffy/docs/ mysqldump -uroot -p123 luffycity>./luffycity.sql # 本地数据库账号 # 2. 在服务器中创建数据和数据库用户 mysql -uroot -pluffy -h47.112.204.45 # 本地登陆线上的mysql数据库 > create database luffycity charset=utf8mb4; > create user luffy_user identified by ‘luffy‘; > grant all privileges on luffycity.* to ‘luffy_user‘@‘%‘; > flush privileges; > exit # 3. 退出服务器数据库终端,使用以下命令导入数据库 cd ~/Desktop/luffy/docs/ mysql -uroot -pluffy -h47.112.204.45 luffycity < ./luffycity.sql # 4. 继续使用manage.py运行django项目,修改数据库的decode错误以后,就正常运行。
第一个错误:注释掉对应的错误
第二个错误:加上decode() # 5. 使用uwsgi来运行django项目 uwsgi --ini uwsgi.ini # 新的配置信息 uwsgi.ini [uwsgi] #使用nginx连接时使用,Django程序所在服务器地址 socket=0.0.0.0:8000 #直接做web服务器使用,Django程序所在服务器地址 #http=127.0.0.1:8000 #http=0.0.0.0:8000 #项目目录 chdir=/home/luffy #项目中wsgi.py文件的目录,相对于项目目录 wsgi-file=luffy/wsgi.py # 进程数 processes=1 # 线程数 threads=1 # uwsgi服务器的角色 master=True # 存放进程编号的文件 pidfile=uwsgi.pid # 日志文件,因为uwsgi可以脱离终端在后台运行,日志看不见。我们以前的runserver是依赖终端的 daemonize=uwsgi.log # 指定依赖的虚拟环境 virtualenv=/root/.virtualenvs/luffyproject
配置好重启uwsgi即可
以上是关于项目部署 nginx + uwsgi的主要内容,如果未能解决你的问题,请参考以下文章
python3 + Django + uwsgi + nginx 配置部署笔记