I have written the following Dockerfile which installs and configures ODBC drivers as described by the Snowflake docs: https://docs.snowflake.com/en/developer-guide/odbc/odbc-linux
FROM ruby:3.1.4-bullseye
# Setup Snowflake ODBC dependencies
RUN wget https://www.unixodbc.org/unixODBC-2.3.11.tar.gz -P /tmp/unixodbc
WORKDIR /tmp/unixodbc
RUN tar -xzf unixODBC-2.3.11.tar.gz
WORKDIR unixODBC-2.3.11
RUN ./configure && make && make install
RUN wget https://sfc-repo.snowflakecomputing.com/odbc/linuxaarch64/3.1.4/snowflake_linux_aarch64_odbc-3.1.4.tgz -P /tmp/snowflakeodbc
WORKDIR /tmp/snowflakeodbc
RUN gunzip snowflake_linux_aarch64_odbc-3.1.4.tgz
RUN tar -xf snowflake_linux_aarch64_odbc-3.1.4.tar
RUN mkdir -p /opt/snowflake/snowflake_odbc
RUN mv /tmp/snowflakeodbc/snowflake_odbc/* /opt/snowflake/snowflake_odbc
# Configuring SnowflakeODBC with unixODBC
WORKDIR /opt/snowflake/snowflake_odbc
RUN ./unixodbc_setup.sh
If I build this and get a bash shell inside the container, then I can connect to Snowflake using ODBC:
docker build .
docker run -it 48a9422eb56f91d2e800b0698cfa1ce522eb050dfffb11c268c7f4436ea04e78 bash
Install some necessary GEMs to test ODBC:
gem install ruby-odbc
gem install sequel
Open irb and create a test connection, the output on the last line shows that this works:
require "odbc"
require "sequel"
connection_str = [
'DRIVER=/opt/snowflake/snowflake_odbc/lib/libSnowflake.so;',
'SERVER=<REDACTED>.snowflakecomputing.com;',
'UID=<REDACTED>;',
'PWD=<REDACTED>;',
].join('')
db = Sequel.odbc(drvconnect: connection_str);
db.fetch("select 1;").all
=> [{:"1"=>"1"}]
However, if I change the docker image to ruby:3.1.4-alpine3.19
and then install some missing things:
FROM ruby:3.1.4-alpine3.19
RUN apk upgrade -U --no-cache && \
apk add --no-cache build-base bash wget
# Setup Snowflake ODBC dependencies
RUN wget https://www.unixodbc.org/unixODBC-2.3.11.tar.gz -P /tmp/unixodbc
WORKDIR /tmp/unixodbc
RUN tar -xzf unixODBC-2.3.11.tar.gz
WORKDIR unixODBC-2.3.11
RUN ./configure && make && make install
RUN wget https://sfc-repo.snowflakecomputing.com/odbc/linuxaarch64/3.1.4/snowflake_linux_aarch64_odbc-3.1.4.tgz -P /tmp/snowflakeodbc
WORKDIR /tmp/snowflakeodbc
RUN gunzip snowflake_linux_aarch64_odbc-3.1.4.tgz
RUN tar -xf snowflake_linux_aarch64_odbc-3.1.4.tar
RUN mkdir -p /opt/snowflake/snowflake_odbc
RUN mv /tmp/snowflakeodbc/snowflake_odbc/* /opt/snowflake/snowflake_odbc
# Configuring SnowflakeODBC with unixODBC
WORKDIR /opt/snowflake/snowflake_odbc
RUN apk add perl # unixodbc_setup.sh uses perl
RUN apk add --no-cache --upgrade grep # grep option -P don't exist in alpine 3.8 which unixodbc_setup.sh uses
RUN ./unixodbc_setup.sh
Now it no longer works. I get this very misleading error when I try to connect:
db = Sequel.odbc(drvconnect: connection_str)
Can't open lib '/opt/snowflake/snowflake_odbc/lib/libSnowflake.so' : file not found
This turned out to be because of this:
ldd /opt/snowflake/snowflake_odbc/lib/libSnowflake.so
/lib/ld-musl-aarch64.so.1 (0xffff8dda3000)
libpthread.so.0 => /lib/ld-musl-aarch64.so.1 (0xffff8dda3000)
libdl.so.2 => /lib/ld-musl-aarch64.so.1 (0xffff8dda3000)
libm.so.6 => /lib/ld-musl-aarch64.so.1 (0xffff8dda3000)
libc.so.6 => /lib/ld-musl-aarch64.so.1 (0xffff8dda3000)
Error loading shared library ld-linux-aarch64.so.1: No such file or directory (needed by /opt/snowflake/snowflake_odbc/lib/libSnowflake.so)
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __syslog_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: fcntl64: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __register_atfork: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __snprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __memcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __fprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __vfprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __sprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strncpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strcat_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: makecontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __memset_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __vsnprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __stpcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: statx: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: backtrace: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __fdelt_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: getcontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: setcontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strftime_l: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: backtrace_symbols: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __printf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __longjmp_chk: symbol not found
I found that adding a bunch of glibc compatibility libs fixes only the first Error, the one about loading a shared library:
RUN apk add --no-cache gcompat libc6-compat libstdc++
Now it just fails in a different way:
db = Sequel.odbc(drvconnect: connection_str);
terminate called after throwing an instance of 'std::system_error'
what(): No error information
Aborted
This is very likely related to the remaining Errors when I do:
ldd /opt/snowflake/snowflake_odbc/lib/libSnowflake.so
/lib/ld-musl-aarch64.so.1 (0xffff8b405000)
libpthread.so.0 => /lib/ld-musl-aarch64.so.1 (0xffff8b405000)
libdl.so.2 => /lib/ld-musl-aarch64.so.1 (0xffff8b405000)
libm.so.6 => /lib/ld-musl-aarch64.so.1 (0xffff8b405000)
libc.so.6 => /lib/ld-musl-aarch64.so.1 (0xffff8b405000)
ld-linux-aarch64.so.1 => /lib/ld-linux-aarch64.so.1 (0xffff873f5000)
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __syslog_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: fcntl64: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __register_atfork: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __snprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __memcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __fprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __vfprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __sprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strncpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strcat_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: makecontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __memset_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __vsnprintf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __stpcpy_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: statx: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: backtrace: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __fdelt_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: getcontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: setcontext: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __strftime_l: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: backtrace_symbols: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __printf_chk: symbol not found
Error relocating /opt/snowflake/snowflake_odbc/lib/libSnowflake.so: __longjmp_chk: symbol not found
Am I out of luck here? Do I basically need Snowflake to release a build compatible with Alpine (musl vs glibc)? Or is there anything I can do except for change base image?
ldd /opt/snowflake/snowflake_odbc/lib/libSnowflake.so
/lib/ld-musl-aarch64.so.1 (0xffff8b405000)
You are trying to use libSnowflake.so
which has been linked against GLIBC on a system that uses Musl.
That is simply not going to work. From Musl FAQ:
Binary compatibility is much more limited, but it will steadily increase with new versions of musl. At present, some glibc-linked shared libraries can be loaded with musl, but all but the simplest glibc-linked applications will fail if musl is dropped-in in place of /lib/ld-linux.so.2.
You should build libSnowflake.so
from source and link it against Musl.
Update:
I didn't realize libSnowflake.so
is a closed-source software. If you can't rebuild it, your only options are:
libSnowflake.so
against GLIBC.