CLOVER🍀

That was when it all began.

Sonatype Nexus 3のDockerレジストリーをDocker Hubのミラーとして使う

これは、なにをしたくて書いたもの?

Dockerデーモンの設定に、Docker Hubのミラーが設定できることを知ったので、Sonatype NexusでDockerレジストリーを
作成して使ってみることにしました。

Docker Hubのミラーを設定する

Docker Hubのミラー設定に関するドキュメントはこちら。

Mirror | Docker Docs

このページでは次の2つの設定が書かれています。

今回はDockerレジストリーとしてSonatype Nexusを使い、Docker Hubのミラーとして設定してみます。

Sonatype Nexusでは、Docker Hubへのプロキシリポジトリーを含むものとします。

環境

今回は次の2つのサーバーで確認を行います。

flowchart LR
        subgraph Host1/192.168.33.10
          A["docker"]
        end
        subgraph Host2/192.168.33.11
          A -- "HTTP" --> B["Sonatype Nexus"]
        end

192.168.33.10のサーバーのDocker。

$ vagrant ssh -c bash
[fog][WARNING] Unrecognized arguments: libvirt_ip_command
vagrant@host1:~$ docker version
Client: Docker Engine - Community
 Version:           28.3.3
 API version:       1.51
 Go version:        go1.24.5
 Git commit:        980b856
 Built:             Fri Jul 25 11:34:09 2025
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          28.3.3
  API version:      1.51 (minimum version 1.24)
  Go version:       go1.24.5
  Git commit:       bea959c
  Built:            Fri Jul 25 11:34:09 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.27
  GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da
 runc:
  Version:          1.2.5
  GitCommit:        v1.2.5-0-g59923ef
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

192.168.33.11ではSonatype Nexus 3.82.0-08が稼働しているものとします。

Dockerレジストリーの作成は、Terraformで行うことにします。

$ terraform version
Terraform v1.12.2
on linux_amd64

Sonatype NexusにDockerレジストリーを作成する

まずはSonatype NexusにDockerレジストリーを作成しましょう。

main.tf

terraform {
  required_version = "v1.12.2"

  required_providers {
    nexus = {
      source  = "datadrivers/nexus"
      version = "2.6.0"
    }
  }
}

provider "nexus" {
  username = "admin"
  password = "admin123"
  url      = "http://192.168.33.11:8081"
  insecure = true
}

resource "nexus_security_realms" "this" {
  active = [
    "NexusAuthenticatingRealm",
    "DockerToken",
  ]
}

resource "nexus_repository_docker_proxy" "dockerhub" {
  name   = "docker-dockerhub-proxy"
  online = true

  docker {
    force_basic_auth = false
    v1_enabled       = false
  }

  docker_proxy {
    index_type = "HUB"
  }

  storage {
    blob_store_name                = "default"
    strict_content_type_validation = true
  }

  proxy {
    remote_url       = "https://registry-1.docker.io"
    content_max_age  = 1440
    metadata_max_age = 1440
  }

  negative_cache {
    enabled = true
    ttl     = 1440
  }

  http_client {
    blocked    = false
    auto_block = true
  }
}

resource "nexus_repository_docker_hosted" "this" {
  name   = "docker-hosted"
  online = true

  docker {
    force_basic_auth = false
    http_port        = 5000
    v1_enabled       = false
  }

  storage {
    blob_store_name                = "default"
    strict_content_type_validation = true
    write_policy                   = "ALLOW"
  }
}

resource "nexus_repository_docker_group" "group" {
  name   = "docker-group"
  online = true

  docker {
    force_basic_auth = false
    http_port        = 15000
    v1_enabled       = false
  }

  group {
    member_names = [
      nexus_repository_docker_hosted.this.name,
      nexus_repository_docker_proxy.dockerhub.name,
    ]
  }

  storage {
    blob_store_name                = "default"
    strict_content_type_validation = true
  }
}

Dockerクライアントから直接アクセスするDockerレジストリーには、ポートを割り当てています。

  docker {
    force_basic_auth = true
    http_port = 5000
    v1_enabled       = false
  }


  docker {
    force_basic_auth = true
    http_port        = 15000
    v1_enabled       = false
  }

これを指定しない場合、Sonatype Nexusがリッスンしているポートを使うのですが、アクセスする時のパスに
Dockerレジストリー名が入ってしまいます。これはDockerクライアントからは受け入れられないので、代わりに専用の
ポートを指定することになります。

Docker Registry / Port Connectors

あと、force_basic_authfalseにしておいて匿名アクセスを有効にしているのですが、以下がないと未ログインでのpullが
うまくいかず、とてもハマりました…。

resource "nexus_security_realms" "this" {
  active = [
    "NexusAuthenticatingRealm",
    "DockerToken",
  ]
}

Realms

では、リソースを作成。

$ terraform init
$ terraform apply

Dockerクライアントから使う

では、Dockerクライアントから使ってみましょう。

HTTPでアクセスするので、insecure-registriesに登録しておきます。

/etc/docker/daemon.json

{
  "insecure-registries": [
    "192.168.33.11:5000",
    "192.168.33.11:15000"
  ]
}

dockerd | Docker Docs

Dockerデーモンを再起動。

$ sudo systemctl restart docker

未ログインでDockerイメージをpullしてみます。

