在現今軟體開發流程中,延遲任務處理已成為不可或缺的一環。本文將逐步示範如何利用 Docker Compose 建構一個包含 Jupyter 開發環境、PostgreSQL 資料函式庫以及 Redis 任務佇列的延遲任務處理系統。首先,我們會建立一個 Python 模組來連線 PostgreSQL 資料函式庫,並將其封裝成可重複使用的函式。接著,我們會使用 Docker Compose 定義和管理多個服務,包含 Jupyter、PostgreSQL、Redis、Worker 和 Monitor。Worker 服務負責處理 Redis 佇列中的任務,而 Monitor 服務則提供一個視覺化介面來監控任務佇列的狀態。最後,我們會示範如何更新 Jupyter Docker 映像檔以安裝必要的套件,例如 psycopg2、Redis 和 RQ,以及如何使用 Git 進行版本控制,確保程式碼的變更得到妥善管理。透過本文的實作步驟,讀者將能快速建立一個功能完善的延遲任務處理系統,並學習如何有效地管理和維護這個系統。

互動式軟體開發

建立 PostgreSQL 連線模組

在互動式軟體開發過程中,將常用的程式碼抽象化成函式是非常重要的步驟。以下展示如何建立一個用於連線 PostgreSQL 資料函式庫的 Python 模組。

程式碼實作

首先,在 Jupyter Notebook 中定義一個函式來連線 PostgreSQL 資料函式庫。

import psycopg2 as pg2

def connect_to_postgres():
    """連線到 PostgreSQL 資料函式庫並傳回連線物件與遊標"""
    con = pg2.connect(host='this_postgres', user='postgres', database='postgres')
    return con, con.cursor()

驗證函式功能

接下來,驗證 connect_to_postgres 函式是否能夠正確連線資料函式庫並執行查詢。

con, cur = connect_to_postgres()
cur.execute("SELECT COUNT(*) FROM adult;")
print(cur.fetchall())
con.close()

輸出結果應為資料函式庫中 adult 表的記錄數。

將函式加入外部 Python 模組

connect_to_postgres 函式加入到一個名為 lib.postgres 的 Python 模組中,以便在其他指令碼中重複使用。

# lib/postgres.py
import psycopg2 as pg2

def connect_to_postgres():
    """連線到 PostgreSQL 資料函式庫並傳回連線物件與遊標"""
    con = pg2.connect(host='this_postgres', user='postgres', database='postgres')
    return con, con.cursor()

在新 Notebook 中測試模組功能

建立一個新的 Jupyter Notebook,並匯入 lib.postgres 模組來測試其功能。

import lib.postgres as psql

con, cur = psql.connect_to_postgres()
cur.execute("SELECT COUNT(*) FROM bc_data;")
print(cur.fetchall())
con.close()

使用 Git 跟蹤專案變更

最後,使用 Git 記錄專案的變更。

git status
git add -A
git commit -m 'initial database connection'

擴充套件應用程式以支援延遲任務處理

為了增強應用程式的功能,將新增 Redis 服務以及兩個根據 Jupyter 映像的額外服務:Worker 服務和 Monitor 服務。Redis 將作為延遲任務處理系統的基礎設施。

更新 docker-compose.yml 檔案

docker-compose.yml 檔案中新增 Redis、Worker 和 Monitor 服務的定義。

version: '3'
services:
  this_jupyter:
    build: docker/jupyter
    ports:
      - "8888:8888"
    volumes:
      - .:/home/jovyan

  this_postgres:
    build: docker/postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

  this_redis:
    image: redis
    volumes:
      - redis_data:/data

  this_worker:
    build: docker/jupyter
    volumes:
      - .:/home/jovyan
    entrypoint: ["tini", "--", "rqworker", "-u", "redis://this_redis:6379"]

  this_monitor:
    build: docker/jupyter
    volumes:
      - .:/home/jovyan
    ports:
      - "5000:5000"
    entrypoint: ["tini", "--", "rq-dashboard", "-H", "this_redis", "-p", "5000"]

volumes:
  postgres_data:
  redis_data:

更新 Jupyter Dockerfile

更新 Jupyter Dockerfile 以包含支援 Worker 和 Monitor 服務所需的函式庫。

# docker/jupyter/Dockerfile
# ... 其他指令 ...

# 安裝必要的函式庫
RUN pip install rq rq-dashboard

啟動服務並驗證功能

啟動所有服務,並驗證 Worker 和 Monitor 服務是否正常運作。

docker-compose up --build

透過上述步驟,成功地將延遲任務處理功能整合到應用程式中,並使用 Redis、Worker 和 Monitor 服務來管理和監控任務佇列。### 詳細解說:使用 Docker Compose 建立多服務應用程式

在前面的章節中,我們已經成功建立了一個用於連線 PostgreSQL 資料函式庫的 Python 模組,並將其整合到我們的專案中。現在,我們將進一步擴充套件我們的應用程式,以支援延遲任務處理功能。這需要新增 Redis 服務以及兩個額外的服務:Worker 和 Monitor。

