暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

在docker容器内使用ProcDump for linux 自动创建dump

码农说一说 2021-10-01
1096

Docker容器内使用ProcDump for linux 自动创建dump

背景介绍

dump

dump又名转储, 对于开发者而言是程序异常的事后分析文件,通俗的讲dump就是进程的内存堆栈的一个快照文件。

因为有了这个快照文件,当程序出现一些难以复现的问题时候,开发者可以对这个文件进行解析,寻找出现异常的原因。

可以说dump文件是一个异常解析的兜底方案,如果能根据程序日志或程序的异常现象定位到的问题则不需要劳烦dump文件了。

ProcDump for linux

ProcDump是微软开源的一款抓取dump工具,ProcDump for linux是在linux平台的版本。

github地址:

https://github.com/Sysinternals/ProcDump-for-Linux

使用ProcDump的原因就是好用,它虽然无法提供监听进程(程序)崩溃时生成dump,但是却提供了一种半自动的方式进行dump抓取。

这种方式就是设定条件,比如内存达到多少兆、cpu使用率达到百分之多少、线程数达到多少。
当进程运行过程中达到了这些条件则自动对该进程进行转储(创建dump文件)。

ProcDump还支持先开启dump抓取监听,当进程启动后且满足预设的条件后再进行转储。这意味着我们不需要先启动进程再启动ProcDump。

我列举下ProcDump几个重要的参数,其他参数可在ProcDump的github项目地址上自行查看。


需要在docker容器环境下抓取dump,我想到了下面几个方案
在docker容器环境下如何抓取dump

  • 纯手动方式,被动的进入容器内使用工具创建dump

  • 纯自动方式,硬编码,在程序内调用工具创建dump

  • 半自动方式,预先设定触发条件,实际运行环境达到预设的阈值后生成dump

上面三种方式都可以生成dump,无非是投入的成本大小不同而已。下面的表格可以直观的对这三种方式进行比较。

方式优势劣势
纯手动投入成本非常低,只需要保证在抓取dump之前在容器内安装好dump抓取的工具即可。效率低下,难以抓取到符合预期的dump。
纯自动效率高,在非强制断电等极其特殊的条件下都能满足开发者抓取到预期的dump。投入成本很高,对应用的源码有侵入性。
半自动对代码无侵入性,允许指定条件抓取dump。在dockerfile内安装好抓取dump工具或提前创建一个基础镜像,在这个镜像内安装好所需的环境即可。1、无法对程序崩溃时自动生成dump(纯自动方式可以实现,监听崩溃事件即可),除非预设的条件同时满足了程序崩溃的情况;
2、需事前设定dump抓取的先决条件,提高了使用者的要求;

考虑到通用性、便捷性的多方位权衡下,我选择了半自动方式。这种方式不需要对源码进行适配,同时也可以通过运维手段实现通用性。

实操

搭建procdump环境

有了上面的知识储备,现在可以开始进入实操环节。

我后续实操过程内使用的进程是一个.NetCore3.1的应用,该应用已经实现了容器化的部署,当然在实操前是缺乏dump生成的环境。

接下来,我们就针对这个应用,给它在容器环境下实现有条件的生成dump。

首先看下最初的Dockerfile

 1#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim
3
4WORKDIR /app
5EXPOSE 28300
6
7ARG ASPNETCORE_ENV
8RUN echo "ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV" 
9
10ENV ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV
11ENV LANG C.UTF-8
12ENV TZ=Asia/Shanghai
13
14COPY /release .
15ENTRYPOINT ["dotnet""tenant.api.dll"]

复制

最初的Dockerfile可以说是“平平无奇”,基础镜像选择的是mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim该镜像算是微软官方提供的.NetCore3.1最小的镜像了,体积是208MB。

该镜像砍掉了许多Linux常用的命令,更别说是procdump了。所以为了能在容器内拥有procdump命令,我就想到了在Dockerfile内安装procdump环境。进入procdump的install说明引导页面, 链接如下:https://github.com/Sysinternals/ProcDump-for-Linux/blob/master/INSTALL.md 

可以看到procdump在不同Linux版本中的安装说明。需要登入到基于mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim镜像的容器中使用命令cat etc/issue
查看容器内的操作系统的版本,查询的结果是Debian GNU/Linux 10
我们还需要一个脚本,该脚本通过procdump的-w
参数特性,发起一个监听,负责抓取指定应用的dump,该脚本如下:

1#!/bin/bash
2mkdir /dumps
3procdump -M 50 -o /dumps/tenant-api.dump -w dotnet &
4# 启动传入的应用
5dotnet $1

复制

接下来,变更Dockerfile,变更后的结果如下:

 1#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2# linux版本=Debian 10
3FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim
4
5# 安装Procdump依赖
6# Register Microsoft key and feed  参考:https://github.com/Sysinternals/ProcDump-for-Linux/blob/master/INSTALL.md
7RUN apt-get update
8RUN apt-get install wget -y
9RUN apt-get install gpg -y
10
11RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg 
12RUN mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
13RUN wget -q https://packages.microsoft.com/config/debian/10/prod.list 
14RUN mv prod.list /etc/apt/sources.list.d/microsoft-prod.list 
15RUN chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg && chown root:root /etc/apt/sources.list.d/microsoft-prod.list
16# Install Procdump
17RUN apt-get update  && apt-get install apt-transport-https -y && apt-get update && apt-get install procdump -y
18
19WORKDIR /app
20EXPOSE 28300
21
22ARG ASPNETCORE_ENV
23RUN echo "ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV" 
24
25ENV ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV
26ENV LANG C.UTF-8
27ENV TZ=Asia/Shanghai
28
29COPY /release .
30RUN chmod +x ./sh/start-procdump.sh
31ENTRYPOINT ["./sh/start-procdump.sh""tenant.api.dll"]

