国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

基于Flask-Angular的項目組網架構與部署

kelvinlee / 3575人閱讀

摘要:基于網,分享項目的組網架構和部署。項目組網架構架構說明流項目訪問分為兩個流,通過分兩個端口暴露給外部使用數據流用戶訪問網站。通過進行配置,使用作為異步隊列來存儲任務,并將處理結果存儲在中。

基于Raindrop網,分享項目的組網架構和部署。

項目組網架構

架構說明 1.流

項目訪問分為兩個流,通過nginx分兩個端口暴露給外部使用:
數據流:用戶訪問Raindrop網站。
控制流:管理人員通過supervisor監控、管理服務器進程。

圖中除了將程序部署在ECS上外,還使用了OSS(對象存儲服務,可以理解成一個nosql數據庫),主要是為了存放一些靜態文件,提高訪問速度。阿里的OSS還可以與CDN一起使用,同樣可以提高訪問速度。

2.nginx

通過nginx對外暴露兩個端口,如上所述,80端口供用戶訪問網站,另一個端口供管理人員使用。
80端口:根據請求的url配置了方向代理,分別導向client(angular)和server(flask).
其中server通過gunicorn部署在[socket]localhost:10000
配置如下:

server {
    listen 80 default_server;

    # set client body size to 4M (add by dh) #
    client_max_body_size 4M;

    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # product
    root /home/raindrop/www/client/dist;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }
    
    # access flask static folder
    location /static/ {
        # product
        root /home/raindrop/www/server/app;
    }

    location /api/ {
        proxy_pass http://localhost:10000/api/;
        proxy_redirect off;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    
    }

    # Error pages
    error_page 413 @413_json;

    location @413_json {
        default_type application/json;      
        return 200 "{"msg": "Request Entity Too Large(max=4M)"}";
    }
}
3.gunicorn

gunicorn作為wsgi容器,用來執行flask server。
gunicorn可以使用異步socket:gevent,其本質是基于greenlet實現協程的第三方庫,改善io阻塞問題,通過簡單的配置就能使程序獲得極高的并發處理能力。

注意:使用gunicorn != 使用gevent,如要開啟gevent socket,啟動gunicorn時需要增加--work-class參數,如下:

gunicorn --workers=4 --worker-class socketio.sgunicorn.GeventSocketIOWorker -b localhost:10000 wsgi:app

除了gunicorn,也可以選用uwsgi,但是有兩點限制需要注意:
1.如果使用了Flask-socketio,請不要使用uwsgi,原因

Note regarding uWSGI: While this server has support for gevent and WebSocket, 
there is no way to use the custom event loop needed by gevent-socketio, 
so there is no directly available method for hosting Flask-SocketIO applications on it.
If you figure out how to do this please let me know!

2.如果使用異步WSGI Server,請勿使用uwsgi,原因:慎用異步 WSGI Server 運行 Flask 應用

 Flask(Werkzeug)的Local Thread無法與uwsgi基于uGreen的微線程兼容,引起Local Thread工作混亂。
4.celery

在程序運行過程中會有一些比較耗時但并非緊急的工作,這些任務可以使用異步任務來處理,提高server的響應速度。
celery - Distributed Task Queue是一個第三方庫,提供異步隊列和任務處理功能。
Raindrop使用celery配合實現feed功能。通過flask進行配置,使用redis作為異步隊列來存儲任務,并將處理結果(feed activity)存儲在redis中。

5.supervisor

如上所述,我們需要在服務器上運行gunicorn和celery兩個進程。
顯然,我們需要一個monitor來幫我們管理這兩個進程,避免進程崩潰不能及時拉起,阻塞業務。
supervisor:Supervisor process control system for UNIX是一個開源monitor程序,并且內置了web管理功能,可以遠程監控、重啟進程。配置如下:

[inet_http_server]
# web 管理端口,通過nginx暴露給遠端用戶
port=127.0.0.1:51000

[program:raindrop]
# 程序啟動命令
command = gunicorn --workers=4 --worker-class socketio.sgunicorn.GeventSocketIOWorker -b localhost:10000 wsgi:app
directory = /home/raindrop/www/server
user = dh                                     
stopwaitsecs=60
stdout_logfile = /var/log/raindrop/supervisor-raindrop.log
redirect_stderr = true

[program:celery]
command = celery -P gevent -A wsgi.celery worker
directory = /home/raindrop/www/server
user = dh                                             
stopwaitsecs=60
stdout_logfile = /var/log/raindrop/supervisor-celery.log
redirect_stderr = true
6.數據庫

mysql:網站主要數據存儲在關系型數據庫中
redis:緩存mysql數據 + celery異步隊列

