コンテンツにスキップ

Distribution で Docker イメージを管理する

以下のような Docker イメージを管理できる環境を構築してみる。

Distribution とは

Distribution は Docker イメージを管理するツールである。これを使うとセルフホスティングで Docker イメージを管理できる。

昔は Registry という名前だったが、別の機関に移管され、名前が変わったらしい。

Distribution の Docker イメージ名がregistryだったり所々にその名残りが見受けられるが、Distribution のことなんだなと思えば良い。

Distribution をデプロイする

Docker Compose で Distribution をデプロイしてみる。

以下のようなdocker-compose.ymlを作成する。

docker-compose.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
services:
  registry:
    image: registry:latest
    ports:
      - 8090:5000
    volumes:
      - ./distribution/registry:/var/lib/registry
    restart: always
  registry-ui:
    image: joxit/docker-registry-ui:main
    restart: always
    ports:
      - 8091:80
    environment:
      - SINGLE_REGISTRY=true
      - REGISTRY_TITLE=Docker Registry UI
      - DELETE_IMAGES=true
      - SHOW_CONTENT_DIGEST=true
      - NGINX_PROXY_PASS_URL=http://registry:5000
      - SHOW_CATALOG_NB_TAGS=true
      - CATALOG_MIN_BRANCHES=1
      - CATALOG_MAX_BRANCHES=1
      - TAGLIST_PAGE_SIZE=100
      - REGISTRY_SECURED=false
      - CATALOG_ELEMENTS_LIMIT=1000

Distribution は画面を持たず動作確認が大変なので、Docker Registry User Interface も同時に導入している。

GitHub - Joxit/docker-registry-ui: The simplest and most complete UI for your private docker registry v2 and v3

ポートは 8090 と 8091 に割り当てているが、好きに変えて良い。

以下のコマンドを実行し、コンテナを起動する。

1
$ docker compose up