使用 Docker Compose 定義多服務架構

Docker Compose 提供了一種簡便的方式來定義和執行多個 Docker 容器的應用程式。在我們的專案中,我們將使用 Docker Compose 來定義四個主要服務:Jupyter、PostgreSQL、Redis、Worker 和 Monitor。

docker-compose.yml 組態詳解
version: '3'
services:
  this_jupyter:
    build: docker/jupyter
    ports:
      - "8888:8888"
    volumes:
      - .:/home/jovyan

  this_postgres:
    build: docker/postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

  this_redis:
    image: redis
    volumes:
      - redis_data:/data

  this_worker:
    build: docker/jupyter
    volumes:
      - .:/home/jovyan
    entrypoint: ["tini", "--", "rqworker", "-u", "redis://this_redis:6379"]

  this_monitor:
    build: docker/jupyter
    volumes:
      - .:/home/jovyan
    ports:
      - "5000:5000"
    entrypoint: ["tini", "--", "rq-dashboard", "-H", "this_redis", "-p", "5000"]

volumes:
  postgres_data:
  redis_data:

詳細解說:docker-compose.yml 中的關鍵組態

  1. this_jupyter 服務

    • 使用 docker/jupyter 目錄中的 Dockerfile 建立映像。
    • 將主機的8888埠對映到容器的8888埠,以便存取 Jupyter Notebook。
    • 將當前目錄掛載到容器的 /home/jovyan 目錄,實作程式碼與資料的持久化。
  2. this_postgres 服務

    • 使用 docker/postgres 目錄中的 Dockerfile 建立 PostgreSQL 資料函式庫映像。
    • postgres_data 卷掛載到容器的 /var/lib/postgresql/data 目錄,確保資料函式庫資料的持久化。
  3. this_redis 服務

    • 直接使用官方的 Redis 映像。
    • redis_data 卷掛載到容器的 /data 目錄,用於儲存 Redis 資料。
  4. this_workerthis_monitor 服務

    • 這兩個服務都根據與 this_jupyter 相同的 Dockerfile 建立映像。
    • this_worker 使用 rqworker 命令來處理 Redis 中的任務佇列。
    • this_monitor 使用 rq-dashboard 命令來提供一個 Web 介面,用於監控 Redis 中的任務佇列狀態。
    • 這兩個服務都使用了 tini 作為入口點,以確保容器內部程式的管理更加穩健。
使用 Docker Compose 建立和管理多容器應用程式

詳細步驟和最佳實踐

  1. 建立 Docker Compose 組態檔案

    • 在專案根目錄下建立 docker-compose.yml 檔案。
    • 定義所需的服務,包括 Jupyter Notebook、PostgreSQL、Redis、Worker 和 Monitor。
  2. 組態各個服務

    • 為每個服務指定適當的映像或建置上下文。
    • 組態埠對映和資料卷,以實作資料持久化和方便除錯。
  3. 構建和啟動應用程式

    docker-compose up --build
    

    使用上述命令構建映像並啟動所有服務。如果只需要啟動服務而不重新構建映像,可以省略 --build 選項。

  4. 管理應用程式生命週期

    • 使用 docker-compose stop 命令停止所有正在執行的服務。
    • 使用 docker-compose rm 命令刪除已停止的容器。
    • 使用 docker-compose logs 檢視各個服務的日誌輸出,便於除錯和監控。
  5. 擴充套件和更新應用程式

    • 修改 docker-compose.yml 檔案以新增或修改服務組態。
    • 使用 docker-compose up --build 命令重新構建和啟動更新後的應用程式。

詳細解說:使用 Docker Compose 的最佳實踐

  1. 版本控制

    • docker-compose.yml 檔案納入版本控制系統(如 Git),以跟蹤變更歷史和協同開發。
  2. 環境變數管理

    • 利用 Docker Compose 的環境變數替換功能,將敏感資訊(如資料函式庫密碼)儲存在 .env 檔案中,避免直接寫入組態檔案。
  3. 日誌管理和監控

    • 組態適當的日誌驅動程式,以便收集和分析各個容器的日誌資料。
    • 利用監控工具(如 Prometheus 和 Grafana)對應用程式效能進行監控和分析。
  4. 安全性考慮

    • 確保容器內的程式以非 root 使用者身份執行,以降低安全風險。
    • 利用 Docker 的網路功能,限制不同服務之間的通訊,以增強安全性。
  5. 持續整合/持續佈署(CI/CD)

    • 將 Docker Compose 與 CI/CD 管道整合,實作自動化的測試、構建和佈署流程,提高開發效率和品質。

透過遵循上述最佳實踐,可以充分發揮 Docker Compose 在多容器應用程式管理方面的優勢,提高開發效率、確保應用程式穩定性和安全性,並簡化佈署流程。

互動式軟體開發的最佳實踐與實作

