Entrypoint

如果您正在使用生產映像檔的預設 entrypoint,則容器啟動時會自動執行一些動作。在某些情況下,您可以將環境變數傳遞給映像檔以觸發某些行為。

控制「執行」行為的變數以 _AIRFLOW 開頭,以將它們與用於建置映像檔且以 AIRFLOW 開頭的變數區分開來。

允許任意使用者執行容器

Airflow 映像檔與 Open-Shift 相容,這表示您可以使用隨機使用者 ID 和群組 ID 0 (root) 啟動它。如果您想使用與 Airflow 不同的使用者執行映像檔,您必須將使用者的 GID 設定為 0。如果您嘗試使用不同的群組,entrypoint 將會以錯誤退出。

OpenShift 在啟動容器時會隨機分配 UID,但如果您手動執行映像檔,您也可以利用這種彈性的 UID。例如,如果您想從 Linux 主機系統掛載 daglogs 資料夾,在這種情況下,UID 應該設定為與您的主機使用者相同的 ID,這可能會很有用。

這可以透過多種方式實現 - 您可以在擴展或自訂映像檔時變更 USER,或者您可以透過在 docker run 命令中新增 --user 旗標,以動態方式將使用者傳遞給 docker run 命令,格式如下 (詳情請參閱 Docker Run 參考資料)

[ user | user:group | uid | uid:gid | user:gid | uid:group ]

在 Docker Compose 環境中,可以透過 docker-compose.yaml 中的 user: 條目進行變更。詳情請參閱 Docker compose 參考資料。在我們使用 Docker-Compose 的快速入門指南中,UID 可以透過 AIRFLOW_UID 變數傳遞,如 初始化 docker compose 環境 中所述。

使用者可以是任何 UID。如果 UID 與預設的 airflow (UID=50000) 不同,則使用者將在進入容器時自動建立。

為了適應許多外部函式庫和專案,Airflow 將在 (/etc/passwd) 中自動建立這樣一個任意使用者,並使其主目錄指向 /home/airflow。許多協力廠商函式庫和套件都需要使用者的主目錄存在,因為它們需要在其中寫入一些快取資訊,因此動態建立使用者是必要的。

此類任意使用者必須能夠寫入需要寫入權限的某些目錄,並且由於不建議允許「其他」寫入權限以確保安全,因此 OpenShift 指南引入了使所有此類資料夾都具有 0 (root) 群組 ID (GID) 的概念。Airflow 生產映像檔中需要寫入權限的所有目錄都將 GID 設定為 0 (並且它們對於群組是可寫入的)。我們遵循這個概念,所有需要寫入權限的目錄都遵循這個概念。

GID=0 設定為 airflow 使用者的預設值,因此它建立的任何目錄預設都將 GID 設定為 0。entrypoint 將 umask 設定為 0002 - 這表示使用者建立的任何目錄也具有群組 0 的「群組寫入」權限 - 它們將可由具有 root 群組的其他使用者寫入。此外,每當任何「任意」使用者建立資料夾 (例如在掛載的磁碟區中) 時,該資料夾都將具有「群組寫入」權限和 GID=0,以便即使稍後由另一個任意使用者掛載此類目錄,使用另一個任意使用者的執行仍將繼續運作。

但是,umask 設定僅適用於容器的執行時間 - 它在映像檔的建置期間未使用。如果您想擴展映像檔並新增自己的套件,您應該記住在您的 docker 命令前面新增 umask 0002 - 這樣任何需要群組存取的安裝所建立的目錄對於群組來說也是可寫入的。例如,可以透過這種方式完成

RUN umask 0002; \
    do_something; \
    do_otherthing;

您可以在 Openshift 最佳實務 中的「支援任意使用者 ID」章節中閱讀更多相關資訊。

等待 Airflow DB 連線

entrypoint 正在等待資料庫連線,與資料庫引擎無關。這讓我們能夠提高環境的穩定性。

等待連線涉及執行 airflow db check 命令,這表示將執行 select 1 as is_alive; 陳述式。然後它會迴圈,直到命令成功為止。它會嘗試 CONNECTION_CHECK_MAX_COUNT 次,並在檢查之間休眠 CONNECTION_CHECK_SLEEP_TIME。若要停用檢查,請設定 CONNECTION_CHECK_MAX_COUNT=0

等待 Celery broker 連線

