コンテナレジストリHarborをRaspberry Pi 4で動かす

Posted by 雅楽斎 on Saturday, May 6, 2023

TOC

伏線回収

NanoPi M4V2にSonatype Nexus3をセットアップして、Dockerのプライベートリポジトリを作る

元々VMware内で使われていたらしい かなり評価が高い arm用のバイナリがなかったため今回は見送り。

以前DockerのプライベートのコンテナレジストリとしてSonatype Nexusを構築した時はHarborはamd64でしかパッケージを提供していなかったので、Raspberry Pi 4(当時使っていたのはNanoPi M4V2ですが)での構築を諦めていました。

ところが、BitnamiがHarborのdockerイメージとしてamd64用とarm64用を公開してくれていることに気付いたので早速構築することに。arm64用は2023/02/24から提供していたみたいです。

動作前提条件としては

  • Docker Engine 1.10.0
  • Docker compose 1.6.0以降推奨

ということになっています。今回もRaspberry Pi 4(RAM8GB)、Ubuntu Server 22.04LTSで構築します。また、今回はプルスルー型のプロキシとしての使い方をメインに扱い、上流をDockerhubとします。

Harbor Containers

Harbor構築

今回はBitnamiのパッケージを使うので、Harbor本体とは違う設定をする必要がある箇所がありますが、ひとまずBitnamiでの構築方法のページを見てみます。

containers/bitnami/harbor-portal at main · bitnami/containers · GitHub

$ mkdircd docker-harbor # 作業ディレクトリをmkdirして移動します
$ curl -LO https://raw.githubusercontent.com/bitnami/containers/main/bitnami/harbor-portal/docker-compose.yml
$ curl -L https://github.com/bitnami/containers/archive/main.tar.gz | tar xz --strip=2 containers-main/bitnami/harbor-portal && cp -RL harbor-portal/config . && rm -rf harbor-portal

手順ではここまでやったあとにいつも通りdocker-compose upすることになっていますが、これで構築すると設定箇所が足りないので変更が必要な箇所をまとめます。

コンテナを動かす前にやること

最低限必要な設定変更をしたdocker-compose.ymlとオリジナルとの差分は以下の通りです。

$ diff -u docker-compose.yml{.org,}
--- docker-compose.yml.org      2023-05-05 12:03:55.668467218 +0900
+++ docker-compose.yml  2023-05-05 13:53:20.131499710 +0900
@@ -40,7 +40,7 @@
       - _REDIS_URL_REG=redis://redis:6379/1
       - PORT=8080
       - LOG_LEVEL=info
-      - EXT_ENDPOINT=http://reg.mydomain.com
+      - EXT_ENDPOINT=http://192.168.1.210:8088
       - DATABASE_TYPE=postgresql
       - REGISTRY_CONTROLLER_URL=http://registryctl:8080
       - POSTGRESQL_HOST=postgresql
@@ -65,6 +65,7 @@
       - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
       - READ_ONLY=false
       - RELOAD_KEY=
+      - PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE=docker-hub
     volumes:
       - core_data:/data
       - ./config/core/app.conf:/etc/core/app.conf:ro
@@ -101,7 +102,8 @@
     volumes:
       - ./config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
     ports:
-      - '80:8080'
+      #- '80:8080'
+      - '8088:8080'
     depends_on:
       - postgresql
       - registry

変更箇所は以下の通りです。

  • Harborを動かすホストをEXT_ENDPOINTとして設定
  • Proxy Cacheとして動かす場合に上位リポジトリとして設定するレジストリの種類をPERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHEとして設定
  • Harborがbindする実ポート番号を8088に変更

また、ログイン時のadminユーザーのパスワードをデフォルトのbitnamiから変更する場合はHARBOR_ADMIN_PASSWORD=bitnamiを変更します。

ボリュームマウントしているファイル・ディレクトリは以下の通りです。必要に応じて書き換えます。

サービスファイル・ディレクトリコンテナ内マッピング
registryregistry_data/storage
./config/registry//etc/registry/:ro
registryctlregistry_data/storage
./config/registry//etc/registry/:ro
./config/registryctl/config.yml/etc/registryctl/config.yml:ro
postgresqlpostgresql_data/bitnami/postgresql
corecore_data/data
./config/core/app.conf/etc/core/app.conf:ro
./config/core/private_key.pem/etc/core/private_key.pem:ro
portaljobservice_data/var/log/jobs
./config/jobservice/config.yml/etc/jobservice/config.yml:ro
harbor-nginx./config/proxy/nginx.conf/opt/bitnami/nginx/conf/nginx.conf:ro
chartmuseumchartmuseum_data/bitnami/data

コンテナの起動と設定

docker-compose.ymlの変更が終わったら、docker-compose up -dでコンテナを起動します。初回は結構時間がかかります。

