返回文章列表

Podman 容器執行管理與日誌操作技巧

本文探討 Podman 容器的執行管理技巧,包含如何檢視容器儲存層、查詢可寫層檔案、利用標準輸出與標準錯誤輸出捕捉日誌,以及在 Pod 中執行容器與日誌大小限制組態等實務操作。同時,文章也說明瞭 Podman 如何與 Kubernetes Pod 概念結合,以及如何在 Pod

容器技術 DevOps

深入理解容器的執行狀態,需要掌握 Podman 提供的日誌管理機制。預設情況下,Podman 將容器日誌儲存在主機檔案系統,並可透過 podman logs 命令輕鬆檢索。利用 --tail 選項,可以限制輸出的日誌行數,方便檢視最新資訊。此外,podman exec 命令允許在執行中的容器內執行新行程,例如使用 ps aux 列出容器內所有行程。Podman 也支援 Kubernetes Pod 的概念,可以建立空的 Pod 並在其中執行多個容器,分享網路、儲存和組態等資源。Infra 容器在 Pod 中扮演關鍵角色,負責持有名稱空間,讓容器引擎連線到 Pod 中的其他容器。為了避免日誌檔案過大,可以設定 log_size_max 引數來限制日誌檔案大小。最後,容器資料的持久化儲存也是容器管理中重要的一環,需要進一步探討如何在容器生命週期之外保留重要資料。

管理執行中的容器

在探討容器的執行機制時,我們可以發現容器的底層實作與其儲存結構息息相關。以 podman inspect 指令為例,我們可以檢視容器的詳細資訊,包括其儲存層的組態。

檢視容器的儲存層

當我們執行以下指令時:

# podman inspect logger --format "{{ .GraphDriver.Data.LowerDir }}"
/var/lib/containers/storage/overlay/4c85102d65a59c6d478bfe6bc0bf32e8c79d9772689f62451c7196380675d4af/diff

我們可以獲得容器的 LowerDir 路徑,這個路徑代表了容器的基礎映像層。接著,我們可以檢查這個路徑下是否有我們需要的檔案,例如 test.log

# cat /var/lib/containers/storage/overlay/4c85102d65a59c6d478bfe6bc0bf32e8c79d9772689f62451c7196380675d4af/diff/tmp/test.log
cat: /var/lib/containers/storage/overlay/4c85102d65a59c6d478bfe6bc0bf32e8c79d9772689f62451c7196380675d4af/diff/tmp/test.log: No such file or directory

結果顯示,test.log 檔案並不存在於這個路徑下。這是因為 LowerDir 代表的是唯讀的映像層,而我們需要的檔案實際上是寫在容器的可寫層中,也就是 UpperDir

查詢可寫層中的檔案

我們可以透過以下指令找到 UpperDir 的路徑:

# podman inspect logger --format "{{ .GraphDriver.Data.UpperDir }}"
/var/lib/containers/storage/overlay/27d89046485db7c775b108a80072eafdf9aa63d14ee1205946d74623fc195314/diff

接著,檢查這個路徑下的 test.log 檔案:

# cat /var/lib/containers/storage/overlay/27d89046485db7c775b108a80072eafdf9aa63d14ee1205946d74623fc195314/diff/tmp/test.log
test
test
test
test
[...]

這裡我們找到了 test.log 檔案,裡麵包含了我們需要的日誌資訊。

從容器中捕捉日誌的最佳實踐

容器中的程式可能會輸出錯誤訊息或狀態資訊到日誌檔案中,但這些日誌檔案可能存放在臨時檔案系統中,或者受到唯讀檔案系統或許可權限制的影響。為了更好地捕捉這些日誌,容器最佳實踐建議利用標準輸出(STDOUT)和標準錯誤輸出(STDERR)。

使用標準輸出和標準錯誤輸出

當我們使用 podman run 指令以分離模式執行容器時,例如:

$ podman run -d -i -t registry.fedoraproject.org/f29/httpd

