快速構建基于AWS Lambda容器鏡像的OCR應用

來源: AWS
作者:易珂
時間:2021-03-05
17333
本文將展示如何基于自建鏡像(public.ecr.awsbitnamipython:3.7),利用AWS官方提供的運行時接口客戶端(RIC)和運行時接口仿真器(RIE),構建運行在AWS Lambda上的OCR應用。

1940a0ad086947b2055b0495de3c-1638536.jpg

摘要

AWS Lambda函數(shù)現(xiàn)已支持打包和部署容器鏡像,開發(fā)者通過官方提供或自己構建鏡像文件,可以非常方便利用現(xiàn)有的開發(fā)工具,工作流輕松構建基于AWS Lambda的應用程序?;谌萜鞔虬膽猛ㄟ^AWS Lambda可以實現(xiàn)更為簡便的操作部署,相比EC2有著更為快速的啟動時間,更為強大的并發(fā)擴展以及高可用,同時無縫與140余種AWS服務集成。

本文將展示如何基于自建鏡像(public.ecr.aws/bitnami/python:3.7),利用AWS官方提供的運行時接口客戶端(RIC)和運行時接口仿真器(RIE),構建運行在AWS Lambda上的OCR應用。

前言

對于機器學習,圖像處理等依賴庫構建復雜且文件較大的應用,AWS Lambda支持最大10GB的容器鏡像,開發(fā)者可以直接使用熟悉的容器開發(fā)工具(docker)在本地構建測試,并將容器鏡像推送到Amazon ECR(全托管的容器注冊表),之后通過指定Amazon ECR鏡像來部署Lambda函數(shù),免去了以往Lambda Layer構建流程,也無需受限于Lambda Layer的大小限制(250MB)。

伴隨AWS Lambda對容器鏡像支持的特性發(fā)布,AWS官方提供了一組Lambda基礎鏡像,可在Amazon ECR(gallery.ecr.aws/lambda)和Docker Hub(amazon/aws-lambda-python)上獲取,該基礎鏡像預裝了包括Node.js,Python,Java等語言的Lambda運行時,必要組件以及構建基礎鏡像的dockerfile。同時AWS官方還開源了運行時接口客戶端(RIC)和運行時接口仿真器(RIE),方便用戶構建同Lambda兼容的容器鏡像并進行本地測試。

OCR應用我們基于tesseract(最早由HP Lab開發(fā)并于2005年開源)實現(xiàn),其中軟件依賴如pillow,libtesseract我們利用AWS進行本地安裝,或者用戶也可以選取官方鏡像public.ecr.aws/lambda編譯以盡可能保證同Lambda兼容。

流程概覽

本文構建的OCR應用會利用到Python,Shell作為開發(fā)語言,PIP/Docker作為開發(fā)工具,構建流程分成如下部分:1)軟件依賴庫的構建,包括pillow,libtesseract編譯;2)Lambda兼容鏡像的構建,包括RIC/RIE的安裝配置,Lambda業(yè)務代碼的打包;3)Lambda業(yè)務代碼實現(xiàn),通過簡單的代碼調用生成的pytesseract庫返回圖片識別結果;4)本地調試驗證,通過RIE實現(xiàn)本地功能調試和迭代。

其中構建容器鏡像的軟件依賴庫有以下幾個途徑:方案一,直接利用已經(jīng)包含軟件依賴庫的容器鏡像,其dockerfile示例如下:

FROM public.ecr.aws/myrepo/shared-lib-layer:1 AS shared-lib-layer

#Layer code

WORKDIR/opt

COPY--from=shared-lib-layer/opt/.

方案二,利用已經(jīng)構建好的Lambda Layer,通過curl的形式拉取到新的鏡像當中,其dockerfile示例如下:

ARG AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-"cn-northwest-1"}

ARG AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-""}

ARG AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-""}

ENV AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}

ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}

ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}

RUN apk add aws-cli curl unzip

RUN mkdir-p/opt

RUN curl$(aws lambda get-layer-version-by-arn--arn arn:aws:lambda:us-east-1:1234567890123:layer:shared-lib-layer:1--query'Content.Location'--output text)--output layer.zip

RUN unzip layer.zip-d/opt

RUN rm layer.zip

