CLOVER🍀

That was when it all began.

Sonatype Nexus Repository 3でDocker Registryを構築する際にPath-Based Routingを使う

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

Sonatype Nexus Repository 3ではDocker Registryを使うことができますが、以前はDocker Registryを作成する度にポートを
追加することになっていました。

3.83.0からはPath-Based Routingというものがデフォルトになっており、パスでのルーティングが可能になったようなので
1度試してみたいと思います。

Docker Registryとルーティング

Sonatype Nexus Repository 3でのDocker Registryに関するドキュメントはこちらです。

Docker Registry

見るべきはこちらですね。

Docker Registry / Understanding the Path to a Docker Repository

こちらに例が書かれていますが、通常docker pullを行う時には以下のように書きます。

$ docker image pull alpine:latest

## または
$ docker image pull registry-1.docker.io/library/alpine:latest

一方で、Sonatype Nexus Repository 3ではhttps://nexus.example/repository/docker-public/library/alpine:latestのような
URLでアクセスすることになります。つまり、URLパスにSonatype Nexus Repository 3の構造が露出します。

そしてDockerクライアントはイメージのパスに関して要件があり、リポジトリーのパスをDocker Registryのへのパスの
一部を含めることを許可していません。

Docker clients have strict requirements for images paths and do not allow a repository path to be included as part of the path to a docker registry.

この回避方法としてSonatype Nexus Repository 3は以下の4つの方法を挙げています。

  • Docker Registry / Path-Based Routing
    • パスベースのルーティングを可能にするリポジトリー設定を行う
    • イメージ名にはリポジトリー名が含まれることになる
    • Sonatype Nexus Repository 3.83.0以降で利用可能
  • Docker Subdomain Connector
    • Docker Registryに対するサブドメインを作成し、サブドメインごとにルーティングする
    • 商用版の機能
  • Docker Reverse Proxy Strategies
    • Sonatype Nexus Repository 3の前段にリバースプロキシーを配置して、リクエストをSonatype Nexus Repository 3側のパスにマッピングする
  • Docker Registry / Port Connectors
    • Docker Registryごとにポートを割り当て、クライアントはそのポートを使用する
    • リソース消費が大きいため、Port Connectorの数は20個までにすることとされている
    • 従来のDocker Registryの構築方法

今回はPath-Based Routingを試してみます。

環境

Sonatype Nexus Repository 3は3.90.1を使い、192.168.121.10で動作しているものとします。

また動作確認にはDockerと

$ docker version
Client: Docker Engine - Community
 Version:           29.3.0
 API version:       1.54
 Go version:        go1.25.7
 Git commit:        5927d80
 Built:             Thu Mar  5 14:25:48 2026
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          29.3.0
  API version:      1.54 (minimum version 1.40)
  Go version:       go1.25.7
  Git commit:       83bca51
  Built:            Thu Mar  5 14:25:48 2026
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v2.2.2
  GitCommit:        301b2dac98f15c27117da5c8af12118a041a31d9
 runc:
  Version:          1.3.4
  GitCommit:        v1.3.4-0-gd6d73eb8
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

環境構築はTerraformで行います。

$ terraform version
Terraform v1.14.7
on linux_amd64

Path-Based Routingの設定を見る

最初に、Path-Based Routingで設定するとしてどういうものになるかWeb UIで見てみましょう。

以下はDocker Hosted Registryを作成する時のスクリーンショットです。「Repository Connectors」で作成したDocker Registryへの
接続方法を選ぶのですが、「Path-Based Routing」の場合は選択するだけです。

リポジトリー名がそのままURLに入ると書かれていますね。

Use the following URL with your Docker client to pull images from this repository:

company.com/repo-name/image:tag

Port Connectorsを使う場合は、使用するプロトコルに合わせてHTTPまたはHTTPSポートを選ぶ必要があります。そして、
Docker Registryを追加する度に使用するポートは増えていきます。

後者をなんとかしたいというのがPath-Based Routingができた背景なのかな、と思います。

