docker image rebase[^docker image rebase]というdocker公式でない個人(?)が作成したツールの使い勝手を試した記録。
docker image rebaseとは[^docker image rebase]
docker公式でない個人(?)が作成した実験段階のツール。
gitのrebaseの感覚で、dockerのimageをrebase(実際にはlayerの置き換え)してくれる模様。
ただ、コミットが2018/2/25〜2018/4/27の2ヶ月程度しかなく、誰も本格的に使っている様子がない。
今回の調査で正常系の100%再現するバグが見つかった。
→作者に問い合わせたら、obsoleteだからコッチ1ね、と言われた。(後日編集追加)
動機
例えばapacheのイメージを目的別に何個も作成したいとき、ベースとなるイメージを元に、その派生物として目的別のイメージを作成すると、レイヤが使い回されて容量が減ると思う。しかし、その後パッケージが古くなってaptやyumなどでそれぞれのイメージを更新すると、目的別のイメージの数分同じようなレイヤが作成されてしまう。
これを、ベースとなるイメージの更新だけで済ませられないか?つまり、rebaseできないか?ということで調べてみた。
作業環境
- VirtualBox上のUbuntu 18.10
- Docker 18.09
- Docker Registry 17.09(TLSあり&Basic認証でDocker Clientはlogin済)
※Docker Registryがないとrebaseできません
作業概要
- privateなDocker Registryにdebianイメージをpush(originalとしてタグ付け)
- originalからコンテナを起動して、終了してcommit/push(v1_baseとしてタグ付け)
- v1_baseからコンテナを起動し、コンテナの中に/home/test/touchという空ファイルを作成して終了してcommit/push(v1としてタグ付け)
- originalからコンテナを起動し、xxxをインストールして終了してcommit/push(v2_baseとしてタグ付け)
- docker image rebaseを使用して、v1_base,v1,v2_baseから、v2としてタグ付けされるイメージを作成する
- 確認
作業内容
(1)Docker Registryにdebianイメージをpush(original)
Docker Hubからdebian:latestをpull
$ docker pull debian
Docker Registry(便宜上example.comとする)上のイメージ(my-debian:original)としてタグ付けしてpush
$ docker tag debian example.com/my-debian:original
$ docker push example.com/my-debian:original
(2)originalからコンテナを起動して、終了してcommit/push(v1_base)
$ docker run -it --name my-debian example.com/my-debian:original
# exit
$ docker commit my-debian example.com/my-debian:v1_base
$ docker push example.com/my-debian:v1_base
$ docker container rm -v my-debian
(3)v1_baseに/home/test/touchという空ファイルを作成してcommit/push(v1)
$ docker run -it --name my-debian example.com/my-debian:v1_base
# mkdir /home/test
# touch /home/test/touch
# exit
$ docker commit my-debian example.com/my-debian:v1
$ docker push example.com/my-debian:v1
$ docker container rm -v my-debian
(4)v1_baseにslをインストールしてcommit/push(v2_base)
$ docker run -it --name my-debian example.com/my-debian:original
# apt update
# apt upgrade
# apt install sl
# /usr/games/sl
# exit
$ docker commit my-debian example.com/my-debian:v2_base
$ docker push example.com/my-debian:v2_base
$ docker container rm -v my-debian
(5)docker image rebaseを使用して、v2作成
(5)-1. golangインストール
$ sudo apt install golang-go
(5)-2. docker image rebaseインストール
$ go get -u github.com/google/image-rebase
※以降では環境変数などが未設定で、$HOME/go/
にインストールされていると仮定
(5)-3. 自己証明書の配置(必要であれば)
今回docker registryで用意したのは自己証明書なので、証明書を/etc/docker/certs.d/*辺りに入れてあった。
しかし、ここを見るのはdockerだけなので、Ubuntuの一般的な証明書登録手順2を踏む。
$ sudo mkdir /usr/local/share/ca-certificates/self
$ sudo cp example.com.crt /usr/local/share/ca-certificates/self/
$ sudo update-ca-certificates
※selfは何でもいい
(5)-4. docker image rebase実行
$ ~/go/bin/image-rebase \
--original=example.com/my-debian:v1 \
--old_base=example.com/my-debian:v1_base \
--new_base=example.com/my-debian:v2_base \
--rebased=example.com/my-debian:v2
(6)確認
$ docker run -it --name my-debian example.com/my-debian:v2
# ls -lAF /home/test # v1でのコミットの反映を確認
# /usr/games/sl # v2_baseでのコミットの反映を確認
# exit
$ docker container rm -v my-debian
/home/test/touchの存在が確認でき、slが動けば成功。
しかし冒頭に書いたとおり、バグのため、v1のコミットの反映を確認できなかった。
以下の修正を加えたところ、成功。
diff --git a/pkg/rebase/rebase.go b/pkg/rebase/rebase.go
index 0884ca9..975f60e 100644
--- a/pkg/rebase/rebase.go
+++ b/pkg/rebase/rebase.go
@@ -163,8 +163,8 @@ func (r Rebaser) Rebase(origStr, oldBaseStr, newBaseStr, rebasedStr string) erro
}
for i := range origLayers[len(oldBaseLayers):] {
rebasedImage, err = mutate.Append(rebasedImage, mutate.Addendum{
- Layer: origLayers[i],
- History: origConfig.History[i],
+ Layer: origLayers[i+len(oldBaseLayers)],
+ History: origConfig.History[i+len(oldBaseLayers)],
})
if err != nil {
return fmt.Errorf("failed to append layer %d of original layers", i)
結論
誰も使ってないものは危ないので使用しない方がいい。
→go-containerregistry1なんてモノがあるのでそれを調べてから。(後日編集追加)
→調べたので続き(後日編集追加)
[^docker image rebase]: docker image rebase