はじめに
Go言語の強みの一つにポータブル性があります。
Go言語はビルドをするとシングルバイナリになるため、ビルドしたバイナリをコンテナやらサーバーに持ち運ぶだけで簡単に実行できます。
多くのアプリケーションでは設定情報などをコンフィグファイルとして外出ししている場合がありますが、そのような場合はビルドしたバイナリファイルはコンフィグファイルに依存してしまって、デプロイ時にコンフィグファイルも一緒に持ち運ぶ必要が出てきます。
しかしgo:embedを使うことでコンフィグファイルもビルド時にバイナリに含めることができてしまうのです!
前提
- go1.16以上
ディレクトリ構成
プロジェクト全体を見たい人はGitHubに公開していますのでそちらをご覧ください。
コンフィグファイルの埋め込み方法
{
"logLevel": "DEBUG",
"server": {
"host": "localhost",
"port": 8080
}
}
今回はこのようなJSON形式の設定ファイルをバイト配列型の変数rawConfig
に埋め込みます。
embed
パッケージをブランクインポートして、埋め込みたい変数にgo:embed <ファイル名>
とコメントをするだけでファイルをバイナリとして埋め込むことができます。
import _ "embed"
//go:embed config.json
var rawConfig []byte
これでビルド時にrawConfig
にconfig.json
の中身が反映されます。
構造体に変換する
せっかくなので、埋め込んだJSONを構造体に変換して表示するところまでやってみましょう。
package config
import (
_ "embed"
"encoding/json"
"log"
)
//go:embed config.json
var rawConfig []byte
type Config struct {
LogLevel string `json:"logLevel"`
Server ServerConfig `json:"server"`
}
type ServerConfig struct {
Host string `json:"host"`
Port uint `json:"port"`
}
func (cfg Config) String() string {
m, err := json.Marshal(cfg)
if err != nil {
log.Fatalln(err)
}
return string(m)
}
func Load() (Config, error) {
cfg := new(Config)
if err := json.Unmarshal(rawConfig, cfg); err != nil {
return Config{}, err
}
return *cfg, nil
}
rawConfig
はJSON形式のデータなのでjson.Unmarshal()
を使って構造体に変換できます。
String()
メソッドは読み込んだConfig
を表示する際に見やすくするためにStringer Interfaceを実装しているだけなので気にしなくてOKです。
config.go
の実装が終わったら、実際に出力してみましょう。
package main
import (
"demo/config"
"log"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatalln(err)
}
log.Printf("config=%s", cfg)
}
動作確認
以下のコマンドでビルドすると、./build/show-config
というバイナリが生成されます。
$ go build -o ./build/show-config ./main.go
生成されたバイナリを実行するとちゃんとconfig.json
の内容が反映されていることがわかります。
$ ./build/show-config
2023/10/14 15:53:42 config={"logLevel":"DEBUG","server":{"host":"localhost","port":8080}}
さいごに
go:embedを活用して設定ファイルをビルド時のバイナリに含める方法を紹介しました。
今回はJSONを例に紹介しましたが、サードパーティのパッケージを使えばYAMLで記述された設定ファイルも同様に扱えると思います。
今回の記事が少しでも参考になれば幸いです。