如果使用 CeleryExecutor,並且使用了 schedulercelery 命令之一,則 entrypoint 將等待,直到 Celery broker DB 連線可用為止。

腳本會根據 URL 結構偵測後端類型,並在 URL 中未指定時分配預設埠號。然後它會迴圈,直到可以建立與指定主機/埠的連線。它會嘗試 CONNECTION_CHECK_MAX_COUNT 次,並在檢查之間休眠 CONNECTION_CHECK_SLEEP_TIME。若要停用檢查,請設定 CONNECTION_CHECK_MAX_COUNT=0

支援的結構

  • amqp(s):// (rabbitmq) - 預設埠 5672

  • redis:// - 預設埠 6379

  • postgres:// - 預設埠 5432

  • mysql:// - 預設埠 3306

等待連線涉及檢查相符的埠是否已開啟。主機資訊衍生自 Airflow 組態。

執行指令

如果第一個引數等於 “bash” - 您將進入 bash shell,或者如果您指定額外引數,則可以執行 bash 命令。例如

docker run -it apache/airflow:2.10.4-python3.8 bash -c "ls -la"
total 16
drwxr-xr-x 4 airflow root 4096 Jun  5 18:12 .
drwxr-xr-x 1 root    root 4096 Jun  5 18:12 ..
drwxr-xr-x 2 airflow root 4096 Jun  5 18:12 dags
drwxr-xr-x 2 airflow root 4096 Jun  5 18:12 logs

如果第一個引數等於 python - 您將進入 python shell,或者如果您傳遞額外參數,則會執行 python 命令。例如

> docker run -it apache/airflow:2.10.4-python3.8 python -c "print('test')"
test

如果第一個引數等於 “airflow” - 其餘引數將被視為要執行的 airflow 命令。範例

docker run -it apache/airflow:2.10.4-python3.8 airflow webserver

如果還有任何其他引數 - 它們只會傳遞給 “airflow” 命令

> docker run -it apache/airflow:2.10.4-python3.8 help
  usage: airflow [-h] GROUP_OR_COMMAND ...

  positional arguments:
    GROUP_OR_COMMAND

      Groups:
        celery         Celery components
        config         View configuration
        connections    Manage connections
        dags           Manage DAGs
        db             Database operations
        jobs           Manage jobs
        kubernetes     Tools to help run the KubernetesExecutor
        pools          Manage pools
        providers      Display providers
        roles          Manage roles
        tasks          Manage tasks
        users          Manage users
        variables      Manage variables

      Commands:
        cheat-sheet    Display cheat sheet
        info           Show information about current Airflow and environment
        kerberos       Start a Kerberos ticket renewer
        plugins        Dump information about loaded plugins
        rotate-fernet-key
                       Rotate encrypted connection credentials and variables
        scheduler      Start a scheduler instance
        sync-perm      Update permissions for existing roles and optionally DAGs
        version        Show the version
        webserver      Start a Airflow webserver instance

  optional arguments:
    -h, --help         show this help message and exit

在 Airflow entrypoint 之前執行自訂程式碼

如果您想在 Airflow 的 entrypoint 之前執行一些自訂程式碼,您可以使用自訂腳本,並將 Airflow 的 entrypoint 作為自訂腳本中的最後一個 exec 指令呼叫。但是,您必須記住以與 Airflow 的 entrypoint 相同的方式使用 dumb-init,否則您可能會遇到訊號傳遞不正確的問題 (請參閱下一章)。

FROM airflow:2.9.0.dev0
COPY my_entrypoint.sh /
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/my_entrypoint.sh"]

您的 entrypoint 可能會動態修改或新增變數。例如,以下 entrypoint 從作為映像檔執行參數傳遞的第一個參數設定 DB 檢查的最大計數 (一個有點沒用的範例,但應該讓讀者了解您可以如何使用它)。

#!/bin/bash
export CONNECTION_CHECK_MAX_COUNT=${1}
shift
exec /entrypoint "${@}"

請確保 Airflow 的 entrypoint 使用 exec /entrypoint "${@}" 作為自訂 entrypoint 中的最後一個命令執行。這樣,訊號將被正確傳遞,並且引數將像往常一樣傳遞給 entrypoint (如果您需要傳遞一些額外引數,可以使用上面的 shift)。請注意,從安全角度來看,以這種方式傳遞機密值或將機密儲存在映像檔中是一個壞主意 - 因為任何有權存取您的 Kubernetes 或映像檔登錄檔日誌的人都可以存取映像檔和執行映像檔的參數。

