在Heroku的Docker容器中访问X-Server

我将一个旧的.NET Web API应用程序移植到Docker容器中的Heroku上运行。 我正在使用单声道图像。

这是我的Dockerfile:

FROM mono:latest EXPOSE 5000 ENV PORT 5000 ADD ./ /api WORKDIR /api RUN nuget restore -NonInteractive RUN msbuild webapi.sln /p:Configuration=Release CMD mono /api/MyProject/bin/Release/MyProject.exe port:$PORT 

非常简单,使用最新的Mono映像,复制源代码,恢复NuGet包,构build解决scheme并运行它。 $ PORT环境variables由Heroku设置,或者我的本地开发环境默认为5000。

这一切都很好,除了一个特定的API控制器生成PDF报告。 该报告由PdfSharp生成,它依赖于System.Drawing程序集进行必要的渲染。 但这意味着依赖于显示。

当我调用该控制器生成报告时,出现以下错误。

 Could not open display (X-Server required. Check your DISPLAY environment variable). 

我需要访问X服务器才能进行必要的渲染。 我尝试了很多东西,但总是被困在这个错误。

通过安装Xvfb(虚拟帧缓冲区),一个实现X11显示服务器协议的显示服务器,得到它的工作。 你可以看看下面更新的Dockerfile。

备注 :除了显示服务器之外,还有更多的PDFSharp在Mono上运行的问题。 我还必须更新apt源并安装Microsoft Core Fonts,因为我生成的报告使用它们。 我也不得不使用PDFSharp的修改版本,它知道如何定位字体。 幸运的是,这已经为我做了:

https://github.com/daniellor/PDFsharp

相关的代码在这里:

https://github.com/daniellor/PDFsharp/blob/master/src/PdfSharp/Fonts/FontLocalizator.cs

有点hacky,你可能需要修改它,以适应你的设置,但它做的工作。 只需创build一个MonoRelease构build,并引用这个程序集,你就可以走了。

Dockerfile

 FROM mono:latest # Update the sources.list for apt-get so it knows where to download the Microsoft Core fonts. RUN echo "deb http://gce_debian_mirror.storage.googleapis.com wheezy contrib non-free" >> /etc/apt/sources.list \ && echo "deb http://gce_debian_mirror.storage.googleapis.com wheezy-updates contrib non-free" >> /etc/apt/sources.list \ && echo "deb http://security.debian.org/ wheezy/updates contrib non-free" >> /etc/apt/sources.list # Install Xvfb and the Microsoft core fonts RUN apt-get update RUN apt-get install -y xvfb ttf-mscorefonts-installer # Configure Xvfb as a daemon. ADD xvfb.init /etc/init.d/xvfb RUN chmod +x /etc/init.d/xvfb RUN update-rc.d xvfb defaults EXPOSE 5000 ENV PORT 5000 ADD ./ /api WORKDIR /api RUN nuget restore -NonInteractive RUN msbuild webapi.sln /p:Configuration=Release # Start Xvfb and the Web Api CMD (service xvfb start; export DISPLAY=:10; mono /api/MyProject/bin/Release/MyProject.exe port:$PORT) 

xvfb.init

 #!/bin/bash # # /etc/rc.d/init.d/xvfbd # # chkconfig: 345 95 28 # description: Starts/Stops X Virtual Framebuffer server # processname: Xvfb # [ "${NETWORKING}" = "no" ] && exit 0 PROG="/usr/bin/Xvfb" PROG_OPTIONS=":10 -ac" PROG_OUTPUT="/tmp/Xvfb.out" case "$1" in start) echo -n "Starting : X Virtual Frame Buffer " $PROG $PROG_OPTIONS>>$PROG_OUTPUT 2>&1 & disown -ar ;; stop) echo -n "Shutting down : X Virtual Frame Buffer" killproc $PROG RETVAL=$? [ $RETVAL -eq 0 ] && /bin/rm -f /var/lock/subsys/Xvfb/var/run/Xvfb.pid echo ;; restart|reload) $0 stop $0 start RETVAL=$? ;; status) status Xvfb RETVAL=$? ;; *) echo $"Usage: $0 (start|stop|restart|reload|status)" exit 1 esac exit $RETVAL