Sanic官翻-部署
部署
Sanic有三個服務(wù)選項:內(nèi)置web服務(wù)器、ASGI web服務(wù)器或gunicorn。
Sanic自己的web服務(wù)器是最快的選擇,它可以安全地在互聯(lián)網(wǎng)上運行。不過,將Sanic放在反向代理后面也是非常常見的,如Nginx部署中所示。
Snaic webserver
定義sanic.Sanic實例后,我們可以使用以下關(guān)鍵字參數(shù)調(diào)用run方法:
host(默認(rèn)為"127.0.0.1"):托管服務(wù)器的地址。
port(默認(rèn)為8000):用于托管服務(wù)器的端口。
unix(默認(rèn)為None): 服務(wù)器所在的Unix套接字名稱(而不是TCP)。
debug(默認(rèn)為False):啟用調(diào)試輸出(降低服務(wù)器速度)。
ssl(默認(rèn)為None):SSLContext用于對工作人員進行SSL加密。
sock(默認(rèn)為None):服務(wù)器接受其連接的套接字。
worker(默認(rèn)值為1):要產(chǎn)生的工作進程數(shù)。
loop(默認(rèn)為None):異步兼容的事件循環(huán)。如果未指定,Sanic將創(chuàng)建其自己的事件循環(huán)。
protocol(默認(rèn)為HttpProtocol):asyncio.protocol的子類。
access_log(默認(rèn)為True):啟用登錄以處理請求(顯著降低服務(wù)器速度)。
app.run(host='0.0.0.0', port=1337, access_log=False)
在上面的示例中,我們決定關(guān)閉訪問日志以提高性能。
Workers
默認(rèn)情況下,Sanic僅使用一個CPU內(nèi)核偵聽主進程。要提高效率,只需在運行參數(shù)中指定workers數(shù)。
app.run(host='0.0.0.0', port=1337, workers=4)
Sanic將自動啟動多個進程并在它們之間路由流量。我們建議您使用盡可能多的核心。
命令啟動
如果您喜歡使用命令行參數(shù),則可以通過執(zhí)行模塊來啟動Sanic Web服務(wù)器。例如,如果您在名為server.py的文件中將Sanic初始化為app,則可以這樣運行服務(wù)器:
sanic server.app --host=0.0.0.0 --port=1337 --workers=4
它也可以直接作為模塊調(diào)用。
python -m sanic server.app --host=0.0.0.0 --port=1337 --workers=
通過這種方式運行sanic,無需在Python文件中調(diào)用app.run。
如果這樣做,請確保將其包裝起來,以便僅在由解釋器直接運行時才執(zhí)行。
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1337, workers=4)
ASGI
Sanic也符合ASGI。這意味著您可以使用首選的ASGI Web服務(wù)器來運行Sanic。ASGI的三個主要實現(xiàn)是Daphne, Uvicorn和 Hypercorn。
按照他們的文檔來運行它們的正確方法,但是它看起來應(yīng)該像這樣:
daphne myapp:app
uvicorn myapp:app
hypercorn myapp:app
使用ASG時需要注意的幾件事
使用Sanic Web服務(wù)器時,Websockets將使用websockets軟件包運行。在ASGI模式下,由于websocket是在ASGI服務(wù)器中管理的,因此不需要此軟件包。
ASGI壽命協(xié)議https://asgi.readthedocs.io/en/latest/specs/lifespan.html僅支持兩個服務(wù)器事件:啟動和關(guān)閉。Sanic有四個:啟動之前,啟動之后,關(guān)閉之前和關(guān)閉之后。因此,在ASGI模式下,啟動和關(guān)閉事件將連續(xù)運行,而實際上不會圍繞服務(wù)器進程的開始和結(jié)束運行(因為現(xiàn)在由ASGI服務(wù)器控制)。因此,最好使用after_server_start和before_server_stop。
Sanic在Trio上運行的實驗支持包括:
hypercorn -k trio myapp:app
Gunicorn
Gunicorn“ Green Unicorn”是用于UNIX的WSGI HTTP服務(wù)器。這是從Ruby的Unicorn項目移植過來的pre-forkworker模型。
為了在Gunicorn上運行Sanic應(yīng)用程序,您需要對Gunicorn worker-class參數(shù)使用特殊的sanic.worker.GunicornWorker:
gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class sanic.worker.GunicornWorker
如果您的應(yīng)用程序遭受內(nèi)存泄漏的困擾,您可以將Gunicorn配置為在處理了給定數(shù)量的請求之后正常重啟工作器。這是幫助限制內(nèi)存泄漏影響的便捷方法。
有關(guān)更多信息,請參見Gunicorn Docs。
其他部署注意事項
禁用調(diào)試日志記錄以提高性能
為了提高性能,請在運行參數(shù)中添加debug = False和access_log = False。
app.run(host='0.0.0.0', port=1337, workers=4, debug=False, access_log=False)
通過Gunicorn運行,您可以設(shè)置環(huán)境變量SANIC_ACCESS_LOG ="False"
env SANIC_ACCESS_LOG="False" gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class sanic.worker.GunicornWorker --log-level warning
或者您可以直接重寫應(yīng)用程序配置
app.config.ACCESS_LOG = False
異步支持和共享循環(huán)
如果您需要與其他應(yīng)用程序(特別是循環(huán))共享Sanic進程,則此方法非常適合。但是,請注意,此方法不支持使用多個進程,并且通常不是運行該應(yīng)用程序的首選方法。
這是一個不完整的示例(請參閱示例中的run_async.py了解更多實用信息):
server = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(server)
loop.run_forever()
注意:使用此方法,調(diào)用app.create_server()將觸發(fā)before_server_start服務(wù)器事件,但不會觸發(fā)after_server_start,before_server_stop或after_server_stop服務(wù)器事件。
對于更高級的用例,您可以使用AsyncioServer對象觸發(fā)這些事件,該對象是通過等待服務(wù)器任務(wù)返回的。
這是一個不完整的示例(請參閱示例中的run_async_advanced.py了解更完整的內(nèi)容):
serv_coro = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True)
loop = asyncio.get_event_loop()
serv_task = asyncio.ensure_future(serv_coro, loop=loop)
server = loop.run_until_complete(serv_task)
server.after_start()
try:
loop.run_forever()
except KeyboardInterrupt as e:
loop.stop()
finally:
server.before_stop()
# Wait for server to close
close_task = server.close()
loop.run_until_complete(close_task)
# Complete all tasks on the loop
for connection in server.connections:
connection.close_if_idle()
server.after_stop()
Nginx部署
概述
盡管Sanic可以直接在Internet上運行,但在它前面使用Nginx這樣的代理服務(wù)器可能會很有用。這對于在同一個IP上運行多個虛擬主機、在單個Sanic應(yīng)用程序旁邊為nodej或其他服務(wù)提供服務(wù)特別有用,而且還允許高效地為靜態(tài)文件提供服務(wù)。SSL和HTTP/2也很容易在這樣的代理上實現(xiàn)。
我們將Sanic應(yīng)用程序設(shè)置為僅在127.0.0.1:8000本地提供服務(wù),而Nginx安裝負責(zé)向域上的公共互聯(lián)網(wǎng)提供服務(wù)example.com網(wǎng)站. 靜態(tài)文件將從/var/www/提供。
代理Sanic應(yīng)用程序
該應(yīng)用程序需要設(shè)置一個用于識別可信代理的密鑰,這樣才能識別真實的客戶端IP和其他信息。這可以防止任何人在互聯(lián)網(wǎng)上發(fā)送假請求頭欺騙他們的IP地址和其他細節(jié)。選擇任意隨機字符串并在應(yīng)用程序和Nginx配置中進行配置。
from sanic import Sanic
from sanic.response import text
app = Sanic("proxied_example")
app.config.FORWARDED_SECRET = "YOUR SECRET"
@app.get("/")
def index(request):
# This should display external (public) addresses:
return text(
f"{request.remote_addr} connected to {request.url_for('index')}
"
f"Forwarded: {request.forwarded}
"
)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, workers=8, access_log=False)
由于這將是一個系統(tǒng)服務(wù),請將代碼保存到/srv/sanicexample/sanicexample.py.
要進行測試,請在終端中運行應(yīng)用程序。
Nginx配置
需要相當(dāng)多的配置來允許快速透明代理,但在大多數(shù)情況下,這些都不需要修改,所以請接受我的建議。
upstream服務(wù)器需要在一個單獨的upstream塊中配置,以啟用HTTP keep alive,這可以極大地提高性能,因此我們使用它,而不是在proxy_pass指令中直接提供upstream地址。在本例中,upstream部分由server_name命名,即公共域名,然后在主機頭中傳遞給Sanic。您可以根據(jù)需要更改名稱。還可以提供多個服務(wù)器用于負載平衡和故障切換。
根據(jù)網(wǎng)站的真實域名更改example.com的兩個匹配項,使用你的應(yīng)用程序選擇的秘密替換YOUR SECRET 。
upstream example.com {
keepalive 100;
server 127.0.0.1:8000;
#server unix:/tmp/sanic.sock;
}
server {
server_name example.com;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
# Serve static files if found, otherwise proxy to Sanic
location / {
root /var/www;
try_files $uri @sanic;
}
location @sanic {
proxy_pass http://$server_name;
# Allow fast streaming HTTP/1.1 pipes (keep-alive, unbuffered)
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off;
# Proxy forwarding (password configured in app.config.FORWARDED_SECRET)
proxy_set_header forwarded "$proxy_forwarded;secret="YOUR SECRET"";
# Allow websockets
proxy_set_header connection "upgrade";
proxy_set_header upgrade $http_upgrade;
}
}
為了避免cookie可見性問題和搜索引擎上的地址不一致,最好將所有訪問者重定向到一個真正的域,始終使用HTTPS:
# Redirect all HTTP to HTTPS with no-WWW
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name ~^(?:www.)?(.*)$;
return 301 https://$1$request_uri;
}
# Redirect WWW to no-WWW
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ~^www.(.*)$;
return 301 $scheme://$1$request_uri;
}
上面的配置部分可以放在/etc/nginx/sites available/default或其他站點配置中(如果創(chuàng)建新的站點,請確保將它們符號鏈接到啟用的站點)。
確保在主配置中配置了SSL證書,或者將SSL_certificate和SSL_certificate_key指令添加到偵聽SSL的每個服務(wù)器部分。
另外,將所有這些內(nèi)容復(fù)制并粘貼到nginx/conf.d/forwarded.conf
# RFC 7239 Forwarded header for Nginx proxy_pass
# Add within your server or location block:
# proxy_set_header forwarded "$proxy_forwarded;secret="YOUR SECRET"";
# Configure your upstream web server to identify this proxy by that password
# because otherwise anyone on the Internet could spoof these headers and fake
# their real IP address and other information to your service.
# Provide the full proxy chain in $proxy_forwarded
map $proxy_add_forwarded $proxy_forwarded {
default "$proxy_add_forwarded;by="_$hostname";proto=$scheme;host="$http_host";path="$request_uri"";
}
# The following mappings are based on
# https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/
map $remote_addr $proxy_forwarded_elem {
# IPv4 addresses can be sent as-is
~^[0-9.]+$ "for=$remote_addr";
# IPv6 addresses need to be bracketed and quoted
~^[0-9A-Fa-f:.]+$ "for="[$remote_addr]"";
# Unix domain socket names cannot be represented in RFC 7239 syntax
default "for=unknown";
}
map $http_forwarded $proxy_add_forwarded {
# If the incoming Forwarded header is syntactically valid, append to it
"~^(,[ \t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|"([\t \x21\x23-\x5B\x5D-\x7E\x80-\xFF]|\\[\t \x21-\x7E\x80-\xFF])*"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|"([\t \x21\x23-\x5B\x5D-\x7E\x80-\xFF]|\\[\t \x21-\x7E\x80-\xFF])*"))?)*([ \t]*,([ \t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|"([\t \x21\x23-\x5B\x5D-\x7E\x80-\xFF]|\\[\t \x21-\x7E\x80-\xFF])*"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|"([\t \x21\x23-\x5B\x5D-\x7E\x80-\xFF]|\\[\t \x21-\x7E\x80-\xFF])*"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem";
# Otherwise, replace it
default "$proxy_forwarded_elem";
}
對于不使用conf.d和可用站點的安裝,上述所有配置也可以放在main的http部分中nginx.conf文件.
更改后重新加載Nginx配置:
sudo nginx -s reload
現(xiàn)在你應(yīng)該可以在https://example.com/連接到你的app。任何404錯誤等都將由Sanic的錯誤頁面處理,并且每當(dāng)一個靜態(tài)文件出現(xiàn)在給定的路徑上時,Nginx將為其提供服務(wù)。
SSL證書
如果您還沒有在服務(wù)器上配置有效的證書,現(xiàn)在是這樣做的好時機。安裝certbot,python3-certbot-nginx,然后運行
certbot --nginx -d example.com -d www.example.com
https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/
作為服務(wù)執(zhí)行
這部分是針對基于systemd的Linux發(fā)行版的。創(chuàng)建單元文件/etc/systemd/system/sanicexample.service:
[Unit]
Description=Sanic Example
[Service]
User=nobody
WorkingDirectory=/srv/sanicexample
ExecStart=/usr/bin/env python3 sanicexample.py
Restart=always
[Install]
WantedBy=multi-user.target
然后重新加載服務(wù)文件,啟動服務(wù)并在引導(dǎo)時啟用:
sudo systemctl daemon-reload
sudo systemctl start sanicexample
sudo systemctl enable sanicexample
總結(jié)
以上是生活随笔為你收集整理的Sanic官翻-部署的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则表达式匹配原理
- 下一篇: 怎么创建具有真实纹理的CG场景岩石?