---
# System prepended metadata

title: Podman Pod 設定 Containers 啟動順序

---

# Podman Pod 設定 App Containers 啟動順序

## 理解 OCI hooks

`Container hooks` 是 `OCI` 規範中的一項功能，它允許使用者在 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
```

檔案內容如下 : 

```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
```
















