はじめに
AWS Lambda+PythonでExcelファイルにPlantUMLを埋め込もうとして苦戦したのでメモ
手こずったところ
- plantwebを自前でレイヤー作成
- requestsのインポートでエラー
https://qiita.com/HLHHS11/items/c26f1632a141a1dcc7a7
2023/12/4以降AWS CloudShell環境がAmazon Linux 2からAmazon Linux 2023に更新されていく予定なので、この情報は使えなくなる可能性があります
2024/1/28追記
Amazon Linux 2023のCloudShellでpyenvを使ってPython3.10をインストールする方法
Amazon Linux 2023のCloudShellでは、Python3.9、OpenSSLは3.0.8がデフォルト
# 準備
sudo dnf install gcc zlib-devel bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel xz-devel
# pyenvインストール
curl https://pyenv.run | bash
# 環境変数設定
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
# 環境変数を再読み込み
. .bashrc
# Python3.10.13インストール
pyenv install 3.10.13
# デフォルト指定
pyenv global 3.10.13
準備 - plantwebのレイヤー
AWS CloudShellでPython3.10環境をビルド
AWS CloudShellでPython3.10環境をビルドします。AWS CloudShellのデフォルトでは3.7です。
OpenSSL 1.1.1をインストール
sudo yum install openssl11 openssl11-devel
Python3.10をインストール
sudo yum install gcc bzip2-devel libffi-devel
wget https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tgz
tar xzf Python-3.10.13.tgz
cd Python-3.10.13
./configure --enable-optimizations
sudo make altinstall
(参考)
https://blog.serverworks.co.jp/install-python3-with-openssl11
https://medium.com/@teamcode20233/how-to-upgrade-python-version-in-aws-cloud-shell-bb248ee4c4b2
plantwebのレイヤー作成
確認
python3.10 --version
cd
mkdir python
cd python
python3.10 -m pip install plantweb "urllib3<2" -t .
cd ..
zip -r python python
Lambdaレイヤー
作成したzipファイルをs3に保存します
aws s3 cp python.zip s3://<bucket名>
Lambdaの、レイヤーの作成で、レイヤーを作成します
(参考)
https://qiita.com/__DASHi__/items/268062f0dba0e93170f2
動かしてみる
関数作成
関数作成時にレイヤーを追加します。以下のレイヤーは公開されているものをARNを指定して使用します
- openpyxl
- Pillow
サンプルソース
import requests
from plantweb.render import render
import json
import boto3
import openpyxl
from openpyxl.drawing.image import Image
import os
import tempfile
from io import BytesIO
s3_client = boto3.client('s3')
bucket_name = "<bucket名>"
template_name = "template.xlsx"
def lambda_handler(event, context):
# TODO implement
object_key = template_name
s3_resp = s3_client.get_object(Bucket=bucket_name, Key=object_key)
wb = openpyxl.load_workbook(BytesIO(s3_resp['Body'].read()),data_only=True)
# main_ws = wb["Sheet1"]
with tempfile.TemporaryDirectory() as tmpdir:
file_name = 'output_20231007'
excel_file_name = f'{file_name}.xlsx'
tmp_file_path = os.path.join(tmpdir, excel_file_name)
content = """
:タイトル;
"""
output = render(
content,
engine = 'plantuml',
format = 'png',
cacheopts = {'use_cache': False}
)
tmp_png_file_path = os.path.join(tmpdir, 'image.png')
with open(tmp_png_file_path, 'wb') as f:
f.write(output[0])
sheet = wb["Sheet1"]
img = Image(tmp_png_file_path)
sheet.add_image(img, "A1")
wb.save(tmp_file_path)
wb.close()
result = s3_client.upload_file(
Bucket=bucket_name,
Key=excel_file_name,
Filename=os.path.join(tmpdir, excel_file_name),
ExtraArgs={"ContentType": "application/vnd.ms-excel", 'ACL':'public-read'}
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
関数URLを有効にして、ブラウザーでURLを表示すると「Hello from Lambda!」と表示されるとともに、S3に出力ファイルが作成されます
こんな感じ