Mac上にDockerでDebian, C/C++開発環境を構築する

# はじめに
　業務でLinuxプログラミングに手を出すことになりました。長年、Windowsプログラミングの世界にいたのでプログラミング環境構築というとWindowsマシーンにVisual Studioをインストールしてツール上でポチポチやって終わりだったのですが、Linuxプログラミングはそうもいかないようです。ということで、まずはLinuxとビルドできる環境を用意することにしました。また、今回は同じ開発環境を開発チーム内で使い回すことを考えて、dockerを用いることにしました。
　というわけで、私自身が初心者ということもあり、記事の内容や表現も初心者向けになっています。間違いがありましたらご指摘いただけるとありがたいです。

# 環境
## ホストPC
 * macOS Catalina
 * Docker version 19.03.2
    * docker for macを https://hub.docker.com/ からダウンロードしてインストールしました。
    
## 構築したい開発環境
 * Linuxディストリビューション Debian 9.2
 * gcc, g++などのC/C++コンパイル環境
 * zshとテーマ（oh-my-zsh)
　 

# Dockerイメージの作成
Dockerは、上記のような開発環境に必要なものを”コンテナ”と呼ばれる箱に入れておき、コンテナをホストPC上で動かす仕組み、というのがざっくりした説明です。
コンテナの素になるのがDockerイメージです。このコンテナの素であるDockerイメージをコピーしてコンテナが作られます。
Dockerイメージは[docker hub](https://hub.docker.com/)から取得したり、"Dockerfile"というイメージの設計図を作成して作ることもできます。

## イメージの設計図 Dockerfileの作成する
今回は、Dockerfileでイメージを構築することにしました。理由はDockerfileをメンテしていくことで今後チーム内で環境を改善していきやすいと考えたためです。
今回Dockerfile作成の際に[こちら](https://github.com/AlexisNo/docker-ubuntu-dev/blob/master/Dockerfile)をお手本にしました。ZSH_THEMEを"robbyrussell"からoh-my-zshのテーマである"candy"に置き換えるということを行っています。
`FROM debian:9.2`と記載すると、docker hubにあるdebian 9.2をベースにします。docker hubには様々なOfficial imageが用意されていて、ユーザはそれらを利用することができます。

```
FROM debian:9.2
MAINTAINER miyatada
WORKDIR /home/projects

# Install basic packages.
RUN apt-get update
RUN apt-get install -y gcc g++ make
RUN apt-get install -y software-properties-common zsh curl wget git htop unzip vim telnet less
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install oh-my-zsh and define zsh as default shell
RUN wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true &&\
    chsh -s /bin/zsh

# Apply custom theme, disable auto-update and fix backspace displaying space in the prompt
RUN sed -i 's/ZSH_THEME="robbyrussell"/ZSH_THEME="candy"/g' /root/.zshrc &&\
    sed -i 's/# DISABLE_AUTO_UPDATE=true/DISABLE_AUTO_UPDATE=true/g' /root/.zshrc &&\
    echo TERM=xterm >> /root/.zshrc

CMD ["/bin/zsh"]
```

## Mac上でDockerfileをビルドしてイメージを作成する
Dockerfileが出来上がったら、ファイルがあるディレクトリ内で以下のコマンドを実行します。

```
$ docker image build -t debian-ccpp .
Sending build context to Docker daemon   2.56kB
Step 1/10 : FROM debian:9.2
 ---> 6d83de432e98
Step 2/10 : MAINTAINER miyatada
...
Successfully built a48bc5610306
Successfully tagged debian-ccpp:latest
```

debian-ccppという名前のdockerイメージが出来上がりました。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
debian-ccpp         latest              a48bc5610306        4 minutes ago       634MB
```

# Dockerイメージからコンテナを起動しよう
## コンテナの起動
先ほど作成したdockerイメージ`debian-ccpp`からコンテナを起動してみます。`docker run オプション image名 シェル`で起動できます。
`-v`オプションをつけるとホストPC上のディレクトリをコンテナ上のディレクトリにマウントできます。今回はホストPC上の`/Users/usr1/Documents/GitHub/`をコンテナ上の`/home/projects`にマウントしています。
シェルは`/bin/bash`でも問題ありません。お好みです。

```
$ docker run -itv /Users/usr1/Documents/GitHub/:/home/projects debian-ccpp /bin/zsh

root@720295dcd1ee [01:57:42] [/home/projects] 
-> # 
```

どんなコンテナが起動しているかは`docker ps`で確認できます。

```
 docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
720295dcd1ee        debian-ccpp         "/bin/zsh"          3 minutes ago       Up 3 minutes                            elegant_faraday
```

ちなみに、同じイメージでdocker runをもう一度実行すると、同じイメージから異なるコンテナが作成されます。IMAGEは同じですが、CONTAINER IDとNAMESが異なりますね。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
e7a880e5792a        debian-ccpp         "/bin/zsh"          7 seconds ago       Exited (0) 3 seconds ago                       busy_ptolemy
720295dcd1ee        debian-ccpp         "/bin/zsh"          24 minutes ago      Up 4 minutes                                   elegant_faraday
```

## コンテナを抜ける
`exit`でコンテナを抜けます。

```
root@720295dcd1ee [02:07:46] [/var/tmp] 
-> # exit
```

抜けると、STATUSが"Exited"になります。この状態ではコンテナは残っているので、再度入ることができます。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
720295dcd1ee        debian-ccpp         "/bin/zsh"          11 minutes ago      Exited (0) 50 seconds ago                       elegant_faraday
```

## 抜けたコンテナにもう一度入るには
以下のようにdocker startとdocker attachコマンドでもう一度入りたいコンテナのCONTAINER IDを指定してあげます。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
720295dcd1ee        debian-ccpp         "/bin/zsh"          14 minutes ago      Exited (0) 4 minutes ago                       elegant_faraday
$ docker start 720295dcd1ee
720295dcd1ee
$ docker attach 720295dcd1ee
root@720295dcd1ee [02:13:00] [/home/projects] 
-> # 
```

コンテナを削除しなければ、コンテナ内で編集したり追加したファイルは保持されます。
以下はそれを確認するための実験です。timestampファイルを作ってから、exitで抜けて再度コンテナに入ってtimestampファイルがあることを確認できました。

```
root@720295dcd1ee [02:16:42] [/var/tmp] 
-> # ls
root@720295dcd1ee [02:16:43] [/var/tmp] 
-> # date > timestamp
root@720295dcd1ee [02:17:00] [/var/tmp] 
-> # cat timestamp 
Mon Oct 14 02:17:00 UTC 2019
root@720295dcd1ee [02:17:03] [/var/tmp] 
-> # ls -ltr
total 4
-rw-r--r-- 1 root root 29 Oct 14 02:17 timestamp
root@720295dcd1ee [02:17:15] [/var/tmp] 
-> # exit
$ docker start 720295dcd1ee
720295dcd1ee
root@720295dcd1ee [02:17:25] [/home/projects] 
-> # cd /var/tmp
root@720295dcd1ee [02:17:42] [/var/tmp] 
-> # ls -ltr
total 4
-rw-r--r-- 1 root root 29 Oct 14 02:17 timestamp
root@720295dcd1ee [02:17:45] [/var/tmp] 
-> # cat timestamp 
Mon Oct 14 02:17:00 UTC 2019
```

## コンテナの削除
ps rmコマンドでコンテナを削除します。削除すると、コンテナ内で編集したファイルも削除されます。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
e7a880e5792a        debian-ccpp         "/bin/zsh"          7 seconds ago       Exited (0) 3 seconds ago                       busy_ptolemy
720295dcd1ee        debian-ccpp         "/bin/zsh"          24 minutes ago      Up 4 minutes                                   elegant_faraday
$ docker rm e7a880e5792a
e7a880e5792a
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
720295dcd1ee        debian-ccpp         "/bin/zsh"          28 minutes ago      Up 8 minutes                            elegant_faraday
```
# まとめ
Mac上にDockerで Debian, C/C++開発環境を構築しました。また、その際に使うdockerコマンドの使い方を記載しました。今後はこれをベースに開発環境をブラッシュアップしていきたいと思っています。