Dockerfileのテンプレートを作るCLIを作った話

2 min read読了の目安(約1900字

初めに

個人開発でDockerを使っているのですが、毎回Dockerfileを作るのが
めんどくさくなったのでテンプレを用意しました。

とりあえずソースコードです

https://github.com/komisan19/kuzira

使い方

initコマンドを叩くと空のDockerfileが作成でき、
createコマンド+言語を指定するとテンプレートの言語が作成されます。

$ kuzira init
$ ls Dockerfile 
Dockerfile

---

$ kuzira create go
create Dockerfile for Golang

仕組み

CLIは以下のライブラリを使っていますが、テンプレートはembedを使ってみました。

https://github.com/urfave/cli

go:embed

Go1.16から追加された機能です。
go:embed はその意味の通り埋め込みができます。1.16以前もosio/ioutilで読み込みなどできましたが、embedを使うとgo build時にバイナリに埋め込むことができます。

工夫点

上記でも記載しましたが、go:embedを使っています。
そのため、今回はこのような形でテンプレートファイルをおいて参照するようにしました。

.
├── README.md
├── action
│   ├── cli.go
│   └── cookbook
│       ├── go-dockerfile
│       └── python-dockerfile
---

cookbook内にテンプレートファイルを置くようにしました。
そしてcli.goにこのような形で書きました。

package action

import (
        "embed"
        "fmt"
        "github.com/urfave/cli"
        "log"
        "os"
)

//go:embed cookbook/*
var cookbook embed.FS

func Create(c *cli.Context) {
        switch os.Args[2] {
        case "go":
                rd, err := cookbook.ReadFile("cookbook/go-dockerfile")
                if err != nil {
                        log.Fatal(err)
                }
                err = os.WriteFile("Dockerfile", rd, 0644)
                if err != nil {
                        log.Fatal(err)
                }
                fmt.Println("create Dockerfile for Golang")
...
}

embedの特徴はここです

//go:embed cookbook/*
var cookbook embed.FS

//go:embed cookbook/*を指定することでその参照したいファイルを選択できます。
例えば//go:embed index.htmlとすることで実行ファイルのindex.htmlを参照することができます。参照ができたら、以下のように書くことでファイルの中身を読み込むことができます。

rd, err := cookbook.ReadFile("cookbook/go-dockerfile")

改善点

今後はこのあたりを改善していこうと思います。

  1. テンプレートが少ない(Go,pythonのみ)
  2. 言語が増えるとswitchが増えてしまう
  3. 自分でカスタマイズできない。

まとめ

久しぶりにCLIを作成したのですが、embedができてからテンプレートの埋め込みがだいぶ楽になりました。
まだまだ改善点が多いですが、今後もCLIを作っていこうと思います。