$ docker image pull 192.168.33.11:15000/nginx:1.29.0-bookworm

OKですね。

$ docker image ls
REPOSITORY                  TAG               IMAGE ID       CREATED       SIZE
192.168.33.11:15000/nginx   1.29.0-bookworm   2cd1d97f893f   2 weeks ago   192MB

Docker Hostedレジストリーにログイン。

$ docker login 192.168.33.11:5000
Username: admin
Password:

WARNING! Your credentials are stored unencrypted in '/home/vagrant/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded

先ほどpullしたDockerイメージのタグをつけ直します。

$ docker image tag 192.168.33.11:15000/nginx:1.29.0-bookworm 192.168.33.11:5000/nginx:1.29.0-bookworm

push。こちらはログイン必須です。

$ docker image push 192.168.33.11:5000/nginx:1.29.0-bookworm

うまくいきました。

The push refers to repository [192.168.33.11:5000/nginx]
f17478b6e8f3: Pushed
0662742b23b2: Pushed
5c91a024d899: Pushed
6b1b97dc9285: Pushed
a6b19c3d00b1: Pushed
30837a0774b9: Pushed
7cc7fe68eff6: Pushed
1.29.0-bookworm: digest: sha256:3651f5785567a226fd58e33adcfb27b41a83ba0c3649d9ee9ac590acd97bad51 size: 1778

Docker GroupレジストリーをDocker Hubのミラーとして使う

次は今回のお題です。Docker GroupレジストリーをDocker Hubのミラーとして使ってみましょう。

daemon.jsonファイルにregistry-mirrorsを追加し、Docker GroupレジストリーのURLを追加します。

/etc/docker/daemon.json

{
  "insecure-registries": [
    "192.168.33.11:5000",
    "192.168.33.11:15000"
  ],
  "registry-mirrors": [
    "http://192.168.33.11:15000"
  ]
}

dockerd | Docker Docs

Dockerデーモンを再起動。

$ sudo systemctl restart docker

ApacheのDockerイメージを、Docker Hubからpullしてみます。

$ docker image pull httpd:2.4.65-bookworm

この時、Sonatype Nexusのログを確認してみます。

$ tail -f sonatype-work/nexus3/log/request.log

すると、最初のリクエストは未ログインとなっているものの、その後にanonymousユーザーでDockerイメージのpullが
できていることがわかります。

192.168.33.10 - - [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/ HTTP/1.1" 401 - 113 11 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-20]
192.168.33.10 - - [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/token?scope=repository%3Alibrary%2Fhttpd%3Apull&service=http%3A%2F%2F192.168.33.11%3A15000%2Fv2%2Ftoken HTTP/1.1" 200 - 60 11 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-148]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "HEAD /repository/docker-group/v2/library/httpd/manifests/2.4.65-bookworm HTTP/1.1" 200 - 0 23 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-88]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/manifests/sha256:fbc12199ccad031d8047e9c789d65aceee2d14f99ba90664cd3a3996867a5582 HTTP/1.1" 200 - 10160 27 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-145]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/manifests/sha256:cc4c94eb4e9c3d94ac2147cb9ce8057096362de83fa12b7aeecd4c0c3d5d1f21 HTTP/1.1" 200 - 2095 21 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-20]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:5bdbc621ec089f8137cf0fdd49caa16748854c8c72739e794d1c2c9ab88dfed7 HTTP/1.1" 200 - 7883 33 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-147]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:c02ce4e0ebb3594adf5979faef0f7a23c3ec1a1e8810d6395dc92927064550e0 HTTP/1.1" 200 - 146 33 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-20]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 HTTP/1.1" 200 - 32 38 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-160]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:fc61fad0f5407d576719977190667f34c33556d8e7b9a57acf4407d93e822e9b HTTP/1.1" 200 - 4208310 50 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-88]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:644bfd3d7e686c06dc8c06f517c9aafd1e06867545b3b6d8737ff3a492ed9fb7 HTTP/1.1" 200 - 295 49 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-20]
192.168.33.10 - anonymous [02/Aug/2025:10:54:52 +0000] "GET /repository/docker-group/v2/library/httpd/blobs/sha256:e7b83145b2097d99a6c7a096934f9ef9f7b6f2818863e20c2652b05f42c1bcb4 HTTP/1.1" 200 - 26067888 79 "docker/28.3.3 go/go1.24.5 git-commit/bea959c kernel/6.8.0-71-generic os/linux arch/amd64 UpstreamClient(Docker-Client/28.3.3 \\(linux\\))" [qtp1529159609-150]

OKですね。

$ docker image ls
REPOSITORY                  TAG               IMAGE ID       CREATED       SIZE
httpd                       2.4.65-bookworm   5bdbc621ec08   9 days ago    148MB
192.168.33.11:15000/nginx   1.29.0-bookworm   2cd1d97f893f   2 weeks ago   192MB
192.168.33.11:5000/nginx    1.29.0-bookworm   2cd1d97f893f   2 weeks ago   192MB

おわりに

Sonatype Nexus 3で作成したDockerレジストリーを、Docker Hubのミラーとして使ってみました。

ミラーという機能自体を知らなかったので、いい機会になりましたね。

Sonatype NexusのDockerレジストリーでの匿名アクセスについてはだいぶハマったので、別エントリーでメモしておこうと
思います…。