另請注意,在 Airflow 的 entrypoint 之前執行的程式碼不應在容器內建立任何檔案或目錄,並且在執行時,一切可能無法以相同的方式運作。在執行 Airflow entrypoint 之前,以下功能不可用

  • umask 未正確設定以允許 group 寫入權限

  • 如果使用任意使用者執行映像檔,則使用者尚未在 /etc/passwd 中建立

  • 資料庫和 broker 可能尚未可用

新增自訂映像檔行為

Airflow 映像檔在 entrypoint 中執行許多步驟,並設定正確的環境,但您可能希望在 entrypoint 建立使用者、設定 umask、設定變數並檢查資料庫是否正在執行後執行額外程式碼。

您可以執行自訂腳本 (您可以將其嵌入到映像檔中),而不是執行常規命令 - schedulerwebserver。當您完成自訂設定後,您甚至可以在您的自訂腳本中執行 airflow 的常用元件 - schedulerwebserver。與自訂 entrypoint 類似,它可以透過擴展映像檔新增到映像檔中。

FROM airflow:2.9.0.dev0
COPY my_after_entrypoint_script.sh /

建置您的映像檔,然後您可以透過執行以下命令來執行此腳本

docker build . --pull --tag my-image:0.0.1
docker run -it my-image:0.0.1 bash -c "/my_after_entrypoint_script.sh"

訊號傳遞

Airflow 使用 dumb-init 作為 entrypoint 中的 “init” 執行。這是為了正確傳遞訊號和清除子程序。這表示您執行的程序不必安裝訊號處理常式即可正常運作,並在容器正常終止時被終止。訊號傳遞的行為由 DUMB_INIT_SETSID 變數配置,預設設定為 1 - 表示訊號將傳遞到整個程序群組,但您可以將其設定為 0 以啟用 dumb-initsingle-child 行為,該行為僅將訊號傳遞到單個子程序。

下表總結了 DUMB_INIT_SETSID 的可能值及其使用案例。

變數值

使用案例

1 (預設)

將訊號傳遞到容器中執行的主程序之程序群組中的所有程序。

如果您透過 ["bash", "-c"] 命令執行程序,並且 bash 在沒有 exec 的情況下產生新程序,這將有助於正常終止您的容器,因為所有程序都將收到訊號。

0

將訊號僅傳遞到主程序。

如果您的主程序優雅地處理訊號,這將非常有用。Celery worker 的暖關機便是一個很好的例子。在這種情況下,dumb-init 將僅將訊號傳遞到主程序,而不會傳遞到與主程序在同一程序群組中產生的程序。例如,在 Celery 的情況下,主程序會將 worker 置於「離線」模式,並等待所有正在執行的任務完成,然後才會終止所有程序。

對於 Airflow 的 Celery worker,您應該將變數設定為 0,並使用 ["celery", "worker"] 命令。如果您透過 ["bash", "-c"] 命令執行它,您需要透過 exec airflow celery worker 作為執行的最後一個命令來啟動 worker。

額外的快速測試選項

以下選項主要用於快速測試映像檔 - 例如使用快速入門 docker-compose 或當您想要使用新增的套件執行本機測試時。它們不應在生產環境中執行,因為它們會為執行額外命令增加額外負荷。生產環境中的這些選項應作為資料庫的維護操作實現,或應嵌入到使用的自訂映像檔中 (當您想要新增套件時)。

升級 Airflow DB

如果您將 _AIRFLOW_DB_MIGRATE 變數設定為非空值,則 entrypoint 將在驗證連線後立即執行 airflow db migrate 命令。當您使用內部 SQLite 資料庫 (預設) 執行 airflow 時,您也可以使用它來升級資料庫並在 entrypoint 建立管理員使用者,以便您可以立即啟動 webserver。注意 - 使用 SQLite 僅適用於測試目的,永遠不要在生產環境中使用 SQLite,因為它在並行性方面存在嚴重限制。

建立管理員使用者

當您進入 entrypoint 時,它也可以自動建立 webserver 使用者。您需要將 _AIRFLOW_WWW_USER_CREATE 設定為非空值才能執行此操作。這不適用於生產環境,僅當您想使用生產映像檔執行快速測試時才有用。您需要至少傳遞密碼,才能透過 _AIRFLOW_WWW_USER_PASSWORD_AIRFLOW_WWW_USER_PASSWORD_CMD 建立此類使用者,與其他 *_CMD 變數類似,*_CMD 的內容將被評估為 shell 命令,其輸出將設定為密碼。

