以Django建立Docker GUI控制界面
前言
在上一篇文章,使用Docker快速建立GUI圖形化的深度學習開發環境中
最後結尾提到,我要來搞一個『以Django爲後端開發集成式管理的Docker開發環境』,於是就有了這篇文章
內容
這篇文章最後完成的專案在 Django Docker GUI
你可能以爲我們要搞個Django的管理後台,然後把Docker的指令包裝起來,讓使用者可以透過網頁來管理開發環境
但是並沒有,因爲這個專案得分成兩個階段
第一個階段,我們得先搞個Django的管理後台,然後把Docker的指令包裝起來
讓使用者可以透過網頁來控制Docker
第二個階段才是把建立開發環境的Docker的指令包裝起來,讓使用者可以透過網頁來管理開發環境
Stage I: Django Docker GUI
本專案可直接查看 Django Docker GUI
大致整理一下要達成這個階段的目標,我們需要以下功能
除了得透過Django定義API去控制裝置的Docker外
我們還要設計登入方式以及簡單的前端頁面來呈現
Authentication
登入的部分,我們採用JWT
這邊我們使用 Simple JWT 來實作
基本上,我之前有寫過一個 Django 的 template
上面有很多標配功能,我們可以直接套用
Django Project Template
在前端的部分,我們需要一個簡易的登入頁面
主要的程式碼可以參考login.html
輸入帳號密碼登入之後,就可以取得 JWT token
Docker API
關於Docker的控制,我們使用已經包裝好的 Docker SDK for Python 來實作
它的使用非常簡單,僅僅兩行就可以建立一個 Docker Client 的 instance
1 | import docker |
Task Queue
Django RQ Task
執行 Docker 指令的時候,我們會需要一些時間來等待 Docker 完成指令
這時候我們就需要一個 Task Queue 來處理這些指令
Survey一些選項,有些人用 celery 或是 Django Q 去控制任務
但我們其實只要一個簡易的 Task Queue 就可以了
所以後來我採用了 Django RQ 來實作
這邊從程式碼內拿一個例子來看,以下是一個建立 Docker Container 的任務
1 |
|
所以有了 Docker SDK ,我們控制 Docker 的方式就變得很容易
但這邊要注意的是send_notification_to_group
這個函數是用來發送 WebSocket 訊息的
在前端的部分,我們有很多地方需要透過 WebSocket 來接收訊息
WebSocket
登入之後的頁面,我們可以看到上面有一個 Container List 的表格
這個表格上的每一個 Container 都有一個操作欄位,裡面有一些按鈕
觸發這些按鈕之後,我們會需要一些時間來等待 Docker 完成指令(使用 Task Queue)
每個連線到這個頁面的瀏覽器就需要透過 WebSocket 來接收訊息,並且更新容器的狀態
如果點進去 Console ,會進到一個網頁版 CMD 的頁面
這個頁面也是透過 WebSocket 來接收訊息,並且更新 CMD 的輸出
在拉取 Image 的時候,我們也需要一個 WebSocket 來接收訊息
所以,websocket 在即時更新狀態上扮演了很重要的角色
- 後端實作
那麼,講了那麼多應用
在後端 Websocket 的部分,我採用 Django Channels 來實作
原本有考慮 Socket.IO ,但是它太特規
除了前後端套件版本都要符合才能用之外,還只能吃同一個path
有夠不友善的,所以就放棄了
相較之下,Django Channels 除了能夠支援前端的原生 WebSocket 之外
還可以以不同用途來使用不同的 path 來做 WebSocket
以這個專案來說,下面是我們的 WebSocket path 例子:
1 | from django.urls import re_path |
可以看到,我們建立三個不同的 Consumer ,並且使用不同的 path 去接收 WebSocket 訊息
另外,在 Task Queue 的部分,我們使用了send_notification_to_group
這個函數
它可以從 server 端去對已經建立連線的 websocket 廣播訊息
以下是這個函數的程式碼:
1 | from asgiref.sync import async_to_sync # 非同步函數轉同步函數 |
這個函數會把訊息傳送給group_notifications
這個頻道
並且它會透過在 consumer 中定義的函數send_notification
把訊息傳送給所有連線的 websocket client
以下是 consumer 中的程式碼:
1 | class NotificationConsumer(AsyncWebsocketConsumer): |
這邊我們可以看到,當有 client 連線到這個 consumer 時
我們會把 client 加入 group,並且在 client 斷線時把 client 從 group 中移除
當 client 還在連線中的狀態下,我們就可以透過send_notification
這個函數把訊息傳送給 client
在後端我們就算是完成了 WebSocket Server 的部分
- 前端實作
對於前端來說,我們要怎麼接收這些訊息呢?
Container Javascript
我們在前端的程式碼,可以使用原生的 WebSocket 來建立連線
並且在收到訊息時,透過onmessage
這個函數來處理訊息
程式碼如下:
1 | function notificationWebsocket() { |
其中,createToastAlert
這個函數可以參考下面的程式碼:
1 | function createToastAlert(msg, isFailure) { |
當我們操作按鈕的時候,所有有透過websocket連線的瀏覽器右上角就會彈跳出訊息
這樣前端就可以正常收發後端傳送過來的訊息了
以上就是這個專案的第一個階段
這個階段的目標是要建立一個可以控制 Docker 的後台
並且透過 WebSocket 來即時更新狀態
結論
我們回顧一下這篇文章
專案最初使用了 Django 來建立一個簡單的後端
然後,我們透過 Docker SDK 來實現控制 Docker
又透過 Django RQ 來實作 Task Queue 來非同步處理 Docker 指令
最後,透過 Django Channels 來實作 WebSocket Server
前端則是使用一些簡易頁面來展示,並且以原生的 WebSocket 來接收訊息
這個專案受到下面這個專案很大的啓發
MahmoudAlyy/docker-django-ui
我把它重構並改寫了一個新的版本
但爲了達成上一篇文章所說的目標
『以Django爲後端開發集成式管理的Docker開發環境』
我們還需要一些努力!下一篇文章終於可以來介紹第二個階段的專案了!
這篇文章同步發表於 Medium ,歡迎留言討論!
Medium 文章連結