Docker Registry UI (http://localhost:8091)にアクセスして、以下のような画面が表示されていれば良い。

Docker イメージを作成する

Distribution に登録する Docker イメージを作成する。既に手元に登録したい Docker イメージがある場合、この手順を無視して良い。

Docker で動く Next.js アプリケーションを作ってみる。

1
$ npx create-next-app@latest

適当に答える。

1
2
3
4
5
6
7
8
9
 What is your project named?  nextjs-example
✔ Would you like to use TypeScript?  No / Yes
✔ Which linter would you like to use?  ESLint
✔ Would you like to use Tailwind CSS?  No / Yes
✔ Would you like your code inside a `src/` directory?  No / Yes
✔ Would you like to use App Router? (recommended)  No / Yes
✔ Would you like to use Turbopack? (recommended)  No / Yes
✔ Would you like to customize the import alias (`@/*` by default)?  No / Yes
Creating a new Next.js app in /path/to/nextjs-example.

以下のコマンドを実行し、アプリケーションが動作することを確認する。

1
$ npm run dev

プロジェクトにDockerfile.dockerignoreを追加する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.
├── .dockerignore
├── Dockerfile
├── README.md
├── eslint.config.mjs
├── next-env.d.ts
├── next.config.ts
├── package-lock.json
├── package.json
├── public
├── src
└── tsconfig.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# ビルド環境に必要なパッケージを用意したステージ
FROM node:22.19.0 AS development-dependencies-env

# ファイルをコピーする
WORKDIR /app
COPY . /app

# パッケージをインストールする
RUN npm ci

# ビルドする
RUN npm run build

# プロダクション環境に必要なパッケージだけを用意したステージ
FROM node:22.19.0 AS production-dependencies-env
WORKDIR /app
COPY ./package.json ./package-lock.json /app
RUN npm ci --omit=dev

# プロダクションステージ
FROM node:22.19.0-slim AS production
WORKDIR /app
# npm run startを実行するためにpackage.jsonをコピーする
COPY --chown=node:node --from=production-dependencies-env /app/package.json /app/package-lock.json /app
# アプリケーションの実行に必要なパッケージをコピーする
COPY --chown=node:node --from=production-dependencies-env /app/node_modules /app/node_modules
# Next.jsアプリケーションのビルド結果をコピーする
COPY --chown=node:node --from=development-dependencies-env /app/.next /app/.next
# リソースをコピーする
COPY --chown=node:node --from=development-dependencies-env /app/public /app/public

# ポートを公開する
EXPOSE 3000

# 実行する
WORKDIR /app
USER node
CMD ["npm", "run", "start"]
.dockerignore
1
2
3
4
5
6
7
8
.dockerignore
.env
.git/
.gitignore
.next/
Dockerfile
README.md
node_modules/

以下のコマンドを実行して Docker イメージを作成する。

1
$ docker build -t nextjs-example:0.1.0 .

以下のコマンドを実行して、一覧にnextjs-exampleが存在すれば Docker イメージの作成に成功している。

1
2
3
$ docker images
REPOSITORY                      TAG           IMAGE ID       CREATED          SIZE
nextjs-example                  0.1.0         281ecaea52cb   51 seconds ago   700MB

Docker イメージを Distribution にプッシュする

以降 Distribution をデプロイしているホストの IP アドレスと Distribution のポート番号をxxx.xxx.xxx.xxx:xxxxと表現する。

タグを作成する。

1
$ docker tag nextjs-example:0.1.0 xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0

Distribution にプッシュする。

1
$ docker push xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0

docker push時にhttp: server gave HTTP response to HTTPS clientというエラーが出る場合

docker push時に以下のエラーが発生することがある。

1
2
3
$ docker push xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0
The push refers to repository [xxx.xxx.xxx.xxx:xxxx/nextjs-example]
Get "https://xxx.xxx.xxx.xxx:xxxx/v2/": http: server gave HTTP response to HTTPS client

これを解決するにはDocker イメージをプッシュする側/etc/docker/daemon.jsonにて以下の設定を行う。ファイルがない場合は作成する。

/etc/docker/daemon.json
1
2
3
{
  "insecure-registries": ["xxx.xxx.xxx.xxx:xxxx"]
}

以下のコマンドを実行し、Docker を再起動する。

1
$ sudo systemctl restart docker.service docker.socket

Rootless モードの場合、以下になる。

1
$ mkdir -p ~/.config/docker
~/.config/docker/daemon.json
1
2
3
{
  "insecure-registries": ["xxx.xxx.xxx.xxx:xxxx"]
}
1
$ systemctl --user restart docker.service

再度プッシュを試す。

Distribution に Docker イメージが登録されていることを確認する

Docker Registry UI にアクセスして、プッシュした Docker イメージが存在することを確認する。

Distribution に登録した Docker イメージを起動する

Distrubution から Docker イメージをプルし、起動する。

ローカルに Docker イメージがある場合、以下のコマンドで消しておく。

1
$ docker rmi -f xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0

以下のコマンドを実行する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ docker run -p 8082:3000 xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0
Unable to find image 'xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0' locally
0.1.0: Pulling from nextjs-example
Digest: sha256:895c9b761a593f98979b806e2ca0128c6f86d7c9dd7c78b3818bf6f8e349f08f
Status: Downloaded newer image for xxx.xxx.xxx.xxx:xxxx/nextjs-example:0.1.0

> nextjs-example@0.1.0 start
> next start

    Next.js 15.5.3
   - Local:        http://localhost:3000
   - Network:      http://yyy.yyy.yyy.yyy:3000

  Starting...
  Ready in 250ms

上の例だとポート 3000 を 8082 に割り当てているので、http://localhost:8082にアクセスし、以下の画面が表示されれば Distribution に登録した Docker イメージの起動に成功したと言える。

その他

Distribution の状態は以下の API でも把握できる。

1
2
3
4
5
# イメージの一覧
http://xxx.xxx.xxx.xxx:xxxx/v2/_catalog

# タグの一覧
http://xxx.xxx.xxx.xxx:xxxx/v2/image-name/tags/list