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

Note

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.

Caution

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)

Important

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