docker上にgoの環境作れたと思ったけど補完ツールとかがなくて困ったので改善した話

6 min読了の目安(約6200字TECH技術記事

以前dockerを使ってgoの環境構築dockerを使ってgoの環境構築(DBと接続), docker上にgoの環境作れたと思ったけど作れていなかった話を書きました。これでgoを使ってサーバを作れるぞと意気込み作業を始めたのですが切り分けたモジュールに対して読み込んだファイルで補完が効かなかくてめちゃくちゃやりづらくて困ったので書き残します。
具体的には以下を解決します。

  • コンテナ上では問題なく動作するファイルに対してvscodeがエラーを示す。
  • vscodeでの開発で入力補完が効かない(特に自作モジュール)。

vscodeを使っている人には参考になるかもしれません。

RemoteContainers

インストール

remote containersはvscodeの拡張機能でDockerコンテナ上でvscodeを開くことができます。なのでエラーや入力補完などをコンテナの環境に合わせて吐いてくれます。

インストールは簡単で、vscodeのエクステンションから'remote container'で検索し、出てきたものをインストールするだけです。

remote-containerのインストール

インストールしたら、左下に緑のアイコンが出てくるのでそこから設定していきます。

緑のアイコン

設定

緑のアイコンを押すと以下のように一覧が出てくるので
Remote-Containers:Add Developement Container Configration Files...
を選択し設定ファイルを作成します。
設定1

すると次にどのファイルを元に設定ファイルを作成するか聞いてきます。今回ですとdocker-compose.ymlを元に作るコンテナなので
From 'docker-compose.yml'
を選択します。
設定2

複数のサービスがある場合どちらのサービスを元に作成するかを聞いてきます。今回はワーキングディレクトリが'app'なので'app'を選択します。ちなみに今回のdocker-compose.ymlは以下のようになります。

docker-compose.yml
version: "3"
services: 
    app:
        build: ./app/
        tty: true
        ports:
            - "8080:8080"
        volumes:
            - ./app:/go/src/app
        depends_on: 
            - mysql
            
    mysql:
        build: ./mysql/
        volumes:
            - ./mysql/init:/docker-entrypoint-initdb.d
            - ./mysql/data:/var/lib/mysql
        environment: 
            - MYSQL_ROOT_PASSWORD=golang
            # -  TZ=Asia/Tokyo
        ports:
            - "3306:3306"
        container_name: mysql-container

すると以下のように設定ファイルが作成されます。

$ tree -a
.
├── .devcontainer
│   ├── devcontainer.json
│   └── docker-compose.yml

重要なのはdevcontainer.jsonです。docker-compose.ymlは削除して構いません。作成されたファイルを以下のように書き換えます。

devcontainer.json
{
	"name": "Existing Docker Compose (Extend)",
	"dockerComposeFile": [
        "../docker-compose.yml"
        // "/docker-compose.yml"は使用しないので削除
	],
    // vscodeで開くコンテナ
    "service": "app",
    // マウンティング先のディレクトリを指定
    "workspaceFolder": "/go/src/app",
    // 各種セッティング
    "settings": {
        "terminal.integrated.shell.linux": "/bin/sh",
        "go.gopath": "/go",
        "go.inferGopath": true,
        "go.useLanguageServer": true
    },
    // コンテナ内で使用するエクステンションの指定
	"extensions": [
	    "golang.go",
	    "wholroyd.jinja"
	]
}
  • 各種セッティングのところはよく分からなければ上をそのまま写していいと思います。
  • 使用するエクステンションはエクステンションのIDを指定します。IDの名前が分からない時は以下のように歯車マークからAdd to devcontainer.jsonを選ぶと自動でextensionsに書き込まれます。エクステンションの追加

緑のアイコンを押して
Remote-Containers: Open Folder in Container...
でディレクトリを指定して開きましょう。指定するディレクトリは特別な理由がなければ'docker-compose.yml'を置いているディレクトリになると思います。

設定ファイルで指定したappディレクトリではなく'docker-compose.yml'でコンテナを立ち上げるディレクトリを選択しましょう。

初めての起動だとイメージの取得などが入るので時間がかかるかもしれません。上手くいくと"workspaceFolder"に指定したディレクトリのファイル一覧を読み込んだvscodeが立ち上がります。

立ち上げの際のビルドの状況をログで確認することもできます。初めての立ち上げ時はエラーが出ることもあるので表示しながら立ち上げるといいと思います。

補完ツールのインストール

この状態だと補完機能等はまだインストールされていない状態です。エクステンションに'golang.go'を読み込んでいますが、これはおそらくgoの補完機能などをvscodeに反映させるためのもので補完機能自体は'gopls'や'guru', 'golint'などが提供しています。これらは、これまでにインストールしてきたパッケージと同じように go getで取得するものになります。

それでは手順を説明していきます。

まずcommand + shift + P(macの場合)で入力ボックスを開いてGo: Install/Update Toolsを選択します。

以下のようにインストールする機能の一覧が出てくるので必要なものにチェックを入れて'OK'を押します。分からない場合は全てにチェックを入れましょう。ただし、gocodegocode-gomodは代わりとなるgoplsがあるのでインストールする必要はないようです。一応それぞれ簡単な説明を入れておきます。

  • dlv
    デバッガ
  • godef
    定義情報の参照、ジャンプ
  • gopkgs
    インポート可能なパッケージのリストを表示
  • go-outline
    JSON表現を抽出するためのシンプルなユーティリティ
  • go-symbols
    ワークスペースシンボル検索
  • golint
    Linter
  • goplay
    Webインターフェース
  • goreturns
    余分なimportを消す、必要なimportを追加する、フォーマットを揃える、function 内で戻り値に合わせた return の補完(zero value)をしてくれる
  • impl
    インターフェースを実装するためのメソッドスタブ生成
  • fillstruct
    構造体のフィールド初期化を行うリファクタリングツール
  • gomodifytags
    golang の struct にタグを付ける
  • gopls
    コードの自動補完補完ツール
  • gotests
    特定のソースファイルまたはディレクトリ全体のテスト生成
  • godoctor
    リファクタリング支援ツール
  • gorename
    変数名や関数名のリネーム等ができるリファクタリングツール
  • guru
    ソースコードの静的解析など行うツール

補完機能のインストール

'OK'を押すとシェルが走ると思います。インストールが終わったらgo/binを見てみてください。以下のように選択した機能がインストールされていると思います。

/go/bin # ls
dlv           go-symbols    golint        goplay        goreturns     impl
fillstruct    godef         gomodifytags  gopls         gotests       realize
go-outline    godoctor      gopkgs        gorename      guru

私は試していませんがgo getで取得しても問題ないと思います。

コンテナの更新

DockerのコンテナはDockerfileを元に作られたイメージを元に立ち上げられるので、そのままだとコンテナを落とした時に補完ツールのインストールで行った作業が消えてしまいます。
そのためコンテナのイメージを今の状態に更新する必要があります。

別のターミナルを開いてまず立ち上がっているコンテナを確認しましょう。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
7bf8827150fa        08go_db_app         "realize start"          About an hour ago   Up 3 minutes        0.0.0.0:8080->8080/tcp              08go_db_app_1
ae2d4ac8e7be        08go_db_mysql       "docker-entrypoint.s…"   About an hour ago   Up 3 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql-container

今回やりたいのは'08go_db_app'というイメージを今立ち上がっている'7bf8827150fa'というコンテナの状態にアップデートすることです。アップデートはdocker commitコマンドでできます。

$ docker commit 7bf8827150fa 08go_db_app
sha256:16946147685a7bf4a40c25711b97f59a3611d219ec2a35d4648d6a3c8c5c8a80

これで元になるイメージがアップデートされたので次回以降に再度インストールする必要はありません。
目的であったコード補完もしっかりやってくれています。

補完機能

最後に

これまでJavaScriptのライブラリである"react"などを使っていましたがエクステンションのインストールやcreate react appなどのコマンドでそのような補完機能も含めてよしなに環境を構築してくれていたので今回の静的解析や補完機能を自分で構築するのはとても良い経験になりました。

最近テストについてのZennの記事を見てテストのイメージが出来てきたので、次は単体テストをやってみようかなと思っています。