ラズパイで Docker のお勉強をする話の導入編

# 自己紹介
社会人一年目、SIer になった豆腐です。
よろしくお願いします。

私の配属先はクラウドを使ったシステム開発をいかにうまく回すかを研究しているところで、新人の私には**マイクロサービスだったり Site Reliability Engineering（SRE）がどういうものでどうして最近の流行りなのかを自分なりに理解しなさい**というお触れが出ました。

Docker も使ったことがないのでとりあえず触ってみるかという気持ちで、先輩から借りた [Docker/Kubernetes 実践コンテナ開発入門](https://www.amazon.co.jp/Docker-Kubernetes-%E5%AE%9F%E8%B7%B5%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-%E5%B1%B1%E7%94%B0-%E6%98%8E%E6%86%B2/dp/4297100339) を読んでいます。

どの OS で Docker を動かそうかなと考えたときに、家に使っていないラズパイ（Raspberry Pi3 Model B+）があったことを思い出したので、なんとなくこいつでやってみることにしました。
ちなみに先輩や上司からは「リソースが貧弱なので Docker を動かすのはおすすめしないが、まぁ好きにすればいいんじゃないか」みたいに言われました。

# ラズパイの設定と Docker のインストール
## PC からラズパイへの ssh <sup>[1](#関連記事)</sup>
ラズパイの OS は [raspbian buster lite（Kernel version : 4.19）](https://www.raspberrypi.org/downloads/raspbian/) を入れました。
同じネットワーク上の PC から ssh できるように、まずは Wi-Fi のコンフィグを追記。
ルートディレクトリに wpa_supplicant.conf ファイルを作成してラズパイを起動すれば、勝手に Wi-Fi 関連のコンフィグが設定されてくれます。

```wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="たとえばatermなんちゃらみたいなSSID名"
    psk="ぱすわーど"
}
```

続いて、ssh できるように、ルートディレクトリに空の ssh ファイルを作成します。

```:console
$ touch ssh
```

これでラズパイへの初期設定は終わり。ラズパイに電源を繋いで起動したら PC からラズパイに ssh できるようになっているはずです。
私の場合、PC は Windows だったので Git Bash から ssh することにしました。

```:console
$ ssh pi@raspberrypi.local
```

初期パスワードは`raspberry`です。
ssh できたら hostname と password を変更しておきました。
以下、ラズパイのコンソール上では hostname が blackpi になっています。

あとこれが私の、自分の脳が Ryzen7 だと勘違いしているラズパイちゃんです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Ryzen7（大嘘）
![Qiita](https://pbs.twimg.com/media/EDcTxpjVAAAjHhI?format=jpg&name=4096x4096)<a href=""></a></p>&mdash; とうふめんたるちきんはーと (@BlueTofuchic) 
<a href="https://twitter.com/BlueTofuchic/status/1168424380289798145?ref_src=twsrc%5Etfw">September 2, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Docker のインストール
[公式 DOC の debian でのチュートリアル](https://docs.docker.com/install/linux/docker-ce/debian/)を参考にしました。
[Docker のダウンロード元](https://download.docker.com/)に飛ぶと、linux 下にちゃんと raspbian 用が用意されているので、それに合わせます。

```:console
pi@blackpi:~ $ sudo apt-get update
pi@blackpi:~ $sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
pi@blackpi:~ $ curl -fsSL https://download.docker.com/linux/raspbian/gpg | sudo apt-key add -
pi@blackpi:~ $ sudo add-apt-repository "deb [arch=armhf] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable"
（省略）
aptsources.distro.NoDistroTemplateException: Error: could not find a distribution template for Raspbian/buster
```

にゃーん:crying_cat_face:
便利なスクリプトがあるのでそちらを利用。（最初からこっちでいいかもですね。）

```:console
pi@blackpi:~ $ curl -fsSL https://get.docker.com -o get-docker.sh
pi@blackpi:~ $ sudo sh get-docker.sh
```

こいつを動かしたら、細かい設定から Docker のインストールまでを一気にやってくれるみたいです。

```:console
pi@blackpi:~ $ docker -v
Docker version 19.03.1, build 74b1e89
```

Docker のバージョンが表示されたら、インストールが完了しています。

# 公開されている Docker イメージのダウンロード

```:console
pi@blackpi:~ $ docker image pull gihyodocker/echo:latest
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/images/create?fromImage=gihyodocker%2Fecho&tag=latest: dial unix /var/run/docker.sock: connect: permission denied
```

**permission denied** ！？
公開されているのでは！？

と思いましたが、[公式 DOC の debian でのチュートリアル](https://docs.docker.com/install/linux/docker-ce/debian/)にちゃんと書いてありました。

> If you would like to use Docker as a non-root user, you should now consider adding your user to the “docker” group with something like:
>> ```:sh
sudo usermod -aG docker your-user
```

どうやらラズパイ側のユーザ名を`docker`というグループに属させないといけないらしいです。

```:console
pi@blackpi:~ $ sudo usermod -aG docker pi
```

これで`pi`というユーザが`docker`グループに属したはず。
一応、次のコマンドで確認できます。

```:console
pi@blackpi:~ $ groups pi
pi : pi adm dialout cdrom sudo audio video plugdev games users input netdev spii2c gpio docker
```

一度 exit して ssh し直してから改めて pull してみたらうまく行きました。

```:console
pi@blackpi:~ $ docker image pull gihyodocker/echo:latest
latest: Pulling from gihyodocker/echo
723254a2c089: Pull complete
abe15a44e12f: Pull complete
409a28e3cc3d: Pull complete
503166935590: Pull complete
abe52c89597f: Pull complete
ce145c5cf4da: Pull complete
96e333289084: Pull complete
39cd5f38ffb8: Pull complete
22860d04f4f1: Pull complete
7528760e0a03: Pull complete
Digest: sha256:4520b6a66d2659dea2f8be5245eafd5434c954485c6c1ac882c56927fe4cec84
Status: Downloaded newer image for gihyodocker/echo:latest
docker.io/gihyodocker/echo:latest
```

この Docker イメージを実行してみようと思います。

```:console
pi@blackpi:~ $ docker container run -t -p 9000:8080 gihyodocker/echo:latest
standard_init_linux.go:211: exec user process caused "exec format error"
```

う～ん。
なんだこれは、とググってみたところ、どうやら armhf で起動できる Docker イメージじゃなかったみたいです。

> dockerを最初に使うときにはシンボルの「クジラ」のイメージwhalesayを試すのが通例である。<sup>[2](#関連記事)</sup>

```:console
pi@blackpi:~ $ docker run docker/whalesay cowsay boo
standard_init_linux.go:211: exec user process caused "exec format error"
```

ラズパイで試す用の Docker イメージとかないんですかね！？

# Docker イメージの作成とコンテナの実行

適当にディレクトリを作り、以下の二つのファイルを作成します。

```main.go
package main

import (
        "fmt"
        "log"
        "net/http"
)

func main(){
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
                log.Println("received request!")
                fmt.Fprintf(w, "Hello Docker!!")

        })

        log.Println("start server")
        server := &http.Server{Addr: ":8080"}
        if err := server.ListenAndServe(); err != nil{
                log.Println(err)
        }
}
```

```:Dockerfile
FROM golang:1.9

RUN mkdir /echo
COPY main.go /echo

CMD ["go", "run", "/echo/main.go"]
```

Hello World の Docker 版ですね。
Docker イメージを作成します。

```:console
pi@blackpi:~/workspace $ docker image build -t example/echo:latest .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM golang:1.9
1.9: Pulling from library/golang
a92bc499a469: Pull complete
d56e34dc5db4: Pull complete
948d2574fcb0: Pull complete
94ced04c5b3f: Pull complete
15b6302ebab8: Pull complete
d0e894008a35: Pull complete
c3d193845877: Pull complete
73ae9a06dd32: Pull complete
Digest: sha256:8b5968585131604a92af02f5690713efadf029cc8dad53f79280b87a80eb1354
Status: Downloaded newer image for golang:1.9
 ---> aa7ee0df9721
Step 2/4 : RUN mkdir /echo
 ---> Running in c6994624af15
Removing intermediate container c6994624af15
 ---> 00bca3e272ba
Step 3/4 : COPY main.go /echo
 ---> a7a96f63ecad
Step 4/4 : CMD ["go", "run", "/echo/main.go"]
 ---> Running in 1904e2193002
Removing intermediate container 1904e2193002
 ---> 53ac562e0136
Successfully built 53ac562e0136
Successfully tagged example/echo:latest
```

ダウンロードまたは作成した Docker イメージは~~`docker container ls -a`か`docker ps -a`~~`docker images ls`か`docker images`で確認できるようです。
作成した Docker イメージを元にバックグラウンドでコンテナを実行してみます。
`-p 9000:8080`というのは、ホスト側ポート 9000 に来た通信をコンテナポート 8080 にポートフォワーディングさせるという意味です。

```:console
pi@blackpi:~/workspace $ docker container run -d -p 9000:8080 example/echo:latest
6fb7ba7a5f95761799eb2eb6313ed81c67bddd3925cb10513819d5ebb6dc584b
```

`docker container ls -a`か`docker ps -a`でコンテナが確認できます。
`-a`を外すと実行中の Docker イメージのみ表示されます。
`PORTS`にポートフォワーディングの設定もしっかり記述してあります。
また、`NAMES`を引数に取ることでコンテナを停止させられるので見ておくと良いです。

```:console
pi@blackpi:~/workspace $ docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                    NAMES
6fb7ba7a5f95        example/echo:latest   "go run /echo/main.go"   9 seconds ago       Up 4 seconds        0.0.0.0:9000->8080/tcp   keen_meninsky
```

Hello Docker!!

```:console
pi@blackpi:~/workspace $ curl http://localhost:9000
Hello Docker!!
```

お片付け。

```:console
pi@blackpi:~/workspace $ docker container stop keen_meninsky
keen_meninsky
```


# 関連記事
1. [Raspberry Piの無線LANをmicroSDで設定する](https://qiita.com/mascii/items/0d1a280ac58ed8f6f999)
1. [Jetson NanoでDockerを動かす(前編)](https://qiita.com/yamamo-to/items/33f57f9a059cc95b9c08)