为Lambda的Python 3.9运行时构建pyodbc
在Lambda中让Python连接到MSSQL并不像通过pip安装其他依赖那样简单。对于早期版本的Lambda运行时,我遵循了此gist中概述的模式,该模式构建了unixODBC和pyodbc,并为包含在Lambda层中做好了准备。到目前为止,这对我来说效果很好,但我最近需要为一个使用Python 3.9的新项目解决这个问题。
我的方法
我的方法使用基于Lambda Python 3.9基础镜像的多阶段Dockerfile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
FROM public.ecr.aws/lambda/python:3.9 as builder
ENV ODBCINI=/opt/odbc.ini
ENV ODBCSYSINI=/opt/
ARG UNIXODBC_VERSION=2.3.9
RUN yum install -y gzip tar openssl-devel && yum groupinstall "Development Tools" -y
RUN curl ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-${UNIXODBC_VERSION}.tar.gz -O \
&& tar xzvf unixODBC-${UNIXODBC_VERSION}.tar.gz \
&& cd unixODBC-${UNIXODBC_VERSION} \
&& ./configure --sysconfdir=/opt --disable-gui --disable-drivers --enable-iconv --with-iconv-char-enc=UTF8 --with-iconv-ucode-enc=UTF16LE --prefix=/opt \
&& make \
&& make install
RUN curl https://packages.microsoft.com/config/rhel/6/prod.repo > /etc/yum.repos.d/mssql-release.repo
RUN yum install e2fsprogs.x86_64 0:1.43.5-2.43.amzn1 fuse-libs.x86_64 0:2.9.4-1.18.amzn1 libss.x86_64 0:1.43.5-2.43.amzn1 -y
RUN ACCEPT_EULA=Y yum install -y msodbcsql17
ENV CFLAGS="-I/opt/include"
ENV LDFLAGS="-L/opt/lib"
RUN mkdir /opt/python/ && cd /opt/python/ && pip install pyodbc -t .
FROM public.ecr.aws/lambda/python:3.9
COPY --from=builder /opt/python /opt/python
COPY --from=builder /opt/microsoft /opt/microsoft
COPY --from=builder /opt/lib /opt/lib
|
Lambda层
要使用此方法创建Lambda层,首先构建镜像:
1
|
docker build -t pyodbc-3-9 .
|
接下来,从文件系统中提取依赖项(在/opt中可用):
1
|
docker run --rm --entrypoint bash -v $PWD:/local pyodbc-3-9 -c "cp -R /opt /local"
|
现在您已在本地文件系统的./opt下获得了构建层所需的所有内容。下一步是将其压缩并创建层。我使用terraform处理此问题,以便轻松在所有环境中提供该层:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
locals {
zip_file = "./${var.name}.zip"
}
data "archive_file" "init" {
type = "zip"
output_path = local.zip_file
source_dir = "./opt"
}
resource "aws_lambda_layer_version" "lambda_layer" {
filename = local.zip_file
description = "This Lambda layer includes pyodbc dependencies"
layer_name = "${var.name}-${terraform.workspace}"
compatible_runtimes = ["python3.9"]
source_code_hash = data.archive_file.init.output_base64sha256
}
|
容器镜像
另一种方法是使用Lambda容器镜像。如果您有其他需要pip之外构建的运行时依赖项,这可能很有用。这里的权衡是您需要完全管理镜像,包括将应用程序代码复制到/var/task目录以及安装所有依赖项。
使用pipenv的示例可能如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
FROM public.ecr.aws/lambda/python:3.9
COPY --from=builder /opt/python /opt/python
COPY --from=builder /opt/microsoft /opt/microsoft
COPY --from=builder /opt/lib /opt/lib
RUN pip install --upgrade pip && pip install pipenv
COPY Pipfile .
COPY Pipfile.lock .
RUN pipenv lock --requirements --keep-outdated > requirements.txt && pip install -r requirements.txt -t /var/task
COPY app ./app
CMD ["app.alb_handler"]
|
如您所见,在安装依赖项并添加代码后,您需要设置处理程序。如果您使用Serverless Framework,可以使用类似以下内容构建和部署镜像以及Lambda:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
provider:
name: aws
timeout: 60
memorySize: 512
versionFunctions: false
stage: ${opt:stage, "dev"}
region: us-east-1
ecr:
images:
appimage:
path: ./
functions:
api:
image:
name: appimage
|
使用示例
一旦依赖项就位,您就可以开始使用pyodbc:
1
2
3
4
5
6
7
8
9
10
11
|
import pyodbc
conn_str = (
r'DRIVER=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.7.so.2.1;'
r'SERVER=DB_HOST;'
r'DATABASE=DB_NAME;'
r'UID=user;'
r'PWD=pass;'
)
cnxn = pyodbc.connect(conn_str)
|
或使用SQLAlchemy的pyodbc:
1
2
3
4
5
|
params = urllib.parse.quote_plus(conn_str)
engine_str = f"mssql+pyodbc:///?odbc_connect={params}"
engine = create_engine(engine_str)
Session = sessionmaker(bind=engine)
session = Session()
|