全部產品
Search
文件中心

Container Compute Service:使用core dump分析執行個體中的程式異常

更新時間:Dec 11, 2024

Core dump是指在程式運行過程中發生異常終止或崩潰時,作業系統將程式的記憶體內容轉儲到一個特殊的檔案中,以便於後續的調試和問題分析(如通過gdb調試工具尋找程式崩潰產生的原因)。本文介紹如何為ACS Pod執行個體開啟core dump能力,以便在容器異常終止時可以查看分析core dump產生的檔案,從而定位問題原因,修複程式異常。

原理介紹

在Linux中,如果程式突然異常終止或者崩潰,作業系統會將程式當時的記憶體狀態記錄下來併產生記憶體狀態檔案,產生完成後會將業務進程同步退出,這種行為就叫做core dump。Core dump過程中產生的記憶體狀態檔案為core dump file,通常稱為core檔案。您可以通過gdb等調試工具查看和分析core檔案,找出引發程式終止的根本原因。

Linux中支援core dump的Signal如下圖所示,其中Action為Core表示該Signal預設會產生core檔案。更多資訊,請參見core dump file

使用方式

預設情況下,ACS叢集中的Pod執行個體不會開啟core dump。因為反覆的core dump行為產生大量的core檔案會導致磁碟佔用過多而影響業務不可用,因此推薦您使用掛載遠程共用儲存(阿里雲OSS或NAS)的方式來儲存生產的core檔案。通過自訂設定core檔案的儲存路徑,既能夠確保獲得完整的core檔案,同時也可以避免因CrashBackOff事件反覆產生core檔案,導致容器rootfs層儲存容量不足的情況。

當出現core檔案過大的情況時,您也可以使用臨時容器的方案。在發生core dump事件後,core檔案會被儲存在容器的rootfs層,您可以直接登入到臨時容器中,對core檔案進行分析。

您可以通過在Pod的annotations中配置alibabacloud.com/core-pattern: core-path/core-pattern來設定core檔案的儲存路徑並開啟core dump。同時將此路徑目錄配置為共用儲存卷,方便後續收集core檔案並進行異常分析。您可以按需自訂core-pattern檔案名稱的輸出格式,例如,在core-%E-%p-%t中:

  • %E:表示引起崩潰的可執行檔的路徑(Executable Path)。

  • %p:表示崩潰時進程的進程ID(Process ID)。

  • %t:表示崩潰時的時間戳記(Timestamp)。

更多core-pattern檔案名稱格式,請參見Man page of core

apiVersion: v1
kind: Pod
metadata:
  annotations:
    alibabacloud.com/core-pattern: "/data/dump-a/core-%E-%p-%t"
...
說明

以下操作即可以配置ACS叢集的kubeconfig使用,也可以在cloudshell中操作。若使用kubeconfig陪配置請確保您本地已經安裝kubectl,並且配置準確的kubeconfig檔案。具體操作,請參見擷取叢集KubeConfig並通過kubectl工具串連叢集

掛載遠程共用儲存

掛載NAS儲存core檔案

基於NAS作為共用儲存卷方式採集容器Crash後核心產生的core檔案。

  1. 建立NAS隱藏檔系統和掛載點。具體操作,請參見建立NAS檔案系統和掛載點

  2. 使用以下YAML內容,建立名為coredump-nas-volume-test的Deployment。具體操作,請參見建立無狀態工作負載Deployment。在建立模板中請替換volumes.volumeAttributes.server的值為您實際的NAS server地址。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredump-nas-volume-test
      labels:
        app: test
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          name: nginx-test
          labels:
            app: nginx
          annotations:
            alibabacloud.com/core-pattern: "/data/dump-a/core-%E-%p-%t" # 設定core檔案儲存路徑
        spec:
          containers:
          - name: nginx
            image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
            volumeMounts:
              - name: nas-volume
                mountPath: /data/dump-a/
          volumes:     # 掛載NAS 實現共用卷
            - name: nas-volume
              csi:
                driver: nasplugin.csi.alibabacloud.com
                fsType: nas
                volumeAttributes:
                  server: "0389a***-nh7m.cn-shanghai.extreme.nas.aliyuncs.com"
                  path: "/"
                  vers: "3"
                  options: "nolock,tcp,noresvport"

    上述Pod在觸發core dump事件後,core檔案會被存放在遠端儲存NAS目錄上

  3. 執行以下命令,查看儲存卷掛載是否生效,以便在coredump行為發生後,能在遠端共用儲存系統上獲得並查看core檔案。

    kubectl exec -it deploy/coredump-nas-volume-test -- sh -c 'df -h | grep aliyun'

    預期輸出:

    0389a***-nh7m.cn-shanghai.extreme.nas.aliyuncs.com:/   10P     0   10P   0% /data/dump-a

    可以看到掛載已經生效。

掛載OSS儲存core檔案