EXT_ENDPOINTで設定したURLにブラウザからアクセスしてまずadminユーザーでログインします。パスワードは変更していなければbitnamiです。

レジストリの作成

プロキシキャッシュとして使う場合はプロジェクトの前にレジストリを作成します。左側のメニューのAdministrationの下にあるRegistriesを選択します。

NEW ENDPOINTとしてDockerhubを追加します。

ProviderはDocker Hubを選択します。Nameはプロジェクトから選択するのでわかりやすい名前にした方が良いでしょう。Endpoint URLはProviderを選択すると自動で入力され、変更不可能です。

TEST CONNECTIONを押すと、繋がるかどうかを確認できます。

OKを押すとRegistriesにDocker Hubが追加されます。

プロジェクトの作成

レジストリを追加したらプロジェクトを作成します。左側のメニューからProjectsを選択し、NEW PROJECTを選択します。

New Projectの入力項目は込み入っています。

  • Project Nameは小文字のみ使用可→コンテナレジストリのURLとして使われる
  • Access Level→Publicの場合、docker loginによる事前ログインが不要
  • Storage Quota→-1の場合無制限
  • Proxy Cache→有効にした場合、作成したレジストリからプルダウンで選ぶのでプロキシキャッシュとして使う場合はレジストリの作成が必須

OKを押すとプロジェクトが作成されます。

(備考)docker-compose.ymlでPERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHEを指定しなかった場合

プロキシキャッシュとしてのHarborは執筆時点で上位リポジトリに

  • Alibaba ACR
  • Artifact Hub
  • Aws ECR
  • Azure ACR
  • Docker Hub
  • Docker Registry
  • DTR
  • Github GHCR
  • Google GCR
  • Harbor
  • Huawei SWR
  • JFrog Artifactory
  • Quay
  • Tencent TCR

を使えるようですが、環境変数PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHEに使用する上位リポジトリを指定しないとエラーが出ます。特にBitnamiのHarborイメージの場合docker-compose.ymlに設定する行がないので、行ごと追加する必要があります。

Dockerクライアントの設定

クライアント(Dockerを使う側)はコンテナのダウンロード元としてHarborを指定する必要があるので、特に今回平文アクセスするので追加の設定が必要です。

また、今回構築したHarborのリポジトリのURLは192.168.1.210:8088/proxy/で、Dockerイメージ名はhello-worldの場合192.168.1.210:8088/proxy/hello-worldになります。このproxyはHarborで作成したプロジェクトの名前です。

Dockerのインストール方法によって参照するファイルが違う可能性がありますが、Rootless Dockerの場合はDockerを実行するユーザーの~/.config/docker/daemon.jsonに設定を記述します。1

HTTP許容設定前に動作確認をするとこうなります。

$ docker run 192.168.1.210:8088/proxy/hello-world
Unable to find image '192.168.1.210:8088/proxy/hello-world:latest' locally
docker: Error response from daemon: Get "https://192.168.1.210:8088/v2/": http: server gave HTTP response to HTTPS client.
See 'docker run --help'.

~/.config/dockerディレクトリがない場合はディレクトリを作成します。

$ mkdir -p ~/.config/docker

~/.config/docker/daemon.jsonを以下の内容で作成します。

{
        "insecure-registries" : [
                "192.168.1.210:8088"
        ]
}

Rootless Dockerに設定を反映させるため、systemdで再起動します。Harborを構築したホストで動作確認をしている場合、docker-composeで起動したコンテナも終了するので、コマンド実行後にdocker-compose up -dを実行してしばらく待ちます。

$ systemctl --user restart docker.service

改めて動作確認。

$ docker run 192.168.1.210:8088/proxy/hello-world
Unable to find image '192.168.1.210:8088/proxy/hello-world:latest' locally
latest: Pulling from proxy/hello-world
Digest: sha256:9eabfcf6034695c4f6208296be9090b0a3487e20fb6a5cb056525242621cf73d
Status: Downloaded newer image for 192.168.1.210:8088/proxy/hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

イメージの取得元を確認します。

$ docker image ls -a
REPOSITORY                             TAG       IMAGE ID       CREATED        SIZE
192.168.1.210:8088/proxy/hello-world   latest    9c7a54a9a43c   39 hours ago   13.3kB

動作確認が終わりました。Harbor側のWebでキャッシュしたリポジトリを確認します。

Harborの自動起動

正常動作が確認できた場合は、docker-compose.ymlを書き換えてOSの再起動時に自動的にHarborが起動するように各サービスのrestartalwaysunless-stoppedを指定すると良いでしょう。最終的なデフォルトからの差分は以下のようになります。

$ diff -u docker-compose.yml{.org,}
--- docker-compose.yml.org      2023-05-05 12:03:55.668467218 +0900
+++ docker-compose.yml  2023-05-06 18:27:04.629054298 +0900
@@ -8,6 +8,7 @@
     volumes:
       - registry_data:/storage
       - ./config/registry/:/etc/registry/:ro
