2017年8月3日

AWS - 編譯 Pandoc 並於 AWS Lambda 上執行 ( AWS - Build Pandoc and run it on AWS Lambda )

Web 應用程式常常會需要轉換文件格式的功能,例如:HTML 檔轉換成 PDF 檔,或是 TXT 轉換成 MS DOCX 檔案。Pandoc 是一個相當好用的轉換文件工具,加上搭配 AWS Lambda 來實作類似的功能是很合適的。但是 Lambda 在使用上有一些限制,所以要在 Lambda 環境下使用 Pandoc,我們必須先將它編譯好然後上傳至 Lambda 環境再執行它。本篇將介紹如何編譯 Pandoc 並在 AWS Lambda 上使用 Pandoc。( 其他 AWS 相關教學可以參考本篇整理。If you want to read this article in English, you can visit here )



前置作業
要編譯可在 Lambda 環境下執行的 Pandoc,我們必須先準備一個相似的環境。幸運地是,我們可以利用 docker-lambda 所提供的 Docker Image 來建置這個環境。接下來範例將使用 Python 環境,所以選擇適合的 Image:
docker pull lambci/lambda:build-python2.7


編譯 Pandoc
將 Docker 容器建立好後,我們就可以接著來準備編譯 Pandoc ( 注意,進入容器後的預設路徑是 /var/task ):
# 安裝開發套件
yum -y install gmp-devel freeglut-devel python-devel zlib-devel gcc m4
除了開發套件外,我們還需要 GHC 與 Cabal:
# 安裝 GHC
GHC='https://downloads.haskell.org/~ghc/8.0.1/ghc-8.0.1-x86_64-centos67-linux.tar.xz'
curl -OL $GHC && tar xf ghc* && cd ghc* && ./configure --prefix=/usr && make install && cd ..

# 安裝 Cabal
CABAL='https://www.haskell.org/cabal/release/cabal-install-1.24.0.0/cabal-install-1.24.0.0-x86_64-unknown-linux.tar.gz'
mkdir .bin && cd .bin && curl -OL $CABAL && tar xf cabal* && cd ..
開始執行編譯:
# 編譯 Pandoc
.bin/cabal sandbox init && \
.bin/cabal update && \
.bin/cabal install hsb2hs && \
.bin/cabal install --disable-documentation pandoc -fembed_data_files

# 編譯完,壓縮 Pandoc
cp .cabal-sandbox/bin/pandoc .
gzip pandoc
完成後將編譯好的檔案後下載即可:
docker cp [container-name]:/var/task/pandoc.gz /path/to/local/pandoc.gz


使用 Pandoc
AWS Lambda 允許你在 /tmp 中下載以及產生檔案,所以我們將欲執行的程式與 Pandoc 壓縮檔上傳至 AWS Lambda 後,執行程式時將 Pandoc 解壓縮至該處後就可以開始使用它了。簡單的 Python 範例如下:
import subprocess

def init_cmd(cmd):
    return subprocess.Popen(
        cmd,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

def execute_cmd():
    cmd = (
        "cp pandoc.gz /tmp/pandoc.gz && "
        "gzip -d /tmp/pandoc.gz && "
        "chmod 755 /tmp/pandoc && "
        "/tmp/pandoc -S -s /tmp/input-file -o /tmp/output-file"
    )
    process = init_cmd(cmd)
    out, err = process.communicate()

    # Do anything you want



Environment :
  ・ Amazon Linux
Reference :
  ・ Pandoc

熱門文章