Harbor

https://goharbor.io/

Prerequistes

Intall docker first.

Install

Download:

$ curl -LO https://github.com/goharbor/harbor/releases/download/v2.12.3/harbor-offline-installer-v2.12.3.tgz

Extract:

$ tar -C ~/workspace/ -xzf harbor-offline-installer-v2.12.3.tgz
$ cd ~/workspace/harbor

Copy file harbor.yml.tmpl to harbor.yml and edit it:

 
 # The IP address or hostname to access admin UI and registry service.
 # DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
-hostname: reg.mydomain.com
+hostname: las3
 
 # http related config
 http:
   # https port for harbor, default is 443
   port: 443
   # The path of cert and key files for nginx
-  certificate: /your/certificate/path
-  private_key: /your/private/key/path
+  certificate: /srv/data/certs/las3.crt
+  private_key: /srv/data/certs/las3.key
   # enable strong ssl ciphers (default: false)
   # strong_ssl_ciphers: false
 
 # The initial password of Harbor admin
 # It only works in first time to install harbor
 # Remember Change the admin password from UI after launching Harbor.
-harbor_admin_password: Harbor12345
+harbor_admin_password: AdminPassword123
 
 # Harbor DB configuration
 database:
   # The password for the user('postgres' by default) of Harbor DB. Change this before any production use.
-  password: root123
+  password: postgres-password
   # The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
   max_idle_conns: 100
   # The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
   conn_max_idle_time: 0
 
 # The default data volume
-data_volume: /data
+data_volume: /srv/data
 
 # Harbor Storage settings by default is using /data dir on local filesystem
 # Uncomment storage_service setting If you want to using external storage
 #   # host for redis+sentinel:
 #   #  <host_sentinel1>:<port_sentinel1>,<host_sentinel2>:<port_sentinel2>,<host_sentinel3>:<port_sentinel3>
 #   host: redis:6379
-#   password: 
+#   password:
 #   # Redis AUTH command was extended in Redis 6, it is possible to use it in the two-arguments AUTH <username> <password> form.
 #   # there's a known issue when using external redis username ref:https://github.com/goharbor/harbor/issues/18892
 #   # if you care about the image pull/push performance, please refer to this https://github.com/goharbor/harbor/wiki/Harbor-FAQs#external-redis-username-password-usage

The configurations use HTTPS, so you may need to “Configure HTTPS” first. Then start to install:

$ sudo ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 28.1.1

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.35.1

[Step 2]: loading Harbor images ...

[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...

[Step 5]: starting Harbor ...
[+] Running 10/10
 ✔ Network harbor_harbor        Created                                0.1s 
 ✔ Container harbor-log         Started                                0.6s 
 ✔ Container harbor-portal      Started                                0.7s 
 ✔ Container harbor-db          Started                                0.9s 
 ✔ Container registry           Started                                0.8s 
 ✔ Container registryctl        Started                                0.8s 
 ✔ Container redis              Started                                0.7s 
 ✔ Container harbor-core        Started                                1.0s 
 ✔ Container nginx              Started                                1.2s 
 ✔ Container harbor-jobservice  Started                                1.2s 
✔ ----Harbor has been installed and started successfully.----

After successful installation, open the url and login by user admin and the configured harbor_admin_password.

Push an image to the harbor:

$ docker tag busybox:1.37.0-glibc las3\:443/busybox:1.37.0-glibc
$ docker login las3\:443 -u admin -p AdminPassword123
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
$ docker push las3\:443/library/busybox:1.37.0-glibc
The push refers to repository [las3:443/library/busybox]
068f50152bbc: Pushed 
1.37.0-glibc: digest: sha256:f2e98ad37e4970f48e85946972ac4acb5574c39f27c624efbd9b17a3a402bfe4 size: 527
$ docker logout las3\:443
Removing login credentials for las3:443

Caution

  • You need always put the port number after your simple hostname, for docker try to add docker.io prefix before your hostname, which is awful design.

  • The project library is public, which means anyone can pull from it.

Configure HTTPS

Generate a Certificate Authority Certificate:

$ openssl genrsa -out ca.key 4096
$ openssl req -x509 -new -nodes -sha512 -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=Lasyard/OU=Lasy/CN=las3" -key ca.key -out ca.crt

The subject fields are explained below (by GitHub Copilot):

  • C: Country — The country code (ISO 3166-1 alpha-2), here “CN” stands for China

  • ST: State or Province — The state or province within the country, here “Beijing”

  • L: Locality — The city or locality, again “Beijing”

  • O: Organization — The name of the organization, here “Lasyard”

  • OU: Organizational Unit — A sub-division or department within the organization, here “Lasy”

  • CN: Common Name — The name of the entity, typically the server name for SSL/TLS certificates or the name of the Certificate Authority (CA). Here, it is “las3”

Create x509 v3 extension file v3.ext:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=las3

Generate a Server Certificate:

$ openssl genrsa -out las3.key 4096
$ openssl req -sha512 -new -subj "/C=CN/ST=Beijing/L=Beijing/O=Lasyard/OU=Lasy/CN=las3" -key las3.key -out las3.csr
$ openssl x509 -req -sha512 -days 3650 -extfile v3.ext -CA ca.crt -CAkey ca.key -CAcreateserial -in las3.csr -out las3.crt
Certificate request self-signature ok
subject=C = CN, ST = Beijing, L = Beijing, O = Lasyard, OU = Lasy, CN = las3

Copy the certs to the path configured in harbor.yml:

$ sudo mkdir /srv/data/cert
$ sudo cp las3.crt las3.key /srv/data/cert/

Trust CA

If we pull images from our new Harbor, we will get:

$ docker pull las3:443/library/busybox:1.37.0-glibc
Error response from daemon: Get "https://las3:443/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority

Because our CA is not trusted by the system.

You can install the ca.crt into the system to make it trusted:

$ sudo cp ca.crt /usr/local/share/ca-certificates/
$ sudo update-ca-certificates 
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

Alternatively, the ca.crt can be copied to docker config dir to make it trusted only by docker:

$ openssl x509 -inform PEM -in las3.crt -out las3.cert
$ sudo mkdir -p /etc/docker/certs.d/las3\:443
$ sudo cp ca.crt /etc/docker/certs.d/las3\:443

Anyway, the docker daemon need to be restarted:

$ sudo systemctl restart docker

Tip

Harbor containers were stopped during restarting of docker, start them by:

$ docker start $(docker ps -a | grep goharbor | cut -d' ' -f1)

To make a kubernetes cluster trust the self signed CA, it need to be added to the system before restarting the container runtime service, e.g. containerd:

$ sudo systemctl restart containerd