VSCodeをフロントにしたPython開発環境の個人的ベストプラクティス

# 概要

機械学習やデータ分析をする上で手元のマシンだけで分析/開発作業が完結することは少ないですよね。GPUのモリモリ載ったリモートサーバ上でDockerなどを利用して開発しているんじゃないかと思います。

VSCodeを起点に、リモート環境でのPython開発について試行錯誤したのでそのまとめです。

なお筆者はVSCodeを使い始めたばかりの初心者ですのでアドバイス等いただけると幸いです。

# 環境
作業した環境です。この環境に縛られるものではないと思います。

- localマシン：Macbook Pro
    - VSCode: v1.48.2
- リモートOS: Ubuntu 20.04 LTS
- Docker
    - local: 2.3.0.4
    - remote: 19.03.8
- docker-compose(remote): 1.26.0


# 実現したいこと

せっかくの統合開発環境なので、localマシン上でVSCodeを立ち上げてlocalのVSCodeだけで作業を完結させたい。

- VSCodeからリモートサーバにSSH接続
- 接続先のサーバでDockerコンテナに接続
- ビジュアルにブレイクポイントの設置などをしながらデバッグ


# 手順

## リモートサーバにSSH接続

[Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)拡張機能を利用します。このExtensionは、SSH、Container、WSLのそれぞれのリモート開発拡張をひとまとめにしたものらしいです（それぞれインストールしても同じぽい）。

参考：https://code.visualstudio.com/docs/remote/ssh#_getting-started

### Extensionの導入

Remote Development：https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

### リモートサーバの追加

コマンドパレットを開き、`Remote-SSH: Connect to Host`を選択すると、接続先の選択リストが出ます。

![スクリーンショット 2020-09-02 16.25.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/94a15b0b-2cff-cf17-16c8-7e626fcaa3de.png)

ここから`Add New SSH Host`を選択するとｓｓｈコマンドの入力を求められるので、ターミナルからssh接続するのと同じコマンドを入れます。
初めて接続する場合は、`Add New SSH Host`の項目しか無かったと記憶してます。

![スクリーンショット 2020-09-02 16.26.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/efd495fb-8887-3d27-f015-953bf038629a.png)

鍵認証の場合、sshコマンドを打つ際に`-i`オプションで鍵を指定します。

これらの設定はデフォルトで`~/.ssh/config`に書かれます。
ポートフォワーディングの設定や鍵ファイルの設定などを直接書くこともできます。（多分ホストの追加も）


### 接続

ホストを追加した時と同様、コマンドパレットの`Remote-SSH: Connect to Host`からリモートサーバを選択します。または、VSCodeの左側にあるショートカットメニューの「RemoteExplorer」からホストを選択してアクセスしてもOKです。


## リモートサーバ上のDockerコンテナを操作

リモートサーバに接続したら、次はDockerコンテナに接続します。

こちらは以下の記事を参考にさせていただきました（参考にというかそのままなぞっただけです。なので是非参照元を確認してください）。
VS CodeからSSHでサーバ上のDockerコンテナを操作する：https://qiita.com/_kani/items/1ce36e36b0bcda403be2

### コンテナの立ち上げ

VSCodeのターミナルを立ち上げ、dockerコマンドなどでコンテナを立ち上げます。
RemoteDevelopment Extensionにはdockerコンテナの立ち上げから接続までサポートする機能もあるのですが、これはローカルマシンでのdocker操作のようです。なので、リモートサーバでコンテナを立てる際には通常のdockerコマンドで操作します（僕ができなかっただけ？）。


### 接続のための準備

#### ポート設定

ポートフォワーディングの設定をします。（これ仕組みがよくわかってないんですよね。。。）

sshのコンフィグを開きます。コマンドパレットを開いて`ssh config`などと入れると項目が出てきますので、選択します。

![スクリーンショット 2020-09-02 16.57.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/d14a42be-b444-2d78-119c-f29eb424a698.png)

該当のリモートホストの設定に`LocalForward`の設定を追記します。

```
Host 192.168.*******
  HostName 192.168.*******
  IdentityFile ~/.ssh/id_rsa
  User *****
  LocalForward 23750 /var/run/docker.sock
```

#### リモートホストでdocker拡張機能のパラメータ設定

VSCodeからリモートホストに接続します。なお、リモートホスト上でもRemoteDevelopmentの拡張機能を入れとく必要があります。

Preferrenceから、以下のようにパラメータを設定します。タブでRemoteを選択して、Docker.hostと検索すれば出てくるようです。

`tcp://localhost:23750`

![スクリーンショット 2020-09-02 17.03.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/28ae4993-74bd-34bb-09bc-1162ea0d958e.png)

これで準備完了です。

なお、設定画面はコマンドパレットから`preferences Open User Setting`などと入力すると出てきます。


### 接続

サイドバーのRemote Explorerから、操作します。
上段のプルダウンメニューでContainersを選択すると、コンテナのリストが現れるので、接続したいコンテナを選択します。
「Attach to Container」でコンテナに接続します（新しくウィンドが立ち上がる）。

![スクリーンショット 2020-09-02 17.14.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/82ce98c7-ad33-e2c6-5986-6437c238209c.png)



## デバッガの利用

VSCodは統合開発環境なので、インタラクティブにブレークポイントを設置するなどしてデバッグができます。しかし、特定の環境ではブレークポイントの設定やステップ実行もできずプログラム終了まで走ってしまう現象が確認できています。

参考：[VSCodeでPython仮想環境のデバッグ実行時にブレークポイントで止まらない問題](https://qiita.com/EngineerShiba/items/6c7d2b97829a4c4092d7）)

これでは困るのですが、デバッガの設定ファイル'launch.json'にパラメータを設定することでデバッガの機能が有効になるようです。

### パラメータの追加

'launch.json'は、VSCodeのサイドメニューからデバッガを開き、上部の歯車マークを押下することでエディタ画面に表示されます。
このjsonファイルにパラメータを追加します。

```
"stopOnEntry":true
```

![スクリーンショット 2020-09-02 17.26.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66005/3bc90069-75ea-3461-0446-6d777c25ca70.png)


### 注意

`stopOnEntry`を入れる順番に注意が必要です。
`args`の前に入れたところ、`args`パラメータが適用されず、引数がデバッガに渡されないという現象に遭遇してしばらくはまってしまいました。

# まとめ

いくつか試行錯誤して現在は上記の手順に落ち着きました。
もっと良い方法ご存知の方教えていただけると助かります。

特にDockerコンテナを操作する仕組みがよくわかってないのが不安です。