Skip to content

antony@notes:~/container$ cat "Podman-Pod-設定-Containers-啟動順序.md"

Podman Pod 設定 Containers 啟動順序

2025-07-26· container

Podman Pod 設定 App Containers 啟動順序

理解 OCI hooks

Container hooksOCI 規範中的一項功能,它允許使用者在 App Container 生命週期 (lifecycle) 的不同時間點,定義並執行特定的動作。

這些 hook 是指一些腳本 (scripts) 或指令 (commands),它們會在特定的事件發生時被執行,例如在 container 被建立 (created)、啟動 (started)、停止 (stopped) 或刪除 (deleted) 的前後。Container hooks 提供了一種擴充 container 行為的方法,可用於多種目的,包括設定 (setup)、配置 (configuration) 和清理 (cleanup) 等任務。

OCI container hooks 包含以下幾種類型:

  • precreate:這個 hook 會在 container 的設定檔產生之後,但在 container 真正啟動之前執行。
  • prestart:這個 hook 會在 container 的主要程序 (primary process) 啟動執行。它可以用來執行像是設定環境變數、配置網路設定或準備 container 的檔案系統 (filesystem) 等任務。
  • poststart:這個 hook 會在 container 的主要程序 (primary process) 啟動執行。它可用於執行那些需要在 container 開始運行後才進行的任務,例如將 container 註冊到服務發現系統 (service discovery system) 或監控工具。
  • poststop:這個 hook 會在 container 的主要程序 (primary process) 退出或 container 被停止執行。它可用於清理任務 (cleanup tasks)、記錄日誌 (logging) 或任何在 container 停止運行後應採取的行動。

Container hooks 可以在 container 的 OCI 設定檔中定義,該設定檔通常儲存為一個 JSON 檔案。此設定檔會指明 hook 腳本或指令的路徑,以及任何需要的參數 (arguments) 或環境變數 (environment variables)。

快速動手實作

Step1: 設定 Podman hook 定義檔的存放位置

執行以下命令,編輯 /etc/containers/containers.conf 檔案:

sudo nano /etc/containers/containers.conf

修改以下內容 :

# Path to OCI hooks directories for automatically executed hooks.
# 將以下三行取消註解
hooks_dir = [
  "/usr/share/containers/oci/hooks.d",
]

Step2: 以 Json 格式設定 Hook 定義檔

sudo mkdir -p /usr/share/containers/oci/hooks.d/
sudo nano /usr/share/containers/oci/hooks.d/prestart-delay.json

檔案內容如下 :

{
  "version": "1.0.0",
  "hook": {
    "path": "/usr/local/bin/delay.sh",
  },
  "when": {
    "annotations": {
       "^delay$": ".+"
    }
  },
  "stages": ["prestart"]
}

Step3: 編輯 Hook 定義檔中宣告的 shell script,並賦予執行權限

sudo nano /usr/local/bin/delay.sh

檔案內容如下 :

#!/bin/bash

set -x

# 將 stderr 重新導向到一個日誌檔案以便除錯,同時也輸出到原始的 stderr
exec 2> >(tee -a /var/log/oci-hooks.log >&2)

# 從標準輸入 (stdin) 讀取容器狀態 JSON
# OCI 執行階段會在 prestart 階段將此 JSON 傳遞給 Hook
input="-"
CONTAINER_CONFIG=$(cat "$input")

# 檢查 jq 是否安裝
if ! command -v jq &> /dev/null; then
    echo "Error: jq is not installed. Cannot parse container state." >&2
    exit 1
fi

# 使用 jq 從 JSON 中解析我們自訂的註解值。
# 註解鍵為 "delay"。
# -r 選項移除引號。
# // "0" 提供一個預設值,如果註解不存在或為 null,則回傳 "0"。
delay_seconds=$(echo "$CONTAINER_CONFIG" | jq -r '.annotations["delay"] // "0"')

# 輸入驗證:確保我們得到的是一個非負整數。
# 這可以防止錯誤或潛在的命令注入。
if ! [[ "$delay_seconds" =~ ^[0-9]+$ ]]; then
    echo "Warning: Invalid value for annotation delay: '$delay_seconds'. Must be a non-negative integer. Defaulting to 0." >&2
    delay_seconds=0
fi

# 如果延遲時間大於 0,則執行 sleep 並記錄日誌。
if [ "$delay_seconds" -gt 0 ]; then
    echo "Dynamic delay hook triggered. Sleeping for $delay_seconds seconds..." >&2
    sleep "$delay_seconds"
    echo "Sleep complete. Container will now start." >&2
else
    # 如果延遲為 0 或無效,也記錄一條資訊,以便追蹤 Hook 是否被觸發。
    echo "Dynamic delay hook triggered, but delay is 0. Starting container immediately." >&2
fi

賦予程式執行權限 :

sudo chmod +x /usr/local/bin/delay.sh

Step4: 執行與驗證

1. 先用 app container 驗證

date; sudo podman run \
  --rm \
  -it \
  --annotation delay=5 \
  docker.io/library/alpine date

執行結果 :

Sat Jul 26 16:41:05 CST 2025
Sat Jul 26 08:41:10 UTC 2025

可以看到只差 5 秒

2. 使用 podman pod 驗證

# 建立 pod
sudo podman pod create --name mypod

# 建立 container c1,指定 annotation
sudo podman create --name c1 --pod mypod \
  --annotation delay=5 \
  docker.io/library/alpine \
  sh -c "date; sleep infinity"

# 建立 container c2,指定 annotation
sudo podman create --name c2 --pod mypod \
  --annotation delay=10 \
  docker.io/library/alpine \
  sh -c "date; sleep infinity"

# 建立 container c3,指定 annotation
sudo podman create --name c3 --pod mypod \
  --annotation delay=15 \
  docker.io/library/alpine \
  sh -c "date; sleep infinity"

# 啟動所有 container
sudo podman start c1 c2 c3

檢視 podman pod logs

$ sudo podman pod logs mypod

執行結果 :

9c922e6a8c15 Sat Jul 26 15:24:33 UTC 2025
caca4df50c11 Sat Jul 26 15:24:58 UTC 2025
5531bc974469 Sat Jul 26 15:24:43 UTC 2025