Docker Private Registry + Mirror + Web UI

私はいつも Vagrant を使って boot2docker や CoreOS をローカルマシンに VM として立てて、いろいろテストしています。

で、テストの度に VM を再構築して、テストで使う Docker のイメージを Docker Hub からダウンロードすることになるんですが、遅い回線だと大変イライラします。

まあ、ローカルマシンは回線もメモリも制約があるから、クラウド使えよって話なんですが。。。

他の案としては、ローカルに Docker Registry を立てて、そこに置けばいいんじゃないのってことですよねー

が、最近 Docker Registry Mirror の存在を知って、これは！
ってなったので、使ってみることにしました。

Docker Hub のイメージをそのまま使いつつ、一度ダウンロードしたイメージはミラーにキャッシュされるので、次回からは超速で `docker pull` 出来るぜー！

使い方は簡単で、こちらに載っております。
https://github.com/docker/docker/blob/master/docs/sources/articles/registry_mirror.md

しかも、Docker Private Registry の機能もそのまま使える設定も出来るんですね。

さらに、ここまで書いて２、３日置いておいたんですが、
https://github.com/kwk/docker-registry-frontend
を発見して、[試した](http://qiita.com/yungsang/items/32a1637036396bad0da7)ので、一気にまとめることにしました。

### 例によって Vagrant でお手軽に立てる Vagrantfile も作りました。

https://github.com/YungSang/docker-registry-mirror

```rb:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

DOCKER_REGISTRY    = "docker-registry-mirror"
DOCKER_REGISTRY_UI = "docker-registry-frontend"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "docker-registry-mirror"

  config.vm.box = "yungsang/boot2docker"

  config.vm.network :private_network, ip: "192.168.33.201"

  config.vm.network :forwarded_port, guest: 2375, host: 2375, disabled: true

  config.vm.synced_folder ".", "/vagrant"

  config.vm.provision :shell do |sh|
    sh.inline = <<-EOT
      docker rm -f #{DOCKER_REGISTRY} 2> /dev/null || true
      docker rm -f #{DOCKER_REGISTRY_UI} 2> /dev/null || true
    EOT
  end

  config.vm.provision :docker do |d|
    d.run "#{DOCKER_REGISTRY}",
      image: "registry",
      args: "-p 5000:5000 -e MIRROR_SOURCE=https://registry-1.docker.io -e MIRROR_SOURCE_INDEX=https://index.docker.io -e SQLALCHEMY_INDEX_DATABASE=sqlite:////tmp/registry/docker-registry.db -v /vagrant/registry:/tmp/registry"
    d.run "#{DOCKER_REGISTRY_UI}",
      image: "konradkleine/docker-registry-frontend",
      args: "-p 80:80 --link #{DOCKER_REGISTRY}:#{DOCKER_REGISTRY} -e ENV_DOCKER_REGISTRY_HOST=#{DOCKER_REGISTRY} -e ENV_DOCKER_REGISTRY_PORT=5000"
  end

  config.vm.provision :shell, run: "always" do |sh|
    sh.inline = <<-EOT
      IS_RUNNING=$(docker inspect --format '{{.State.Running}}' #{DOCKER_REGISTRY} 2> /dev/null)
      if [ "$IS_RUNNING" != "true" ] ; then
        docker start #{DOCKER_REGISTRY}
      fi
      IS_RUNNING=$(docker inspect --format '{{.State.Running}}' #{DOCKER_REGISTRY_UI} 2> /dev/null)
      if [ "$IS_RUNNING" != "true" ] ; then
        docker start #{DOCKER_REGISTRY_UI}
      fi
    EOT
  end
end
```

### 起動

```
$ git clone https://github.com/YungSang/docker-registry-mirror.git
$ cd docker-registry-mirror
$ vagrant up
```

Web UI は http://192.168.33.201/ でアクセス出来ます。
この IP アドレスは Vagrantfile 内の以下の行で設定を変更出来ます。

```rb
  config.vm.network :private_network, ip: "192.168.33.201"
```

### 使う側の Docker デーモンの設定はそれぞれの OS に依存するので、サンプルを用意しました。

- [boot2docker 用](https://github.com/YungSang/docker-registry-mirror/blob/master/samples/boot2docker/Vagrantfile)

- [CoreOS 用](https://github.com/YungSang/docker-registry-mirror/blob/master/samples/coreos/Vagrantfile)

- [Fedora Atomic 用](https://github.com/YungSang/docker-registry-mirror/blob/master/samples/atomic/Vagrantfile)

### 使い方

まず、上記サンプルの一つを使ってミラーのテストをしてみます。

```
$ cd samples/boot2docker
$ vagrant up
$ docker pull yungsang/busybox
```

これでミラーを通してイメージがダウンロードされ、ローカルにキャッシュされます。
場所は `registry/images` の下です。ローカルマシンのフォルダーでも入っているのが確認出来ると思います。

```
$ docker rmi yungsang/busybox
$ docker pull yungsang/busybox
```

と、一度消してプルし直すと違いがわかると思います。

次に、Private Registry の機能をテストします。

```
$ docker tag yungsang/busybox 192.168.33.201:5000/busybox
$ docker push 192.168.33.201:5000/busybox
```

Private 用のアドレスのタグ Prefix を付けてプッシュします。
これで Private のレジストリに登録されます。
イメージは先程のものと同じなので増えませんが、`registry/repositories` の下に `library/busybox` が作られているのがわかると思います。
Web UI でも http://192.168.33.201/#/repository/library/busybox/ に現れるはずです。

### 工夫したところ

1. Vagrant の Synced Folder を使ってレジストリの永続化をしていますが、その Synced Folder は VM のブート後に設定されるので、`docker run --restart=alway` をやっても再起動時に上手くフォルダーを使えません。
そこで、今回の Vagrantfile では `--restart=alway` を使わずに、手動で再起動しています。これで、`vagrant destory & up` や `vagrant reload`、`vagrant provision` でもちゃんと意図した通りに動くようになりました。

2. Docker 公式の `registry` イメージのデフォルトでは、検索用のバックエンドに SQLite が使われていますが、パスが `/tmp/docker-registry.db` になっているので、registry 用のフォルダと別になっているので、このままでは永続化の時に上手く行きません。
そこで、`-e SQLALCHEMY_INDEX_DATABASE=sqlite:////tmp/registry/docker-registry.db` とし、registry 用フォルダーである `/tmp/registry/` の下に持ってくることによって、問題無く永続化＋ポータブルにすることが出来ました。