为Lambda Python 3.9运行时构建pyodbc的技术指南

本文详细介绍了如何在AWS Lambda的Python 3.9运行时环境中构建pyodbc连接MSSQL数据库,包括使用Docker多阶段构建、创建Lambda层和使用容器镜像的方法,提供了完整的技术实现步骤和代码示例。

为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()
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计