In my previous post, I walked through building pyodbc
for Python 3.9 Lambda functions. With the release of Python 3.13 support in Lambda, it’s time for an update.
Here’s the Dockerfile
that builds a Lambda container image with pyodbc
and SQL Server support:
Dockerfile
FROM public.ecr.aws/lambda/python:3.13 AS builder
ENV ODBCINI=/opt/odbc.ini
ENV ODBCSYSINI=/opt/
ARG UNIXODBC_VERSION=2.3.12
RUN dnf install -y gzip tar openssl-devel gcc gcc-c++ make automake kernel-devel
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/9/prod.repo > /etc/yum.repos.d/mssql-release.repo
RUN dnf install -y e2fsprogs fuse-libs libss
RUN ACCEPT_EULA=Y dnf install -y msodbcsql18
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.13
RUN dnf install -y openssl
COPY --from=builder /opt/python /opt/python
COPY --from=builder /opt/microsoft /opt/microsoft
COPY --from=builder /opt/lib /opt/lib
The key differences from the Python 3.9 version include:
- Updated base image to
public.ecr.aws/lambda/python:3.13
- Switched to
dnf
fromyum
for package management - Upgraded to ODBC Driver 18 for SQL Server
- Upgraded unixODBC to the 2.3.12
- Added explicit OpenSSL installation in the final image
Example Usage
Create a simple Lambda function (app.py
) to test the SQL Server connection:
Python
import os
import pyodbc
def handler(event, context=None):
conn_str = (
"DRIVER=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.4.so.1.1;"
f"SERVER={os.getenv('DB_HOST', 'db')};"
f"DATABASE={os.getenv('DB_NAME', 'master')};"
f"UID={os.getenv('DB_USER', 'sa')};"
f"PWD={os.getenv('DB_PASSWORD')};"
"TrustServerCertificate=yes"
)
try:
with pyodbc.connect(conn_str) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT @@VERSION")
return str(cursor.fetchone()[0])
except Exception as e:
return str(e)
To test the build with a real SQL Server instance, create this docker-compose.yml
:
YAML
services:
db:
image: mcr.microsoft.com/mssql/server:2022-latest
ports:
- "1433:1433"
environment:
SA_PASSWORD: "YourStrong@Passw0rd"
ACCEPT_EULA: "Y"
healthcheck:
test: ["CMD", "/bin/bash", "-c", "timeout 5 bash -c '</dev/tcp/localhost/1433' || exit 1"]
interval: 10s
timeout: 5s
retries: 50
start_period: 60s
lambda:
build:
context: .
dockerfile: ./Dockerfile
ports:
- "9000:8080"
environment:
DB_HOST: "db"
DB_USER: "sa"
DB_PASSWORD: "YourStrong@Passw0rd"
DB_NAME: "master"
volumes:
- ./app.py:/var/task/app.py
command: app.handler
depends_on:
db:
condition: service_healthy
test:
image: curlimages/curl:latest
depends_on:
- lambda
command: >
sh -c "sleep 5 && curl -X POST 'http://lambda:8080/2015-03-31/functions/function/invocations' -d '{}'"
Run it:
Bash
docker compose up --build
The Lambda function will connect to SQL Server and return its version string, verifying that the pyodbc
connection is working correctly:
Bash
Share this: lambda-1 | 11 Jan 2025 20:32:54,776 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
test-1 | % Total % Received % Xferd Average Speed Time Time Time Current
test-1 | Dload Upload Total Spent Left Speed
lambda-1 | START RequestId: 710a4f6b-cef8-471c-9fb2-1a96eb3d355c Version: $LATEST
lambda-1 | 11 Jan 2025 20:33:00,058 [INFO] (rapid) INIT START(type: on-demand, phase: init)
lambda-1 | 11 Jan 2025 20:33:00,058 [INFO] (rapid) The extension's directory "/opt/extensions" does not exist, assuming no extensions to be loaded.
lambda-1 | 11 Jan 2025 20:33:00,058 [INFO] (rapid) Starting runtime without AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN , Expected?: false
lambda-1 | 11 Jan 2025 20:33:00,195 [INFO] (rapid) INIT RTDONE(status: success)
lambda-1 | 11 Jan 2025 20:33:00,195 [INFO] (rapid) INIT REPORT(durationMs: 136.556000)
lambda-1 | 11 Jan 2025 20:33:00,195 [INFO] (rapid) INVOKE START(requestId: 45044b00-449a-47ee-b26d-f6f30fe9cc4a)
lambda-1 | 11 Jan 2025 20:33:00,267 [INFO] (rapid) INVOKE RTDONE(status: success, produced bytes: 0, duration: 72.559000ms)
lambda-1 | END RequestId: 45044b00-449a-47ee-b26d-f6f30fe9cc4a
lambda-1 | REPORT RequestId: 45044b00-449a-47ee-b26d-f6f30fe9cc4a Init Duration: 0.06 ms Duration: 209.34 ms Billed Duration: 210 ms Memory Size: 3008 MB Max Memory Used: 3008 MB
100 208 100 206 100 2 939 9 --:--:-- --:--:-- --:--:-- 949
test-1 | "Microsoft SQL Server 2022 (RTM-CU16) (KB5048033) - 16.0.4165.4 (X64) \n\tNov 6 2024 19:24:49 \n\tCopyright (C) 2022 Microsoft Corporation\n\tDeveloper Edition (64-bit) on Linux (Ubuntu 22.04.5 LTS) <X64>"
test-1 exited with code 0