Podman 會將容器的 STDOUTSTDERR 輸出儲存到主機檔案系統中的日誌檔案中。如果我們以 root 使用者身份執行 Podman,可以透過以下步驟找到這些日誌檔案:

  1. 首先,執行容器並記錄其 ID:

podman run -d -i -t registry.fedoraproject.org/f29/httpd

c6afe22eac7c22c35a303d5fed45bc1b6442a4cec4a9060f392362bc4cecb25d


2. 然後,進入 `/var/lib/containers/storage/overlay-containers/` 目錄下對應的容器 ID 目錄:
```bash
# cd /var/lib/containers/storage/overlay-containers/c6afe22eac7c22c35a303d5fed45bc1b6442a4cec4a9060f392362bc4cecb25d/
  1. 最後,檢視 userdata/ctr.log 檔案中的日誌內容:

cat userdata/ctr.log

2021-09-27T15:42:46.925288013+00:00 stdout P => sourcing 10-set-mpm.sh … 2021-09-27T15:42:46.925604590+00:00 stdout F 2021-09-27T15:42:46.926882725+00:00 stdout P => sourcing 20-copy-config.sh … …


#### 日誌驅動程式的影響

值得注意的是,上述方法依賴於 `containers.conf` 檔案中的 `log_driver` 欄位設定為 `k8s-file`。如果該欄位被設定為其他值,例如 `journald`,則需要使用相應的日誌檢索工具,如 `journalctl` 指令來檢視日誌。

## 管理執行中的容器

在處理容器日誌時,我們首先需要了解 Podman 的日誌管理機制。預設情況下,Podman 將容器日誌儲存在主機檔案系統中。要檢視日誌驅動程式的預設設定,可以檢查 `/usr/share/containers/containers.conf` 檔案中的 `log_driver` 欄位。

```bash
# grep log_driver /usr/share/containers/containers.conf

儘管如此,我們不需要每次都手動查詢日誌檔案。Podman 提供了一個內建的 podman logs 命令,可以輕鬆地檢索和列印容器的最新日誌。以下是一個範例:

# podman logs c6afe22eac7c22c35a303d5fed45bc1b6442a4cec4a9060f392362bc4cecb25d
=> sourcing 10-set-mpm.sh ...
=> sourcing 20-copy-config.sh ...
=> sourcing 40-ssl-certs.sh ...
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.88.0.9. Set the 'ServerName' directive globally to suppress this message
[Mon Sep 27 15:42:46.996748 2021] [ssl:warn] [pid 1:tid 139708367605120] AH01882: Init: this version of mod_ssl was compiled against a newer library (OpenSSL 1.1.1b FIPS 26 Feb 2019, version currently loaded is OpenSSL 1.1.1 FIPS 11 Sep 2018) - may result in undefined or erroneous behavior
...
[Mon Sep 27 15:42:47.099445 2021] [core:notice] [pid 1:tid 139708367605120] AH00094: Command line: 'httpd -D FOREGROUND'

內容解密:

此範例展示瞭如何使用 podman logs 命令檢視指定容器的日誌。其中,c6afe22eac7c22c35a303d5fed45bc1b6442a4cec4a9060f392362bc4cecb25d 是容器的完整 ID。Podman 也支援使用容器的短 ID。

我們也可以使用 --tail 選項來限制輸出的日誌行數,如下所示:

# podman logs --tail 2 c6afe22eac7c
[Mon Sep 27 15:42:47.099403 2021] [mpm_event:notice] [pid 1:tid 139708367605120] AH00489: Apache/2.4.39 (Fedora) OpenSSL/1.1.1 configured -- resuming normal operations
[Mon Sep 27 15:42:47.099445 2021] [core:notice] [pid 1:tid 139708367605120] AH00094: Command line: 'httpd -D FOREGROUND'

內容解密:

此命令僅輸出了日誌的最後兩行。--tail 選項非常適合用於檢視最新的日誌資訊。

