【golang】DockerでGoの開発環境を構築する

:::note info
当コンテンツと同様の記事を Zenn でも公開しています。
:::

https://zenn.dev/yusuke49/articles/9ed37838861b1d


Goでボイラープレートを作っていくのですが、その際にDockerを利用して環境構築をしました。
## こんな方におすすめ
- Goで開発を進めていきたいけど極力自分のPC環境を汚したくない
- go module を利用する
- 一つのアプリ開発を通して、Go以外にもnodeやRDBなどの他の技術も必要になる

## 前提
Dockerとdocker-composeが用意できている前提で進めていきます。
Macならターミナルで、WindowsならPowerShellで以下のコマンドを叩くと確認できます。
```
<!-- Macの場合 -->
$ docker --version
$ docker-compose --version

<!-- Windowsの場合 -->
$ docker version
$ docker-compose version
```

# Docker
Dockerとは、コンテナ技術を利用して、迅速に仮想環境を構築できる
オープンプラットフォームのことです。
> Docker is an open platform for developing, shipping, and running applications.
> Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. 
> Docker streamlines the development lifecycle by allowing developers to work in standardized environments using local containers which provide your applications and services.
> 
> (訳)Dockerとは、アプリケーションを開発・配置・実行するためのオープンプラットフォームです。
> アプリケーションをインフラから分離できるため、ソフトウェアを迅速に提供できます。
> Dockerを利用することで、開発者がアプリケーションとサービスを提供するローカルコンテナを使用して標準化された環境で作業できるようになるので、開発ライフサイクルを合理化できます。
> 
> 引用: [Docker overview | Docker Documentation](https://docs.docker.com/get-started/overview)

つまり、コンテナ仮想化を用いたOSレベルの仮想化により、アプリケーションを開発・実行環境から切り離し、アプリケーションを素早く開発・提供できるということです。

## コンテナ作成
まず、ディレクトリを作成します。
今回ディレクトリ名を**BoilerPlateDevEnv**としました。
ボイラープレートの環境ファイルなども配置していくため、**DevEnv**を付けています。
```
$ mkdir BoilerPlateDevEnv
```
続いてディレクトリ構成は以下のようにします。
```
.
├── build
│   ├── .go_env
│   └── Dockerfile
├── boiler-plate
│   └── cmd
│      └── hello
│         └── main.go
├── docker-compose.yml
```
:::note info
[Standard Go Project Layout](https://github.com/golang-standards/project-layout/blob/master/README_ja.md) に則ったディレクトリ構成にしています。
Goプロジェクトにおいてスタンダードとなるプロジェクト構成の説明がなされています。
:::
### build
コンテナの作成や、Goプロジェクトの環境ファイルなどを配置するディレクトリです。

### Dockerfile
DockerHubから取得するイメージや開発に合わせた基本的な設定を行います。
このDockerfileを元にイメージが作成されます。

```docker:Dockerfile
# goバージョン
FROM golang:1.19.1-alpine
# アップデートとgitのインストール
RUN apk update && apk add git
# boiler-plateディレクトリの作成
RUN mkdir /go/src/github.com/boiler-plate
# ワーキングディレクトリの設定
WORKDIR /go/src/github.com/boiler-plate
# ホストのファイルをコンテナの作業ディレクトリに移行
ADD . /go/src/github.com/boiler-plate
# パッケージのインポート
RUN go get -u golang.org/x/tools/cmd/goimports
```
FROMには[Docker Hub](https://hub.docker.com/_/golang)の公式イメージを指定します。
Goは2022年8月にリリースされた最新バージョンの 1.19.1[^1] にします。 
今回は、alpineベースのイメージを選択しました。他と比べて余計なものが入っていないため、非常に容量が小さく、軽量なイメージを構築できるからです。

> Alpine Linux is much smaller than most distribution base images (~5MB), and thus leads to much slimmer images in general.
> 
> (訳)Alpine Linuxは、ほとんどのディストリビューションベースイメージ(~5MB)よりもはるかに小さいため、イメージが非常に軽量になります。
> 
> 引用: [Docker Hub | golang:\<version\>-alpine](https://hub.docker.com/_/golang)

下記コマンドの`apk update`で利用可能なパッケージのインデックスを最新化し、`apk add`で指定したパッケージの追加をしています。 (今回はgitを追加)
```docker
# アップデートとgitのインストール
RUN apk update && apk add git
```

:::note alert
alpineベースのイメージは軽量性を追求し、gitやbashなどのツールが搭載されていません。
そのため、apkコマンドでgitをインストールする必要があります。

> To minimize image size, additional related tools (such as git, gcc, or bash) are not included in Alpine-based images.
> 
> (訳)イメージ容量を最小化するために、git、gcc、そしてbashなどの関連ツールは Alpineベースのイメージには含まれていません。
> 
> 引用: [Docker Hub | golang:\<version\>-alpine](https://hub.docker.com/_/golang)
:::

### docker-compose.yml
今後RDBやnodeなどの複数のコンテナを立てることを想定し、当ファイルを作成します。
他のコンテナ同士の接続や環境などの設定ができます。
> Compose is a tool for defining and running multi-container Docker applications.
> Then, with a single command, you create and start all the services from your configuration.
> 
> (訳)Composeは、複数コンテナのDockerアプリケーションを定義して実行するためのツールです。
> そして、1つのコマンドで、構成からすべてのサービスを作成し、開始することができます。
> 
> 引用: [Overview | Docker Documentation](https://docs.docker.com/compose/)

```yaml:docker-compose.yml
version: '3' # composeファイルのバージョン
services:
  boiler-plate: # サービス名
    container_name: boiler-plate
    build: # ビルドに使うDockerファイルのパス
      context: .
      dockerfile: ./build/Dockerfile
    volumes: # マウントディレクトリ
      - ./boiler-plate:/go/src/github.com/boiler-plate
    tty: true # コンテナの永続化
    env_file: # .envファイル
      - ./build/.go_env
    environment:
      - TZ=Asia/Tokyo
```
### .go_env
Goプロジェクトの環境ファイルです。
今のところは一旦、GOPATHを通しておくだけにします。
```.env:.go_env
GOPATH=/go
```

## イメージのビルド
**docker-compose.yml**まで作成できたら、以下のコマンドを実行し、イメージをビルドする。
```
$ docker-compose build
```
以下のようにメッセージが表示されれば、ビルド完了です。
```
Successfully built b005943411b4
Successfully tagged boilerplatedevenv_boiler-plate:latest
```
一応以下コマンドでイメージができているか確認できます。
```
$ docker images
REPOSITORY                       TAG       IMAGE ID       CREATED         SIZE
boilerplatedevenv_boiler-plate   latest    b005943411b4   4 minutes ago   368MB
```

## main.goの作成
main.goファイルに以下を記述し、実行時に「Hello World」と表示させるようにします。
```go:main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}
```

## コンテナの起動
以下コマンドを実行し、先ほど作成したイメージをもとにコンテナを起動します。
```
$ docker-compose up -d
```
:::note info
`-d`オプションをつけ、バックグラウンドで起動しています。
:::
一応以下のコマンドでコンテナが起動できているか確認できます。
```
$ docker ps
CONTAINER ID   IMAGE                            COMMAND     CREATED          STATUS          PORTS                    NAMES
4bb4f03cfc30   boilerplatedevenv_boiler-plate   "/bin/sh"   13 minutes ago   Up 13 minutes                            boiler-plate
```

## 動作確認
コンテナの起動が確認できたら、以下のコマンドでコンテナの中に入ります。
```
$ docker exec -it boiler-plate /bin/sh
```
:::note info
`/bin/sh`コマンドで入っていますが、`ash`でも入れます。
:::
そして、作成したmain.goのあるhelloファイルまで移動し、実行します。
```
$ cd cmd/hello
$ go run main.go
```
`Hello World`と表示されていれば、成功です。
```
Hello World
```


[^1]: 当記事を公開した2022年9月時点