方案三,完全從零開始的用戶可以考慮直接在容器里面構建軟件依賴庫,其dockerfile示例如下:

FROM python:3.8-alpine AS installer

#Layer Code

COPY extensionssrc/opt/

COPY extensionssrc/requirements.txt/opt/

RUN pip install-r/opt/requirements.txt-t/opt/extensions/lib

FROM scratch AS base

WORKDIR/opt/extensions

COPY--from=installer/opt/extensions.

接下來的OCR方案考慮到tesseract的依賴構建相對復雜,為了構建流程的獨立和依賴庫的共享,我們將采用方案二,即先利用Shell和Docker構建Lambda業(yè)務代碼調用的所有依賴,再將構建完畢后的zip包存放到Lambda Layer中供后續(xù)Lambda鏡像構建調用。

創(chuàng)建步驟

軟件依賴庫的構建

首先安裝pillow,創(chuàng)建requirements文件,寫入以下內容。

pillow

接著創(chuàng)建shell腳本(build_py37_pkgs.sh),寫入以下內容并執(zhí)行,執(zhí)行完畢后會在相同目錄下生成pythonlibs-layer.zip文件。

set-e

rm-rf pythonlibs-layer.zip exit 0

rm-rf python/exit 0

docker run-v"$PWD":/var/task"lambci/lambda:build-python3.7"/bin/sh-c"pip install-r requirements.txt-t python/lib/python3.7/site-packages/;exit"

chmod 777 python/

zip-r pythonlibs-layer.zip python>/dev/null

rm-rf python/

Pillow構建完畢后,開始構建tesseract依賴,創(chuàng)建dockerfile(Dockerfile-tess4),文件內容可以直接參考這里

FROM lambci/lambda-base:build

#Proxy setup if exists

#ENV http_proxy'http://ip:port'

#ENV https_proxy'https://ip:port'

ARG LEPTONICA_VERSION=1.78.0

ARG TESSERACT_VERSION=4.1.0-rc4

ARG AUTOCONF_ARCHIVE_VERSION=2017.09.28

ARG TMP_BUILD=/tmp

ARG TESSERACT=/opt/tesseract

ARG LEPTONICA=/opt/leptonica

ARG DIST=/opt/build-dist

#change OCR_LANG to enable the layer for different languages

ARG OCR_LANG=chi_sim

#change TESSERACT_DATA_SUFFIX to use different datafiles(options:"_best","_fast"and"")

ARG TESSERACT_DATA_SUFFIX=""

ARG TESSERACT_DATA_VERSION=4.0.0

后續(xù)省略

……

創(chuàng)建shell腳本(build_tesseract4.sh),寫入以下內容并執(zhí)行,執(zhí)行完畢后會在相同目錄下生成tesseract-layer.zip

set-e

rm-rf tesseract-layer.zip exit 0

rm-rf configs exit 0

rm-rf tessconfigs exit 0

#Download tessconfigs folder

git clone https://github.com/tesseract-ocr/tessconfigs.git tesseractconfigs

mv tesseractconfigs/configs.

mv tesseractconfigs/tessconfigs.

rm-rf tesseractconfigs

#Build Docker image containing Tesseract

docker build-t tess_layer-f Dockerfile-tess4.

#Copy Tesseract locally

CONTAINER=$(docker run-d tess_layer false)

docker cp$CONTAINER:/opt/build-dist layer

docker rm$CONTAINER

##Zip Tesseract

cd layer/

zip-r../tesseract-layer.zip.

#Clean

cd..

rm-rf layer/

rm-rf tessconfigs/

rm-rf configs/

將前面步驟生成的zip文件(pythonlibs-layer.zip/tesseract-layer.zip)通過AWS Console或者AWS命令行的方式上傳至Lambda Layer,并記錄下對應的ARN,類似arn:aws-cn:lambda:cn-northwest-1:xxxxxxxx:layer:ocrTesseract:1。

quickly-build-ocr-applications-based-on-lambda-container-images1.png

quickly-build-ocr-applications-based-on-lambda-container-images2.png

Lambda兼容鏡像的構建