在執行中的容器中執行行程

Podman 利用 Linux 的 namespace 功能來隔離容器。我們可以透過 podman exec 命令在執行中的容器內執行新的行程。

# podman run -d -i -t registry.fedoraproject.org/f29/httpd
47fae73e4811a56d799f258c85bc50262901bec2f9a9cab19c01af89713a1248
# podman exec -ti 47fae73e4811a56d799f258c85bc50262901bec2f9a9cab19c01af89713a1248 /bin/bash
bash-4.4$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
default        1  0.6  0.6  20292 13664 pts/0    Ss+  13:37   0:00 httpd -D FOREGROUND
...

內容解密:

此範例展示瞭如何使用 podman exec 命令在執行中的容器內啟動一個新的 Bash 行程,並執行 ps aux 命令來列出容器內的執行行程。-ti 選項用於分配一個偽終端並保持 STDIN 流開啟。

圖表說明

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Podman 容器執行管理與日誌操作技巧

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

此圖示展示了 Podman 中容器的生命週期以及如何與執行中的容器互動。

組態日誌大小限制

預設情況下,Podman 不限制日誌檔案的大小。為了避免日誌檔案過大,可以在 /etc/containers/containers.conf 組態檔案中設定 log_size_max

[containers]
log_size_max=10000000

內容解密:

此組態將每個容器的日誌檔案大小限制在 10 MB。對於已經執行的容器,需要重新啟動後組態才會生效。

綜上所述,Podman 提供了一系列強大的工具來管理和監控容器,包括檢視日誌和在執行中的容器內執行新行程。透過合理組態和管理,可以有效地維護容器的穩定性和安全性。

在 Pod 中執行容器

在我們邁向容器管理世界的旅程中,我們將在下一節中探討 Podman 提供的一些功能,以便在 Kubernetes 容器協調世界中啟用容器化工作負載。

在 Pod 中執行容器

正如我們在第 2 章「比較 Podman 和 Docker」一節中提到的,Podman 提供了輕鬆採用一些基本的 Kubernetes 概念的功能。Kubernetes(有時也簡稱為 k8s)是事實上的容器協調工具。

Pod 的概念是隨著 Kubernetes 一起引入的,代表 Kubernetes 叢集中最小的執行單元。使用 Podman,使用者可以建立空的 Pod,然後輕鬆地在其中執行容器。

將兩個或多個容器分組在單個 Pod 中可以帶來許多好處,例如:

  • 共用相同的網路名稱空間,包括 IP 位址
  • 共用相同的儲存卷以儲存永續性資料
  • 共用相同的組態

此外,將兩個或多個容器放在同一個 Pod 中實際上可以讓它們共用相同的行程間通訊(IPC)Linux 名稱空間。這對於需要使用共用記憶體相互通訊的應用程式來說非常有用。

建立 Pod 並開始使用它的最簡單方法是使用以下命令:

# podman pod create --name myhttp
3950703adb04c6bca7f83619ea28c650f9db37fd0060c1e263cf7ea34dbc8dad
# podman pod ps
POD ID    NAME    STATUS    CREATED        INFRA ID    # OF CONTAINERS
3950703adb04    myhttp    Created    6 seconds ago    1bdc82e77ba2    1

如前面的範例所示,我們建立了一個名為 myhttp 的新 Pod,然後檢查主機系統上 Pod 的狀態:只有一個 Pod 處於建立狀態。

#### 內容解密:

此命令建立了一個名為 myhttp 的新 Pod。podman pod ps 命令用於列出主機系統上的所有 Pod。在此範例中,我們可以看到剛剛建立的 myhttp Pod。

我們現在可以啟動 Pod 如下,並檢查會發生什麼:

# podman pod start myhttp
3950703adb04c6bca7f83619ea28c650f9db37fd0060c1e263cf7ea34dbc8dad
# podman pod ps
POD ID    NAME    STATUS    CREATED        INFRA ID    # OF CONTAINERS
3950703adb04    myhttp    Running    About a minute ago    1bdc82e77ba2    1