如果未設定任何 PASSWORD 變數,使用者建立將會失敗 - 由於安全原因,密碼沒有預設值。

參數

預設值

環境變數

使用者名稱

admin

_AIRFLOW_WWW_USER_USERNAME

密碼

_AIRFLOW_WWW_USER_PASSWORD_CMD_AIRFLOW_WWW_USER_PASSWORD

名字

Airflow

_AIRFLOW_WWW_USER_FIRSTNAME

姓氏

Admin

_AIRFLOW_WWW_USER_LASTNAME

電子郵件

airflowadmin@example.com

_AIRFLOW_WWW_USER_EMAIL

角色

Admin

_AIRFLOW_WWW_USER_ROLE

如果指定了密碼,將嘗試建立使用者,但如果嘗試失敗,entrypoint 不會失敗 (這說明了使用者已建立的情況)。

例如,您可以使用以下命令在生產映像檔中啟動 webserver,同時初始化內部 SQLite 資料庫並建立 admin/admin 管理員使用者

docker run -it -p 8080:8080 \
  --env "_AIRFLOW_DB_MIGRATE=true" \
  --env "_AIRFLOW_WWW_USER_CREATE=true" \
  --env "_AIRFLOW_WWW_USER_PASSWORD=admin" \
    apache/airflow:2.10.4-python3.8 webserver
docker run -it -p 8080:8080 \
  --env "_AIRFLOW_DB_MIGRATE=true" \
  --env "_AIRFLOW_WWW_USER_CREATE=true" \
  --env "_AIRFLOW_WWW_USER_PASSWORD_CMD=echo admin" \
    apache/airflow:2.10.4-python3.8 webserver

上述命令執行 SQLite 資料庫的初始化,建立具有 admin 密碼和管理員角色的管理員使用者。它們還將本機埠 8080 轉發到 webserver 埠,並最終啟動 webserver。

安裝額外的需求

警告

以這種方式安裝需求是一種非常方便的 Airflow 執行方法,對於測試和偵錯非常有用。但是,不要被它的便利性所迷惑。您永遠不應該在生產環境中使用它。我們刻意選擇將其作為開發/測試相依性,並且每當使用它時,我們都會印出警告。在生產環境中使用此方法存在固有的安全相關問題。以這種方式安裝需求可能會在任何時間發生 - 當您的容器重新啟動時,當您的 K8S 叢集中的機器重新啟動時。在 K8S 叢集中,這些事件可能在任何時間發生。這會讓您面臨嚴重的漏洞,您的生產環境可能會因為從 PyPI 中移除單個相依性而崩潰 - 甚至是您的相依性的相依性。這表示您將生產服務的可用性交給了協力廠商開發人員。協力廠商開發人員隨時都可能讓您的生產 Airflow 實例崩潰,包括週末和假日,而您甚至都不知道。這是一個嚴重的漏洞,類似於臭名昭著的 leftpad 問題。您可以透過建置自己的、不可變的自訂映像檔 (其中已內建相依性) 來完全防止這種情況發生。您已被警告。

可以透過指定 _PIP_ADDITIONAL_REQUIREMENTS 變數來安裝額外的需求。變數應包含在進入容器時應額外安裝的需求清單。請注意,此選項會減慢 Airflow 的啟動速度,因為每次任何容器啟動時都必須安裝新的套件,並且在生產環境中使用時,它會開啟巨大的潛在安全漏洞 (請參閱下文)。因此,此選項僅應用於測試。測試完成後,您應該建立自己的自訂映像檔,其中內建了相依性。

範例

docker run -it -p 8080:8080 \
  --env "_PIP_ADDITIONAL_REQUIREMENTS=lxml==4.6.3 charset-normalizer==1.4.1" \
  --env "_AIRFLOW_DB_MIGRATE=true" \
  --env "_AIRFLOW_WWW_USER_CREATE=true" \
  --env "_AIRFLOW_WWW_USER_PASSWORD_CMD=echo admin" \
    apache/airflow:2.10.4-python3.8 webserver

此方法僅適用於 Airflow 2.1.1 及更高版本的 Docker 映像檔。

此條目是否有幫助?