服務器

使用阿里云的服務器
ECS:部署服務端程序
OSS:存儲前端靜態文件(速度很快,對前端體驗改善很大,采用angular框架強烈推薦使用)

組件

nginx: HTTP Server
angularjs: client框架
flask:server框架
gunicorn: web 容器
celery: 異步任務處理
supervisor: monitor
redis: 數據緩存 + 任務隊列
mysql: 數據庫

本地開發環境與工具

ubuntu12.04 64: 操作系統
virtualenv: python虛擬環境(隔離項目開發環境,不用擔心包沖突了)
vagrant: 基于virtualbox的本地虛擬環境(環境可以導入導出,團隊開發必備)
gulp: angular工程打包工具
pip: python包管理工具
fabric: 基于python的遠程腳本(自動化部署神器)

打包部署

基于Ubuntu 12.0.4,其它系統安裝命令(apt-get 等)請自行修改。

繁瑣VS自動化

如果是第一次部署,需要初始化ECS服務器,安裝基本工具:
nginx, supervisor, redis, mysql, pip, virtualenv

打包項目代碼

發布靜態文件到OSS服務器

發布項目代碼到ECS服務器,安裝server依賴的包

修改mysql, nginx, supervisor配置文件

拉起所需進程

然后各種apt-get install, scp, tar, cp, mv,不得不說,這是一個煩人且毫無技術含量的工作,干過幾次后基本就可以摔鍵盤了。
不過,有繁瑣的地方,一定有自動化。其實完成上面這些工作,三條命令足以:

fab init_env
fab build
fab deploy

這要感謝Fabric:Simple, Pythonic remote execution and deployment項目,封裝了非常簡潔的遠程操作命令。

Fabric

使用Fabric,只需要編寫一個fabile.py腳本,在啟動定義init_env, build, deploy三個任務:

# -*- coding: utf-8 -*-

import os, re, hashlib
from termcolor import colored
from datetime import datetime
from fabric.api import *
from fabric.contrib.files import exists

class FabricException(Exception):
    pass

env.abort_exception = FabricException

# 服務器地址,可以有多個,依次部署:
env.hosts = [
    "user@120.1.1.1"
]

env.passwords = {
    "user@120.1.1.1:22":"123456"
}

# sudo用戶為root:
env.sudo_user = "root"

# mysql
db_user = "root"
db_password = "123456"

_TAR_FILE = "raindrop.tar.gz"
_REMOTE_TMP_DIR = "/tmp"
_REMOTE_BASE_DIR = "/home/raindrop"
_ALIYUN_OSS = {
    "endpoint"       : "oss-cn-qingdao.aliyuncs.com",
    "bucket"         : "yourbucketname",
    "accessKeyId"    : "youraccessKeyId" ,
    "accessKeySecret": "youraccessKeySecret"
}

def build():
    """
    必須先打包編譯client,再打包整個項目
    """
    with lcd(os.path.join(os.path.abspath("."), "client")):
        local("gulp build")
    
    # 上傳靜態文件到oss服務器,并修改index.html中對靜態文件的引用
    with lcd(os.path.join(os.path.abspath("."), "client/dist")):
        with lcd("scripts"):
            for file in _list_dir("./"):
                if oss_put_object_from_file(file, local("pwd", capture=True) + "/" + file):
                    _cdnify("../index.html", file)

        with lcd("styles"):
            for file in _list_dir("./"):
                if oss_put_object_from_file(file, local("pwd", capture=True) + "/" + file):
                    _cdnify("../index.html", file)
        
        # 注意在oss上配置跨域規則,否則fonts文件無法加載
        # !!修改fonts文件夾請放開此段程序!!
        # with lcd("fonts"):
        #     for file in _list_dir("./"):
        #         oss_put_object_from_file("fonts/%s" % file, local("pwd", capture=True) + "/" + file)                

    with lcd(os.path.join(os.path.abspath("."), "server")):
        local("pip freeze > requirements/common.txt")
        excludes = ["oss", "distribute"]
        [local("sed -i -r -e "/^.*" + exclude + ".*$/d" "requirements/common.txt"") for exclude in excludes]

    local("python setup.py sdist")