Pod 現在正在執行,但 Podman 究竟在執行什麼?我們建立了一個空的 Pod,沒有容器在裡面!讓我們透過執行 podman ps 命令來檢視正在執行的容器,如下所示:

# podman ps
CONTAINER ID    IMAGE    COMMAND    CREATED        STATUS    PORTS    NAMES
1bdc82e77ba2    k8s.gcr.io/pause:3.5    About a minute ago    Up 6 seconds ago    3950703adb04-infra

#### 內容解密:

podman ps 命令用於列出主機系統上所有正在執行的容器。在此範例中,我們可以看到一個名為 3950703adb04-infra 的容器正在執行,該容器使用 k8s.gcr.io/pause:3.5 映象。這個容器被稱為 infra 容器,它的作用是持有名稱空間並允許容器引擎連線到 Pod 中的其他容器。

podman ps 命令顯示了一個正在執行的容器,其映象名為 pause。這個容器由 Podman 預設執行為 infra 容器。這種容器什麼也不做——它只是持有名稱空間,讓容器引擎連線到 Pod 中的任何其他正在執行的容器。

現在我們已經揭開了這個特殊容器在 Pod 中的角色,接下來讓我們簡要介紹一下啟動多容器 Pod 所需的步驟。

首先,讓我們在前面建立的現有 Pod 中執行一個新容器,如下所示:

# podman run --pod myhttp -d -i -t registry.fedoraproject.org/f29/httpd
Cb75e65f10f6dc37c799a3150c1b9675e74d66d8e298a8d19eadfa125dffdc53

然後,我們可以檢查現有的 Pod 是否已更新其包含的容器數量,如下面的程式碼片段所示:

# podman pod ps
POD ID    NAME    STATUS    CREATED        INFRA ID    # OF CONTAINERS
3950703adb04    myhttp    Running    21 minutes ago    1bdc82e77ba2    2

#### 內容解密:

此命令在 myhttp Pod 中執行一個新的 httpd 容器。podman pod ps 命令顯示 myhttp Pod 現在包含 2 個容器。

最後,我們可以要求 Podman 提供具有關聯 Pod 名稱的正在執行的容器列表,如下所示:

# podman ps -p
CONTAINER ID    IMAGE    COMMAND    CREATED        STATUS    PORTS    NAMES    POD ID    PODNAME
1bdc82e77ba2    k8s.gcr.io/pause:3.5        22 minutes ago    Up 20 minutes ago    3950703adb04-infra    3950703adb04    myhttp
cb75e65f10f6    registry.fedoraproject.org/f29/httpd:latest    /usr/bin/run-http...    4 minutes ago    Up 4 minutes ago    determined_driscoll    3950703adb04    myhttp

#### 內容解密:

podman ps -p 命令用於列出主機系統上所有正在執行的容器,並顯示其關聯的 Pod 名稱。在此範例中,我們可以看到兩個正在執行的容器都與名為 myhttp 的 Pod 相關聯。

重點提示

使用相同的方法,我們可以在同一個 Pod 中新增越來越多的容器,讓它們共用我們之前描述的所有資料。

為容器的資料實作儲存

在前面的章節中,我們探討瞭如何使用 Podman 執行和管理我們的容器,但我們很快就會意識到,在某些場景中,這些操作並不是很有用,因為我們的容器中的應用程式需要以持久模式儲存資料。預設情況下,容器是短暫的,這是它們的主要特點之一,正如我們在本文的第一章中所述,因此,我們需要一種方法將持久儲存附加到正在執行的容器,以儲存容器的重要資料。

在本章中,我們將涵蓋以下主要主題:

  • 為什麼儲存對容器很重要?
  • 容器的儲存功能
  • 將檔案複製到容器中和從容器中複製出來
  • 將主機儲存附加到容器