VS Codeの開発環境：既存のコンテナをRemote-Containersとして利用する

[Python3の実行環境をDockerで用意する](https://qiita.com/legacyworld/items/1c9ac1d3859a321d6e84)という記事を書いたのだが、これに少し追加情報
# 環境
Windows PC + Docker Desktop

# lintに困る
Dockerを実行環境としてVS Codeで開発を行うのは快適なのだが一つ問題点がある。lintだ。
VS CodeからはWindowsのPythonを見ているので、ここにpip等でモジュールが入っていないとlintで怒られる。
かと言ってWindows側に綺麗に入れるのは面倒くさいし、それをしたくないからコンテナを実行環境にしているわけである。
Interpreterとしてコンテナ内部のPythonを指定したいのだ。
ググること1分もたたずに、答えが見つかりました。

# VS Code Remote Development Extension
名前もそのままでした。いつものようにExtensionとして入れれば準備OK。
本家のマニュアルも非常に充実しているが、充実しすぎてて迷子になってしまう。
なので、既存で既に動いているコンテナにどうやって繋ぐか、という点に絞る。

# とりあえずやってみる
こういう構成で始めます。

```
test2
│  docker-compose.yml
└─app
    │  Dockerfile
    └─src
         | test.py
```

```yml:docker-compose.yml
version: '3.7'
services:
  remotedev:
    build:
      context: ./app
      dockerfile: Dockerfile
    container_name: remotedev
    command: /bin/sh -c "while :; do sleep 10; done"
```
まずVS codeで上記のフォルダを開いておく。何かしょうもないことを間違っている気はするがこうしないと**From docker-compose.yml**の選択肢が出てこない。
VS codeにExtensionを入れると左下にこんなのが出てくるのでクリックする。
![remote-dev-status-bar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/83a5d565-7e73-2f9f-c281-1c46a58b04a8.png)
次に**Remote-Containers: Open Folder in Container..**を選ぶ
<img width="392" alt="1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/dcbcc309-778c-4cc8-15f2-0211e1e76ff9.png">
フォルダを選ぶダイアログが出てくるのでdocker-compose.ymlがあるフォルダを選ぶ（ここではtest2）
更に次のような選択肢が出てくるので**From docker-compose.yml**を選ぶ
<img width="386" alt="2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/66fb139f-1f8f-6b4b-4cee-2c19c2be9c2d.png">
この時点で新しいコンテナが自動的に作成されている。

```
c:\source\test2>docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c7586573d867        test2_remotedev     "/bin/sh -c 'while s…"   8 minutes ago       Up 8 minutes                                 remotedev
```
このコンテナが上記のdocker-compose.ymlをベースにRemote Containersとして使えるようにしたものである。
最初はこれがどういう設定で立ち上がってきているのかよく理解できなかった。
# docker-compose.ymlを重ねて使う
さて元のフォルダ（test2）を見てみる。

```
test2
│  docker-compose.yml
├─.devcontainer
│      devcontainer.json
│      docker-compose.yml
└─app
    │  Dockerfile
    └─src
        │  test.py
```
**.devcontainer**という新しいフォルダにdevcontainer.jsonとdocker-compose.ymlが自動で生成されている。
うまく行くと何をやっているのかさっぱりわからなかったのだが、ひょんなことから失敗してコマンドがわかった。
いろいろやってるっぽいが結局これを実行している

```
docker-compose -f c:\source\test2\docker-compose.yml -f c:\source\test2\.devcontainer\docker-compose.yml
```
ここの説明が非常にわかりやすい。
[※docker-composeで複数環境を構築](https://ikasamak503.hatenablog.com/entry/dry-docker-compose-yaml)
まぁ、要するに後に設定した方で上書きされるということである。
何が書いてあるかというとこんな感じ（長いので一部コメントは消してます）

```yml:.devcontainer/docker-compose.yml
version: '3.7'
services:
  # Update this to the name of the service you want to work with in your docker-compose.yml file
  remotedev:
#...省略
    volumes:
      # Update this to wherever you want VS Code to mount the folder of your project
      - .:/workspace:cached
#...省略
    # Overrides default command so things don't shut down after the process ends.
    command: /bin/sh -c "while sleep 1000; do :; done"
```
大したことは無くて**volumes**で"test2"をコンテナ内の"/workspace"にマウントしているだけである。
**command:**はコンテナが落ちないようにするためのものである
実際コンテナ内部はこんな感じ

```
c:\source\test2>docker exec -it remotedev bash
[root@c7586573d867 workspace]# ls
app  docker-compose.yml
[root@c7586573d867 workspace]# ls app/src/
test.py
```
VS codeはこんな風に見えている。
<img width="700" alt="3.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/5ed4cf17-19a5-9c80-b1d7-5ff32cfab88b.png">
Extensionを見ると**LOCAL**と**DEV CONTAINER**で分けてあり、DEV CONTAINER側には何もない。
なのでこの状態では普段利用しているPythonのExtensionが全く効いていないわけだ。
ではこのあたりの設定をどうすればよいのかというと、それが**.devcontainer/devcontainer.json**である。
これもコメントだらけなので殆ど省略する

```json:.devcontainer/devcontainer.json
{
	"name": "Existing Docker Compose (Extend)",

	// Update the 'dockerComposeFile' list if you have more compose files or use different names.
	// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
	"dockerComposeFile": [
		"..\\docker-compose.yml",
		"docker-compose.yml"
	],

	// The 'service' property is the name of the service for the container that VS Code should
	// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
	"service": "remotedev",

	// The optional 'workspaceFolder' property is the path VS Code should open by default when
	// connected. This is typically a file mount in .devcontainer/docker-compose.yml
	"workspaceFolder": "/workspace",

	// Set *default* container specific settings.json values on container create.
	"settings": { 
		"terminal.integrated.shell.linux": null
	},

	// Add the IDs of extensions you want installed when the container is created.
	"extensions": []

// ...省略
}
```
基本的には**"extensions"**以外は無視して良いんじゃないかと思う。
ここには各extensionの下記の部分を入力すればよい(**ms-python.python**)
<img width="289" alt="4.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/fbc057c9-77a8-d956-b061-385d63495c32.png">
こんな感じ

```
"extensions": ["ms-python.python","dbaeumer.vscode-eslint"]
```

最後にこのコンテナをRebuildする
左下の緑の部分をクリックして**Remote-Containers: Rebuild Container**
立ち上げてPythonファイルを表示すると
![install-linter-message.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629456/03a3f136-fbb3-52d4-a9f3-38bc022c7581.png)
と聞いてくるので**Install**をクリックするとpipでインストールしてくれる。
これで今までPyPDF2やtabulaでimportのところに赤い波線が出てうっとうしかったのだがすっきりした。

※閉じるときは左下の緑をクリックして**Close Remote Connection**から閉じておこう。VS codeをそのまま閉じると次回も接続しに行ってしまう

# virtualenvを自動で有効にしているコンテナは気をつけよう
元々centos/python-36-centos7:latestというイメージをベースにしていた。
CentOS7ベースで既にPythonが入っていたのであとはJDK突っ込むだけだったので楽だったのだ。
しかしこれのせいでlintがが有効にならず悩んだ。
Pylintをインストールするか？と聞いてくるところまでは問題なかったが、pipでのpylintのインストールにどうしても失敗する。

```
(app-root) bash-4.2# /opt/app-root/bin/python /opt/app-root/src/.vscode-server/extensions/ms-python.python-2020.4.76186/pythonFiles/pyvsc-run-isolated.py pip install -U pylint --user
Can not perform a '--user' install. User site-packages are not visible in this virtualenv.
```
どうやらvirutualenvが有効なってるから無理、ってことらしい。
そこでこのイメージのDockerfileの最後の部分を見てみるとこうなってた
https://github.com/sclorg/s2i-python-container/blob/master/3.6/Dockerfile

```dockerfile

# - Create a Python virtual environment for use by any application to avoid
#   potential conflicts with Python packages preinstalled in the main Python
#   installation.
# - In order to drop the root user, we have to make some directories world
#   writable as OpenShift default security model is to run the container
#   under random UID.
RUN source scl_source enable rh-python36 && \
    virtualenv ${APP_ROOT} && \
    chown -R 1001:0 ${APP_ROOT} && \
    fix-permissions ${APP_ROOT} -P && \
    rpm-file-permissions
```
何か色々面倒なので結局素のCentOS7からBuildすることにした