Harborを題材に、Docker Compose風運用をPodmanでする

Posted by 雅楽斎 on Wednesday, September 13, 2023

TOC

コンテナが多いHarbor

Harborはrootless dockerで構築しましたが、これもPodmanで動かします。

ただ、これまでPodman(systemd)で動かしてきたNginxやNavidromeと違って、Harborはdocker-compose.ymlに定義されているコンテナが多いので今までとは毛色の違う作業になりました。

Podmanシリーズとしては前回記事の続きです。

LAN上のMinIOからRcloneで曲データを引っ張りながらNavidromeを題材に、Docker Compose風運用をPodmanで動かす

rootless dockerでHarborを動かした時の記事はこちら。

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

以前の記事を参照くださいと言いたいところですがRPi4で構築した時からdocker-compose.ymlがガラッと変わっていたのでお気を付け下さい。具体的にはchartmuseumが全部なくなっていました。

[bitnami/harbor-portal] Release 2.8.1-debian-11-r9 (#34966) · bitnami/containers@510a9a3 · GitHub

podman-composeで動かす

いつも通り、podman-composeでHarborを動かします。

$ mkdir -p ~/podmancompose/harbor
$ cd ~/podmancompose/harbor
$ 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
$ tree .
.
├── config
│   ├── core
│   │   ├── app.conf
│   │   └── private_key.pem
│   ├── jobservice
│   │   └── config.yml
│   ├── proxy
│   │   └── nginx.conf
│   ├── registry
│   │   ├── config.yml
│   │   ├── passwd
│   │   └── root.crt
│   └── registryctl
│       └── config.yml
└── docker-compose.yml

6 directories, 9 files

docker-compose.ymlを以下の内容で作成。

# Copyright VMware, Inc.
# SPDX-License-Identifier: APACHE-2.0

version: '2'

services:
  registry:
    image: docker.io/bitnami/harbor-registry:2
    environment:
      - REGISTRY_HTTP_SECRET=CHANGEME
    volumes:
      - /var/containers/harbor_registry_data:/storage
      - /var/containers/harbor_config/registry/:/etc/registry/:ro
  registryctl:
    image: docker.io/bitnami/harbor-registryctl:2
    environment:
      - CORE_SECRET=CHANGEME
      - JOBSERVICE_SECRET=CHANGEME
      - REGISTRY_HTTP_SECRET=CHANGEME
    volumes:
      - /var/containers/harbor_registry_data:/storage
      - /var/containers/harbor_config/registry/:/etc/registry/:ro
      - /var/containers/harbor_config/registryctl/config.yml:/etc/registryctl/config.yml:ro
  postgresql:
    image: docker.io/bitnami/postgresql:13
    container_name: harbor-db
    environment:
      - POSTGRESQL_PASSWORD=bitnami
      - POSTGRESQL_DATABASE=registry
    volumes:
      - /var/containers/harbor_postgresql_data:/bitnami/postgresql
  core:
    image: docker.io/bitnami/harbor-core:2
    container_name: harbor-core
    depends_on:
      - registry
    environment:
      - CORE_KEY=change-this-key
      - _REDIS_URL_CORE=redis://redis:6379/0
      - SYNC_REGISTRY=false
      - CHART_CACHE_DRIVER=redis
      - _REDIS_URL_REG=redis://redis:6379/1
      - PORT=8080
      - LOG_LEVEL=info
      - EXT_ENDPOINT=http://192.168.1.114:8088
      - DATABASE_TYPE=postgresql
      - REGISTRY_CONTROLLER_URL=http://registryctl:8080
      - POSTGRESQL_HOST=postgresql
      - POSTGRESQL_PORT=5432
      - POSTGRESQL_DATABASE=registry
      - POSTGRESQL_USERNAME=postgres
      - POSTGRESQL_PASSWORD=bitnami
      - POSTGRESQL_SSLMODE=disable
      - REGISTRY_URL=http://registry:5000
      - TOKEN_SERVICE_URL=http://core:8080/service/token
      - HARBOR_ADMIN_PASSWORD=bitnami
      - CORE_SECRET=CHANGEME
      - JOBSERVICE_SECRET=CHANGEME
      - ADMIRAL_URL=
      - WITH_NOTARY=False
      - CORE_URL=http://core:8080
      - JOBSERVICE_URL=http://jobservice:8080
      - REGISTRY_STORAGE_PROVIDER_NAME=filesystem
      - REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
      - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
      - READ_ONLY=false
      - RELOAD_KEY=
      - PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE=docker-hub,github-ghcr
    volumes:
      - /var/containers/harbor_core_data:/data
      - /var/containers/harbor_config/core/app.conf:/etc/core/app.conf:ro
      - /var/containers/harbor_config/core/private_key.pem:/etc/core/private_key.pem:ro
  portal:
    image: docker.io/bitnami/harbor-portal:2
    container_name: harbor-portal
    depends_on:
      - core
  jobservice:
    image: docker.io/bitnami/harbor-jobservice:2
    container_name: harbor-jobservice
    depends_on:
      - redis
      - core
    environment:
      - CORE_SECRET=CHANGEME
      - JOBSERVICE_SECRET=CHANGEME
      - CORE_URL=http://core:8080
      - REGISTRY_CONTROLLER_URL=http://registryctl:8080
      - REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
      - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
    volumes:
      - /var/containers/harbor_jobservice_data:/var/log/jobs
      - /var/containers/harbor_config/jobservice/config.yml:/etc/jobservice/config.yml:ro
  redis:
    image: docker.io/bitnami/redis:7.0
    environment:
      # ALLOW_EMPTY_PASSWORD is recommended only for development.
      - ALLOW_EMPTY_PASSWORD=yes
  harbor-nginx:
    image: docker.io/bitnami/nginx:1.25
    container_name: nginx
    volumes:
      - /var/containers/harbor_config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
    ports:
      - '8088:8080'
    depends_on:
      - postgresql
      - registry
      - core
      - portal
volumes:
  registry_data:
    driver: local
  core_data:
    driver: local
  jobservice_data:
    driver: local
  postgresql_data:
    driver: local

オリジナルからの差分は以下。

--- docker-compose.yml.org	2023-08-23 18:59:58.126100661 +0900
+++ docker-compose.yml	2023-08-23 19:05:31.019270215 +0900
@@ -9,8 +9,8 @@
     environment:
       - REGISTRY_HTTP_SECRET=CHANGEME
     volumes:
-      - registry_data:/storage
-      - ./config/registry/:/etc/registry/:ro
+      - /var/containers/harbor_registry_data:/storage
+      - /var/containers/harbor_config/registry/:/etc/registry/:ro
   registryctl:
     image: docker.io/bitnami/harbor-registryctl:2
     environment:
@@ -18,9 +18,9 @@
       - JOBSERVICE_SECRET=CHANGEME
       - REGISTRY_HTTP_SECRET=CHANGEME
     volumes:
-      - registry_data:/storage
-      - ./config/registry/:/etc/registry/:ro
-      - ./config/registryctl/config.yml:/etc/registryctl/config.yml:ro
+      - /var/containers/harbor_registry_data:/storage
+      - /var/containers/harbor_config/registry/:/etc/registry/:ro
+      - /var/containers/harbor_config/registryctl/config.yml:/etc/registryctl/config.yml:ro
   postgresql:
     image: docker.io/bitnami/postgresql:13
     container_name: harbor-db
@@ -28,7 +28,7 @@
       - POSTGRESQL_PASSWORD=bitnami
       - POSTGRESQL_DATABASE=registry
     volumes:
-      - postgresql_data:/bitnami/postgresql
+      - /var/containers/harbor_postgresql_data:/bitnami/postgresql
   core:
     image: docker.io/bitnami/harbor-core:2
     container_name: harbor-core
@@ -42,7 +42,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.114:8088
       - DATABASE_TYPE=postgresql
       - REGISTRY_CONTROLLER_URL=http://registryctl:8080
       - POSTGRESQL_HOST=postgresql
@@ -65,10 +65,11 @@
       - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
       - READ_ONLY=false
       - RELOAD_KEY=
+      - PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE=docker-hub,github-ghcr
     volumes:
-      - core_data:/data
-      - ./config/core/app.conf:/etc/core/app.conf:ro
-      - ./config/core/private_key.pem:/etc/core/private_key.pem:ro
+      - /var/containers/harbor_core_data:/data
+      - /var/containers/harbor_config/core/app.conf:/etc/core/app.conf:ro
+      - /var/containers/harbor_config/core/private_key.pem:/etc/core/private_key.pem:ro
   portal:
     image: docker.io/bitnami/harbor-portal:2
     container_name: harbor-portal
@@ -88,8 +89,8 @@
       - REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
       - REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
     volumes:
-      - jobservice_data:/var/log/jobs
-      - ./config/jobservice/config.yml:/etc/jobservice/config.yml:ro
+      - /var/containers/harbor_jobservice_data:/var/log/jobs
+      - /var/containers/harbor_config/jobservice/config.yml:/etc/jobservice/config.yml:ro
   redis:
     image: docker.io/bitnami/redis:7.0
     environment:
@@ -99,9 +100,9 @@
     image: docker.io/bitnami/nginx:1.25
     container_name: nginx
     volumes:
-      - ./config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
+      - /var/containers/harbor_config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
     ports:
-      - '80:8080'
+      - '8088:8080'
     depends_on:
       - postgresql
       - registry

ボリュームについて、相対パスで書かれているので絶対パスに変更しています。

サービスファイル・ディレクトリコンテナ内マッピング
registry/var/containers/harbor_registry_data/storage
/var/containers/harbor_config/registry//etc/registry/:ro
registryctl/var/containers/harbor_registry_data/storage
/var/containers/harbor_config/registry//etc/registry/:ro
/var/containers/harbor_config/registryctl/config.yml/etc/registryctl/config.yml:ro
postgresql/var/containers/harbor_postgresql_data/bitnami/postgresql
core/var/containers/harbor_core_data/data
/var/containers/harbor_config/core/app.conf/etc/core/app.conf:ro
/var/containers/harbor_config/core/private_key.pem/etc/core/private_key.pem:ro
portal/var/containers/harbor_jobservice_data/var/log/jobs
/var/containers/harbor_config/jobservice/config.yml/etc/jobservice/config.yml:ro
harbor-nginx/var/containers/harbor_config/proxy/nginx.conf/opt/bitnami/nginx/conf/nginx.conf:ro

ボリュームで使用するディレクトリ(config)は使用する場所に移動します。移動先の所有者はrootなので以下の作業はrootユーザーでやります。

# mv /home/hogehoge/podmancompose/harbor/config /var/containers/harbor_config

上表のコンテナ内マッピングでroが付いていないファイルはharborコンテナから生成するものと思われるので、ディレクトリを作ります。

ディレクトリを作る際に、今回のrootless podmanで使うことになるUIDは166536、GIDは166537なので、オーナーのUIDとGIDはこれで作ります。

# cd /var/containers/
# install -d -m 755 -o 166536 -g 166537 harbor_registry_data harbor_postgresql_data harbor_core_data harbor_jobservice_data

podman-composeでコンテナを起動します。

$ ~/podmancompose/harbor
$ podman-compose up -d

今回はエンドポイントを http://192.168.1.114:8088 にしているので、ブラウザからHarborのログイン画面が表示できることを確認したらコンテナを落とします。

$ podman-compose down

systemdのユニットファイルを生成

HarborをOS起動時に起動したいのでもう一回Harborを上げます。

$ podman-compose up -d
$ podman-compose ps
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 3.4.4
podman ps -a --filter label=io.podman.compose.project=harbor
CONTAINER ID  IMAGE                                   COMMAND               CREATED        STATUS            PORTS                   NAMES
dd386831b04b  docker.io/bitnami/harbor-registry:2     /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor_registry_1
a229d4ac970f  docker.io/bitnami/harbor-registryctl:2  /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor_registryctl_1
abfa45cc746d  docker.io/bitnami/postgresql:13         /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor-db
894910c11a99  docker.io/bitnami/redis:7.0             /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor_redis_1
892e85a7bc3a  docker.io/bitnami/harbor-core:2         /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor-core
0e6164b7fc45  docker.io/bitnami/harbor-portal:2       /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor-portal
f32487978a09  docker.io/bitnami/harbor-jobservice:2   /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago                          harbor-jobservice
7e4064016cba  docker.io/bitnami/nginx:1.25            /opt/bitnami/scri...  2 minutes ago  Up 2 minutes ago  0.0.0.0:8088->8080/tcp  nginx
exit code: 0

systemdで起動する時の起動順序を確認します。

docker-compose.ymlのservicesとdepends_onの関係は以下の表の通り。

servicedepends_onコンテナ名
registryharbor_registry_1
registryctlharbor_registryctl_1
postgresqlharbor-db
coreregistryharbor-core
portalcoreharbor-portal
jobserviceredis
core
harbor-jobservice
redisharbor_redis_1
harbor-nginxpostgresql
registry
core
portal
nginx

何も考えずにユニットファイル生成→全然ダメ

podman generate systemdがこれらの依存関係を汲み取ってユニットファイルを生成してくれると期待して生成してみます。

$ podman generate systemd --new --files --name nginx
$ cat container-nginx.service 
# container-nginx.service
# autogenerated by Podman 3.4.4
# Wed Aug 30 18:15:15 JST 2023

[Unit]
Description=Podman container-nginx.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --sdnotify=conmon --replace --name=nginx -d --requires=harbor-portal,harbor_registry_1,harbor-db,harbor-core --label io.podman.compose.config-hash=c290d564c40fa6c1d633731cd80b143fe71352c4bc065646f3adae1db6ad5682 --label io.podman.compose.project=harbor --label io.podman.compose.version=1.0.6 --label PODMAN_SYSTEMD_UNIT=podman-compose@harbor.service --label com.docker.compose.project=harbor --label com.docker.compose.project.working_dir=/home/hogehoge/podmancompose/harbor --label com.docker.compose.project.config_files=docker-compose.yml --label com.docker.compose.container-number=1 --label com.docker.compose.service=harbor-nginx -v /home/hogehoge/podmancompose/harbor/config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro --net harbor_default --network-alias harbor-nginx -p 8088:8080 docker.io/bitnami/nginx:1.25
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target

んー。どうなんでしょうこれ。とりあえずやってみる。

$ podman-compose down
$ mv container-nginx.service ~/.config/systemd/user/
$ systemctl --user enable container-nginx.service 
$ systemctl --user start container-nginx.service 
Job for container-nginx.service failed because the control process exited with error code.
See "systemctl --user status container-nginx.service" and "journalctl --user -xeu container-nginx.service" for details.

エラーで終わってるのでjournalctl --user -xeu container-nginx.serviceでどんなエラーか確認したらこんなのでした。

Aug 30 18:22:58 ubuntu podman[24993]: Error: "harbor-portal" is not a valid container, cannot be used as a dependency: no container with name or ID "harbor-portal" found: no such container
Aug 30 18:22:59 ubuntu systemd[791]: container-nginx.service: Main process exited, code=exited, status=125/n/a
Aug 30 18:22:59 ubuntu podman[25171]: Error: error reading CIDFile: open /run/user/1001/container-nginx.service.ctr-id: no such file or directory
Aug 30 18:22:59 ubuntu systemd[791]: container-nginx.service: Control process exited, code=exited, status=125/n/a

これが5回表示されてフィニッシュです。とりあえずsystemdから無効化してユニットファイルを削除します。

$ systemctl --user stop container-nginx
$ systemctl --user disable container-nginx
Removed /home/hogehoge/.config/systemd/user/default.target.wants/container-nginx.service.
$ rm ~/.config/systemd/user/container-nginx.service 

ちゃんとコンテナの起動順を適用して解決するまで持っていく試み

従前の表をもう一度よく見てみると、起動したコンテナ名nginxはdepends_onとしてpostgresqlregistrycoreportalが書かれているので、docker-compose/podman-composeでコンテナを起動した場合は事前にこの4つのサービスの起動が終わってる状態でnginxは起動するように設定されていて、エラーログも「harbor-portalがない」と書かれている。ということから考えると、nginxよりも先にharbor-portalを起動すればこのエラーは出なくなりそうです。

ということで、depends_onが色々設定されているので8個のサービスの依存関係を整理するとこんな感じになるのでは。

graph TB registryctl postgresql core-->registry portal-->core jobservice-->redis jobservice-->core harbor-nginx-->postgresql harbor-nginx-->registry harbor-nginx-->core harbor-nginx-->portal

字に起こすとこうなるんですが、

  • registryを最初に起動
  • coreをregistryの後に起動
  • redisを起動
  • coreとredisの後にjobserviceを起動
  • coreの後にportalを起動
  • postgresqlを起動
  • registryとcoreとportalとpostgresqlの後にharbor-nginxを起動
  • registructlを起動(いつでもいい)

冗長な依存を減らします。

  • coreの起動前にregistryは起動しているので、harbor-nginxからregistryの依存を削除
  • portalの前にcoreは起動しているので、harbor-nginxからcoreへの依存を削除
graph TB registryctl core-->registry portal-->core jobservice-->redis jobservice-->core harbor-nginx-->postgresql harbor-nginx-->portal

これを元にそれぞれのSystemdのユニットファイルを生成して起動してみます。podmanが4.0.0以降であればpodman generate systemdコマンドは--requiresで依存systemdユニットを指定できます。--wantsも同じ様に依存systemdユニットを指定する引数ですが、Wantsは指定ユニットの起動に失敗しても起動をするオプションらしく、今回の用途では依存ユニットが起動失敗したらシステムとしての用をなさないのでRequiresで依存ユニットを指定します。また、起動順の指定は--requiresとは別に--afterで指定します。Afterで指定しないと、Requiresで指定したユニットの起動終了を待たずに並行して起動します(systemdの仕様)。

とpodmanの機能を書いたところですが、今回使っているUbuntu 22.04のpodmanは3.4.4なのでrequiresもafterも手で書き込みます。

まずはpodman-composeでharborサービスを起動します。

$ podman-compose up -d

依存ユニットのないコンテナのユニットファイル生成

registryctl、registry、redis、postgresqlは依存ユニットがないのでサクッと行きます。

$ podman generate systemd --new --files --name harbor_registryctl_1 
/home/hogehoge/podmancompose/harbor/container-harbor_registryctl_1.service
$ podman generate systemd --new --files --name harbor_registry_1 
/home/hogehoge/podmancompose/harbor/container-harbor_registry_1.service
$ podman generate systemd --new --files --name harbor_redis_1 
/home/hogehoge/podmancompose/harbor/container-harbor_redis_1.service
$ podman generate systemd --new --files --name harbor-db
/home/hogehoge/podmancompose/harbor/container-harbor-db.service

依存ユニットのあるコンテナのユニットファイル生成

coreはregistryが依存ユニットです。

$ podman generate systemd --new --files --name harbor-core
/home/hogehoge/podmancompose/harbor/container-harbor-core.service

以下の様に書き換えます。Requires/After行を変更します。

--- container-harbor-core.service.org	2023-09-01 23:31:01.459048829 +0900
+++ container-harbor-core.service	2023-09-01 23:38:47.853545922 +0900
@@ -5,8 +5,8 @@
 [Unit]
 Description=Podman container-harbor-core.service
 Documentation=man:podman-generate-systemd(1)
-Wants=network-online.target
-After=network-online.target
+Requires=container-harbor_registry_1.service
+After=network-online.target container-harbor_registry_1.service
 After=network-online.target
 RequiresMountsFor=%t/containers

portalはcoreが依存ユニットです。

$ podman generate systemd --new --files --name harbor-portal 
/home/hogehoge/podmancompose/harbor/container-harbor-portal.service

以下の様に書き換えます。Requires/After行を変更します。

--- container-harbor-portal.service.org	2023-09-01 23:31:28.594740677 +0900
+++ container-harbor-portal.service	2023-09-01 23:34:18.792200193 +0900
@@ -5,8 +5,8 @@
 [Unit]
 Description=Podman container-harbor-portal.service
 Documentation=man:podman-generate-systemd(1)
-Wants=network-online.target
-After=network-online.target
+Requires=container-harbor-core.service
+After=network-online.target container-harbor-core.service
 After=network-online.target
 RequiresMountsFor=%t/containers

jobserviceはredisとcoreが依存ユニットです。

$ podman generate systemd --new --files --name harbor-jobservice 
/home/hogehoge/podmancompose/harbor/container-harbor-jobservice.service

以下の様に書き換えます。Requires/After行を変更します。

--- container-harbor-jobservice.service.org	2023-09-01 23:31:56.750408062 +0900
+++ container-harbor-jobservice.service	2023-09-01 23:35:46.015990350 +0900
@@ -5,8 +5,8 @@
 [Unit]
 Description=Podman container-harbor-jobservice.service
 Documentation=man:podman-generate-systemd(1)
-Wants=network-online.target
-After=network-online.target
+Requires=container-harbor_redis_1.service container-harbor-core.service
+After=network-online.target container-harbor_redis_1.service container-harbor-core.service
 After=network-online.target
 RequiresMountsFor=%t/containers

harbor-nginxはportalとpostgresqlが依存ユニットです。

$ podman generate systemd --new --files --name nginx
/home/hogehoge/podmancompose/harbor/container-nginx.service

以下の様に書き換えます。Requires/After行を変更します。

--- container-nginx.service.org	2023-09-01 23:32:13.729811161 +0900
+++ container-nginx.service	2023-09-01 23:36:51.647207502 +0900
@@ -5,8 +5,8 @@
 [Unit]
 Description=Podman container-nginx.service
 Documentation=man:podman-generate-systemd(1)
-Wants=network-online.target
-After=network-online.target
+Requires=container-harbor-portal.service container-harbor-db.service
+After=network-online.target container-harbor-portal.service container-harbor-db.service
 After=network-online.target
 RequiresMountsFor=%t/containers

全部終わったらpodman-composeでコンテナを落とします。

$ podman-compose down

Systemdへのユニットファイルの登録

作った8ファイルをsystemdに登録します。

$ mv container-harbor-core.service container-harbor-db.service container-harbor-jobservice.service container-harbor-portal.service container-harbor_redis_1.service container-harbor_registry_1.service container-harbor_registryctl_1.service container-nginx.service ~/.config/systemd/user/

enableとstartは依存を壊さない順序で行います。

$ systemctl --user enable container-harbor_registryctl_1.service 
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor_registryctl_1.service → /home/hogehoge/.config/systemd/user/container-harbor_registryctl_1.service.
$ systemctl --user start container-harbor_registryctl_1.service 
$ systemctl --user enable container-harbor_registry_1.service 
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor_registry_1.service → /home/hogehoge/.config/systemd/user/container-harbor_registry_1.service.
$ systemctl --user start container-harbor_registry_1.service
$ systemctl --user enable container-harbor_redis_1.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor_redis_1.service → /home/hogehoge/.config/systemd/user/container-harbor_redis_1.service.
$ systemctl --user start container-harbor_redis_1.service
$ systemctl --user enable container-harbor-db.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor-db.service → /home/hogehoge/.config/systemd/user/container-harbor-db.service.
$ systemctl --user start container-harbor-db.service
$ systemctl --user enable container-harbor-core.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor-core.service → /home/hogehoge/.config/systemd/user/container-harbor-core.service.
$ systemctl --user start container-harbor-core.service
$ systemctl --user enable container-harbor-portal.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor-portal.service → /home/hogehoge/.config/systemd/user/container-harbor-portal.service.
$ systemctl --user start container-harbor-portal.service
$ systemctl --user enable container-harbor-jobservice.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-harbor-jobservice.service → /home/hogehoge/.config/systemd/user/container-harbor-jobservice.service.
$ systemctl --user start container-harbor-jobservice.service
$ systemctl --user enable container-nginx.service
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-nginx.service → /home/hogehoge/.config/systemd/user/container-nginx.service.
$ systemctl --user start container-nginx.service

エラーが表示されずに終了したら、各ユニットの状態を確認します。(関係のないものは削除しています)

$ systemctl --user list-dependencies
default.target
● ├─container-harbor-core.service
● ├─container-harbor-db.service
● ├─container-harbor-jobservice.service
● ├─container-harbor-portal.service
● ├─container-harbor_redis_1.service
● ├─container-harbor_registry_1.service
● ├─container-harbor_registryctl_1.service
● ├─container-nginx.service

ブラウザからHarborの管理画面にアクセスできることを確認したらOSを再起動して同じ様にブラウザからHarborの管理画面にアクセスできることを確認します。

OS再起動した結果

Systemdの設定でOSの起動時にも起動するようになっているので、試しにOSを再起動してみます。

$  systemctl --user list-dependencies
default.target
● ├─container-harbor-core.service
● ├─container-harbor-db.service
● ├─container-harbor-jobservice.service
● ├─container-harbor-portal.service
● ├─container-harbor_redis_1.service
● ├─container-harbor_registry_1.service
● ├─container-harbor_registryctl_1.service
● ├─container-navidrome_navidrome_1.service
● ├─container-nginx.service

全て色付きの●になっていればOKです。

DockerHubとGitHub Container Registryをキャッシュするように設定する

OCI準拠のコンテナをダウンロードするときにDockerHubは今でも最もよく使われるコンテナレジストリですが、他にGitHub Container Registry(ghcr.io)もかなりよく見ます。GitHubのCI/CDからできるからという理由だと思うのですが。

なので、この2つのレジストリに対してPodman等のコンテナランタイムからアクセスする際はイメージをHarborにキャッシュするように設定します。

画像は以前のHarbor構築にあるものと同じなので、画像は省略します。

レジストリの作成

左側のメニューのAdministrationの下にあるRegistriesを選択します。

NEW ENDPOINTとしてDockerHubとGHCRを追加します。Registries画面から「NEW ENDPOINT」を選択し、New Registry Endpoint画面で以下の設定値で作成します。

  • Provider Docker Hub
  • Name 任意(入力必須)
  • Endpoint URL 自動入力のまま
  • Access ID/Access Secret 空欄のまま
  • Verify Remote Cert ☑のまま(デフォルト)

  • Provider Github GHCR

  • Name 任意(入力必須)

  • Endpoint URL 自動入力のまま

  • Access ID/Access Secret 空欄のまま

  • Verify Remote Cert ☑のまま(デフォルト)

プロジェクトの作成

左側のメニューからProjectsを選択し、NEW PROJECTを選択します。以下の情報をDockerHubとGHCRそれぞれに作ります。

  • Project Name 任意(URLの一部になる。小文字のみ入力可) 今回は dockerhub と ghcr で作成
  • Access Level ☑Public
  • Storage Quota -1のまま(無設定)
  • Proxy Cache トグルボタンを有効にして右のプルダウンから作成したレジストリを選択。Endpointは自動入力される

プロジェクトを作成した場合、HarborのリポジトリURLは192.168.1.114:8088/dockerhub となり、hello-worldのDockerイメージURLは http://192.168.1.114:8088/dockerhub/hello-world になります。

リポジトリのテスト・podmanクライアントの設定

試しにdockerhubのhello-worldを実行してみます。

$ podman run 192.168.1.114:8088/dockerhub/hello-world
Trying to pull 192.168.1.114:8088/dockerhub/hello-world:latest...
Error: initializing source docker://192.168.1.114:8088/dockerhub/hello-world:latest: pinging container registry 192.168.1.114:8088: Get "https://192.168.1.114:8088/v2/": http: server gave HTTP response to HTTPS client

はい。ということでエラーが出ましたので対応します。(Harborはhttpsの設定をしていないため)

コンテナレジストリの定義を設定

久しぶりにPodmanとUbuntuでの現状(2023年7月)

httpとしてコンテナレジストリを指定できるよう、コンテナレジストリの定義を設定しますが、Podmanではシステムワイドに設定を適用する場合とpodmanコマンド実行ユーザーだけに設定を適用する場合で編集するべき設定ファイルが違います。

  • システムワイド /etc/containers/registries.conf /etc/containers/registries.conf.d/*.conf
  • ユーザー単位 ~/.config/containers/registries.conf ~/.config/containers/registries.conf.d/*.conf

今回はユーザー単位の設定として~/.config/containers/registries.conf.d/harbor.confに設定を書き込むことにします。普通はディレクトリがないのでディレクトリを作成してから。

$ mkdir ~/.config/containers/registries.conf.d
[[registry]]
location = "192.168.1.114:8088"
insecure = true

これでもう一回podman runを実行してみます。

$ podman run 192.168.1.114:8088/dockerhub/hello-world
Trying to pull 192.168.1.114:8088/dockerhub/hello-world:latest...
Getting image source signatures
Copying blob 70f5ac315c5a done  
Copying config b038788ddb done  
Writing manifest to image destination
Storing signatures

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.
    (arm64v8)
 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/

無事にARM64v8のイメージをダウンロードして実行できていることが確認できました。

いちいちコンテナレジストリをHarborに向けるのが面倒なので、DockerHubにアクセスしようとしたらHarborからイメージをダウンロードするように設定

ここからはもう一歩踏み込んだ設定です。Podmanの機能を使ってDockerHub(docker.io)にアクセスしようとしたら別のコンテナレジストリにアクセスするように設定します。

先程と同じ様にコンテナレジストリの定義を変更します。今回は~/.config/containers/registries.conf.d/dockerhub_routing.confというファイルに設定を書き込むことにします。

unqualified-search-registries = ["docker.io"]

[[registry]]
prefix = "docker.io"
location = "192.168.1.114:8088/dockerhub"
insecure = true

なお、registries.conf.dの下のファイルはファイル名がAlphanumericの順に読み込まれます。

$ podman pull alpine --log-level debug
(snip)
DEBU[0000] Pulling image alpine (policy: always)        
DEBU[0000] Looking up image "alpine" in local containers storage 
DEBU[0000] Trying "alpine" ...                          
DEBU[0000] Loading registries configuration "/etc/containers/registries.conf" 
DEBU[0000] Loading registries configuration "/etc/containers/registries.conf.d/shortnames.conf" 
DEBU[0000] Loading registries configuration "/home/hogehoge/.config/containers/registries.conf.d/harbor.conf" 
DEBU[0000] Loading registries configuration "/home/hogehoge/.config/containers/registries.conf.d/dockerhub_routing.conf" 
DEBU[0000] Trying "docker.io/library/alpine:latest" ... 
DEBU[0000] parsed reference into "[overlay@/var/containers/storage_hogehoge+/run/user/1001:overlay.mount_program=/usr/bin/fuse-overlayfs,overlay.mount_program=/usr/bin/fuse-overlayfs]@5053b247d78b5e43b5543fec77c856ce70b8dc705d9f38336fa77736f25ff47c" 
DEBU[0000] Found image "alpine" as "docker.io/library/alpine:latest" in local containers storage 
DEBU[0000] Found image "alpine" as "docker.io/library/alpine:latest" in local containers storage ([overlay@/var/containers/storage_hogehoge+/run/user/1001:overlay.mount_program=/usr/bin/fuse-overlayfs,overlay.mount_program=/usr/bin/fuse-overlayfs]@5053b247d78b5e43b5543fec77c856ce70b8dc705d9f38336fa77736f25ff47c) 
DEBU[0000] Image alpine resolved to local image docker.io/library/alpine:latest which will be used for pulling 
DEBU[0000] Attempting to pull candidate docker.io/library/alpine:latest for docker.io/library/alpine:latest 
DEBU[0000] parsed reference into "[overlay@/var/containers/storage_hogehoge+/run/user/1001:overlay.mount_program=/usr/bin/fuse-overlayfs,overlay.mount_program=/usr/bin/fuse-overlayfs]docker.io/library/alpine:latest" 
Trying to pull docker.io/library/alpine:latest...
DEBU[0000] Copying source image //alpine:latest to destination image [overlay@/var/containers/storage_hogehoge+/run/user/1001:overlay.mount_program=/usr/bin/fuse-overlayfs,overlay.mount_program=/usr/bin/fuse-overlayfs]docker.io/library/alpine:latest 
DEBU[0000] Trying to access "192.168.1.114:8088/dockerhub/library/alpine:latest" 
DEBU[0000] No credentials for 192.168.1.114:8088 found  
DEBU[0000] Using registries.d directory /etc/containers/registries.d for sigstore configuration 
DEBU[0000]  No signature storage configuration found for 192.168.1.114:8088/dockerhub/library/alpine:latest, using built-in default file:///home/hogehoge/.local/share/containers/sigstore 
DEBU[0000] Looking for TLS certificates and private keys in /etc/docker/certs.d/192.168.1.114:8088 
DEBU[0000] GET https://192.168.1.114:8088/v2/           
DEBU[0000] Ping https://192.168.1.114:8088/v2/ err Get "https://192.168.1.114:8088/v2/": http: server gave HTTP response to HTTPS client (&url.Error{Op:"Get", URL:"https://192.168.1.114:8088/v2/", Err:(*errors.errorString)(0x400063acd0)}) 
DEBU[0000] GET http://192.168.1.114:8088/v2/            
DEBU[0000] Ping http://192.168.1.114:8088/v2/ status 401 
DEBU[0000] GET http://192.168.1.114:8088/service/token?scope=repository%3Adockerhub%2Flibrary%2Falpine%3Apull&service=harbor-registry 
DEBU[0000] GET http://192.168.1.114:8088/v2/dockerhub/library/alpine/manifests/latest 
DEBU[0003] Content-Type from manifest GET is "application/vnd.docker.distribution.manifest.list.v2+json" 
DEBU[0003] Using blob info cache at /home/hogehoge/.local/share/containers/cache/blob-info-cache-v1.boltdb 
DEBU[0003] Source is a manifest list; copying (only) instance sha256:b312e4b0e2c665d634602411fcb7c2699ba748c36f59324457bc17de485f36f6 for current system 
DEBU[0003] GET http://192.168.1.114:8088/v2/dockerhub/library/alpine/manifests/sha256:b312e4b0e2c665d634602411fcb7c2699ba748c36f59324457bc17de485f36f6 
DEBU[0004] Content-Type from manifest GET is "application/vnd.docker.distribution.manifest.v2+json" 
DEBU[0004] IsRunningImageAllowed for image docker:docker.io/library/alpine:latest 
DEBU[0004]  Using default policy section                
DEBU[0004]  Requirement 0: allowed                      
DEBU[0004] Overall: allowed                             
DEBU[0004] Downloading /v2/dockerhub/library/alpine/blobs/sha256:f6648c04cd6ce95adc05b3aa55265007b95d64d508755be8506cee652792952c 
DEBU[0004] GET http://192.168.1.114:8088/v2/dockerhub/library/alpine/blobs/sha256:f6648c04cd6ce95adc05b3aa55265007b95d64d508755be8506cee652792952c 
Getting image source signatures
(snip)

ということで、ホスト名を省略→dockerhub.io→LAN内のHarbor(192.168.1.114:8088/dockerhub)と変換されていって、ホスト名を省略した場合でもLAN内のHarborをProxyとして使うことができました。

これで将来DockerHubがドメイン名移転orサービス停止して別会社が移転してイメージが一括で移転しても設定ファイルの書き換えで対応できますね。

スポンサーリンク


comments powered by Disqus