Docker RegistryをTerraformで作成する

では、Docker Registryを作成します。Terraformを使います。

ただ、現在のNexus ProviderではPath-Based Routingに対応していないようなので、そこは構築後に手動で変更することにします。

Add path based routing for docker by maxemontio · Pull Request #572 · datadrivers/terraform-provider-nexus · GitHub

Terraformの構成ファイル。

main.tf

terraform {
  required_version = "1.14.7"

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

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

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

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

  docker {
    force_basic_auth = false
    v1_enabled       = false
    ## http_portやhttps_portは不要
  }

  storage {
    blob_store_name                = "default"
    strict_content_type_validation = true
    write_policy                   = "ALLOW_ONCE" ## 再デプロイ不可
    latest_policy                  = true         ## latestタグのみ再デプロイ可
  }
}

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

  docker {
    force_basic_auth = false
    v1_enabled       = false
    ## http_portやhttps_portは不要
  }

  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_group" "this" {
  name   = "docker-group"
  online = true

  docker {
    force_basic_auth = false
    v1_enabled       = false
    ## http_portやhttps_portは不要
  }

  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
  }
}

Hosted Registry(docker-hosted)、Proxy Registry(docker-dockerhub-proxy)、これらをまとめた
Group Registry(docker-group)を作成します。

適用。

$ terraform init
$ terraform apply

構築されたDocker Registryを見ると、「Repository Connectors」がすべて「Other Connectors」になっています。

これを「Path based routing」を選択するようにして「Save」します。

全Docker Registryに対して設定したら、準備完了です。

使ってみる

それでは使ってみましょう。

作成したDocker Registryは以下の3つでした。

  • docker-hosted
  • docker-dockerhub-proxy
    • Docker Hubへのプロキシー
  • docker-group

Docker Daemonにinsecure-registriesを設定。

/etc/docker/daemon.json

{
  "insecure-registries": [
    "192.168.121.10:8081"
  ]
}

再起動。

$ sudo systemctl restart docker

Proxy Registryから使ってみましょう。

イメージはどうやって指定すればよいのでしょうか?Dockerクライアントはパスに関する要件があるということでした。

リポジトリーのページにあるURLをそのまま使ってアクセスすると、失敗しました。

$ docker image pull 192.168.121.10:8081/repository/docker-dockerhub-proxy/nginx:1.29.6-trixie
Error response from daemon: failed to resolve reference "192.168.121.10:8081/repository/docker-dockerhub-proxy/nginx:1.29.6-trixie": 192.168.121.10:8081/repository/docker-dockerhub-proxy/nginx:1.29.6-trixie: not found

この指定ではないようです。

よくよく見ると、こちらにやり方が書いていました。

Docker Registry / Accessing Repositories

こういう形式になるようです。namespaceの箇所をリポジトリー名にすればよさそうですね。

$ docker <command> <nexus-hostname>:<https-repository-port>/<namespace>/<image>:<tag>
$ docker search <nexus-hostname>:<https-repository-port>/<search-term>

確認。

$ docker image pull 192.168.121.10:8081/docker-dockerhub-proxy/nginx:1.29.6-trixie
1.29.6-trixie: Pulling from docker-dockerhub-proxy/nginx
9baba07a35b6: Pull complete
4174e33a2c9e: Pull complete
ec781dee3f47: Pull complete
6b40784e4837: Pull complete
980067d12da2: Pull complete
f0b77348d9b0: Pull complete
0289d65812c3: Pull complete
c96ca1f4ddf7: Download complete
00238b7dc6b2: Download complete
Digest: sha256:dec7a90bd0973b076832dc56933fe876bc014929e14b4ec49923951405370112
Status: Downloaded newer image for 192.168.121.10:8081/docker-dockerhub-proxy/nginx:1.29.6-trixie
192.168.121.10:8081/docker-dockerhub-proxy/nginx:1.29.6-trixie

OKでした。

