頑張らないために頑張る

ゆるく頑張ります

Debian busterベースのPython用コンテナでvscodeとpyodbcを使ってSQL Serverにアクセスにする

Posted at — Aug 19, 2020

はじめに

今回はDockerコンテナ上で、pyodbcを使ってSQL Serverにアクセス可能な環境を構築します。また、Pythonコードを記述するのにVisual Studio Code(以下、vscode)の拡張機能であるRemoteを利用して、Dockerコンテナに対しリモートでのソース編集と実行を行います。この環境を構築するには、下記のように各種ドライバーなどが必要になります。

これらの要求をすべて満たすような、Dockerfileやvscodeの設定ファイルなどを用意します。

フォルダ構成

│  Dockerfile
│  requirements.txt
│
├─.devcontainer
│      devcontainer.json
│
├─.vscode
│      extensions.json
│      settings.json
│
└─src
        main.py

冒頭にピリオドのついたフォルダは、vscode用の設定フォルダですのでフォルダ名は固定です。「src」は、実行するPythonのソースコードを格納するだけなので、名前は何でもいいです。もちろん、中身のPythonファイルも名前は任意です。

Dockerfile

なにはともあれ、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として直接記述します。

OpenSSLの設定ファイル書き換えについて

apt-getと同時にsedopenssl.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だけを持ってコンテナをビルドすればいいので、別のプラットフォームで環境構築する際に余計な手間がかかりません。

vscodeの設定ファイル

以下の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で利用する場合は、この設定は削除してしまって問題ありません。

vscodeの拡張機能設定用ファイル

以下のファイルは、「.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"
    ],
}

導入する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)

【venv不要】Remote Containersで作る最強のPython開発環境【VSCode/Docker】

comments powered by Disqus