复制

当然,还有我在jenkins配置的docker run脚本

1docker run -d \
2           --name $SVR_NAME \
3           --restart unless-stopped \         
4           --net xx-net \
5           --ip "172.16.238.14" \
6           -e "ASPNETCORE_URLS=http://*:28300" \
7           -p 28300:28300 \
8           -v /opt/hy/uat/$SVR_NAME_FILE/dumps:/dumps \
9           $SVR_NAME:$GITHASH

复制

上面脚本中的变量无需在意,懂意思即可。细心的观察可以发现 -v参数后面是将容器内的dump存放目录与宿主机的/opt/hy/uat/$SVR_NAME_FILE
进行了映射,这样可以对容器内生成的dump进行持久化存储。

ok~一顿操作了,看下最终的成效吧。登入到创建的docker容器后,先检查procdump是否安装成功。
执行
procdump -h
命令,出现如下结果表示procdump已经安装成功。

再试下手动生成一个dump文件,执行procdump -p 9 这里的9是在运行的dotnet进程。可是这次执行结果却意外出现了error。

这种感觉就好比万里长城建设到最后发现少了两块砖一样。

我自然不能放弃,一顿操作过后还是没搞定。最终吃了晚饭,晚饭过后忽然灵光一闪,我特么的docker run
命令没有加root权限。赶忙在原有的脚本上加上了--privileged=true
参数。

尝试下发现搞定了,事实证明有难以逾越的bug的时候,停下来吃点东西喝点饮料,灵感会在你最放松时候到来~

你以为这就完了??
no!这种方式有一个很大的弊端,一个开发者不能容忍的弊端。就是在构建容器时候速度太慢了。
原来的Dockerfile根本不需要安装太多花里胡哨的环境,现在放到Dockerfile内导致构建速度堪忧。
解决思路其实上面也说了,直接构建一个基础镜像,后续的应用在此基础镜像上构建。
这是基础的镜像:

 1# 创建dotnetcore3.1的镜像,该镜像携带了ProcDump
2# linux版本=Debian 10
3FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim
4# 安装Procdump依赖
5# Register Microsoft key and feed  参考:https://github.com/Sysinternals/ProcDump-for-Linux/blob/master/INSTALL.md
6RUN apt-get update
7RUN apt-get install wget -y
8RUN apt-get install gpg -y && apt-get install procps -y
9
10RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg 
11RUN mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
12RUN wget -q https://packages.microsoft.com/config/debian/10/prod.list 
13RUN mv prod.list /etc/apt/sources.list.d/microsoft-prod.list 
14RUN chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg && chown root:root /etc/apt/sources.list.d/microsoft-prod.list
15# Install Procdump
16RUN apt-get update  && apt-get install apt-transport-https -y && apt-get update && apt-get install procdump -y

复制

在上面Dockerfile的目录下执行此命令,本地build一个镜像

1docker build -t aspnet-custom:3.1 .

复制


可以看到,生成的镜像大小是302MB。这个大小还可以接受~

上传基础镜像至阿里云私人仓库

为了更好的享用这个镜像,我将它推送到阿里云的私人镜像仓库内。
第一次连接阿里云镜像仓库需要手动执行登陆命令。

1docker login --username=xxxx@qq.com registry.cn-hangzhou.aliyuncs.com

复制

然后,给需要推送到阿里云的镜像再添加tag,这个tag最好是具备镜像本身的含义与版本信息,因为阿里云的镜像列表页面没有一个字段可以对镜像进行备注说明的。后续通过tag字段能一眼get到该镜像的信息最好。

1docker tag f0eb4f26d82f registry.cn-hangzhou.aliyuncs.com/xxx/private_hub:aspnet3.1-custom

复制

上传镜像的最后一步就是push了

1docker push registry.cn-hangzhou.aliyuncs.com/xxx/private_hub:aspnet3.1-custom

复制

登陆到阿里云容器镜像仓库服务页面,点击【镜像版本】菜单可以查阅到我已上传的镜像信息。可以发现上传后的镜像反而变小了呢,我想应该是阿里云对其进行了压缩导致的。

最终效果

最终我变更了应用的Dockerfile,将基础镜像设置为已上传的阿里云镜像,移除了procdump依赖。
应用的Dockerfile如下:

 1FROM registry.cn-hangzhou.aliyuncs.com/xxxx/private_hub:aspnet3.1-custom
2
3WORKDIR /app
4EXPOSE 28300
5
6ARG ASPNETCORE_ENV
7RUN echo "ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV" 
8
9ENV ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENV
10ENV LANG C.UTF-8
11ENV TZ=Asia/Shanghai
12
13COPY /release .
14RUN chmod +x ./sh/start-procdump.sh
15ENTRYPOINT ["./sh/start-procdump.sh""tenant.api.dll"]

复制

start-procdump.sh
脚本如下

1#!/bin/bash
2mkdir /dumps
3procdump -M 50 -o /dumps/tenant-api.dump -w dotnet &
4# 启动传入的应用
5dotnet $1

复制

jenkins发布应用的docker容器后,我到dump文件映射地址上找到了由procdump自动创建的dump文件:

至此完美的实现了我的需求,唯一还需要注意的就是必须先在应用部署的服务器上登陆阿里云的镜像仓库。后续,只需要静静的等待生成出来的dump,针对性的迭代应用,增强应用的稳定性。


文章转载自码农说一说,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论