在 AWS Lambda 上使用 System.Drawing.Common NuGet 包时无法加载 DLL 'libdl'

Unable to load DLL 'libdl' when using System.Drawing.Common NuGet package on AWS Lambda

我们有一个缩略图生成器 lambda 函数,我正在尝试将其更新到 .NET Core 2.0,但在使用 Microsoft 的 System.Drawing.Common NuGet 程序包时遇到以下错误:

TypeInitializationException

The type initializer for 'Gdip' threw an exception. at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(Int32 width, Int32 height, Int32 stride, Int32 format, HandleRef scan0, IntPtr& bitmap) at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format) at TestFailExample.Function.FunctionHandler(String input, ILambdaContext context) in C:\work\graphics\TestFailExample\Function.cs:line 25 at lambda_method(Closure , Stream , Stream , LambdaContextInternal )

引起

DllNotFoundException

Unable to load DLL 'libdl': The specified module or one of its dependencies could not be found.\n (Exception from HRESULT: 0x8007007E) at Interop.Libdl.dlopen(String fileName, Int32 flag) at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary() at System.Drawing.SafeNativeMethods.Gdip..cctor()

我看到了this问题,但是没有解决。

重现问题的最少代码是这样的:

public string FunctionHandler(string input, ILambdaContext context)
{
    using (var bmp = new Bitmap(100, 100))
    {
        return bmp.Width.ToString();
    }
}

只需创建一个 .NET Core 2.0 Lambda 函数项目,添加对 System.Drawing.Common NuGet 包的引用,并将函数处理程序替换为上述代码。在 AWS 上检查它并 运行 它得到错误。我注意到,在您尝试实际使用它之前,引用该包不会导致问题,但这可能归结为编译器优化。

我已经将 MCVE 打包成一个项目并将其上传到 GitHub here 以简化人们重现问题的步骤。

我可以看到 /lib64/libdl.so.2 存在,但 /lib64/libdl.so 不存在。由于符号链接似乎不可能(只读文件系统),我不确定如何解决这个问题。我尝试使用 LD_LIBRARY_PATH 环境变量,方法是在 /tmp 中创建一个文件夹并将文件符号链接到那里作为该函数所做的第一件事。不幸的是,它似乎在这里寻找所有库,所以函数根本没有 运行。我也试过将 LD_LIBRARY_PATH 设置为 /var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/tmp,虽然我现在可以再次 运行 该函数,但这仍然没有帮助,我只是得到相同的 Gdip 错误。

我注意到 /var/task/lib 已经包含在 LD_LIBRARY_PATH 中,所以我尝试用我的函数打包 libdl.so 和 libgdiplus.so,但这一次也失败了声明在 libdgiplus.so 中未找到入口点 GdiplusStartup。这些文件不是来自 Amazon Linux 实例,所以我现在尝试安装 Mono 并从 Amazon Linux 实例获取它们。这没有帮助。

我已经尝试使用 CoreCompat drawing library,但这也报告了与 libgdiplus.so 有关的问题,即使我尝试将其与该功能捆绑在一起也是如此。

从那以后我就在自己的 Linux 实例上进行了尝试,可以确认 System.Drawing.Common 有效。

是否有一些聪明的解决方案可以让我在 AWS Lambda 上使用 System.Drawing.Common?有没有其他方法可以让我的 lambda 函数拥有 libdl 并正常工作?

更新:

我们最近的尝试涉及使用 AWS Lambda 层并仔细提取 Docker Amazon Linux 图像中由 apt 安装的所有包,然后将它们应用到它们自己的层。但我们最终还是遇到了 "libdl" 问题,所以我们放弃了。

人们提出的很多图书馆问题是他们没有正确呈现日语文本,这对我们很重要。这似乎是一个在 AWS Lambda 上不会变得更好的问题,它没有帮助,最终在 Go 中重写我们的函数比继续使用 C# 更容易。

由于下面答案中提到的库似乎适合一般用途 - 并且现在可能确实支持日语文本 - 我选择接受我确信可以在 AWS Lambda 上运行的答案。

对于 .NET Core Lambda 中的图像处理,我使用 SixLabors.ImageSharp

这是我在最近的 AWS re:Invent 演讲中使用的代码,它在图像处理时做了一个日志:

var imageBuffer = new MemoryStream();

var resizeOptions = new ResizeOptions
{
    Size = new SixLabors.Primitives.Size { Width = this.TileSize, Height = this.TileSize},
    Mode = ResizeMode.Stretch
};
image.Mutate(x => x.Resize(resizeOptions));
image.Save(imageBuffer, new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder());

imageBuffer.Position = 0;

我找到了适合我的这个问题的解决方案:

起初我从项目中删除了 System.Drawing.Common 库,然后我安装了你可以找到的库 here。它使用相同的 类.

using System.Drawing
...
var bmp = new Bitmap(100,100);

最后我安装了 this 其他库,其中包含在 Linux 和 Lambda 上使用绘图库所需的所有 dll。通过执行此步骤,代码可以毫无问题地上传到 AWS。

我在 Ubuntu 18 服务器 运行 dotnet core 2.1.500 版本上上传我的应用程序后遇到了同样的问题。我使用 MichaelSimons 的建议通过此解决方案 https://github.com/dotnet/dotnet-docker/issues/618 解决了这个问题。

我运行

#sudo apt-get update
#sudo apt-get install -y --allow-unauthenticated \
        libc6-dev \
        libgdiplus \
        libx11-dev \ 
#sudo rm -rf /var/lib/apt/lists/*

这解决了问题。

如果有人使用centOS,那么下面的命令有帮助。

  • sudo yum 安装 libgdiplus