基於OSS作為共用儲存卷方式採集容器Crash後核心產生的core檔案。

  1. 建立OSS Bucket。具體操作,請參見靜態掛載OSS儲存卷

  2. 使用以下YAML內容,建立名為coredump-oss-volume-test的Deployment。具體操作,請參見建立無狀態工作負載Deployment。例如,在建立的模板中請替換.Spec.csi.volumeAttributes中您真實的OSS的Endpoint地址和密鑰等配置資訊。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredump-oss-volume-test
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
          annotations:
            alibabacloud.com/core-pattern: "/data/dump-a/core-%E-%p-%t"    # 設定core檔案儲存路徑
        spec:
          containers:
          - name: nginx
            image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
            volumeMounts:
              - name: oss-volume
                mountPath: /data/dump-a/
          volumes:
            - name: oss-volume
              persistentVolumeClaim:
                claimName: oss-pvc
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: oss-pvc
    spec:
      storageClassName: test # 這裡的 storageClass name 只做 binding mapping 作用, 無需實際資源
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 50Gi
      selector:
        matchLabels:
          alicloud-pvname: oss-csi-pv
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: oss-csi-pv
      labels:
        alicloud-pvname: oss-csi-pv
    spec:
      storageClassName: test # 這裡的 storageClass name 只做 binding mapping 作用, 無需實際資源
      capacity:
        storage: 50Gi
      accessModes:
        - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      csi:
        driver: ossplugin.csi.alibabacloud.com
        volumeHandle: oss-csi-pv
        volumeAttributes:
          bucket: "oss-test"
          url: "oss-cn-hangzhou-internal.aliyuncs.com"
          otherOpts: "-o max_stat_cache_size=0 -o allow_other"
          akId: "<your AccessKey ID>"
          akSecret: "<your AccessKey Secret>"

    上述Pod在觸發core dump事件後,core檔案會被存放在遠端儲存OSS目錄上。

  3. 執行以下命令,查看儲存卷掛載是否生效,以便在coredump行為發生後,能在遠端共用儲存系統上獲得並查看core檔案。

    kubectl exec -it deploy/coredump-oss-volume-test -- sh -c 'df -h | grep s3fs'

    預期輸出:

    s3fs             16E     0   16E   0% /data/dump-a

    可以看到掛載已經生效。

注入臨時容器

通過注入一個臨時容器,將core檔案的路徑以emptyDir volume的形式掛載到容器上,從而擷取core檔案。

  1. 使用以下YAML內容,建立名為coredump-emptydir-volume-test的Deployment。具體操作,請參見建立無狀態工作負載Deployment

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredump-emptydir-volume-test
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
          annotations:
            alibabacloud.com/core-pattern: "/data/dump-a/core-%E-%p-%t"    # 設定core檔案儲存路徑
        spec:
          containers:
          - name: nginx
            image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
            volumeMounts:
              - name: emptydir-volume
                mountPath: /data/dump-a/
          volumes:
            - name: emptydir-volume
              emptyDir: {}

    建立一個Deployment,同時掛載名為emptydir-volume的儲存卷。完成設定後可以登入到臨時容器的共用掛載點查看core檔案。

    重要

    當前kubectl debug的社區版本不支援向Pod中注入臨時容器的同時配置掛載,因此接下來的步驟將採用kubectl proxy配置本地代理環境的方式進行驗證。同時,您需要在本地開啟兩個相同的終端視窗並且保持配置代理的視窗不被關閉。

  2. 在一個終端視窗執行以下命令,啟動本地到叢集的代理服務。

    kubectl proxy 

    預期輸出:

    Starting to serve on 127.0.0.1:8001
    說明

    您可以在執行kubectl proxy 命令時,通過--port參數來指定連接埠。更多資訊,請參見kubectl proxy命令

  3. 開啟另一個終端視窗並執行以下命令,完成對於某個指定的Pod上注入臨時容器的操作。命令列中的coredump-emptydir-volume-test-xxxxxtarget-container等參數可以根據實際情況進行修改。

    curl -k http://127.0.0.1:8001/api/v1/namespaces/default/pods/coredump-emptydir-volume-test-xxxxx/ephemeralcontainers -X PATCH  -H 'Content-Type: application/strategic-merge-patch+json' -d '{
      "spec": {
        "ephemeralContainers": [
          {
            "name": "debugger-container-name",
            "command": [
              "/bin/sh",
              "-c",
              "sleep 3600"
            ],
            "image": "registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest",
            "stdin": true,
            "tty": true,
            "targetContainerName": "target-container", # 當Pod記憶體在多個容器的時候可選指定容器
            "volumeMounts": [
              {
                "name": "emptydir-volume",
                "mountPath": "/data/dump-a/"
              }
            ]
          }
        ]
      }
    }'

    部分參數說明如下。

    參數

    說明

    ...namespaces/${NAMESPACE}...

    注入臨時容器的命名空間。

    ...pods/${POD_NAME}...

    注入臨時容器的Pod名。

    spec: ${SPEC_DETAIL}

    具體臨時容器的Spec內容。

    重要

    建議您逐步按需替換,並通過一些額外的工具校正Spec欄位內容是否為合法的JSON格式。

    Spec.ephemeralContainers.name

    指定臨時容器的名字,多次執行臨時容器注入命令時需要保證臨時容器的名字不重複。

    Spec.ephemeralContainers.command

    臨時容器的啟動命令,使用自訂鏡像時按需配置。

    Spec.ephemeralContainers.targetContainerName

    當前Pod存在多個容器的時候可選擇指定具體的容器名進行注入。

    Spec.ephemeralContainers.volumeMounts

    臨時容器掛載點目錄,與Pod的core-pattern值保持一致。

  4. 臨時容器運行成功後,執行以下命令登入到臨時容器中。

    kubectl exec -it -n default coredump-emptydir-volume-test-xxxxx -c debugger-container-name sh
  5. 在臨時容器中,執行以下命令,確認可以訪問到已掛載的目錄。

    cd /data/dump-a && pwd

    預期輸出:

    /data/dump-a