運行時接口客戶端(RIC)作為AWS開源項目,實現(xiàn)了Lambda的運行時API,包括調用事件檢索,調用響應返回,調用錯誤處理和初始化錯誤等功能實現(xiàn)Lambda能正確接收處理調用并返回結果。運行時接口仿真器(RIE)實際是一個輕量級的web服務器,代理Lambda的運行時和擴展API,使開發(fā)者可以在本地通過Docker,CURL進行本地測試而不用將Lambda容器鏡像部署上云。

接下來我們基于自建鏡像(public.ecr.aws/bitnami/python:3.7)構建Lambda容器的dockerfile并針對其中部分操作進行解釋。

創(chuàng)建entry.sh文件,用作容器在云上部署和本地調試的自動切換,內容如下:

if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then

    exec /usr/local/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $1

else

    exec /usr/local/bin/python -m awslambdaric $1

fi

創(chuàng)建dockerfile(dockerfile-custom-tesseract),內容摘錄如下,原文件參見這里:

安裝必要工具

ARG LAYER_DIR="/opt"

FROM public.ecr.aws/bitnami/python:3.7 as build-image

RUN apt-get update && \

  apt-get install -y \

  g++ \

  make \

  cmake \

  unzip \

  libcurl4-openssl-dev

RUN pip install opencv-python-headless

RUN apt-get install -y libpng-dev

安裝運行時接口客戶端(RIC)

RUN mkdir -p ${LAYER_DIR}

RUN pip install \

        --target ${LAYER_DIR} \

        awslambdaric

取前面步驟生成的Lambda Layer

ARG AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-"cn-northwest-1"}

ARG AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-"xxxx"}

ARG AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-"xxxx"}

ENV AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}

ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}

ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}

RUN apt-get install-y curl unzip

RUN curl"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"-o"awscliv2.zip"

RUN unzip awscliv2.zip

RUN./aws/install

#ocrTesseract

RUN curl$(aws lambda get-layer-version-by-arn--arn arn:aws-cn:lambda:cn-northwest-1:xx:layer:ocrTesseract:3--query'Content.Location'--output text)--output pythonlibs-layer.zip

#COPY pythonlibs-layer.zip.

RUN unzip pythonlibs-layer.zip-d${LAYER_DIR}

RUN rm pythonlibs-layer.zip

#pythonlibs-layer

RUN curl$(aws lambda get-layer-version-by-arn--arn arn:aws-cn:lambda:cn-northwest-1:xx:layer:pythonlibs-layer:1--query'Content.Location'--output text)--output tesseract-layer.zip

#COPY tesseract-layer.zip.

RUN unzip tesseract-layer.zip-d${LAYER_DIR}

RUN rm tesseract-layer.zip

打包Lambda業(yè)務代碼(代碼邏輯下一小節(jié)會提到)和entry.sh

#Multi-stage build:grab a fresh copy of the base image,use custom image instead of official one

FROM public.ecr.aws/bitnami/python:3.7

#Include global arg in this stage of the build

ARG LAYER_DIR

#Copy in the build image dependencies

WORKDIR${LAYER_DIR}

COPY--from=build-image${LAYER_DIR}.

COPY app.py.

COPY entry.sh/

RUN chmod 755/entry.sh

ENV LD_LIBRARY_PATH="/opt:/opt/lib:${LD_LIBRARY_PATH}"

ENV PATH="/opt:/opt/bin:${PATH}"

#Production env

ENTRYPOINT["/entry.sh"]

開始構建鏡像并推送到ECR,至此OCR業(yè)務的Lambda鏡像構建完畢

docker build-t local-lambda-python3.8-custom-ocr--build-arg AWS_DEFAULT_REGION=cn-northwest-1--build-arg AWS_ACCESS_KEY_ID=xx--build-arg AWS_SECRET_ACCESS_KEY=xx-f dockerfile-custom-tesseract.

docker tag local-lambda-python3.8-custom-ocr:latest xx.dkr.ecr.cn-northwest-1.amazonaws.com.cn/local-lambda-python3.8-custom-ocr

aws ecr get-login-password--region cn-northwest-1|docker login--username AWS--password-stdin xx.dkr.ecr.cn-northwest-1.amazonaws.com.cn

docker push xx.dkr.ecr.cn-northwest-1.amazonaws.com.cn/local-lambda-python3.8-custom-ocr:latest

Lambda業(yè)務代碼實現(xiàn)