在現代軟體開發過程中,互動式開發已成為一種重要的開發模式。本章節將探討如何利用互動式開發來提升軟體開發的效率和品質,並以實際案例來說明其應用。

Docker 環境組態與管理

在進行互動式軟體開發時,Docker 提供了一個強大的容器化環境,能夠有效地隔離和管理不同服務之間的依賴關係。

更新 Jupyter Docker 映像檔

首先,我們需要更新 docker/jupyter/Dockerfile 以安裝必要的套件。

# 使用官方的 Jupyter SciPy 映像檔作為基礎映像檔
FROM jupyter/scipy-notebook

# 切換到 root 使用者以安裝套件
USER root

# 安裝 psycopg2 和 Redis 相關套件
RUN conda install --yes --name root psycopg2
RUN conda install --yes --name root redis rq

# 安裝 rq-dashboard
RUN ["bash", "-c", "source activate root && pip install rq-dashboard"]

# 切換回預設的 jovyan 使用者
USER jovyan

內容解密:

  1. 基礎映像檔選擇:使用 jupyter/scipy-notebook 作為基礎映像檔,能夠直接獲得 Jupyter Notebook 環境和 SciPy 相關的科學計算套件。
  2. 切換使用者:使用 USER root 切換到 root 使用者,以取得安裝套件的許可權。
  3. 安裝必要套件:使用 conda 安裝 psycopg2(用於連線 PostgreSQL 資料函式庫)和 redisrq(用於處理非同步任務)。
  4. 安裝 rq-dashboard:使用 pip 安裝 rq-dashboard,以提供一個視覺化的介面來監控 RQ 任務佇列。
  5. 切換回 jovyan 使用者:完成安裝後,切換回預設的 jovyan 使用者,以保持安全性。

專案結構與 Docker Compose 管理

本專案採用 Docker Compose 來管理和協調多個服務,包括 Jupyter Notebook、PostgreSQL 資料函式庫和 Redis 伺服器。

檢視專案結構

使用 tree 命令可以檢視目前的專案結構。

$ tree
.
├── data
│   └── adult.data
├── docker
│   ├── jupyter
│   │   └── Dockerfile
│   └── postgres
│       ├── Dockerfile
│       ├── get_data.sh
│       └── initdb.sql
├── docker-compose.yml
├── ipynb
│   ├── 20170611-Examine_Database_Requirements.ipynb
│   ├── 20170613-Initial_Database_Connection.ipynb
│   └── 20170613-Verify_Database_Connection.ipynb
└── lib
    ├── __init__.py
    ├── postgres.py
    └── __pycache__
        ├── __init__.cpython-35.pyc
        └── postgres.cpython-35.pyc

內容解密:

  1. 專案結構:專案被組織成多個目錄,分別用於存放資料、Docker 相關設定、Jupyter Notebook 和 Python 函式庫。
  2. docker-compose.yml:定義了多個服務之間的關係和組態,是啟動整個專案的關鍵檔案。

啟動與管理服務

使用 Docker Compose 可以輕鬆地啟動和管理多個服務。

啟動服務

$ docker-compose up -d --build

檢視執行中的容器

$ docker-compose ps

內容解密:

  1. docker-compose up -d --build:使用 --build 引數強制重新建構映像檔,並在背景啟動所有服務。
  2. docker-compose ps:檢視目前執行中的容器及其狀態。

除錯與日誌管理

在開發過程中,除錯是不可或缺的一環。Docker Compose 提供了方便的日誌管理功能。

檢視特定服務的日誌

$ docker-compose logs this_monitor
$ docker-compose logs this_worker

內容解密:

  1. docker-compose logs:用於檢視指定服務的日誌輸出,有助於除錯和監控服務狀態。

版本控制與變更管理

在開發過程中,使用 Git 來管理程式碼變更是非常重要的。

提交變更

$ git add -A
$ git commit -m 'add delayed job system'

內容解密:

  1. git add -A:將所有變更新增到 Git 索引中。
  2. git commit -m 'add delayed job system':提交變更並新增描述訊息。

擴充套件 PostgreSQL 模組

在互動式開發過程中,我們可能會需要擴充套件現有的模組或功能。例如,編寫一個函式來編碼目標變數。

編碼目標變數

首先,在 Jupyter Notebook 中開發和測試函式。

def encode_target(_id):
    """為單一行編碼目標變數為布林值。接受一個行 _id。"""
    con, cur = connect_to_postgres()
    # ... 省略實作細節 ...
    con.close()

將函式移到模組中

將測試透過的函式移到 lib/postgres.py 模組中,以便重複使用。

將函式傳遞給工作執行緒

透過任務佇列將函式傳遞給工作執行緒執行。

內容解密:

  1. 互動式開發:在 Jupyter Notebook 中進行互動式開發,可以快速測試和驗證想法。
  2. 模組化:將可重複使用的程式碼抽象成函式,並放入適當的模組中。
  3. 非同步處理:透過任務佇列,將耗時的任務交由工作執行緒處理,提高系統的回應性和吞吐量。