Docker とVisual Studio Code を使った Go (Golang) 開発環境構築

Golang の開発環境を Docker と Visual Studio Code で約 3 分で構築する手順を解説します

Docker と Visual Studio Code を組み合わせて開発環境を準備する利点については
次の記事を参照してください:

- [【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code](https://futureys.tokyo/lets-develop-program-without-installing-language-by-docker-and-vscode/)

開発のためのエディターとして Visual Studio Code を利用する利点については
次の記事を参照してください:

- [ファイルやプログラムの編集には Visual Studio Code を使おう | ultra code](https://futureys.tokyo/lets-use-visual-studio-code-for-editing-file-or-program/)

この手順で開発環境が構築できる理屈については次の記事を参照してください:

- [【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code](https://futureys.tokyo/lets-develop-program-without-installing-language-by-docker-and-vscode/)

## あらかじめインストールしておくアプリケーション

- [Docker Desktop](https://docs.docker.com/desktop/#download-and-install)
- [Visual Studio Code](https://code.visualstudio.com/download)
    - [Remote Development 拡張機能](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)

Golang のインストールは必要ありません

## 手順

手順内の解説はなるべく省いており、詳細の解説はすべての手順の後に用意してあります

### 1. Docker Compose のためのファイル準備

プロジェクトフォルダーを新規作成、Visual Studio Code で開き、次の 2 つのファイルを新規作成します:

```text
project/
+---Dockerfile
+---docker-compose.yml
```

```docker:Dockerfile
FROM golang:1.17.0-bullseye
# Visual Studio Code Remote Development 拡張機能がデフォルトで開くディレクトリーであるため
WORKDIR /workspace
# 2021-06-10 時点で Visual Studio Code でコードのフォーマットや Lint などの支援を受けるのに必要なモジュール
# モジュール未インストール時に Visual Studio Code を開き、次のコマンドで一覧表示されたものです:
# Ctrl + Shift + P -> Go: Install/Update Tools
RUN go get github.com/uudashr/gopkgs/v2/cmd/gopkgs
RUN go get github.com/ramya-rao-a/go-outline
RUN go get github.com/cweill/gotests/...
RUN go get github.com/fatih/gomodifytags
RUN go get github.com/josharian/impl
RUN go get github.com/haya14busa/goplay/cmd/goplay
RUN go get github.com/go-delve/delve/cmd/dlv
# div-dap のインストール方法は次のドキュメントを参考にしました:
# https://github.com/golang/vscode-go/blob/v0.26.0/docs/dlv-dap.md#updating-dlv-dap
RUN GOBIN=/tmp/ go get github.com/go-delve/delve/cmd/dlv@master \
 && mv /tmp/dlv $GOPATH/bin/dlv-dap
RUN go get github.com/golangci/golangci-lint/cmd/golangci-lint
RUN go get golang.org/x/tools/gopls
```

```yaml:docker-compose.yml
version: "3.8"
services:
  golang:
    build: .
    image: yourrepository/golang:development
```

### 2. Developing inside a Container のための設定ファイルの追加

Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック
-> [Remote-Containers: Add Development Container Configuration Files…] をクリック:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267233/8c2edc41-3065-75eb-6f93-994d17a01ab0.png)
すると、どのように設定を作成するかを尋ねるメニューが表示されるので、
[From ‘docker-compose.yml’] をクリック:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267233/ea55eb7f-3fa5-fb5a-b5af-e07ffd8ba576.png)
すると次のファイルが追加されます:

```text
project/
+---.devcontainer/
    +---devcontainer.json
    +---docker-compose.yml
```

### 3. 拡張機能や Lint の設定を追加

.devcontainer/devcontainer.json に設定を追加します:

```diff_jsonnet:.devcontainer/devcontainer.json
- 	"settings": {},
+ 	"settings": {
+ 		"go.lintTool": "golangci-lint",
+ 		"go.lintFlags": [
+ 			"--fast"
+ 		]
+ 	},

// ~~~

- 	"extensions": []
+ 	"extensions": [
+ 		"golang.go"
+ 	]
```

コピー & ペースト用:

```jsonnet
	"settings": {
		"go.lintTool": "golangci-lint",
		"go.lintFlags": [
			"--fast"
		]
	},
```

```jsonnet
	"extensions": [
		"golang.go"
	]
```

参考:

- [Integrations | golangci-lint](https://golangci-lint.run/usage/integrations/)
- [Go with Visual Studio Code](https://code.visualstudio.com/docs/languages/go)

### 4. コンテナーを起動して Visual Studio Code で開く

Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック
-> [Reopen in Container] をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267233/0cd30c43-aa76-355d-cd32-e9817acfe733.png)

### 5. Golang プロジェクトの初期化

ターミナルを開き、次のようにコマンド実行:

```console
go mod init <repository path>
```

例:

```console
go mod init github.com/yukihiko-shinoda/hello-world-golang
```

※ リポジトリーのパスは後から変えることもできます

すると、ファイル: `go.mod` が作成されます

### 6. 利用することがわかっているパッケージを依存関係としてファイル: `go.mod` に追加

例: AWS SDK (https://github.com/aws/aws-sdk-go-v2) の場合:

```console
go get -d github.com/aws/aws-sdk-go-v2
```

※ または、コードに import 文を書いてから、
　 コマンド: `go mod tidy` でファイル: `go.mod` に反映させることもできます

### 7. コーディング開始

例:
ファイル `hello_world.go` を作成:

```golang:hello_world.go
package main

import "fmt"

func main() {
    fmt.Println("hello world")
}
```

直接実行して動作確認:

```console
go run hello_world.go
```

次のコマンドで、main パッケージの main() を実行可能:

```console
go run .
```

参考: [Go by Example: Hello World](https://gobyexample.com/hello-world)

## 解説

Docker と Visual Studio Code による開発環境構築の基本的な理屈については
次の記事を参照してください:

- [【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code](https://futureys.tokyo/lets-develop-program-without-installing-language-by-docker-and-vscode/)

ここでは Golang 特有の内容について解説します

### Dockerfile について

#### `FROM golang:<tag>`

Golang は公式イメージが提供されています
Golang 以外に必要なツールが特にない場合はこのイメージを使うと良いでしょう:
[Golang - Official Image | Docker Hub](https://hub.docker.com/_/golang)

タグの意味なども上記 Docker Hub の [Description] タブに記載されていますので
さらっと確認しておきましょう

#### `RUN go get <package>`

これらのモジュールを環境にインストールしないと
Visual Studio Code で Golang のコードフォーマットや Lint などの支援を受けることができません

ちなみに、インストールしなかった場合、
Visual Studio Code がダイアログでインストールを促してくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267233/b2f81039-fafd-95f5-055d-2d8bca7c8917.png)
しかし、Dockerfile の RUN 命令を使わずにインストールした場合は
環境を再構築することになった時、
必ずこれらのモジュールをインストールし直す時間を浪費することになります

Dockerfile にインストールするよう記載しておいた方が
環境を再構築することになった際も時間が節約できる可能性が高くなるのでおすすめです
(Docker は構築の結果をキャッシュするため)

参考: [Best practices for writing Dockerfiles | Docker Documentation](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache)