サーバレスで画像のモザイク処理を作ってみた①

こんにちは、保険システム部の宮内です。
AWSの画像分析サービスであるAmazon Rekognitionを利用して顔にモザイクをかける、という紹介ページはいくつかありますが、サーバ(EC2)を利用しているものがほとんどです。
今回はEC2に頼らず、サーバレスで顔のモザイク処理を作ってみたいと思います。

今回は実装の下準備まで説明し、モザイク処理の実装内容は次回説明します。

Lambdaでライブラリを利用する方法

今回はモザイク処理の実装のため、Pythonの画像編集ライブラリであるPillow(PIL)をLambdaで利用します。
しかしLambdaでは、Pillowのようなライブラリを標準で利用することができません。実際、インポートしようとするとエラーが発生します。

Pillow インポートエラー

Pillowのようなライブラリを利用するには、次の2つの対応方法があります。

1.Lambdaの実行ファイル(Lambda関数)と必要なライブラリでZipファイルを作成し、Lambdaにアップロード(Lambda関数を作成)する
2.必要なライブラリでZipファイルを作成し、Lambda Layerにアップロードする

今回は2つ目の方法で実装しますが、まずはLambda Layerについて簡単に説明します。

Lambda Layerとは

Lambda Layerはre:Invent 2018で発表された機能で、ライブラリをレイヤーに設定することにより、複数のLambdaで共有して利用できる仕組みになります。

Lambda Layer 概要図

Lambdaでライブラリを使いたい場合、Lambda Layerが登場するまでは、Lambda関数と使用するライブラリをまとめてLambdaを作成する必要がありましたが(左図)、Lambda Layerを利用することでライブラリを複数のLambdaで共有して利用できるようになります(右図)。

Lambda Layerを利用するためにZipファイルを用意する必要がありますが、Zipファイル作成では注意すべきことが2つあります。

【注意点1】Zipファイルを作成するサーバのOS

LambdaのOSは「Amazon Linux」、または「Amazon Linux2」が使用されています。
使用するプログラム言語やバージョンによって使用するOSも変わりますが、「Zipファイルを作成するサーバのOS」は「コードを実行するLambdaのOS」に合わせる必要があります。
次の表は、LambdaにおけるPythonの実行環境の一覧です。

Lambda Python Runtimes
公式ドキュメント(Lambda runtimes)より抜粋

注意点を踏まえると、

  • Python3.7はAmazon Linuxで実行されるため、OSがAmazon LinuxのサーバでZipファイルを作成
  • Python3.8はAmazon Linux2で実行されるため、OSがAmazon Linux2のサーバでZipファイルを作成

といった考慮が必要になる訳です。

その他のプログラム言語と対応するOSについては、以下の公式ドキュメントをご覧下さい。
https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html

【注意点2】Zipファイルのフォルダ構成

Lambda Layerに設定したモジュールは、

from PIL import Image

といったように、パスを特別に設定すること無く、自然にインポートして利用したいですよね。
この場合、Zipファイルを固める際のフォルダ構成に注意する必要があります。

前提として、PythonにおけるLambda Layerでは以下の2つの仕様があります。

  • Lambda LayerにアップロードしたZipファイルは /opt 配下に展開される
  • /opt 配下の特定のパスは、あらかじめライブラリ検索用のパスとして設定されている

ライブラリ検索用の「特定のパス」について、システムパス(sys.path)を確認するプログラムコードをLambdaで実行してみましょう。

import sys

def lambda_handler(event, context):
  # sys.pathを確認
  return {
    'sys.path' : sys.path
  }

実行すると、以下のような結果となります。

Python3.8 Lambda システムパス

この中で /opt 配下のパスとして設定されているのは

  • /opt/python
  • /opt/python/lib/python3.8/site-packages

の2つなので、Zipファイルを固める際には、以下のフォルダ構成にすると自然にインポートできます。

  • python
    └(Lambda Layerに設定したいライブラリ群)
  • python
    └ lib
     └ python3.8
      └ site-packages
       └(Lambda Layerに設定したいライブラリ群)

