今回はDockerコンテナ上で、pyodbcを使ってSQL Serverにアクセス可能な環境を構築します。また、Pythonコードを記述するのにVisual Studio Code(以下、vscode)の拡張機能であるRemoteを利用して、Dockerコンテナに対しリモートでのソース編集と実行を行います。この環境を構築するには、下記のように各種ドライバーなどが必要になります。
sql.h
に依存しているため、unixodbc-devのインストールが必要これらの要求をすべて満たすような、Dockerfileやvscodeの設定ファイルなどを用意します。
│ Dockerfile
│ requirements.txt
│
├─.devcontainer
│ devcontainer.json
│
├─.vscode
│ extensions.json
│ settings.json
│
└─src
main.py
冒頭にピリオドのついたフォルダは、vscode用の設定フォルダですのでフォルダ名は固定です。「src」は、実行するPythonのソースコードを格納するだけなので、名前は何でもいいです。もちろん、中身のPythonファイルも名前は任意です。
なにはともあれ、Dockerコンテナを生成しないことには始まりません。
ここでは「python:3.8-buster」を利用しています。PythonとDebianのバージョンは、動作させたいアプリケーションの要求する環境に合わせて変更します。ここでは特段のこだわりがないので適当です。
FROM python:3.8-buster
ENV ACCEPT_EULA=Y
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update \
&& apt-get install -y g++ \
apt-utils \
apt-transport-https \
gcc \
build-essential \
unixodbc \
unixodbc-dev \
msodbcsql17 \
mssql-tools \
&& apt-get upgrade -y \
&& apt-get clean \
&& sed -i -E 's/(CipherString\s*=\s*DEFAULT@SECLEVEL=)2/\11/' /etc/ssl/openssl.cnf \
&& pip install --upgrade pip \
&& pip install --no-cache-dir \
autopep8 \
flake8 \
&& rm -rf /var/lib/apt/lists/*
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
RUN /bin/bash -c "source ~/.bashrc"
ADD . /home/workdir
WORKDIR /home/workdir
COPY ./requirements.txt ${PWD}
RUN pip install -r requirements.txt
WORKDIR /home/workdir/src
EXPOSE 8888
コンテナのビルドは、vscodeのRemoteを利用します。Remoteを利用したコンテナのビルドとアクセス方法はこちらです。
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list
この2行はSQL Serverへのアクセスに必要なパッケージを準備します。2行目のdebian/10/
の数字部分は、採用したDebianのバージョンで変わります。今回はBusterを選択しているので10ですが、stretchなどを選択した場合は9になります。
これはpyodbcを実行するのに必要です。これがないと「sql.h
が見つからないよ!」とエラーになります。
こっちはSQL Serverへアクセスするために必要。先ほどのMicrosoftへアクセスするcurl
は、これらのパッケージを利用するのに必要な場合なデータを、マイクロソフトのサーバーから取得しているわけです。
会社や学校内などからアクセスする場合、プロキシ情報をDockerコンテナのビルド時に付与する必要があります。あるいはDockerfile内にENV
として直接記述します。
apt-get
と同時にsed
でopenssl.cnf
を書き換えています。これは、デフォルトで設定されたセキュリティレベルを2から1に変更しているからです。
Debianはbusterからセキュリティの要件が変更になり、OpenSSLのセキュリティレベルがデフォルトでは「2」に設定されています。ところが、デフォルトの設定だとsqlcmd
などでSQL Serverへアクセスした際に下記のエラーを出力します。
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : TCP Provider: Error code 0x2746.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Client unable to establish connection.
このエラーを回避するために、セキュリティレベルを従来の「1」に書き換えています。なお、この操作が必要になるのはデフォルトの値が変わったbuster以降の話なので、stretch以前ではこの書き換えは必要ないはず。
このように、Dockerfile内に書き換えを行うコマンドを記述しておくことで、ビルド後にbash経由などで書き換える必要がなくなります。また、このDockerfileだけを持ってコンテナをビルドすればいいので、別のプラットフォームで環境構築する際に余計な手間がかかりません。
以下の2ファイルは、「.vscode」というフォルダを作成して格納します。内容は利用する拡張機能と、vscodeの設定です。
{
"recommendations": [
"ms-vscode-remote.remote-containers"
]
}
拡張機能ではリモートでコンテナ内のPythonソースを編集するので、Remoteが必須です。
{
"python.pythonPath": "/usr/local/bin/python",
"python.languageServer": "Jedi"
}
本来、Language ServerはデフォルトがJediなので変更する必要はないと思うのですが、どうもPythonの拡張機能をインストールするとLanguage ServerがMicrosoftに変更されるっぽいです。ちょっと確証がないのですけど。なので、明示的に設定をデフォルトのJediに戻しています。Language ServerをMicrosoftで利用する場合は、この設定は削除してしまって問題ありません。
以下のファイルは、「.devcontainer」という名前のフォルダを作成して格納します。内容は拡張機能のPythonにおける設定や、flake8のLint設定などです。各設定の詳細は割愛します。
{
"name": "work python project",
"dockerFile": "../Dockerfile",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": [
"--ignore=E402,E501"
],
"python.formatting.provider": "autopep8",
"python.formatting.autopep8Args": [
"--ignore",
"E402,E501"
],
"[python]": {
"editor.formatOnSave": true
}
},
"extensions": [
"ms-python.python"
],
}
今回はpip
を用いてインストールするPythonのライブラリについて、Dockerfile上では記述しないで、requirements.txtに記述しています。内容は下記の通り。
numpy
pandas
matplotlib
seaborn
tqdm
scikit-learn
pyodbc
requests
jupyter
現状では指定していないものの、各ライブラリについてインストールする対象のバージョンを指定できるので、依存関係上必要な場合はバージョンを都度指定します。
また基準となる環境がすでにある場合は、その環境でpip freeze > requirements.txt
と実行すれば簡単にバージョン指定まで含んだrequirements.txtが用意できます。
コンテナのビルドはdocker
コマンドで実行してもいいですが、ここではvscodeのRemoteを用いてビルドします。vscodeのRemoteを利用したコンテナのビルドとアクセス方法はこちらです。
コンテナのビルドが終わったら、vscodeでmain.py
を編集します。事前にコードを書いてもいいですが、せっかくなのでvscodeでコンテナビルドをやってリモートで書いてみました。
Pythonコードの実行はF5キーでの実行でもいいですし、コンテナのbashなどでpython main.py
と入力して実行しても問題ありません。どちらでも動作するはずです。
実を言うと、このDockerfileの作成が結構難産でした。というのもあまりドキュメントがないことと、必要なライブラリやパッケージなどが多数存在したためです。「XXXを実行するにはYYYが必要で、YYYをインストールするにはZZZが必要」みたいな感じで、実行してみてコケてはググって・・・という、トライアンドエラーの繰り返しでした。果てはコンテナのビルドが成功したので、喜び勇んでpyodbcを実行してみたらエラーを吐いて異常終了・・・なんて状態だったので、我ながらよく心折れなかったなぁと思います。とりあえず二度とやりたくないw
なにはともあれ、これでSQL Serverにアクセスできつつ、リモートでコーディング可能な環境が揃いました。上記では言及していませんが、Jupyter notebookの実行も可能です。vscodeでnotebookを書いてもいいし、ブラウザからコンテナにアクセスすれば普段どおりブラウザで編集できます。
新しく環境を用意する場合は、このファイル一式をまるっとコピペしてコンテナをビルドするだけで再現します。
本当に、Dockerとvscodeの組み合わせって便利ですよね。まぁ、その環境構築が割りと大変なんだけどね!
Microsoft ODBC Driver for SQL Server をインストールする
Docker内からホストのSQL Serverへアクセスする
Error: TCP Provider: Error code 0x2746. During the Sql setup in linux through terminal
Can’t connect to Sqlserver with Openssl 1.1.1c (Error code 0x2746)