代碼的調用邏輯如下,handler接收傳入的圖片文件(u64編碼)并調用pytesseract實現(xiàn)圖片中文字的識別并返回。

import sys

import os

sys.path.append('/opt/python/lib/python3.7/site-packages')

# sys.path.append('/opt/python/lib/python3.7/site-packages/pytesseract')

# sys.path.append('/opt/python/lib/python3.7/site-packages/PIL')

# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import base64

import pytesseract

import cv2

def write_to_file(save_path, data):

  with open(save_path, "wb") as f:

    f.write(base64.b64decode(data))

def handler(event, context=None):

    write_to_file("/tmp/photo.jpg", event['body'])

    img = cv2.imread("/tmp/photo.jpg")

    ocr_text = pytesseract.image_to_string(img, config = "eng")

    # Return the result data in json format

    return {

      "statusCode": 200,

      "body": ocr_text

    }

本地調試驗證

本地安裝RIE,盡量減少Lambda鏡像需要安裝的文件

mkdir-p~/.aws-lambda-rie&&curl-Lo~/.aws-lambda-rie/aws-lambda-rie

https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie

&&chmod+x~/.aws-lambda-rie/aws-lambda-rie

本地運行容器并通過curl測試結果,其中helloWorld文件為顯示有hello world字樣圖片對應的u64編碼文件,成功的話我們可以看到輸出的hello world。

docker run-d-v~/.aws-lambda-rie:/aws-lambda-p 9000:8080--entrypoint/aws-lambda/aws-lambda-rie local-lambda-python3.8-custom-ocr:latest/usr/local/bin/python-m awslambdaric app.handler

curl-X POST"http://localhost:9000/2015-03-31/functions/function/invocations"-d@helloWorld

待功能測試成功后我們可以將該鏡像最終部署上云,無縫對接其他AWS服務實現(xiàn)更加豐富的功能。

對接其他服務

Lambda鏡像構建完畢后,用戶可以結合API Gateway實現(xiàn)HTTP前端調用來整合我們后端的OCR能力,通過SAM(Serverless Application Model)模版快速構建一個無服務器架構的OCR應用,示例模版部分內容如下所示:

Resources:

  HelloWorldFunction:

    Type: AWS::Serverless::Function

    Properties:

      PackageType: Image

      Events:

        HelloWorld:

          Type: Api

          Properties:

            Path: /hello

            Method: get

      ImageUrl: ‘xxxx.dkr.ecr.cn-northwest-1.amazonaws.com.cn/local-lambda-python3.8-custom’

  ImageConfig:

      Command:

        - "app.handler"

      EntryPoint:

        - "/entry.sh"

      WorkingDirectory: "/opt"

    Metadata:

      DockerTag: python3.x-v1

      DockerContext: ./hello-world

      Dockerfile: Dockerfile

之后通過SAM CLI實現(xiàn)AWS API Gateway,Lambda以及對應IAM的編譯,調試和部署,有關SAM的具體的操作參見這里。待服務部署完畢后,用戶可通過調用類似curl–request POST-H“Content-Type:image/png”–data-binary“@/path/ocrimage.png”https://xxxx.execute-api.cn-northwest-1.amazonaws.com.cn/prod/upload

命令獲取OCR識別結果。

寫在最后

Lambda針對容器鏡像的支持,將無服務器化,容器這兩個熱門的技術領域進行了完美結合,用戶在原有的容器開發(fā)環(huán)境基礎上利用無服務器化架構的低運維,高擴展,高可用等特性,可以更加便捷的構建和開發(fā)諸如機器學習,圖像識別等數(shù)據(jù)密集型負載應用。

立即登錄,閱讀全文
AWS
版權說明:
本文內容來自于AWS,本站不擁有所有權,不承擔相關法律責任。文章內容系作者個人觀點,不代表快出海對觀點贊同或支持。如有侵權,請聯(lián)系管理員(zzx@kchuhai.com)刪除!
掃碼登錄
打開掃一掃, 關注公眾號后即可登錄/注冊
加載中
二維碼已失效 請重試
刷新
賬號登錄/注冊
個人VIP
小程序
快出海小程序
公眾號
快出海公眾號
商務合作
商務合作
投稿采訪
投稿采訪
出海管家
出海管家