2つ目はフォルダの階層が多く複雑なので、今回は1つ目のフォルダ構成でZipファイルを作成します。

Zipファイルの作成

Zipファイル作成のため、ここではEC2を利用します。
(モザイク処理でEC2は使わないですが、準備ではEC2が必要です…)

EC2インスタンスの作成

EC2インスタンス構築時の注意点をまとめます。

Amazon Machine Image(AMI)、及びインスタンスタイプは無料利用枠の対象のものでOKです。
今回はZipファイル作成が目的なので、高いスペックは必要ありません。

EC2 AMI
EC2 インスタンスタイプ

最後にキーペアの選択を求められますが、SSHクライアントソフト(Tera Term、WinSCP等)を利用してZipファイルを取得する場合は、ここで設定するキー(pemファイル)が必要となります。
(今回は、SSHクライアントソフトを使用しない方法でEC2へアクセスします)

EC2 キーペア設定

注意点は以上です。
その他、セキュリティ設定等は必要に応じて設定頂いて構いません。

SSH接続してコマンド実行

次に、作成したEC2インスタンスにSSH接続してZipファイルを作成します。
今回はEC2 Instance Connectを利用して接続します。
EC2 Instance ConnectはブラウザベースのSSHクライアントで、AWSマネジメントコンソールから利用できます。

EC2のインスタンス一覧から先ほど作成したインスタンスを選択し、右上の「接続」をクリックします。

EC2 インスタンス接続

EC2インスタンスの接続方法が表示されますので、EC2 Instance Connectを選択して接続します。

EC2 Instance Connectに接続

接続すると、SSHクライアントの画面がブラウザ上で開きます。

EC2 Instance Connect 画面

早速、コマンドを実行していきましょう!

Python3.8のインストール

Amazon Linux2には標準でPython2.7が入っていますが、今回はPython3.8を利用するため、まずはPython3.8をインストールします。Python2.7のアンインストールは不要です。

# Python3.8 をインストール
sudo amazon-linux-extras install python3.8

実行するとインストールの可否の確認があるため、y(YES)を入力します。

EC2 Python3.8 install

これでPython3.8がインストールされます。
バージョンを確認すると、インストールされていることが確認できます。

EC2 Python3.8 インストール確認

Pillowのインストール

次にPillowのインストールです。
まずは「python」という名前のディレクトリを作成しましょう。

# フォルダを作成
mkdir python

mkdirは「make directory」の略で、ディレクトリを作成するコマンドです。
次にpipというPythonのライブラリを管理するコマンドを利用し、Pillowをインストールします。

# Pillowのインストール
pip3.8 install Pillow -t python

「-t」のオプションを付ける事で、インストール先のディレクトリを指定できるので、pythonディレクトリを指定しています。

EC2 Pillow インストール

Zipファイル作成

最後にZipファイルの作成です。以下のコマンドを実行しましょう。

# Zipファイルの作成
# 【例】 zip -r (作成するZipファイル名)(圧縮対象のディレクトリ名)
zip -r PIL.zip python

「-r」はZip圧縮の対象をディレクトリとする際に必要なオプションになります。
作成するZipファイル名は好きなように設定頂いてOKです。

EC2 Zipファイル作成

Zipファイルの転送

Lambda LayerにZipファイルを設定する方法として、

  • PC内に保存したZipファイルをアップロード
  • S3に保存したZipファイルをアップロード

の2通りがあります。
今回は2つ目の方法を利用するため、EC2で作成したZipファイルをS3にアップロードしたいと思います。

S3バケットの作成

バケットを作成する際の注意点としては、S3とEC2を連携するので、S3のリージョンはZipファイルの作成で利用したEC2のリージョンと合わせる必要があります。
他の注意点はありません。全てデフォルト値でOKです。

S3 バケット作成

AWS CLIへアカウント情報紐づけ

