How to setup Harbor registry using Ansible playbook
Here in this article we will try to install and configure Harbor registry using Ansible playbook.
Test Environment
Fedora 41 server
Docker version 27.3.1
Docker Compose version v2.29.7
What is Harbor
Harbor is an open source registry that secures artifacts with policies and role-based access control, ensures images are scanned and free from vulnerabilities, and signs images as trusted. Harbor, a CNCF Graduated project, delivers compliance, performance, and interoperability to help you consistently and securely manage artifacts across cloud native compute platforms like Kubernetes and Docker.
Here is the project structure for harbor setup.
admin@fedser:learnansible$ tree harbour/
harbour/
├── inventory
│ ├── hosts
│ └── host_vars
│ └── linuxser.stack.com.yml
├── linux_setup_harbour.yml
├── README.md
└── roles
├── linux_download_harbour
│ └── tasks
│ └── main.yml
├── linux_expose_harbour
│ ├── defaults
│ │ └── main.yml
│ └── tasks
│ └── main.yml
├── linux_install_harbour
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── harbor.yml.j2
├── linux_ping
│ └── tasks
│ └── main.yml
├── linux_start_harbour
│ └── tasks
│ └── main.yml
└── linux_stop_harbour
└── tasks
└── main.yml
Also, here are the global variables set in the host_vars folder that we will be using in the ansible roles.
admin@fedser:harbour$ cat inventory/host_vars/linuxser.stack.com.yml
---
home_dir: /home/admin/stack
artifact_dir: /home/admin/stack/artifacts
extract_dir: /home/admin/stack/extracts
harbour_repo: https://github.com/goharbor/harbor/releases/download/v2.12.0
harbour_package: "harbor-offline-installer-v2.12.0.tgz"
Here is the inventory file with the node “linuxser.stack.com” on which the harbor setup is going to be carried out.
admin@fedser:harbour$ cat inventory/hosts
[harbour]
linuxser.stack.com
Procedure
Step1: Download Harbor package
As a first step we are going to download and extract the “Harbor offline installer” package. Here is the ansible role “linux_download_harbour” for the same.
admin@fedser:harbour$ cat roles/linux_download_harbour/tasks/main.yml
---
- name: ensure home directory exists
file:
path: "{{ home_dir }}"
state: directory
mode: '0755'
owner: admin
group: admin
- name: ensure artifacts directory exists
file:
path: "{{ artifact_dir }}"
state: directory
mode: '0755'
owner: admin
group: admin
- name: download harbour_package
get_url:
url: "{{ harbour_repo }}/{{ harbour_package }}"
dest: "{{ artifact_dir }}/{{ harbour_package }}"
mode: '0440'
owner: admin
group: admin
- name: extract harbour_package
unarchive:
src: "{{ artifact_dir }}/{{ harbour_package }}"
dest: "{{ home_dir }}"
remote_src: yes
- name: ensure home directory permissions updated
file:
path: "{{ home_dir }}"
state: directory
mode: '0755'
owner: admin
group: admin
recurse: true
Step2: Install harbor package
Once the harbor package has been download and extracted. Next we will need to install the harbor package. Here we are going to setup harbor to listen on https port.
For https setup we will need to generate server certificate key pair. We are using “sscg” package to generate a self signed certificate key pair along with the ca certificate.
Once the certificates are generated we are required to copy and make them available for harbor and docker as shown below. We need to convert linuxser.stack.com.crt to linuxser.stack.com.cert, for use by Docker. Please restart the docker service once necessary cert files have been copied.
Next we need to configure harbor using the “harbor.yml” file. When you extract the harbor installer package, you will get a “harbor.yml.tmpl” which we can update to configure harbor. In this file i am updating the hostname to my FQDN and the https section provide the location of server certificate and key file. Every other setting is kept the default. For clarity i have removed all the other default except for the ones that i have changed.
Now we are reading to install harbor with the updated configuration. Here we are installing harbor with trivy enabled so we can use it to scan images.
habor.yml template
admin@fedser:harbour$ cat roles/linux_install_harbour/templates/harbor.yml.j2
# Configuration file of Harbor
# 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: {{ ansible_host }}
# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 80
# https related config
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: {{ home_dir }}/certs/{{ ansible_host }}.crt
private_key: {{ home_dir }}/certs/{{ ansible_host }}.key
# enable strong ssl ciphers (default: false)
# strong_ssl_ciphers: false
...
linux_install_harbour role
admin@fedser:harbour$ cat roles/linux_install_harbour/tasks/main.yml
---
- name: ensure sscg present
dnf:
name: sscg
state: present
- name: ensure certs directory exists
file:
path: "{{ home_dir }}/certs"
state: directory
mode: '0700'
owner: admin
group: admin
recurse: true
- name: check if cert file exists
stat:
path: "{{ home_dir }}/certs/{{ ansible_host }}.crt"
register: result
- name: generate self signed certificate
shell: "cd {{ home_dir }}/certs; sscg --cert-file={{ ansible_host }}.crt --cert-key-file={{ ansible_host }}.key --ca-file=ca.crt --ca-key-file=ca.key"
when: not result.stat.exists
- name: convert crt file to cert
shell: "openssl x509 -inform PEM -in {{ home_dir }}/certs/{{ ansible_host }}.crt -out {{ home_dir }}/certs/{{ ansible_host }}.cert"
- name: ensure certs directory permissions updated
file:
path: "{{ home_dir }}/certs"
state: directory
mode: '0700'
owner: admin
group: admin
recurse: yes
- name: ensure certs directory exists in docker
file:
path: "/etc/docker/certs.d/{{ ansible_host }}"
state: directory
mode: '0700'
- name: copy server cert to docker certs directory
copy:
src: "{{ home_dir }}/certs/{{ ansible_host }}.cert"
dest: "/etc/docker/certs.d/{{ ansible_host }}"
remote_src: yes
- name: copy server key to docker certs directory
copy:
src: "{{ home_dir }}/certs/{{ ansible_host }}.key"
dest: "/etc/docker/certs.d/{{ ansible_host }}"
remote_src: yes
- name: copy ca cert to docker certs directory
copy:
src: "{{ home_dir }}/certs/ca.crt"
dest: "/etc/docker/certs.d/{{ ansible_host }}"
remote_src: yes
- name: "ensure docker service restarted"
service:
name: docker
state: restarted
- name: configure harbor.yml
template:
src: "harbor.yml.j2"
dest: "{{ home_dir }}/harbor/harbor.yml"
owner: admin
group: admin
mode: '0755'
- name: execute harbour installation script
shell: "{{ home_dir }}/harbor/install.sh --with-trivy"
Step3: Expose harbor service ports
Here we are going to expose the following ports at the linux firewall level.
Port | Protocol | Description |
443 | HTTPS | Harbor portal and core API accept HTTPS requests on this port. You can change this port in the configuration file. |
4443 | HTTPS | Connections to the Docker Content Trust service for Harbor. You can change this port in the configuration file. |
80 | HTTP | Harbor portal and core API accept HTTP requests on this port. You can change this port in the configuration file. |
linux_expose_harbour role
admin@fedser:harbour$ cat roles/linux_expose_harbour/defaults/main.yml
---
harbor_http_port: "80"
harbor_https_port: "443"
harbor_trustservice_port: "4443"
linux_expose_harbour role
admin@fedser:harbour$ cat roles/linux_expose_harbour/tasks/main.yml
---
- name: expose http port
firewalld:
port: "{{harbor_http_port}}/tcp"
permanent: true
immediate: true
state: enabled
- name: expose https port
firewalld:
port: "{{harbor_https_port}}/tcp"
permanent: true
immediate: true
state: enabled
- name: expose trustservice port
firewalld:
port: "{{harbor_trustservice_port}}/tcp"
permanent: true
immediate: true
state: enabled
- name: restart firewalld service
service:
name: firewalld
state: restarted
Step4: Start Harbor service
We need to ensure that the docker service is up and running. Once the docker serivce is started we can start our harbor using the docker compose command as shown below.
linux_start_harbour role
admin@fedser:harbour$ cat roles/linux_start_harbour/tasks/main.yml
---
- name: "ensure docker service restarted"
service:
name: docker
state: started
- name: ensure harbor service is started
shell: "cd {{ home_dir }}/harbor; docker compose up -d"
Step5: Stop Harbor service
Here the role to stop docker and harbor service as shown below.
admin@fedser:harbour$ cat roles/linux_stop_harbour/tasks/main.yml
---
- name: "ensure docker service stopped"
service:
name: docker
state: stopped
- name: ensure harbor service is stopped
shell: "cd {{ home_dir }}/harbor; docker compose down -v"
Step6: Executing the Playbook
Here is the complete playbook.
admin@fedser:harbour$ cat linux_setup_harbour.yml
---
- hosts: "harbour"
serial: 1
become: true
become_user: root
roles:
- { role: "linux_ping", tags: "linux_ping" }
- { role: "linux_download_harbour", tags: "linux_download_harbour" }
- { role: "linux_install_harbour", tags: "linux_install_harbour" }
- { role: "linux_expose_harbour", tags: "linux_expose_harbour" }
- { role: "linux_stop_harbour", tags: "linux_stop_harbour" }
- { role: "linux_start_harbour", tags: "linux_start_harbour" }
Here are the instructions for executing each role individually.
admin@fedser:harbour$ cat README.md
# Instructions for execution
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_ping" -v
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_download_harbour" -v
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_install_harbour" -v
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_expose_harbour" -v
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_stop_harbour" -v
ansible-playbook linux_setup_harbour.yml -i inventory/hosts --tags "linux_start_harbour" -v
Let us comment out “linux_stop_harbour” role execution in “linux_setup_harbour.yml” and execute the playbook.
admin@fedser:harbour$ ansible-playbook linux_setup_harbour.yml -i inventory/hosts
PLAY [harbour] *************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_ping : ansible ping pong validation] ***************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_download_harbour : ensure package home directory exists] *******************************************************************
ok: [linuxser.stack.com]
TASK [linux_download_harbour : ensure artifacts directory exists] **********************************************************************
ok: [linuxser.stack.com]
TASK [linux_download_harbour : ensure extracts directory exists] ***********************************************************************
ok: [linuxser.stack.com]
TASK [linux_download_harbour : download harbour_package] *******************************************************************************
ok: [linuxser.stack.com]
TASK [linux_download_harbour : extract harbour_package] ********************************************************************************
changed: [linuxser.stack.com]
TASK [linux_download_harbour : ensure home directory permissions updated] **************************************************************
changed: [linuxser.stack.com]
TASK [linux_install_harbour : ensure sscg present] *************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : ensure certs directory exists] ***************************************************************************
changed: [linuxser.stack.com]
TASK [linux_install_harbour : check if cert file exists] *******************************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : generate self signed certificate] ************************************************************************
skipping: [linuxser.stack.com]
TASK [linux_install_harbour : convert crt file to cert] ********************************************************************************
changed: [linuxser.stack.com]
TASK [linux_install_harbour : ensure certs directory permissions updated] **************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : ensure certs directory exists in docker] *****************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : copy server cert to docker certs directory] **************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : copy server key to docker certs directory] ***************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : copy ca cert to docker certs directory] ******************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : ensure docker service restarted] *************************************************************************
changed: [linuxser.stack.com]
TASK [linux_install_harbour : configure harbor.yml] ************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_install_harbour : execute harbour installation script] *********************************************************************
changed: [linuxser.stack.com]
TASK [linux_expose_harbour : expose http port] *****************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_expose_harbour : expose https port] ****************************************************************************************
ok: [linuxser.stack.com]
TASK [linux_expose_harbour : expose trustservice port] *********************************************************************************
ok: [linuxser.stack.com]
TASK [linux_expose_harbour : restart firewalld service] ********************************************************************************
changed: [linuxser.stack.com]
TASK [linux_start_harbour : ensure docker service restarted] ***************************************************************************
ok: [linuxser.stack.com]
TASK [linux_start_harbour : ensure harbor service is started] **************************************************************************
changed: [linuxser.stack.com]
PLAY RECAP *****************************************************************************************************************************
linuxser.stack.com : ok=26 changed=8 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Step7: Validate Harbor service
Once the playbook execution is completed. The installation will instantiate multiple docker container to provide the harbor service as shown below on the harbor host.
admin@linuxser:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4adeb4bf60af goharbor/harbor-jobservice:v2.12.0 "/harbor/entrypoint.…" 56 seconds ago Up 54 seconds (healthy) harbor-jobservice
a2a13a37a650 goharbor/nginx-photon:v2.12.0 "nginx -g 'daemon of…" 56 seconds ago Up 54 seconds (healthy) 0.0.0.0:80->8080/tcp, [::]:80->8080/tcp, 0.0.0.0:443->8443/tcp, [::]:443->8443/tcp nginx
36a9ebb4c0f7 goharbor/trivy-adapter-photon:v2.12.0 "/home/scanner/entry…" 56 seconds ago Up 55 seconds (healthy) trivy-adapter
7e95714f5770 goharbor/harbor-core:v2.12.0 "/harbor/entrypoint.…" 56 seconds ago Up 55 seconds (healthy) harbor-core
371b84a71497 goharbor/redis-photon:v2.12.0 "redis-server /etc/r…" 56 seconds ago Up 55 seconds (healthy) redis
286825e1b892 goharbor/harbor-portal:v2.12.0 "nginx -g 'daemon of…" 56 seconds ago Up 55 seconds (healthy) harbor-portal
850fc847fad1 goharbor/harbor-db:v2.12.0 "/docker-entrypoint.…" 56 seconds ago Up 55 seconds (healthy) harbor-db
c3bc7a29cdef goharbor/registry-photon:v2.12.0 "/home/harbor/entryp…" 56 seconds ago Up 55 seconds (healthy) registry
80ac07979004 goharbor/harbor-registryctl:v2.12.0 "/home/harbor/start.…" 56 seconds ago Up 55 seconds (healthy) registryctl
862d9f3914ba goharbor/harbor-log:v2.12.0 "/bin/sh -c /usr/loc…" 56 seconds ago Up 55 seconds (healthy) 127.0.0.1:1514->10514/tcp
Now let us try to login to the registry using the docker utility as shown below.
admin@linuxser:~/stack/harbor$ docker login linuxser.stack.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /home/admin/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
You can also launch the harbor portal using the following https url.
URL - https://linuxser.stack.com/
username - admin
password - Harbor12345
NOTE: We are using the default credentials which needs to be updated or changed in production environment.
Hope you enjoyed reading this article. Thank you..
Leave a Reply
You must be logged in to post a comment.