# e.g command: fab deploy:"",Fasle
# 注意命令兩個參數間不要加空格
def deploy(archive="", needPut="True"):
    if archive is "":
        filename = "%s.tar.gz" % local("python setup.py --fullname", capture=True).strip()
        archive = "dist/%s" % filename
    else:
        filename = archive.split("/")[-1]
    
    tmp_tar = "%s/%s" % (_REMOTE_TMP_DIR, filename)

    if eval(needPut):
        # 刪除已有的tar文件:
        run("rm -f %s" % tmp_tar)

        # 上傳新的tar文件:
        put(archive, _REMOTE_TMP_DIR)

    # 創建新目錄:
    newdir = "raindrop-%s" % datetime.now().strftime("%y-%m-%d_%H.%M.%S")
    with cd(_REMOTE_BASE_DIR):
        sudo("mkdir %s" % newdir)
        
    # 重置項目軟鏈接:
    with cd(_REMOTE_BASE_DIR):
        # 解壓到新目錄:
        with cd(newdir):
            sudo("tar -xzvf %s --strip-components=1" % tmp_tar)    

        # 保存上傳文件
        if exists("www/server/app/static/upload/images/", use_sudo=True):
            sudo("cp www/server/app/static/upload/images/ %s/server/app/static/upload/ -r" % newdir)

        sudo("rm -f www")
        sudo("ln -s %s www" % newdir)

    with cd(_REMOTE_BASE_DIR):
        with prefix("source %s/env/local/bin/activate" % _REMOTE_BASE_DIR):
            sudo("pip install -r www/server/requirements/common.txt")

            # 啟動服務
            with cd("www"):
                # mysql
                sudo("cp etc/my.cnf /etc/mysql/")
                sudo("restart mysql")

                # monitor
                sudo("cp etc/rd_super.conf /etc/supervisor/conf.d/")
                sudo("supervisorctl stop celery")
                sudo("supervisorctl stop raindrop")
                sudo("supervisorctl reload")
                sudo("supervisorctl start celery")
                sudo("supervisorctl start raindrop")
                
                # nginx
                sudo("cp etc/rd_nginx.conf /etc/nginx/sites-available/")
                # ln -f —-如果要建立的鏈接名已經存在,則刪除之
                sudo("ln -sf /etc/nginx/sites-available/rd_nginx.conf /etc/nginx/sites-enabled/default")
                sudo("nginx -s reload")

def init_env():
    sudo("aptitude update")
    sudo("aptitude safe-upgrade")

    # sudo("apt-get install nginx")
    sudo("aptitude install python-software-properties")
    sudo("add-apt-repository ppa:nginx/stable")
    sudo("aptitude update")
    sudo("apt-get install nginx")

    sudo("apt-get install supervisor")
    sudo("apt-get install redis-server")
    sudo("apt-get install mysql-server")

    sudo("apt-get install python-pip python-dev build-essential")

    sudo("pip install virtualenv")

    run("mkdir /var/log/raindrop -p")

    with cd ("/home/raindrop"):
        sudo("virtualenv env")

def oss_put_object_from_file(key, file_path):
    from oss.oss_api import *
    oss = OssAPI(_ALIYUN_OSS["endpoint"], _ALIYUN_OSS["accessKeyId"], _ALIYUN_OSS["accessKeySecret"])
    res = oss.put_object_from_file(_ALIYUN_OSS["bucket"], key, file_path)
    return res.status == 200 and True or False


def _expand_path(path):
    print path
    return ""$(echo %s)"" % path

def sed(filename, before, after, limit="", backup=".bak", flags=""):
    # Characters to be escaped in both
    for char in "/"":
        before = before.replace(char, r"\%s" % char)
        after = after.replace(char, r"\%s" % char)
    # Characters to be escaped in replacement only (they"re useful in regexen
    # in the "before" part)
    for char in "()":
        after = after.replace(char, r"\%s" % char)
    if limit:
        limit = r"/%s/ " % limit
    context = {
        "script": r""%ss/%s/%s/%sg"" % (limit, before, after, flags),
        "filename": _expand_path(filename),
        "backup": backup
    }

    # Test the OS because of differences between sed versions

    with hide("running", "stdout"):
        platform = local("uname")
    if platform in ("NetBSD", "OpenBSD", "QNX"):
        # Attempt to protect against failures/collisions
        hasher = hashlib.sha1()
        hasher.update(env.host_string)
        hasher.update(filename)
        context["tmp"] = "/tmp/%s" % hasher.hexdigest()
        # Use temp file to work around lack of -i
        expr = r"""cp -p %(filename)s %(tmp)s 
&& sed -r -e %(script)s %(filename)s > %(tmp)s 
&& cp -p %(filename)s %(filename)s%(backup)s 
&& mv %(tmp)s %(filename)s"""
    else:
        context["extended_regex"] = "-E" if platform == "Darwin" else "-r"
        expr = r"sed -i%(backup)s %(extended_regex)s -e %(script)s %(filename)s"
    command = expr % context
    return local(command)

