minimumgo: Linuxでgolangの実行ファイルをひとつだけ動かすときに必要最小限の初期化処理をしてくれるgolangのパッケージ

# はじめに
[gokrazy](https://qiita.com/tetsu_koba/items/aa2d245a61db98299a89) や [dockerでの実験](https://qiita.com/tetsu_koba/items/acd969494d58d7638b57)で最小限のルートファイルシステムはどういうものかがわかってきました。次はそれを最もシンプルに実装するにはどうするのがよいかを考えました。
そしてたどりついたのが、初期化処理に必要なことを全てパッケージのinit()の中で済ませてしまおうということです。
それをgithubに置きました。

https://github.com/tetsu-koba/minimumgo

なお、dockerで動かす場合にはこのパッケージは不要です。このパッケージでやっていることはdockerが自動でやってくれます。
「追加ファイル」の章だけ参考にしてください。


# minimumgoパッケージの使い方

githubのREADME.md も見てください。

## インストール

```
go get github.com/tetsu-koba/minimumgo
```

## 使い方

実行したいgolangのプログラムのmain()を含むソースコードで、以下のようにこのパッケージをブランクインポートします。

```
import _ "github.com/tetsu-koba/minimumgo"
```

パッケージの初期化はimportに書いた順番に行われます。このパッケージの初期化が一番最初に行われるように、この行は他のimportよりも上に書いて下さい。
[サンプル](https://github.com/tetsu-koba/minimumgo/blob/master/example/httpfileserver/httpfileserver.go)

```go:example/httpfileserver/httpfileserver.go
package main

// This should be imported at first
import _ "github.com/tetsu-koba/minimumgo"

import (
	"log"
	"net/http"
)

func main() {
	log.Fatal(http.ListenAndServe(":80", http.FileServer(http.Dir("/"))))
}
```

これを `go build` して、initとして動かします。実行ファイルを/sbin/init という名前でルートファイルシステムに置くか、カーネルパラメータに `init=` を追加してその実行ファイルがinitとして扱われるようにしてください。

[example/initramfs](https://github.com/tetsu-koba/minimumgo/tree/master/example/initramfs)ではRaspberry Pi用にinitramfsのイメージを作って動かす方法を説明しています。

## カーネルパラメータの指定

### ネットワークの設定

`ip=dhcp` をつけてください。
### 時刻設定サーバの指定

時刻を教えてもらうのに、ntpとrdate(ポート37のtime protocol)のどちらかが使用できます。(time protoclは秒単位の精度のため、精度の面ではntpが優位です)
`minimumgo.ntp`
ntpサーバを指定します

`mimimumgo.rdate`
time protocolを提供しているサーバを指定します。

カーネルパラメータの例

```
console=serial0,115200 ip=dhcp minimumgo.ntp=ntp.nict.jp
```

## 追加ファイル

最小限としてはgolangの実行ファイルをひとつ入れておくだけで動かすことができます。
ただし、時刻はUTCのみでTLS(暗号化通信)は使用できません。
hostnameを指定する場合は /etc/hostname を追加してください。
ローカルタイムで時刻を扱いたい場合は /etc/localtime を追加してください。
それ以外のタイムゾーンも扱いたい場合は /usr/share/zoneinfo/ 以下のファイルを用意してください。
TLS(暗号化通信)を行うためには/etc/ssl/certs/ 以下の証明書のファイルが必要です。

これらの追加ファイルに関しては、[example/initramfs/build.sh](https://github.com/tetsu-koba/minimumgo/blob/master/example/initramfs/build.sh) を参考にしてください。

こちらのメモも参考にしてください。
[golangのruntimeからアクセスする/etcのファイル](https://qiita.com/tetsu_koba/items/d9447eadf9c419264603)

# gokrazy との比較

gokrazyはそれなりに実用性を考慮して作られていますし、いくつかの[作例](https://gokrazy.org/showcase.html)もあります。
それに対して、miminumgoはどこまで小さくできるかを探求したものです。

## 共通点

- どちらも実行ファイルがgolangで書かれたものだけでルートファイルシステムを作成できる。
- カーネルモジュールをロードするしくみは無い。(必要なものはカーネルにビルトインしておく必要がある)
- デバイスの抜き差しのイベントを扱わない。(通常のLinuxシステムだったらudevが担当していること)

## 相違点

### initプロセス
gokrazy はinitが独立したプロセスとして存在して、WebUIでプロセスの状態を見たり、プロセスが終了したときに再起動してくれる。
minimumgo ではユーザの実行ファイルが唯一のプロセスになる。新たなプロセスを生成することは可能であるが、それが終了したときの処理はユーザーに一任されている。また、initとして起動されたプロセス(つまり pid=1)が終了してしまうとカーネルパニックになる。(pid=1 のプロセスは終了してはいけない。)

### IPアドレスの取得
gokrazyではDHCPクライアントの動作を行うデーモンがいる。
minimumgoでは、カーネルパラメータに `ip=dhcp` をつけてカーネルの機能に任せている。

### 現在時刻の取得
gokrazyではNTPデーモンが定期的に時刻の再設定を行う。
miminumgoでは最初に一度だけntpまたはrdateで時刻設定を行う。

### ブートイメージの生成
gokrazyではgokr-packerというコマンドが用意されている。これはRaspberry Pi 3 専用。(64bit armのコードを生成する)
miminumgoではそこまでのコマンドは無い。
[example/initramfs](https://github.com/tetsu-koba/minimumgo/tree/master/example/initramfs)でRaspberry Pi 1/2/3/Zero 用にinitramfsのイメージを作って動かす方法の説明がある。