Apache Dolphin Scheduler - Dockerfile 詳解

AaronLin 發表於 2021-09-19
Docker

Apache DolphinScheduler 是一個分散式去中心化,易擴充套件的視覺化 DAG 工作流任務排程系統。簡稱 DS,包括 Web 及若干服務,它依賴 PostgreSQL 和 Zookeeper,自身的服務模組包括:api, alert, master, worker(有一個 logger 服務,執行在 worker 中)等。詳細部署可以參考:Docker 部署 Dolphin Scheduler

官方提供了構建 Docker 映象的 Dockerfile,位於專案的 docker/build/ 目錄下,本文以 v1.3.8 版本為例,講解 Dockerfile 內的具體內容

Dockerfile 流程

v1.3.8 docker/build/ 目錄結構:

docker/build
├── checkpoint.sh
├── conf
│   └── dolphinscheduler
│       ├── alert.properties.tpl
│       ├── application-api.properties.tpl
│       ├── common.properties.tpl
│       ├── datasource.properties.tpl
│       ├── env
│       │   └── dolphinscheduler_env.sh.tpl
│       ├── logback
│       │   ├── logback-alert.xml
│       │   ├── logback-api.xml
│       │   ├── logback-master.xml
│       │   └── logback-worker.xml
│       ├── master.properties.tpl
│       ├── quartz.properties.tpl
│       ├── supervisor
│       │   └── supervisor.ini
│       ├── worker.properties.tpl
│       └── zookeeper.properties.tpl
├── Dockerfile
├── hooks
│   ├── build
│   ├── build.bat
│   ├── push
│   └── push.bat
├── startup-init-conf.sh
└── startup.sh

Dockerfile 流程:

  1. 引用基礎映象,設定環境變數
  2. 安裝所需的軟體依賴,設定時區
  3. 新增 DS 的專案檔案到容器中,設定工作目錄
  4. 將所需的指令碼和配置檔案拷貝到容器內指定目錄,並進行預先的處理
  5. 暴露網路埠
  6. 使用 Tini 程式管理器啟動 startup.sh

Dockerfile:

FROM openjdk:8-jre-slim-buster

# 需要在執行時使用 --build-arg <引數名>=<值> 覆蓋 VERSION 變數
ARG VERSION

# 使得 apt-get 在安裝過程不詢問問題
ARG DEBIAN_FRONTEND=noninteractive

# 時區選擇上海
ENV TZ Asia/Shanghai
# 修改編碼集,解決 Docker 容器亂碼
ENV LANG C.UTF-8

# 自定義環境變數,用於標識當前是 Docker 環境,在 dolphinscheduler-daemon.sh 中會引用該變數
ENV DOCKER true

ENV DOLPHINSCHEDULER_HOME /opt/dolphinscheduler

# 設定 Debian 的源,這段程式碼預設是註釋的,為了順利下載依賴,需要放開註釋
RUN { \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free"; \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free"; \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free"; \
    echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free"; \
} > /etc/apt/sources.list