次にEC2のAWS CLIに対して、IAMユーザのアカウント情報と紐づけを行います。
紐づけで必要になるのが、使用しているIAMユーザのアクセスキーID、シークレットアクセスキーです。

使用しているIAMユーザの認証情報からアクセスキーの作成が可能です。
手元にアクセスキーの情報が無ければ作成し、アクセスキーIDとシークレットアクセスキーを控えておきましょう。

IAM アクセスキー

それでは、EC2 Instance ConnectからAWS CLIを利用して、アカウントの紐づけを行います。
AWS CLIはEC2に標準でインストールされています。AWS CLIの設定を行うために、以下のコマンドを実行しましょう。

# AWS CLIの設定を行う
aws configure

実行するとアクセスキーID、シークレットアクセスキー、AWSリージョン、出力形式の入力を求められます。
今回はアクセスキーID、シークレットアクセスキーのみ入力でOKです。リージョン、出力形式は使用しないので、未設定で構いません。

AWS CLI configure 設定

これでアカウントの紐づけは完了です。
確認のため、S3情報を取得してみましょう。

# アカウントに紐づくS3の情報を取得
aws s3 ls

正常に紐づけができていれば、S3のバケット情報を取得できます。
転送先のS3が表示されていることを確認して下さい。(receive-from-ec2 というバケットがファイル転送先です)

AWS CLI configure 確認

EC2からS3へファイル転送

いよいよS3へZipファイルを転送します。以下のコマンドを実行しましょう。

# ファイル転送
# 【例】 aws s3 cp (転送ファイル名) s3://(転送先のS3バケット名)
aws s3 cp ./PIL.zip s3://receive-from-ec2

コマンド実行後、「upload: …」と表示されればアップロード成功です!

EC2 S3 ファイル転送

S3にファイルがあることも確認できました。

EC2からS3にファイル転送 結果

EC2 Instance Connectは「exit」と入力するとSSH接続を切断できます。
また、S3にZipファイルが転送できたら、EC2の役目は終了なので停止しましょう。
(停止し忘れて課金されないように気を付けましょう!)

Lambda Layerの設定

いよいよLambda Layerの設定です。
まずはLambda LayerにZipファイルをアップロードしてレイヤーを作成し、次にLambdaへレイヤーの適用を行います。

レイヤーの作成

マネジメントコンソールからLambdaにアクセスし、レイヤーのページを開きます。
右上にある「レイヤーの作成」をクリックしましょう。

Lambda Layer一覧

レイヤー設定の画面が開きますので、必要な項目を入力します。

Lambda Layer設定

注意すべき点として、AmazonS3のリンクURLには作成したZipファイルのオブジェクトURLを設定しましょう。

S3 オブジェクトプロパティ

レイヤーの設定ページ下部にある「作成」ボタンを押下すると、レイヤーが作成されます。

Lambda Layer 設定完了

Lambdaにレイヤー適用

最後に、作成したレイヤーをLambdaへ適用します。
レイヤーを適用するLambdaを開き、レイヤーのタブにある「レイヤーの追加」をクリックします。

Lambda Layer適用

追加するレイヤーを選択する画面が開きますので、必要な項目を入力します。
レイヤーはバージョン管理が自動で行われており、変更が行なわれる(Zipファイルを再度アップロードする)と、新しいバージョンで保存されます。新規作成のレイヤーはバージョンが1で設定されます。
右下の「追加」をクリックすると、Lambda Layerの設定が完了します。

Lambda Layer追加

インポート再実行

改めて、インポートエラーとなったコードを実行すると…

Pillow インポート成功

無事、Pillowのインポートエラーが解消できました!
以上で下準備は完了です。

さいごに

今回はモザイク処理実装の下準備として、EC2を利用したZipファイルの作成、及びS3への転送と、Lambda Layerの設定まで行いました。
次回はモザイク処理の実装について説明したいと思います。
次回のキーワードは「BytesIO」と「BoundingBox」です!

AWSLambda

Posted by koukimiy