PyCharmでリモートGPUマシンのDockerコンテナで開発するためのプロジェクトテンプレート

## はじめに

PyCharmでリモートマシンのDocker環境でデバッグできるようにするためのプロジェクトテンプレートを作りました。

PyCharmのGUIによる面倒な設定が最小限になり、さくっと新しいリポジトリをつくり、PyCharmをつかってリモート開発ができます。もちろん、既存のOSSを動かすための環境をすぐ作りデバッグするためにも利用できます。

私はComputer VisionやDeep Learning、Data Scienceなどの分野でPythonをつかって開発をしているエンジニアですが、同業の方には役立つ内容だと思います。Kaggleなどコンペ用のリポジトリテンプレートとしても使えるんじゃなかろうか。

作成したリポジトリはこちらです。

https://github.com/tkat0/cookiecutter-pycharm-remote-docker

## PyCharmでのリモート開発

Python用のIDEであるPyCharmは、コードやdocstringの補間やデバッグの機能が優れており、特別設定をしなくてもすぐ使いこなせることから最近は愛用しています。

PyCharmは、今回紹介する[ローカルで開発しリモートで実行・デバッグするための機能](https://pleiades.io/help/pycharm/remote-debugging-with-product.html)を持っています。有料のPro版でしか使えませんが、生産性は課金により高められるので買いましょう。

特にComputer VisionやDeep Learningのような計算リソースを大量に使用する分野では、開発PCと実行・デバッグ環境が同一でない場合も多いのではないでしょうか。例えばローカルの開発マシンで開発し、実行・デバッグ環境はAWSやGCP、所属組織のGPUサーバーを使うような開発スタイルです。こうした環境において、PyCharmのリモートデバッグ機能は役立ちます。

## 開発・実行環境をDockerにする利点

今回は、PyCharmを用いてリモート環境の**Dockerコンテナで**実行・デバッグする方法について着目しています。

機械学習の文脈で開発・実行環境をDockerにする利点はすでに多くの方が述べています。私自身、チーム内での環境を統一したり、１つのマシン上で複数のプロジェクトを並行して作業したり、環境を簡単に再現したりするためにはDockerは欠かせないものだと思っています。

例えばComputer Visionにおいては、プロジェクトごとにOpenCVの異なるビルドを利用したり、CUDAのバージョンが異なったり、さらにはUbuntuのバージョンやGCCのバージョンがそれぞれ異なったりと、pyenvやpipenvなどPythonの仮想環境だけでは環境を分離できないことも多いです。しかし、これらは開発・実行環境をDockerにすることで解決することができます。

また、OSSを公開する上でもDockerfileを同梱することで、作者の環境を共有でき、面倒な環境構築を抜きにすぐに使い始めることができます。以下はその例です。こんなところに精度再現されたYOLOv3のPyTorch実装があるらしいぞ。

https://github.com/DeNA/PyTorch_YOLOv3#docker-environment

## PyCharm Dockerリモート開発は設定が面倒

というわけで、PyCharmでリモートサーバーのDockerコンテナでデバッグをしたいのですが、PyCharmの設定が面倒という課題がありました。

プロジェクトの新規作成時は、以下のようなことをGUIの設定でぽちぽちする必要があります。

- Pythonインタプリタの設定
- Dockerfileのビルドの設定
- ローカル・リモート間のファイル共有（Deployment）の設定
- 実行とデバッグの構成を追加（Pythonスクリプト、unittest、Sphinxドキュメント...）

一度やってしまえば良いのですが、新規にリポジトリをつくって同様の設定をしようとするたびにげんなりしてしまい、また同僚に手順を共有するためにWikiにスクリーンショットを貼る生活にはつかれてしまいました。自動化できないだろうか。

そこで、PyCharmでリモートデバッグするための設定の労力を最小限にし、新しいリポジトリの立ち上げやOSSの動作確認をさくっと開始するために、Cookiecutterを利用してつくったプロジェクトテンプレートが、前記の[cookiecutter-pycharm-remote-docker](https://github.com/tkat0/cookiecutter-pycharm-remote-docker)です。

## 使い方

前置きが長くなりました。

使い方は、リポジトリのREADMEに書いてある以上のことはないので、ここでは省略します。

https://github.com/tkat0/cookiecutter-pycharm-remote-docker

上記は拙い英語ですが、日本語のREADMEも記載しています。

https://github.com/tkat0/cookiecutter-pycharm-remote-docker/blob/master/README.ja.md

## あとがき

本リポジトリは、プロジェクトのテンプレートを作成するためによく使われる、Cookiecutterを利用しています。公式では、Cookiecutterを利用した3rd-partyのリポジトリを紹介しているので、同様のテンプレートを作成する方の参考になると思います。例えばPythonのパッケージのリポジトリをつくるテンプレートや、C++のプロジェクトテンプレートなど色々あります。

ちょっと技術的な話をします。

PyCharmを始め、JetBrainsのIDEは、プロジェクトのルートに`.idea`というIDE用のディレクトリが作成され、この中にXMLファイルで設定が書かれています。例えば、以下は[Dockerfileのビルド設定の抜粋](https://github.com/tkat0/cookiecutter-pycharm-remote-docker/blob/4086c024f436ba7d38840ddb2b8d036d1a2fac76/%7B%7Bcookiecutter.project_name%7D%7D/.idea/runConfigurations/docker_build.xml#L6-L21)ですが、`{{ cookiecutter.python_version }}`のようにDockerfileの`ARG`で指定する引数をテンプレート化しています。これがリポジトリ作成時に指定した値で埋められます。

```xml
<option name="buildArgs">
  <list>
    <DockerEnvVarImpl>
      <option name="name" value="UID" />
      <option name="value" value="{{cookiecutter.remote_uid}}" />
    </DockerEnvVarImpl>
    <DockerEnvVarImpl>
      <option name="name" value="PYTHON_VERSION" />
      <option name="value" value="{{cookiecutter.python_version}}" />
    </DockerEnvVarImpl>
    <DockerEnvVarImpl>
      <option name="name" value="TIMEZONE" />
      <option name="value" value="{{cookiecutter.timezone}}" />
    </DockerEnvVarImpl>
  </list>
</option>
```

これらは、最初手作業で作成したXMLの値を`{{ cookiecutter.hoge }}`に置換する事により生成されました。

[cookiecutter-pycharm-remote-docker](https://github.com/tkat0/cookiecutter-pycharm-remote-docker)は最低限の設定しか記述していないので、どうぞforkしてproject specificな拡張してみてください。
例えば、ドキュメントの目次を予めかいておくとか、requirements.txtを予め書いておくとか。自分自身でよく使う設定やチーム内で共通化したい設定などを予めテンプレート化しておくと便利です。

## 参考

このテンプレートはCookpadの@takahi-iさんの[cookiecutter-docker-science](https://github.com/docker-science/cookiecutter-docker-science)に強く影響を受けています。terminalで実行・デバッグしたり、リポジトリを公開する上では非常に便利です。今回はこれのPyCharm版といっても過言ではありません。

https://qiita.com/takahi-i/items/12fd6016cd83e8ca1c8d