# 使用 apt-get update 更新軟體列表
# 使用 --no-install-recommends 來避免安裝非必須的檔案,以減小映象的體積
RUN apt-get update && \
    apt-get install -y --no-install-recommends tzdata dos2unix python supervisor procps psmisc netcat sudo tini && \
    echo "Asia/Shanghai" > /etc/timezone && \
    rm -f /etc/localtime && \
    dpkg-reconfigure tzdata && \
    rm -rf /var/lib/apt/lists/* /tmp/*

# 需要將 Maven 構建的壓縮包 放在 Dockerfile 同級目錄,使用 ADD 命令會將 tar 壓縮包解壓到容器內
ADD ./apache-dolphinscheduler-${VERSION}-bin.tar.gz /opt/

# 使用軟連結將解壓後的資料夾連結到 /opt/dolphinscheduler
RUN ln -s -r /opt/apache-dolphinscheduler-${VERSION}-bin /opt/dolphinscheduler
# 設定工作目錄
WORKDIR /opt/apache-dolphinscheduler-${VERSION}-bin

# 拷貝配置檔案到容器內指定位置
COPY ./checkpoint.sh /root/checkpoint.sh
COPY ./startup-init-conf.sh /root/startup-init-conf.sh
COPY ./startup.sh /root/startup.sh
COPY ./conf/dolphinscheduler/*.tpl /opt/dolphinscheduler/conf/
COPY ./conf/dolphinscheduler/logback/* /opt/dolphinscheduler/conf/
COPY ./conf/dolphinscheduler/supervisor/supervisor.ini /etc/supervisor/conf.d/
COPY ./conf/dolphinscheduler/env/dolphinscheduler_env.sh.tpl /opt/dolphinscheduler/conf/env/

# 使用 sed 替換配置中的檔案字尾
# 使用 dos2unix 將指令碼中 \r\n 轉換為\n,避免指令碼執行錯誤
# 刪除 /bin/sh 使用 bash
# echo PS1=\"\\w \\$ \" >> ~/.bashrc:修改命令提示符設定(PS1) 格式
# Set disable_coredump false:重新啟用核心轉儲,以解決容器內使用 sudo 導致的 Operation not permitted 問題
RUN sed -i 's/*.conf$/*.ini/' /etc/supervisor/supervisord.conf && \
    dos2unix /root/checkpoint.sh && \
    dos2unix /root/startup-init-conf.sh && \
    dos2unix /root/startup.sh && \
    dos2unix /opt/dolphinscheduler/script/*.sh && \
    dos2unix /opt/dolphinscheduler/bin/*.sh && \
    rm -f /bin/sh && \
    ln -s /bin/bash /bin/sh && \
    mkdir -p /tmp/xls && \
    echo PS1=\"\\w \\$ \" >> ~/.bashrc && \
    echo "Set disable_coredump false" >> /etc/sudo.conf

# 暴露埠
EXPOSE 5678 1234 12345 50051

# 使用 Tini 啟動 /root/startup.sh
ENTRYPOINT ["/usr/bin/tini", "--", "/root/startup.sh"]

使用的基礎映象是:openjdk:8-jre-slim-buster

使用到了 ARG 和 ENV 設定環境變數:ARG 設定的環境變數僅在構建期間可用,在將來容器執行時是不會存在的

ENV DOCKER true 是為了標識當前是 Docker 環境,在dolphinscheduler-daemon.sh 中會引用該變數,新增 JVM 引數:-XX:-UseContainerSupport,這允許JVM 從主機讀取 cgroup 限制,例如可用的 CPU 和 RAM,並進行相應的配置。這樣當容器超過記憶體限制時,會丟擲 OOM 異常,而不是殺死容器

主要安裝了這些依賴:tzdata dos2unix python supervisor procps psmisc netcat sudo tini

使用 echo "Asia/Shanghai" > /etc/timezone && rm -f /etc/localtime && dpkg-reconfigure tzdata && 設定容器時區

因為已經完成依賴安裝了所以可以使用 rm -rf /var/lib/apt/lists/* /tmp/* 刪除軟體列表和臨時目錄,減小壓映象體積

Supervisor 是用Python開發的一套通用的程式管理程式,能將一個普通的命令列程式變為後臺 daemon,並監控程式狀態,它的配置檔案是:/etc/supervisor/supervisord.conf,配置中包含下面的配置,預設引入 /etc/supervisor/conf.d/ 下的所有 .conf 檔案

[include]
files = /etc/supervisor/conf.d/*.conf

Dockerfile 將自定義的配置檔案拷貝到容器內指定的目錄,其中:將conf/dolphinscheduler/supervisor/supervisor.ini 拷貝到 /etc/supervisor/conf.d/目錄下,supervisor.ini 是 .ini 而 Supervisor 預設配置是 .conf,為了使 Supervisor 能夠讀取到自定義的配置,使用命令 sed -i 's/*.conf$/*.ini/' /etc/supervisor/supervisord.conf*.conf 替換為 *.ini,就變成了下面的樣子

[include]
files = /etc/supervisor/conf.d/*.ini

Windows格式檔案的換行符為 \r\n ,而Unix&Linux檔案的換行符為 \n ,dos2unix命令其實就是將檔案中的 \r\n 轉換為 \n

使用 Tini 程式管理器,它是一個最小化到 init 系統,執行在容器內部,用於啟動一個子程式,並等待程式退出時清理殭屍和執行訊號轉發,它是一個替代龐大複雜的 systemd 體系的解決方案

startup.sh 主要做了這些事:

  1. 檢查資料庫連線
  2. 初始化資料庫,執行 script/create-dolphinscheduler.sh,最終執行 org.apache.dolphinscheduler.dao.upgrade.shell.CreateDolphinScheduler Java 程式
  3. 檢查 zookeeper 連線
  4. 初始化配置檔案:執行 startup-init-conf.sh ,這個指令碼定義了各個引數的預設配置,遍歷所有 的 tpl 檔案,填充配置的值,輸出填充後的配置檔案
  5. 讀取執行 Shell 時傳入的第一個引數 ($1),根據這個判斷需要啟動哪些服務
  6. 建立 logs 目錄
  7. 啟動 supervisord,supervisord 會間接讀取 supervisor.ini 的配置,這裡定義了每個服務啟動的方式,通過呼叫 dolphinscheduler-daemon.sh 執行具體的啟動邏輯

構建映象

使用 打包 apache-dolphinscheduler-${VERSION}-bin.tar.gz 這裡的 VERSION 為 1.3.8-SNAPSHOT

mvn -U clean package -Prelease -Dmaven.test.skip=true

將壓縮包拷貝到 docker/build/ 下,使用 --build-arg 傳入版本,構建 Docker 映象

docker build --build-arg VERSION=1.3.8-SNAPSHOT -t apache/dolphinscheduler:1.3.8-SNAPSHOT .

參考資料

When building from Dockerfile, Debian/Ubuntu package install debconf Noninteractive install not allowed
Ubuntu的安裝引數DEBIAN_FRONTEND詳解
容器環境的JVM記憶體設定最佳實踐
apt-get install 的引數(add-apt-repository)
Dockerfile設定時區
Docker 中如何設定 container 的時區
Docker tini程式管理器
Supervisor使用詳解
SED 簡明教程
linux系統終端命令提示符設定(PS1)記錄
sudo: setrlimit(RLIMIT_CORE): Operation not permitted
What does the curly-brace syntax ${var%.*} mean?
linux bash shell之變數替換::=句法、=句法、:-句法、-句法、=?句法、?句法、:+句法、+句法