crane rebase作業記録

昨日書いた記事([docker image rebase作業記録](https://qiita.com/wwbQzhMkhhgEmhU/items/4166248cf26e614d03ff))で使っていたdocker image rebaseがobsoleteになってたので、それが取り込まれたというgo-containerregistryを調査することにしました。この中で、rebaseが実際に出来るのは、crane rebaseみたいなので、今回はそれを試してみる。

# go-containerregistryとは[^go-containerregistry]
googleが作成したコンテナレジストリをいじるためのライブラリ(ツールも付属してた)。元はcontainerregistryというpythonのツール。今回はこの中から、gitのrebaseの感覚で、dockerのimageをrebase(実際にはlayerの置き換え)してくれるcrane rebaseを使用する。

# 動機
例えばapacheのイメージを目的別に何個も作成したいとき、ベースとなるイメージを元に、その派生物として目的別のイメージを作成すると、レイヤが使い回されて容量が減ると思う。しかし、その後パッケージが古くなってaptやyumなどでそれぞれのイメージを更新すると、目的別のイメージの数分同じようなレイヤが作成されてしまう。

これを、ベースとなるイメージの更新だけで済ませられないか？つまり、rebaseできないか？ということで調べてみた。

# 作業環境
- VirtualBox上のUbuntu 18.10
- Docker 18.09
- Docker Registry 17.09(TLSあり&Basic認証でDocker Clientはlogin済)

※Registryがないとrebaseできません

# 作業概要
元のツール(docker image rebase)には超分かりやすい絵がついていたが、obsoleteになった瞬間readmeからその絵も消えてしまい、新しいツール(crane rebase)には絵がなかったので、こちらにリンクを載せておく。

https://github.com/google/image-rebase/blob/0018cb875047e316c378ec9930423928c4d32271/rebase.png

こういうことをしたいので、パラメータに必要なイメージと以下の手順で作成し、rebaseする。

1. privateなDocker Registryにdebianイメージをpush(originalとしてタグ付け)
2. originalからコンテナを起動して、終了してcommit/push(v1_baseとしてタグ付け)
3. v1_baseからコンテナを起動し、コンテナの中に/home/test/touchという空ファイルを作成して終了してcommit/push(v1としてタグ付け)
4. originalからコンテナを起動し、xxxをインストールして終了してcommit/push(v2_baseとしてタグ付け)
5. crane rebaseを使用して、v1_base,v1,v2_baseから、v2としてタグ付けされるイメージを作成する
6. 確認

# 作業内容

## (1)Docker Registryにdebianイメージをpush(original)

Docker Hubからdebian:latestをpull

```console
$ docker pull debian
```

Docker Registry(便宜上example.comとする)上のイメージ(my-debian:original)としてタグ付けしてpush

```console
$ docker tag debian example.com/my-debian:original
$ docker push example.com/my-debian:original
```
## (2)originalからコンテナを起動して、終了してcommit/push(v1_base)

```console
$ 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)

```console
$ 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)

```console
$ 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)crane rebaseを使用して、v2作成

### (5)-1. golangインストール

```console
$ sudo apt install golang-go
```
### (5)-2. craneインストール

```console
$ go get -u github.com/google/go-containerregistry/cmd/crane
```

※以降では環境変数などが未設定で、```$HOME/go/```にインストールされていると仮定

### (5)-3. 自己証明書の配置(必要であれば)

今回docker registryで用意したのは自己証明書なので、証明書を/etc/docker/certs.d/*辺りに入れてあった。
しかし、ここを見るのはdockerだけなので、Ubuntuの一般的な証明書登録手順[^証明書登録手順]を踏む。

```console
$ 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. crane rebase実行

```console
$ ~/go/bin/crane 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)確認

```console
$ 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が動けば成功。
→成功

# 結論
google様万歳

[^docker image rebase]: [docker image rebase](https://github.com/google/image-rebase)
[^証明書登録手順]: https://askubuntu.com/questions/645818/how-to-install-certificates-for-command-line
[^go-containerregistry]: [go-containerregistry](https://github.com/google/go-containerregistry)