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文件。
創建NAS存儲文件系統和掛載點。具體操作,請參見創建NAS文件系統和掛載點。
使用以下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目錄上
執行以下命令,查看存儲卷掛載是否生效,以便在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文件。
創建OSS Bucket。具體操作,請參見靜態掛載OSS存儲卷。
使用以下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目錄上。
執行以下命令,查看存儲卷掛載是否生效,以便在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文件。
使用以下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
配置本地代理環境的方式進行驗證。同時,您需要在本地打開兩個相同的終端窗口并且保持配置代理的窗口不被關閉。在一個終端窗口執行以下命令,啟動本地到集群的代理服務。
kubectl proxy
預期輸出:
Starting to serve on 127.0.0.1:8001
說明您可以在執行
kubectl proxy
命令時,通過--port
參數來指定端口。更多信息,請參見kubectl proxy命令。打開另一個終端窗口并執行以下命令,完成對于某個指定的Pod上注入臨時容器的操作。命令行中的
coredump-emptydir-volume-test-xxxxx
和target-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
值保持一致。臨時容器運行成功后,執行以下命令登錄到臨時容器中。
kubectl exec -it -n default coredump-emptydir-volume-test-xxxxx -c debugger-container-name sh
在臨時容器中,執行以下命令,確認可以訪問到已掛載的目錄。
cd /data/dump-a && pwd
預期輸出:
/data/dump-a