PyCharmのProject Interpreterにremote dockerのPythonを使う

# 概要

PyCharmで、ローカルマシンにあるコードをdockerコンテナのPythonで実行する方法です。

全体像としては以下の様になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/80f50d8e-9869-8cca-b7ba-be0b312f2629.png)


# 事前準備
- リモートサーバ：Dockerのインストール
- ローカルマシン：Pycharm Professional
- リモートサーバへのssh接続できる状態にしておく

# リモートサーバの設定
## リモートAPIの設定

リモートサーバ上のDockerをAPIで接続できるように設定します。
公式：[How do I enable the remote API for dockerd](https://success.docker.com/article/how-do-i-enable-the-remote-api-for-dockerd)

Dockerをインストールしたサーバ上で実行

```
# 設定の修正
$ sudo vim /etc/systemd/system/docker.service.d/startup_options.conf

# 設定への記載内容
$ cat /etc/systemd/system/docker.service.d/startup_options.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:// -H tcp://0.0.0.0:2376

# 読み込み＆再起動
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker.service

# 設定の確認
# "/usr/bin/dockerd -H unix:// -H tcp://0.0.0.0:2376"があればOK
$ service docker status
Redirecting to /bin/systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/docker.service.d
           └─docker-bridge-yj.conf, startup_options.conf
   Active: active (running) since Tue 2019-06-18 12:54:47 JST; 4 days ago
     Docs: https://docs.docker.com
 Main PID: 4595 (dockerd)
    Tasks: 26
   Memory: 9.2G
   CGroup: /system.slice/docker.service
           └─4595 /usr/bin/dockerd -H unix:// -H tcp://0.0.0.0:2376
```

## コードの転送先ディレクトリの作成
remote dockerで実行する際、コードをリモートサーバ上に転送する必要があるので転送先のディレクトリを用意しておきます。
この記事ではリモートサーバのホームディレクトリ上に `test_project` というディレクトリを用意しておきます。

```
$ mkdir ~/test_project
```




# Dockerイメージの用意
好きなイメージを用意します。
この記事ではanacondaを使います。
コンテナはPyCharmが作成するので、ここではコンテナの作成は行いません。

```
$ docker pull continuumio/anaconda3
$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
continuumio/anaconda3   latest              cb34e4508fdc        4 weeks ago         3.72GB
```

# PyCharmの設定
## Projectの作成
Projectを作成して下さい。

この記事ではtest_projectというProjectを作成し、hello_world.pyをremote dockerで実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/830216f0-6d3d-86dd-32d3-b9a41159ce53.png)

## Dockerの設定

メニューバーから「PyCharm」→「Preferences...」を選択します。
Preferencesで、「Build, Execution, Deployment」→「Docker」で、remote dockerの設定を行います。

以下の様に設定します。
Engine API URLのhostnameの部分には、リモートサーバのホスト名を入力。
Certificates folderはid_rsaがあるディレクトリを設定。
リモートサーバのDockerへの接続が成功すると、Connection successfulと表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/48c5ba74-82a2-a52e-76a6-53f7d279b39c.png)

## Project Interpreterの設定
Preferencesで、「Project:XXXX」→「Project Interpreter」で、remote dockerのpythonを追加します。
Project Interpreterの右側にある歯車アイコンを押して、「Add…」を選択します。

左のメニューでDockerを選択すると、先程設定した名前のServerが選択できるようになっています。
Image nameはリモートサーバ上のDocker Imageが選択できるので、利用したいイメージを選びます。(この記事だとcontinuumio/anaconda3)
設定ができたらOKを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/dfba84a2-4ce7-e477-64ff-61d8734ffde5.png)

追加ができるとPackageが読み込まれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/7a6f7ff6-4aec-5a30-b2b7-5dc64347499e.png)

次にPath MappingsでDockerコンテナ内でPython実行時のパスを設定します。
Path Mappingsが(Empty)になっているので、右にあるフォルダのボタンを押してEdit Project Path Mappingsを開きます。
Local Pathはローカルマシンでプロジェクトのルートディレクトリを指定します。
Remote PathはDockerコンテナ内でPythonを実行する際のパスを設定します(今回は/workspaceにします)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/b7333e01-40c8-2bd6-510a-98cc0b55f8f6.png)

設定が完了すると以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/f74c3db9-0536-7702-2f6d-6b43ca3e517f.png)


## Deploymentの設定
ローカルマシンのコードをリモートサーバに転送する設定を行います。

Preferencesで「Build, Execution, Deployment」→「Deployment」を選択して、リモートサーバの設定を以下の様に入力します。
まだOKは押さず、「Mappings」のタブを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/5029225f-e480-6ecc-33da-53ed90dd00d2.png)

Local pathはローカルマシンのプロジェクトのルートディレクトリが指定されていると思うので、Deployment pathの方だけ設定します。
Deployment pathは、"コードの転送先ディレクトリの作成"で作成したリモートサーバ上のディレクトリを指定します。

Deploymentでデフォルトが指定されていないと面倒なので、作成した設定(この記事だとdocker server)を選択し、✓を押します。押すと設定が太字になります。

指定が済んだらOKを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/8f015993-f735-3647-99a3-8843bfaf3c01.png)

# Pycharmで実行する

## コードをリモートサーバへ転送する

プロジェクトのルートディレクトリを選択して右クリックを押し、「Deployment」→「Upload to docker server」を選択します。"docker server"の部分はDeploymentで設定した名前です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/013abda5-3986-bd0f-84cd-5b365f82ae33.png)

## Python実行時の設定
メニューバーから「Run」→「Edit Configurations...」を選択します。
下の方に「Docker container settings」があるので、ディレクトリのアイコンを押して「Edit Docker Container Settings」を開きます。
Container pathは"Project Interpreterの設定"でマッピングしたディレクトリを指定します(この記事では/workspace)
Host pathは分かりにくいのですが、Deploymentで設定したリモートサーバ上のパスを指定します。
この設定は、Pycharmがコンテナを起動する際にリモートサーバ上のパス(Host path)をコンテナにマウントするためのものです。こうしないと、Runを実行した際にコンテナ内からコードが見えずにエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/47e46648-6d87-fa8f-615b-8410786ebb9d.png)

後はRunするだけです！
Debugも同じ様にConfigurationsで設定すればブレークポイントなどもすべて使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12165/89180486-16af-7d30-6d6d-c5b62f52cd17.png)


おまけ

Pycharmでコードを編集した場合、編集結果を毎回UploadしないとRunした場合に実行されるコードは編集前のままです。
毎回Uploadを押すのも面倒なので、メニューバーの「Tool」→「Deployment」→「Automatic Upload」を押してチェックを付けておくと、保存するたびにコードがリモートサーバへアップロードされるので、実行されるコードがずれるということがなくて便利です。