Monday, February 25, 2019

AWS Lambda & Perl/Vendoring Libraries - A Case Study w/Image::Magick (Part I)

Now here's where things get interesting.

This is a two part blog that discusses how to package libraries for your Perl Lambdas.

So you'd like to use Image::Magick in your Perl Lambda? And you thought you would just use Image::Magick? Or perhaps you were smarter than that because you are using a Lambda Layer and have Perl 5.28.1 installed, so you thought might just install it via your Perl 5.28.1 Docker image that mimics the Lambda runtime environment using cpanm? Well, not so fast...

The first challenge is installing Image::Magick, the next challenge is actually running it in your Lambda.  Spoiler alert...both of these challenges are possible to overcome! In part 1 we'll install Image::Magick.


Using the Docker image approach is a  good start and not a bad guess, however you'll quickly find that the latest version of Image::Magick (6.89) will require you to download the ImageMagick source and build that first.  There is a version of the ImageMagick libraries on the Lambda runtime, however there is no Image::Magick Perl module installed on the Lambda runtime.

You can try as I did to install various older versions of Image::Magick to see if you can get a clean build and test using cpanm, however I found that to be futile.  Most of the time I could get the package to build, but all of the time some tests failed.  I resorted to installing the ImageMagick-perl rpm and seeing what version of Image::Magick did actually work in this environment, understanding that although you can't install rpms to the Lambda runtime, I could at least look to see if the package offered clues as to how I could build the perl modules myself.  I thought if I could find the correct version of Image::Magick I might be able to build that version against the installed libraries.  No luck as the version specified in the working version contained in the rpm was not found on CPAN or BackPAN (it looks like it might be version specific to the source and not on CPAN?).

 So it looks like I'll need to install the latest source, compile that and then try to install the Perl package.

FROM perl-5.28.1-runtime              
RUN curl -s http://www.imagemagick.org/download/ImageMagick-6.9.10-28.tar.gz -o /tmp/ImageMagick-6.9.10-28.tar.gz      
RUN cd /tmp; \                    
    tar xfvz ImageMagick-6.9.10-28.tar.gz; \
    cd ImageMagick-6.9.10-28; \
    ./configure; \
    make && make install
RUN /opt/perl-5.28.1/bin/cpanm --install Image::Magick 

What I found is that installing Image::Magick using cpanm failed because the tests fail...with not a lot of guidance regarding the causes. :-(

But alas, you can apparently configure ImageMagick to build the Perl packages during the installation phase...so after some experimenting...I tried...

RUN cd /tmp; \                    
    tar xfvz ImageMagick-6.9.10-28.tar.gz; \
    cd ImageMagick-6.9.10-28; \
    ./configure --with-perl --with-gslib=yes; \
    make && make install

...but that also failed miserably when trying to build and install the Perl package.

gcc -std=gnu99 -std=gnu99 -c -I../ -I..   -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16  -I"/usr/include/ImageMagick"  -I../../ -I../..   -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_Q[176/1810]
TH=16  -I"/usr/include/ImageMagick" -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -I/usr/include/libxm
l2   -I/usr/include/libpng12       -I/usr/include/freetype2        -fopenmp -g -O2 -Wall -mtune=core-avx2 -fexceptions -pthread -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -O2   -DVERSION
=\"6.9.10\" -DXS_VERSION=\"6.9.10\" -fPIC "-I/opt/perl-5.28.1/lib/5.28.1/x86_64-linux/CORE" -D_LARGE_FILES=1 -DHAVE_CONFIG_H  -D_LARGE_FILES=1 -DHAVE_CONFIG_H Q16.c
Q16.xs:548:33: error: ‘MagickPixelIntensityOptions’ undeclared here (not in a function)            
     { "Grayscale", { {"method", MagickPixelIntensityOptions} } },                                                       
                                 ^                                              
Q16.xs:569:37: error: ‘MagickAutoThresholdOptions’ undeclared here (not in a function)                                                                                                                 
     { "AutoThreshold", { {"method", MagickAutoThresholdOptions} } }     


I did see a clue however...and looking at the environment BEFORE I tried to install ImageMagick I see a /usr/include/ImageMagick directory. Hmmm...maybe the compile phase of the Perl module is using the wrong include files?  I removed directory prior to compile and tried the process once more more. That seems to have done the trick. Bingo!  Image::Magick is now installed.  Here's the final Docker recipe:

FROM perl-5.28.1-runtime          
RUN curl -s http://www.imagemagick.org/download/ImageMagick-6.9.10-28.tar.gz -o /tmp/ImageMagick-6.9.10-28.tar.gz
RUN rm -rf /usr/include/ImageMagick  
RUN export PATH=/opt/perl-5.28.1/bin:$PATH; \
    cd /tmp; \
    tar xfvz ImageMagick-6.9.10-28.tar.gz; \
    cd ImageMagick-6.9.10-28; \ 
    ./configure --with-perl --with-gslib=yes; \
    make && make install
RUN mkdir /opt/lib; \
    cp /usr/local/lib/libMagickCore-6.Q16.so.6.0.0 /opt/lib; \
    ln -s /opt/lib/libMagickCore-6.Q16.so.6.0.0 /opt/lib/libMagickCore-6.Q16.so; \
    ln -s /opt/lib/libMagickCore-6.Q16.so.6.0.0 /opt/lib/libMagickCore-6.Q16.so.6; \
    cp /usr/local/lib/libMagickWand-6.Q16.so.6.0.0 /opt/lib; \  
    ln -s /opt/lib/libMagickWand-6.Q16.so.6.0.0 /opt/lib/libMagickWand-6.Q16.so.6; \
    ln -s /opt/lib/libMagickWand-6.Q16.so.6.0.0 /opt/lib/libMagickWand-6.Q16.so; \
    cp /usr/local/lib/libMagick++-6.Q16.so.8.0.0 /opt/lib; \ 
    ln -s /opt/lib/libMagick++-6.Q16.so.8.0.0 /opt/lib/libMagick++-6.Q16.so.8; \
    ln -s /opt/lib/libMagick++-6.Q16.so.8.0.0 /opt/lib/libMagick++-6.Q16.so;
RUN /opt/perl-5.28.1/bin/perl -MImage::Magick -e 1;  
RUN cd /opt; zip -r -9 /tmp/perl-5.28.1-image-magick.zip * 

In part II of this blog I'll discuss shared libraries and what you'll need to do to make sure Perl modules that are linked against the work in your Lambda execution environment.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.