項目部署 nginx + uwsgi

1.項目部署的相關概念

關於部署流程,主要包含如下兩個方面:部署方案、部署環境:css

1.1部署方案

1. 分析項目的產品需求文檔,定好部署方案的方向
2. 分析項目開發文檔,按照功能邊界,設計部署的結點
3. 分析項目功能軟件,合理的取捨,選符合當前業務場景的
4. 梳理項目部署涉及到的部署軟件實現方案,根據上面第2點肯定的結點,肯定第一版部署方案
5. 根據項目實際狀況,調整優化並肯定項目部署方案

1.2部署環境

1.2.1我的開發環境:

工做人員:本身
工做平臺:我的筆記本、公司配的電腦
平臺特色:環境是本身配的,團隊中不一樣的我的開發環境能夠不同
工做內容:項目的子模塊,子功能
完成標準:完成領導安排的內容[項目的功能子模塊開發]

1.2.2公司開發環境:

工做人員:開發團隊
工做平臺:公司內部服務器
平臺特色:服務器環境和線上的服務器環境徹底一致
工做內容:項目子模塊間的功能聯調
完成標準:項目階段開發、調試完成

1.2.3項目測試環境:

工做人員:測試團隊
工做平臺:公司內部服務器
平臺特色:服務器環境和線上的服務器環境徹底一致
工做內容:項目功能/非功能/探索等測試
完成標準:項目階段功能正常運行

1.2.4項目預發佈環境:

工做人員:運維團隊
工做平臺:公司線上服務器組中的一臺
平臺特色:服務器環境和線上的服務器環境徹底一致
工做內容:特殊功能測試(好比支付)、數據壓力測試、其餘安全測試等
完成標準:項目階段功能正常運行,最後一道防線

1.2.5項目生產環境:

工做人員:運維團隊
工做平臺:公司線上服務器組
平臺特色:標準線上的服務器環境
工做內容:代碼部署和維護、記錄內部架構文檔
完成標準:項目正常運行

項目總體架構

 

 

服務器部署

服務器數量: 1000QPS 每秒請求數html

服務器類型:物理服務器,雲服務器前端

併發瓶頸:vue

1. 帶寬:200M/10K
2. 處理併發的能力
3. 數據庫查詢能力:mysql 1000次/S

可使用apache ab工具進行壓測python

 

2.前端項目部署

將先後端項目上傳碼雲mysql

 

 2.1第一步:編譯。在本機電腦上找到前端項目位置

 自動化程序會將打包的文件自動生成到項目的dist文件夾中。linux

npm run build

注意,編譯的文件,必需要經過http協議才能訪問到,直接點擊index.html,是沒法訪問的。nginx

由於根據咱們上面的部署方案,咱們須要安裝nginx來運行這個項目。git

 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;
  # }
} }

重啓nginxgithub

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

修改配置中的地址相關便可。藍色部分爲修改部分

DEBUG = False

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^(#x0l@!pp6@^!0u5lyq+4ctyui)sxmsc4*r7644@(4uh@'

# 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運行在生產環境中,咱們會關閉debug調試,那麼項目將再也不提供靜態文件的支持,須要將靜態文件交給靜態文件的nginx服務器來提供訪問。

咱們先收集全部靜態文件。項目中的靜態文件除了咱們使用的上傳文件以外,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文件 上傳到碼雲

 

3.5 django的程序一般使用uwsgi服務器來運行

3.5.1修改wsgi.py文件

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 進程號

 

3.6 本地配置完後部署到服務器並使用uwsgi服務器運行

3.6.1.導出當前虛擬環境中的模塊包列表

pip freeze > requirements.txt

3.6.2.在服務器中使用git拉取最新的項目內容。

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便可

相關文章
相關標籤/搜索