開発環境を作るためにDockerを使った話


こちらは[ラクス Advent Calendar 2018](https://qiita.com/advent-calendar/2018/rakus)箸休めの４日目です。

仕事でもプライベートでもあまりコードを書いていないので、
そろそろ何か開発をしたいなぁと思い始めました。

そうなると開発環境を整えていく必要が出てくるわけなのですが、
ローカルのPCに新しく環境を準備するのもやだなぁと思ってしまいました。

そこで、楽にどこでも開発ができると便利だなぁ
なんかDockerで開発環境ってよく聞くけど正直よくわかってないなぁ。。。
Dockerやってみよ！というのがことの動機です。

今回は簡単なDockerの紹介と手軽にできる開発環境の構築についてです。
非常に今更かつ、新規性がない話かと思いますが、お付き合いいただければと思います。

# Dockerって？
[Docker](https://www.docker.com/why-docker)は、コンテナ型の仮想環境を作成、配布、実行することができるプラットフォームです。

仮想環境というと仮想マシンを思い浮かべることが多いかと思いますが、
仮想マシンの場合は、ハードウェアを仮想化し、その中でOSやアプリケーションなどを動作させるといったことを行います。
対して、コンテナ型の仮想環境の場合は、コンテナ技術を使い実行環境を他のプロセスから隔離し、その中でアプリケーションを動作させることができます。
また、コンテナはプロセスとして実行されるため、それぞれ固有の設定を持つことができます。
<img width="587" alt="スクリーンショット 2018-12-03 21.09.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/195788/0d6d902f-4c63-6422-dbf8-9ef3bd22a98e.png">

Dockerを利用するメリットは以下の点です。

- ミドルウェアのインストールや各種環境設定をコード化して管理することができる。
- コード化したファイルを共有することで、誰にでもOSを気にせず同じ環境を作ることができる。
- スクラップ＆ビルドが簡単にできる

このような特徴を活かすことで、開発環境として使っていた環境をそのまま本番環境で利用したり、環境設定をコード化したものを共有することで開発環境の準備に時間を費やすことがなくなる
といったことができるみたいです。

今回は[さくらのナレッジ](https://knowledge.sakura.ad.jp/13265/)のDocker入門を学習に利用させていただきました。
Dockerの使い方といった部分は割愛しますが、初心者の私が学習してみた所感を載せておきます。

- いいとこ
  - Dockerイメージが公開されている「[Docker Hub](https://hub.docker.com/)」のお影で、簡単に使いたいコンテナを用意できる
  - 自身で作成した各種環境設定をDockerFileとして管理することで、別の場所でも簡単に構築ができる
  - コンテナを削除してしまえば、手軽に一からやり直しできる
- よくなかったとこ
  - コンテナの停止、Dockerイメージの削除などが面倒・・・
  - Dockerイメージ・コンテナが簡単に作れてしまうだけにきちんと管理しておかないとどんどん増やしてしまう


# 簡単なGolangの開発環境を作ってみる。
元々の目的である開発環境の構築をやってみようと思います。
以下のようなものを想定して作成しようと思います。

このような構成を作ろうと思うと複数のDockerイメージ・コンテナを用意し、起動や停止を管理しなければいけません。
Dockerのみでやってみるとこれが意外と大変でした。。。

今回はそんな課題を簡単にしてくれる「[Docker Compose](https://docs.docker.com/compose/)」を利用して、[Golang](https://golang.org/)の開発環境を作ってみます。
Golangを選んだところには特に意味はありません。（強いていうならDockerがGolangで書かれているので、とでもしておきます）

### 準備

Docker Composeを利用するためにはディレクトリ構成を整えておく必要がありますので、以下のように構築しておきます。

```
<任意のディレクトリ>
|-- Dockerfile
|-- docker-compose.yml
|-- main.go
```

それぞれのファイルは以下のように作成します。
##### docker-compose.yml

```docker-compose.yml
version: '3'
services:
  app:
    build: .
```

`build`は`Dockerfile`の配置しているディレクトリを指定しています。
その他の記載の詳細は[公式のリファレンス](http://docs.docker.jp/compose/compose-file.html)をご覧ください。
##### Dockerfile

```Dockerfile
#ベースのDockerイメージをgolangで指定
FROM golang:latest
#ワークディレクトリを設定する
WORKDIR /go
#ホストのディレクトリを/go配下にコピー
ADD . /go
#main.goを実行
CMD ["go", "run", "main.go"]
```
簡単にコメントに記載しましたが、詳細については例のごとく[公式のリファレンス](https://docs.docker.com/engine/reference/builder/)をご覧ください。

##### main.go

```main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go World")
}
```
見ての通り`Hello, Go World`を出力するのみですね。
golangの学習はこれからなのでご容赦を・・・
### 実行
あとは`docker-compose.yml`と同じ階層で`docker-compose build`を実行することで、Dockerイメージが作成されます。
作成後は以下のように2つのDockerイメージが作成できているかと思います。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
app_app             latest              07d424d7d085        3 minutes ago       774MB
golang              latest              df6ac9d1bf64        2 weeks ago         774MB
```
あとは`docker-compose up`を実行しコンテナを作成することで、

```
$ docker-compose up
Starting app_app_1 ... done
Attaching to app_app_1
app_1  | Hello, Go World
app_app_1 exited with code 0
```
やりました。`main.go`が実行できました。
main.goを編集して再度実行するときは`docker-compose build`とすることで、すでにpullしているDockerイメージはそのままで、Dockerfileを参考にしてイメージをbuildすることで編集したmain.goが反映されます。

今後は「DockerとDocker Composeとディレクトリ構成」があればどこでもGolangを書いて実行できそうです。
ディレクトリはGitに上げておけば管理もできるのでさらにお手軽ですね。
**「これは…いいものだ！」**

# 初心者あるある？小一時間悩んだ話
さて、無事Golangの開発環境は出来上がったわけですが、いい感じにしょうもないところで詰まってしまったので紹介しようと思います。
今回詰まったエラーはこいつです。

```txt
Service 'app' failed to build: pull access denied for go, repository does not exist or may require 'docker login'
```

`docker login`もしたし、`docker pull`でgolangのDockerイメージpullできたんだけどなぁ。。。と思っている中、
勘のいい人はすぐにお分かりでしょう。

DockerもDocker Composeも初心者な私は小一時間悩み、ようやく気づきました。
pullしなきゃいけないのは「go」じゃない「golang」であると・・・
**「golang」であると**

そうです。
間抜けなことに、はじめDockerfileを下のように書いていました。

```
FROM go:latest　#goなんてないよ

WORKDIR /go
ADD . /go

CMD ["go", "run", "main.go"]
```
こんなことをしていれば当然「repository does not exist」と言われるわけです。。。
非常に悲しい気持ちになりましたが、おかげさまで「docker-compose.yml」と「Dockerfile」の関係性が少しわかったような気がします。
**「これが、若さか」**

# まとめ
はじめは開発環境を整えたいというところから手をつけたDockerですが、環境構築の手軽さに少し驚きました。


Dockerではもちろんプロセス間通信もできますのでDBを別のコンテナにしたり、APIサーバを別コンテナにしてみたりするなど、もう少し「アプリケーションらしく」してやりたいなと思っています。
（何を作るのかは全く決まっていませんが。。。）
もっと理解が深まれば[Kubernetes](https://kubernetes.io/)なんかにも手を出せればと思います。

明日以降も**ラクス Advent Calendar 2018** お楽しみに