+    restart: unless-stopped
   registryctl:
     image: docker.io/bitnami/harbor-registryctl:2
     environment:
@@ -18,6 +19,7 @@
       - registry_data:/storage
       - ./config/registry/:/etc/registry/:ro
       - ./config/registryctl/config.yml:/etc/registryctl/config.yml:ro
+    restart: unless-stopped
   postgresql:
     image: docker.io/bitnami/postgresql:13
     container_name: harbor-db
@@ -26,6 +28,7 @@
       - POSTGRESQL_DATABASE=registry
     volumes:
       - postgresql_data:/bitnami/postgresql
+    restart: unless-stopped
   core:
     image: docker.io/bitnami/harbor-core:2
     container_name: harbor-core
@@ -40,7 +43,7 @@
       - _REDIS_URL_REG=redis://redis:6379/1
       - PORT=8080
       - LOG_LEVEL=info
-      - EXT_ENDPOINT=http://reg.mydomain.com
+      - EXT_ENDPOINT=http://192.168.1.210:8088
       - DATABASE_TYPE=postgresql
       - REGISTRY_CONTROLLER_URL=http://registryctl:8080
       - POSTGRESQL_HOST=postgresql
@@ -65,15 +68,18 @@
       - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
       - READ_ONLY=false
       - RELOAD_KEY=
+      - PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE=docker-hub
     volumes:
       - core_data:/data
       - ./config/core/app.conf:/etc/core/app.conf:ro
       - ./config/core/private_key.pem:/etc/core/private_key.pem:ro
+    restart: unless-stopped
   portal:
     image: docker.io/bitnami/harbor-portal:2
     container_name: harbor-portal
     depends_on:
       - core
+    restart: unless-stopped
   jobservice:
     image: docker.io/bitnami/harbor-jobservice:2
     container_name: harbor-jobservice
@@ -90,23 +96,27 @@
     volumes:
       - jobservice_data:/var/log/jobs
       - ./config/jobservice/config.yml:/etc/jobservice/config.yml:ro
+    restart: unless-stopped
   redis:
     image: docker.io/bitnami/redis:7.0
     environment:
       # ALLOW_EMPTY_PASSWORD is recommended only for development.
       - ALLOW_EMPTY_PASSWORD=yes
+    restart: unless-stopped
   harbor-nginx:
     image: docker.io/bitnami/nginx:1.23
     container_name: nginx
     volumes:
       - ./config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
     ports:
-      - '80:8080'
+      #- '80:8080'
+      - '8088:8080'
     depends_on:
       - postgresql
       - registry
       - core
       - portal
+    restart: unless-stopped
   chartmuseum:
     container_name: chartmuseum
     image: docker.io/bitnami/chartmuseum:0
@@ -122,6 +132,7 @@
       - INDEX_LIMIT=0
     volumes:
       - chartmuseum_data:/bitnami/data
+    restart: unless-stopped
 volumes:
   registry_data:
     driver: local

(余談)動作確認が終わったところで気付いたこと

無事にRaspberry Pi 4でHarborを動かすという目標は達成できましたが、dockerは通常docker-composeで動かします。docker-composeでダウンロードするDockerイメージはdocker-compose.ymlの中に書きますが、大抵の場合ホスト名を省略します。例えばNextcloudを構築した時はこんなふうになっています。

services:
  db:
    image: mariadb
    restart: always

指定したimageを処理する場合にホスト名がないのでDockerhubからイメージをダウンロードするのがデフォルト動作になっている事自体は自然なことですが、dockerではどんな手を使ってもホスト名を省略した場合に参照するデフォルトのコンテナレジストリをDockerhub以外に変更できなさそうな仕様であることを知り、結構愕然としています。Dockerhubが落ちたりクラックされたら全てのimage行を書き換えるという作業が発生し、それが終わるまで何もできなくなります。

How to set a default registry to pull from in docker machine? - Stack Overflow

例外として、Redhatがフォークしたdockerは--add-repositoryを指定することでデフォルトのコンテナレジストリを変更できたようですが、ご存知の通りRHEL8からdockerは削除され、Redhatとしてはpodmanを使うという方針のようなので、この仕様を踏襲したdockerのフォークが広く普及しない限りはDockerhubが落ちないことを祈りながら使うしかないという状況です。

このことを考えるとダウンロード元や検索先としてホスト名を変更できるpodmanに軸足を移すべきなのかなという必然性を感じており、また現在のpodmanはdocker-composeからも操作できるようなのでできることとできないことを確認してみたいと考えています。

スポンサーリンク


  1. Dockerの起動引数に”–insecure-registry ドメイン:ポート番号”で指定することもできますがsystemdではなくファイルに書いた方がわかりやすいかなと個人的には思います [return]

comments powered by Disqus