連接埠與開啟按鈕
連接埠如何被發布
容器內的連接埠在主機把它發布出去之前,是無法從網際網路連上的。啟動時,每個宣告的容器連接埠都會被對應到主機上的一個空閒連接埠,取自該主機可用的範圍。你連的是主機連接埠,而它幾乎不會和容器連接埠是同一個號碼 — 原因和你的 SSH 連接埠不是 22 一樣。
容器會透過每個已發布 TCP 連接埠各一個的環境變數,得知它的每個連接埠落在哪個主機連接埠上:
# inside the instance
env | grep SUPERHEAT_TCP_PORT_
# SUPERHEAT_TCP_PORT_22=40123
# SUPERHEAT_TCP_PORT_8080=41007
SUPERHEAT_TCP_PORT_<n> 存放容器連接埠 <n> 所對應的已發布主機連接埠。這只是資訊性的:它存在是為了讓執行個體上的處理程序能正確宣告自己的公開位址。UDP 連接埠沒有這種變數。
各種啟動模式會發布什麼
連接埠來自範本,再加上啟動模式所需要的:
| 啟動模式 | 自動發布 | 然後 |
|---|---|---|
ssh | 容器連接埠 22 | 加上範本上宣告的每一個連接埠 |
jupyter | 容器連接埠 22 與 8080 | 加上範本上宣告的每一個連接埠 |
args | 不自動發布任何東西 | 只有範本上宣告的連接埠 |
vm | 容器連接埠 22 | 加上範本上宣告的每一個連接埠 |
宣告的連接埠可以帶一個標籤。標籤為 open、open_button 或 open-button 會把該連接埠標記為開啟按鈕的目標。其他所有標籤都只是描述性的,該連接埠會被當成一般的應用程式連接埠處理。
開啟按鈕
當範本宣告了一個開啟按鈕連接埠時,執行個體的 連線 頁籤會在 SSH 指令上方顯示一個 開啟 按鈕,指向主機上的那個連接埠。它是你的映像檔所提供的網頁介面的捷徑 — 推論前端、儀表板、檢視器 — 讓你不必自己去查已發布的連接埠。
連接埠號碼也會以 OPEN_BUTTON_PORT 交給容器,以防處理程序需要知道主控台正在宣傳它的哪一個連接埠。
每一種啟動模式都可以有開啟按鈕,args 也不例外。args 模式的範本執行的是映像檔自己的 entrypoint,但它仍然會收到 OPEN_BUTTON_PORT,也仍然會有開啟按鈕 —— 否則提供網頁介面的映像檔就永遠無法從主控台開啟,而那正是 args 模式最主要的用途。
jupyter 模式的執行個體除了這個按鈕之外,還會有自己的 開啟 JupyterLab 按鈕。請見開啟 JupyterLab。
執行個體存取權杖
範本需要權杖的每個執行個體,在你部署時都會拿到自己的密鑰:存取權杖。它和 JupyterLab 權杖是同一個值。執行個體的 連線 頁籤會以 存取權杖 顯示它,預設遮蔽,並附有顯示與複製的按鈕;API 也會在執行個體上以 access_token 回傳給你的組織。執行個體一旦被銷毀,它就消失了。
每個你能啟動、並在已發布連接埠上提供網頁介面或 API 的精選範本,都會在那個連接埠上要求這個權杖:
| 範本 | 連接埠 | 你如何出示權杖 |
|---|---|---|
| ComfyUI、Stable Diffusion WebUI (A1111)、Fooocus、Kohya_ss、Faster-Whisper(它的語音辨識 API) | 應用程式的連接埠 | 應用程式前面有一層存取代理。開啟 按鈕會讓你登入;指令碼則送出 Authorization: Bearer <token> |
| Text Embeddings Inference | 80 | 伺服器把它當成自己的 API 金鑰檢查:每個請求都要帶 Authorization: Bearer <token> |
| Triton Inference Server | 8000(HTTP)、8001(gRPC) | 除了健康檢查以外的每個 API:HTTP 用 Authorization: Bearer <token>,gRPC 用中繼資料 triton-grpc-protocol-authorization: Bearer <token> |
| Open WebUI | 8080 | 以 admin@superheat.local 登入,密碼就是這個權杖。註冊功能已關閉,所以其他人無法建立帳號 |
權杖只涵蓋範本開始要求它之後部署的執行個體。更早部署的執行個體,連接埠維持原樣 — 任何找到它們的人都連得上 — 直到你銷毀它為止;重新部署才會拿到權杖。
Ollama、InvokeAI、LLaMA-Factory 與 vLLM 目前標示為 即將推出。它們的伺服器無法在每一條路由上要求權杖 — vLLM 的 API 金鑰會留下一條推論路由沒有保護 — 所以在做得到之前先下架。已經從它們啟動、正在執行的執行個體不受影響。
# An API port behind the token — Text Embeddings Inference here
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"inputs": "hello"}' \
http://203.0.113.14:41007/embed
開啟按鈕如何讓你登入
對於位在存取代理後面的範本,開啟 連結會以 ?token= 帶著權杖。第一次開啟時,代理會把權杖換成那個瀏覽器裡的 cookie,並把你導到不帶權杖的同一個位址,讓權杖立刻離開網址列。之後在同一個瀏覽器造訪就不需要權杖。沒有帶權杖也沒有那個 cookie 的請求會得到 401。
這個 cookie 只對應用程式自己的頁面、以及直接開啟應用程式有效。由其他來源的頁面讓你的瀏覽器送出的請求 — 包括同一台機器上的其他連接埠 — 會以 403 拒絕,所以主機上其他租用者的應用程式無法拿你的 cookie 來操作你的應用程式。
直接連線 — 機器的 IP 位址加上已發布的連接埠 — 是純 HTTP。開啟連結裡的權杖、cookie 以及那條連線上的其他一切都是不加密傳輸的,所以請像對待密碼一樣對待開啟連結:不要把它貼到任何你不會貼上權杖的地方。
瀏覽器會把 cookie 送給同一個位址上的每一個連接埠,而不只是設定它的那一個。直接連線時,開啟同一台機器上其他租用者執行的應用程式 — 也就是這台機器位址上其他連接埠的任何連結 — 就等於把你的 cookie 交給對方,連同你的應用程式一起,只要執行個體還在就一直有效。請在另一個瀏覽器或無痕視窗裡開啟這個位址上別人的連結,或改用 SSH 轉送連上你自己的應用程式。
透過 SSH 轉送連接埠可以繞過代理直接連到應用程式,因為 SSH 已經驗證過你了。在代理後面,應用程式接聽的是 127.0.0.1,所以請轉送到那個位址:
ssh -N -L 8188:127.0.0.1:8188 -p 40123 root@203.0.113.14
你自己的範本
你自己的範本,只會在宣告了方式的連接埠上要求權杖 — 也就是範本編輯器裡這個連接埠的存取控制設定(存取代理 或 應用程式驗證權杖),或透過 API 設定的 auth。沒有這個欄位的連接埠,會和以前完全一樣地發布:任何找到機器位址與連接埠的人都連得上。請在它前面放一個會驗證身分的東西,或改用 SSH 轉送連上它。請見連接埠。
連上你自己啟動的服務
連接埠是在執行個體啟動時發布的。在執行中的執行個體裡啟動伺服器不會發布任何東西,所以剛跑起來的 python -m http.server 8000 從外面連不上,不管你筆電上的防火牆怎麼設定都一樣。
你有兩個選擇。
在範本上宣告連接埠,然後重新部署。 對於任何你會執行不只一次的東西,這是持久的答案。把連接埠加到範本的連接埠清單底下,給它一個標籤,然後重新部署。請見連接埠。
透過 SSH 轉送。 這不需要重新部署,而且對於你沒有事先規劃的連接埠可以立即生效:
ssh -N -L 8000:localhost:8000 -p 40123 root@203.0.113.14
讓它一直跑著,然後在瀏覽器打開 http://localhost:8000。流量走的是你已經建立的 SSH 連線,所以不會有新的東西暴露到網際網路上。
不論你走哪條路,如果希望已發布的連接埠能用,請把你的服務綁定到 0.0.0.0 而不是 127.0.0.1。只監聽 loopback 的處理程序可以透過 SSH 轉送連上,但無法透過已發布的主機連接埠連上。唯一的例外是位在存取代理後面的應用程式:在那裡,應用程式接聽 loopback,由代理掌管已發布的連接埠。
協定
宣告的連接埠會指定一種協定:tcp、udp、http 或 https。前兩者才是實際在主機上保留的。後兩者只是關於該連接埠提供什麼服務的提示,而且都是走 TCP。
相關內容
- 連接埠 — 在範本上宣告連接埠
- 透過 SSH 連線
- 開啟 JupyterLab