1度削除。

$ docker image rm 192.168.121.10:8081/docker-dockerhub-proxy/nginx:1.29.6-trixie
Untagged: 192.168.121.10:8081/docker-dockerhub-proxy/nginx:1.29.6-trixie
Deleted: sha256:dec7a90bd0973b076832dc56933fe876bc014929e14b4ec49923951405370112

Docker Group Registryもpullしてみます。

$ docker image pull 192.168.121.10:8081/docker-group/nginx:1.29.6-trixie
1.29.6-trixie: Pulling from docker-group/nginx
4174e33a2c9e: Pull complete
0289d65812c3: Pull complete
9baba07a35b6: Pull complete
ec781dee3f47: Pull complete
980067d12da2: Pull complete
6b40784e4837: Pull complete
f0b77348d9b0: Pull complete
00238b7dc6b2: Download complete
c96ca1f4ddf7: Download complete
Digest: sha256:dec7a90bd0973b076832dc56933fe876bc014929e14b4ec49923951405370112
Status: Downloaded newer image for 192.168.121.10:8081/docker-group/nginx:1.29.6-trixie
192.168.121.10:8081/docker-group/nginx:1.29.6-trixie

OKです。

あとはHosted Registryですね。

こんなDockerfileを作成。

Dockerfile

FROM ubuntu:24.04

CMD ["echo", "Hello World"]

Dockerイメージをビルド。

$ docker image build -t 192.168.121.10:8081/docker-hosted/hello-world:latest .

確認。

$ docker container run -it --rm 192.168.121.10:8081/docker-hosted/hello-world:latest
Hello World

Sonatype Nexus Repository 3にログインして

$ docker login 192.168.121.10:8081
Username: admin
Password:

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

Login Succeeded

push。

$ docker image push 192.168.121.10:8081/docker-hosted/hello-world:latest
The push refers to repository [192.168.121.10:8081/docker-hosted/hello-world]
817807f3c64e: Pushed
e774f9d8c2ac: Pushed
latest: digest: sha256:3d509ffca02b4158da260859f147cb9038a7ae4b603b894f79ce40ab7fe5e943 size: 855

OKです。

ローカルからは削除して

$ docker image rm 192.168.121.10:8081/docker-hosted/hello-world:latest
Untagged: 192.168.121.10:8081/docker-hosted/hello-world:latest
Deleted: sha256:3d509ffca02b4158da260859f147cb9038a7ae4b603b894f79ce40ab7fe5e943

pullと同時に実行。

$ docker container run -it --rm 192.168.121.10:8081/docker-hosted/hello-world:latest
Unable to find image '192.168.121.10:8081/docker-hosted/hello-world:latest' locally
latest: Pulling from docker-hosted/hello-world
e774f9d8c2ac: Download complete
Digest: sha256:3d509ffca02b4158da260859f147cb9038a7ae4b603b894f79ce40ab7fe5e943
Status: Downloaded newer image for 192.168.121.10:8081/docker-hosted/hello-world:latest
Hello World

Group Registryに対しても行ってみます。

$ docker container run -it --rm 192.168.121.10:8081/docker-group/hello-world:latest
Unable to find image '192.168.121.10:8081/docker-group/hello-world:latest' locally
latest: Pulling from docker-group/hello-world
Digest: sha256:3d509ffca02b4158da260859f147cb9038a7ae4b603b894f79ce40ab7fe5e943
Status: Downloaded newer image for 192.168.121.10:8081/docker-group/hello-world:latest
Hello World

こちらもOKですね。

使い方はわかったと思います。

おわりに

Sonatype Nexus Repository 3でDocker Registryを構築する際に、Path-Based Routingを使ってみました。

存在は前々から知っていたのですがなかなか試せていなかったので、この機会にちゃんと確認できてよかったです。

Dockerクライアントから使う時のイメージの指定方法にはちょっと注意ですね。
あとNexus Provider側のPull Requestが取り込まれるのを待つとしましょう。