Docker engine + VSCode開発環境 備忘録

# 概要
TensoorflowのGPU環境構築にあたってはインストールに関する情報も多く、インストーラも心持ちユーザフレンドリーになっているし、何より自前で環境構築するのに慣れてしまったこともあり、イライラすることはほぼなくなった。 

昔は知識不足でGPU環境を構築することが困難だったので[TensorFlow Docker image](https://www.tensorflow.org/install/docker?hl=ja)を使うことがままあった。その時はホスト環境のブラウザからコンテナに接続してJupyter notebookで開発することがもっぱらであった。 

仕事でDockerを使う機会があり自分のDocker情報も更新されたので環境構築について備忘録に残す。
なお、(有料な)Docker desktopは使用しない。

- 実施期間: 2023年3月
- 環境：Host: Ubuntu20.04.2 LTS, Container: Ubuntu20.04.5 LTS

## 1. Docker engineインストール

オフィシャルの手順に沿うだけで完了する。

https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/ubuntu/#install-using-the-repository

インストール後、[Linux のインストール後](https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/linux-postinstall/)を忘れずに実行すること。

## 2. Ubuntu imageのコンテナ化
Host OSと同じUbuntu20.04のイメージでコンテナ作成する。
コンテナのUbuntuにはPythonが入っていないので、一度にPython環境まで整えるためにコンテナ作成にはDockerfileをbuildする。
ソースコードはHost OSでも確認できるようにバインドマウントする。

```Dockerfile
FROM ubuntu:20.04

RUN mkdir /usr/local/src/python_src
RUN apt-get update
RUN apt-get install -y python3.8 python3.8-dev python3-pip
RUN pip3 install numpy pandas matplotlib

VOLUME /usr/local/src/python_src
```

Dockerfileをおいたディレクトリでイメージ(ubuntu:py38)とコンテナ(test_1)を作成する。

```terminal
docker build -t ubuntu:py38 .
docker image ls

REPOSITORY              TAG          IMAGE ID       CREATED          SIZE
ubuntu                  py38         8f2cd82f8cb3   19 seconds ago   662MB

docker run --name test_1 -it ubuntu:py38 bash
```

起動したコンテナのterminalでUbuntuのバージョンくらい見ておく。

```terminal
cat /etc/lsb-release

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
```


Host OSで別terminalを起動し、run中のコンテナ情報を抜き出してコンテナの/usr/local/src/python_srcがHost OSのどこにマウントされたか確認する。そこに簡単なpyファイルを作成する。

```terminal
docker ps

CONTAINER ID   IMAGE         COMMAND   CREATED              STATUS              PORTS     NAMES
91fa06d195c2   ubuntu:py38   "bash"    About a minute ago   Up About a minute             test_1

docker inspect 91fa06d195c2 > test_1.JSON
cat test_1.JSON | jq ".[].Mounts[].Source"

"/var/lib/docker/volumes/a0020fa7a6ed93819b9099e7a7bdc311248891a5e86534137528bd415559d828/_data"

cd /var/lib/docker/volumes/a0020fa7a6ed93819b9099e7a7bdc311248891a5e86534137528bd415559d828/_data
sudo touch test.py
sudo vim test.py
```

vimで"hello world!"を出力するコード（割愛）を書いておく。

コンテナのterminalでそれが参照できるか確認する。

```terminal
cd /usr/local/src/python_src
ls

test.py
```

:::note info
Dockerの仕様上、マウント元(Host OS)のディレクトリを指定することはできず、Dockerが自動的にマウント元を作成する。つまり複数コンテナからHost OS上のひとつのディレクトリを参照することはできない（という理解）。
:::

## 3. VSCode
下記サイトを参考にさせていただいた。

https://tech.nri-net.com/entry/using_docker_containers_with_vscode

VSCodeの機能拡張にDev Containersをインストールしておく。これが起動中のコンテナに環境を接続してくれる。

![Screenshot from 2023-03-05 14-05-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/45716953-551f-f234-cab8-304634bf7e31.png)

表示されているコンテナは`docker ps -a`で表示されるコンテナたちで、実行中のものには再生マークがついている。ここではコンテナtest_1を選択する。同時にPythonのインタプリタがコンテナ中の環境に切り替わる。起動していないコンテナを選択すると起動して接続してくれる。
接続すると、pythonのインタプリタが切り替わる。

![Screenshot from 2023-03-05 14-08-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/b85a39d4-c4b5-3219-aa6b-c38035fe0e78.png)

編集するpyファイルを指定するため、コンテナ内のディレクトリを指定する。

![Screenshot from 2023-03-05 14-07-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/d1c18339-3e79-c923-cf3b-f4862f35fd40.png)

OKを押すと、その中の全ファイルが表示されるので所望のものを選択する。

![Screenshot from 2023-03-05 14-09-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/8408ca3f-297a-c38d-41dd-00ccd3f08ce2.png)

このままではデバッグモードにならない。
Host OSでもVSCodeを初めてインストールしたときと同じように、コンテナの環境でもVSCodeの実行が初めてとなるため機能拡張をインストールする。

![Screenshot from 2023-03-05 14-11-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/72a08d46-876a-d87f-14b7-b2eab1138cf6.png)

これで開発環境の準備は終わり。
VSCodeで編集した内容はもちろんマウント元であるHost OSのディレクトリにそのまま反映される。

runで起動したコンテナのterminalは`exit`するだけでコンテナがstopする。


## 4. 開発を再開するとき

VSCodeを起動すると前回の環境がコンテナだったことを記憶しているためか、下図が表示される。
"Start Container"を選択すると、勝手に`docker start`してくれる。VSCodeを閉じてもこのコンテナはstart状態なので、terminalから必要に応じて`docker stop`させなければならない。


![Screenshot from 2023-03-05 15-29-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/671a73fa-c4c7-2cfe-e8d1-7869715dcafb.png)

terminalを起動したければコンテナはあるのでstartしてterminalをアタッチする。

```python
docker start --name test_1
docker exec -it text_1 bash
```

start状態にexecでアタッチしたので、このterminalをexecしてもコンテナはstart状態のまま。

## 番外（Docker Hubの全Tagの確認）
Docker Hubに置かれているオフィシャルのtagは[Stack Overflow](https://stackoverflow.com/questions/24481564/how-can-i-find-a-docker-image-with-a-specific-tag-in-docker-registry-on-the-dock?noredirect=1&lq=1)によると下記で確認可能。

```terminal
curl -s -S 'https://registry.hub.docker.com/v2/repositories/library/ubuntu/tags/' | jq '."results"[]["name"]' |sort

"focal"
"focal-20230301"
"jammy"
"jammy-20230301"
"kinetic"
"kinetic-20230217"
"latest"
"lunar"
"lunar-20230301"
"rolling"

docker run -it ubuntu:focal bash
```

タグはバージョン番号ではなくコードネームになっている。コンテナを作ってみたけど、最小構成で心もとなかったので使用していない。

以上