def _cdnify(index_file, cdn_file):
    sed(index_file, "([^<]*(src|href)=")[^<]*" + cdn_file + """, "1http://" + _ALIYUN_OSS["bucket"] + "." + _ALIYUN_OSS["endpoint"] + "/" + cdn_file + """)

def _list_dir(dir=None, access=lcd, excute=local):
    """docstring for list_dir"""
    if dir is None:
        return []

    with access(dir):
        string = excute("for i in *; do echo $i; done", capture=True)
        files = string.replace("
","").split("
")
        return files        

通過fabric自動化部署有兩點需要注意:
1.安裝mysql時,設置的密碼不能生效,需要登到服務器上手動設置一下:

mysql -u root
use mysql;
update user set password=PASSWORD("123456") where User="root";
flush privileges;
quit;

2.服務器上的用戶需要自己手動創建。

gulp

在build任務中,使用gulp build打包client的angular代碼。
這里先不多說,有需要請參考github項目generator-gulp-angular

setup

setup是python自己的打包工具。
build任務中,最后使用python setup.py sdist命令把整個工程打包成一個tar.gz文件,上傳到服務器。
使用這個工具需要編寫如下兩個文件:
setup.py:打包腳本

#!/usr/bin/env python

from setuptools import setup, find_packages
import server

try:
    long_description = open("README.md").read()
except:
    long_description = server.__description__

REQUIREMENTS = []
exclude_lib = ["oss", "distribute"]
for lib in open("server/requirements/common.txt").readlines():
    for exclude in exclude_lib:
        if lib.lower() not in exclude:
            REQUIREMENTS.append(lib)

setup(
    name="raindrop",
    url="https://www.yudianer.com",
    version=server.__version__,
    author=server.__author__,
    author_email=server.__email__,
    description=server.__description__,
    long_description=long_description,
    license=server.__license__,
    packages=find_packages(),
    zip_safe=False,
    platforms="any",    
    install_requires=REQUIREMENTS
)

MANIFEST.in:指定打包哪些文件夾

recursive-include etc *
recursive-include client/dist *
recursive-include server/app *
recursive-include server/requirements *
recursive-exclude server *.pyc
prune server/app/static/upload/images
prune server/env 
prune server/tests

本文由raindrop網碼農撰寫。歡迎轉載,但請注明出處。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11719.html

相關文章

  • 基于Segment Routing技術構建新一代骨干網:智能、可靠、可調度(一)

    摘要:為了解決骨干網當前的問題,基礎網絡團隊在年下半年開始,對新一代骨干網架構進行重新設計硬件選型,在新一代骨干網架構設計中采用了當前比較流行的源路由即技術以下簡稱,在介紹新一代骨干網架構之前先給大家簡單介紹一下技術的基本概念。前言隨著網絡技術的發展和云計算業務的快速普及,當前各行各業的客戶都有迫切上云的需求,越來越多的關鍵業務,如:web前端、視頻會議、辦公應用、數據存儲等開始部署在云端;新的網...

    Tecode 評論0 收藏0
  • 為什么選擇混合云?UCloud混合云UHybrid產品優勢、架構傳統IDC、自建私有云對比

    摘要:立即咨詢產品文檔優刻得上線了混合云自建機房火爆預售官方補貼活動中針對混合云作了介紹,老劉博客本篇文章分享給大家有關產品優勢架構及與傳統自建私有云的對比。UCloud混合云UHybrid可提供豐富的IaaS和PaaS產品和專業的服務,整合UCloud公有云、托管云、私有云和客戶自有托管IDC等資源,重點解決存量IT資源合理利用,實現多云互聯互通,多區域靈活組網;滿足各個行業上云業務穩定,平滑過...

    Tecode 評論0 收藏0
  • 17.WLAN拓撲介紹_無線分布式系統

    摘要:架構優點無需架線挖槽,快速部署。只有電信部分有權利在公共場所布設電纜,而無線橋接方式則可根據客戶需求使用和免許可的頻段靈活定制專網。組網快,支持緊急通信保障。模式作為葉子節點以型網橋向上連接型網橋。 ...

    afishhhhh 評論0 收藏0
  • 基于Segment Routing技術構建新一代骨干網:智能、可靠、可調度(二)

    摘要:在上篇基于技術構建新一代骨干網智能可靠可調度一中提到了數據中心野蠻式增長給網絡和骨干網帶來了極大挑戰以及骨干網的演進路線技術部分原理介紹。介紹完整個骨干網的架構設計后,我們將分別針對骨干網的智能可靠可調度三大特性進行剖析。在上篇《基于Segment Routing技術構建新一代骨干網:智能、可靠、可調度(一)》中提到了UCloud數據中心野蠻式增長給MAN網絡和骨干網帶來了極大挑戰以及UCl...

    Tecode 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<