DEV-302: abolish manual installation steps
parent
0bbf0bc719
commit
37d94b5166
@ -1,3 +1,59 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
harbor_version: v2.4.1
|
harbor_version: v2.4.1
|
||||||
|
|
||||||
|
harbor_hostname: '{{ stage_server_domain }}'
|
||||||
|
harbor_external_url: 'https://{{ stage_server_domain }}'
|
||||||
|
|
||||||
|
harbor_admin_username: '{{ harbor_admin_username_vault }}'
|
||||||
|
harbor_admin_password: '{{ harbor_admin_password_vault }}'
|
||||||
|
|
||||||
|
traefik_id: '{{ inventory_hostname }}-harbor'
|
||||||
|
|
||||||
|
harbor_dockercompose_customized:
|
||||||
|
services:
|
||||||
|
core:
|
||||||
|
extra_hosts:
|
||||||
|
- '{{ shared_service_keycloak_hostname }}:{{ shared_service_keycloak_ip }}'
|
||||||
|
- '{{ shared_service_mail_hostname }}:{{ shared_service_mail_ip }}'
|
||||||
|
proxy:
|
||||||
|
networks:
|
||||||
|
- harbor
|
||||||
|
- front-tier
|
||||||
|
ports: [] # not exposing ports - already used by traefik
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.{{ traefik_id }}.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}.service={{ traefik_id }}"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}.rule=Host(`{{ harbor_hostname }}`)"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}.tls=true"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.{{ traefik_id }}.loadbalancer.server.port=8080"
|
||||||
|
- "traefik.http.middlewares.{{ traefik_id }}-monitor.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}-monitor.service={{ traefik_id }}-monitor"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}-monitor.rule=Host(`{{ harbor_hostname }}`)"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}-monitor.entrypoints=monitoring-harbor"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}-monitor.tls=true"
|
||||||
|
- "traefik.http.routers.{{ traefik_id }}-monitor.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.{{ traefik_id }}-monitor.loadbalancer.server.port=9090"
|
||||||
|
networks:
|
||||||
|
front-tier:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
harbor_base_configuration:
|
||||||
|
email_host: '{{ shared_service_mail_hostname }}'
|
||||||
|
email_port: 25
|
||||||
|
email_from: '{{ ansible_fqdn }}@{{ shared_service_mail_hostname }}'
|
||||||
|
email_password: ''
|
||||||
|
email_username: ''
|
||||||
|
email_insecure: true
|
||||||
|
auth_mode: oidc_auth
|
||||||
|
oidc_name: docker
|
||||||
|
oidc_endpoint: 'https://{{ shared_service_keycloak_hostname }}/auth/realms/docker'
|
||||||
|
oidc_client_id: docker-registry
|
||||||
|
oidc_groups_claim: groups
|
||||||
|
oidc_scope: openid
|
||||||
|
oidc_verify_cert: true
|
||||||
|
oidc_auto_onboard: true
|
||||||
|
oidc_admin_group: '/admin'
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: "Add harbor base configuration via API"
|
||||||
|
delegate_to: 127.0.0.1
|
||||||
|
become: false
|
||||||
|
uri:
|
||||||
|
url: "{{ harbor_external_url }}/api/v2.0/configurations"
|
||||||
|
user: '{{ harbor_admin_username }}'
|
||||||
|
password: '{{ harbor_admin_password }}'
|
||||||
|
method: PUT
|
||||||
|
body_format: json
|
||||||
|
force_basic_auth: yes
|
||||||
|
body: "{{ base_configuration }}"
|
||||||
|
headers:
|
||||||
|
Content-Type: application/json
|
||||||
|
status_code: [200]
|
||||||
|
register: base_setting
|
||||||
|
delay: 10
|
||||||
|
retries: 10
|
||||||
|
until: base_setting.status in [200]
|
||||||
@ -0,0 +1,154 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
### tags:
|
||||||
|
|
||||||
|
- name: "Setup DNS configuration for {{ inventory_hostname }} harbor"
|
||||||
|
include_role:
|
||||||
|
name: _digitalocean
|
||||||
|
tasks_from: domain
|
||||||
|
vars:
|
||||||
|
record_data: "{{ stage_server_ip }}"
|
||||||
|
record_name: "{{ inventory_hostname }}"
|
||||||
|
|
||||||
|
- name: 'Ensures {{ service_base_path }}/{{ inventory_hostname }} directory exists'
|
||||||
|
file:
|
||||||
|
state: directory
|
||||||
|
path: '{{ service_base_path }}/{{ inventory_hostname }}'
|
||||||
|
tags:
|
||||||
|
- update_deployment
|
||||||
|
- update_config
|
||||||
|
|
||||||
|
- name: Install pip dependencies
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- docker-compose
|
||||||
|
|
||||||
|
- name: 'Copy hacky upgrade script'
|
||||||
|
template:
|
||||||
|
src: 'hacky_harbor_upgrade.sh.j2'
|
||||||
|
dest: '/root/hacky_harbor_upgrade.sh'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: '0744'
|
||||||
|
tags:
|
||||||
|
- upgrade-helper
|
||||||
|
|
||||||
|
# work around for DEV-271("container start failure after reboot")
|
||||||
|
- name: Ensure systemd file
|
||||||
|
template:
|
||||||
|
src: harbor-systemd.service.j2
|
||||||
|
dest: /etc/systemd/system/harbor.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: "Check if harbor tarball exists"
|
||||||
|
stat:
|
||||||
|
path: '{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz'
|
||||||
|
register: harbor_tarball
|
||||||
|
|
||||||
|
- name: Download harbor offline installer
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://github.com/goharbor/harbor/releases/download/{{ harbor_version }}/harbor-offline-installer-{{ harbor_version }}.tgz
|
||||||
|
dest: "{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz"
|
||||||
|
when:
|
||||||
|
- not harbor_tarball.stat.exists
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
remote_docker_compose_file_path: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/docker-compose.yml'
|
||||||
|
|
||||||
|
- name: "Check if {{ inventory_hostname }}/harbor/docker-compose.yml exists"
|
||||||
|
stat:
|
||||||
|
path: '{{ remote_docker_compose_file_path }}'
|
||||||
|
register: harbor_installation
|
||||||
|
|
||||||
|
- name: Extract harbor-offline-installer-{{ harbor_version }}.tgz into {{ service_base_path }}/{{ inventory_hostname }}
|
||||||
|
ansible.builtin.unarchive:
|
||||||
|
src: "{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz"
|
||||||
|
dest: "{{ service_base_path }}/{{ inventory_hostname }}"
|
||||||
|
remote_src: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
- name: Ensure config template files are populated from templates/harbor
|
||||||
|
template:
|
||||||
|
src: "harbor.yml.j2"
|
||||||
|
dest: "{{ service_base_path }}/{{ inventory_hostname }}/harbor/harbor.yml"
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: "Exec harbor install.sh "
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: './install.sh {{ harbor_install_opts | default("--with-trivy --with-chartmuseum") }}'
|
||||||
|
chdir: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/'
|
||||||
|
ignore_errors: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
- name: "Stopping harbor"
|
||||||
|
community.docker.docker_compose:
|
||||||
|
project_src: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/'
|
||||||
|
stopped: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
- name: "ensure harbor systemd service also stopped"
|
||||||
|
systemd:
|
||||||
|
name: harbor
|
||||||
|
state: stopped
|
||||||
|
daemon_reload: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
# create backup in case just sth weird had happened
|
||||||
|
- name: "Create backup of generated docker-compose.yml by install.sh"
|
||||||
|
copy:
|
||||||
|
src: '{{ remote_docker_compose_file_path }}'
|
||||||
|
dest: '{{ remote_docker_compose_file_path}}_from_installsh'
|
||||||
|
remote_src: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
- name: "Create backup of common/config/nginx/nginx.conf"
|
||||||
|
copy:
|
||||||
|
src: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/common/config/nginx/nginx.conf'
|
||||||
|
dest: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/common/config/nginx/nginx.conf_orig'
|
||||||
|
remote_src: yes
|
||||||
|
when:
|
||||||
|
- not harbor_installation.stat.exists
|
||||||
|
|
||||||
|
- name:
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/common/config/nginx/nginx.conf'
|
||||||
|
state: absent
|
||||||
|
regexp: 'proxy_set_header'
|
||||||
|
|
||||||
|
- name: "Read remote docker-compose.yml from harbor DIR"
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: '{{ remote_docker_compose_file_path }}'
|
||||||
|
register: docker_compose_file_remote_encoded
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
harbor_dockercompose_merged: '{{ docker_compose_file_remote_encoded.content | b64decode | from_yaml | combine(harbor_dockercompose_customized, recursive=True) }}'
|
||||||
|
|
||||||
|
- name: "Create docker-compose.yml with merged VARs"
|
||||||
|
copy:
|
||||||
|
content: "{{ harbor_dockercompose_merged | to_nice_yaml(indent=2) }}"
|
||||||
|
dest: '{{ remote_docker_compose_file_path }}'
|
||||||
|
owner: 'root'
|
||||||
|
group: 'root'
|
||||||
|
mode: '0644'
|
||||||
|
register: docker_compose_change
|
||||||
|
|
||||||
|
- name: "Ensure harbor systemd service restarted"
|
||||||
|
systemd:
|
||||||
|
name: harbor
|
||||||
|
state: restarted
|
||||||
|
when: docker_compose_change.changed
|
||||||
|
|
||||||
|
- name: "Ensure harbor systemd service started"
|
||||||
|
systemd:
|
||||||
|
name: harbor
|
||||||
|
state: started
|
||||||
@ -1,117 +1,60 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
### tags:
|
- name: "Install harbor"
|
||||||
|
include_tasks: install.yml
|
||||||
- name: "Setup DNS configuration for {{ inventory_hostname }} harbor"
|
args:
|
||||||
include_role:
|
apply:
|
||||||
name: _digitalocean
|
tags:
|
||||||
tasks_from: domain
|
- harbor-install
|
||||||
vars:
|
|
||||||
record_data: "{{ stage_server_ip }}"
|
- name: "harbor BASE settings"
|
||||||
record_name: "{{ inventory_hostname }}"
|
block:
|
||||||
|
- name: "BLOCK: Login with keycloak-admin"
|
||||||
- name: 'Ensures {{ service_base_path }}/{{ inventory_hostname }} directory exists'
|
include_role:
|
||||||
file:
|
name: keycloak
|
||||||
state: directory
|
tasks_from: _authenticate
|
||||||
path: '{{ service_base_path }}/{{ inventory_hostname }}'
|
|
||||||
tags:
|
- name: "GET available clients from <<{{ harbor_base_configuration.oidc_name }}>>-realm"
|
||||||
- update_deployment
|
delegate_to: localhost
|
||||||
- update_config
|
become: False
|
||||||
|
uri:
|
||||||
- name: 'Ensure directory structure for harbor exists'
|
url: "{{ keycloak_server_url }}/auth/admin/realms/{{ harbor_base_configuration.oidc_name }}/clients"
|
||||||
file:
|
method: GET
|
||||||
path: "{{ service_base_path }}/{{ inventory_hostname }}/{{ item.path }}"
|
headers:
|
||||||
state: directory
|
Content-Type: "application/json"
|
||||||
owner: "{{ docker_owner }}"
|
Authorization: "Bearer {{ access_token }}"
|
||||||
group: "{{ docker_group }}"
|
status_code: [200]
|
||||||
mode: 0755
|
register: realm_clients
|
||||||
with_filetree: "templates/harbor"
|
|
||||||
when: item.state == "directory"
|
# available clients: get needed ID
|
||||||
tags:
|
- set_fact:
|
||||||
- update_config
|
id_of_client: '{{ ( realm_clients.json | selectattr("clientId","equalto", harbor_base_configuration.oidc_client_id ) | first ).id }}'
|
||||||
|
|
||||||
- name: 'Copy hacky upgrade script'
|
- name: "BLOCK: GET client-secret for client <<{{ harbor_base_configuration.oidc_client_id }}>> in realm <<{{ harbor_base_configuration.oidc_name }}>>"
|
||||||
template:
|
delegate_to: localhost
|
||||||
src: 'hacky_harbor_upgrade.sh.j2'
|
become: False
|
||||||
dest: '/root/hacky_harbor_upgrade.sh'
|
uri:
|
||||||
owner: 'root'
|
url: "{{ keycloak_server_url }}/auth/admin/realms/{{ harbor_base_configuration.oidc_name }}/clients/{{ id_of_client }}/client-secret"
|
||||||
group: 'root'
|
method: GET
|
||||||
mode: '0744'
|
headers:
|
||||||
tags:
|
Content-Type: "application/json"
|
||||||
- upgrade-helper
|
Authorization: "Bearer {{ access_token }}"
|
||||||
|
status_code: [200]
|
||||||
- name: Ensure config template files are populated from templates/harbor
|
register: client_secret
|
||||||
template:
|
|
||||||
src: "{{ item.src }}"
|
- set_fact:
|
||||||
dest: "{{ service_base_path }}/{{ inventory_hostname }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
dict:
|
||||||
owner: "{{ docker_owner }}"
|
oidc_client_secret: '{{ client_secret.json.value }}'
|
||||||
group: "{{ docker_group }}"
|
|
||||||
mode: 0644
|
- set_fact:
|
||||||
with_filetree: "templates/harbor"
|
harbor_base_configuration_merged: '{{ harbor_base_configuration | combine( dict ,recursive=True ) }}'
|
||||||
when: item.state == 'file' and item.src is match('.*\.j2$')
|
|
||||||
tags:
|
- name: "BLOCK: Configure harbor BASE settings"
|
||||||
- update_config
|
include_tasks: configure_base_config.yml
|
||||||
|
vars:
|
||||||
# work around for DEV-271("container start failure after reboot")
|
base_configuration: '{{ harbor_base_configuration_merged }}'
|
||||||
- name: Ensure systemd file
|
args:
|
||||||
template:
|
apply:
|
||||||
src: harbor-systemd.service.j2
|
tags:
|
||||||
dest: /etc/systemd/system/harbor.service
|
- harbor-configure-base
|
||||||
owner: root
|
# end of block for base settings
|
||||||
group: root
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
- name: Ensure config files are populated from from templates/harbor
|
|
||||||
copy:
|
|
||||||
src: "{{ item.src }}"
|
|
||||||
dest: "{{ service_base_path }}/{{ inventory_hostname }}/{{ item.path }}"
|
|
||||||
owner: "{{ docker_owner }}"
|
|
||||||
group: "{{ docker_group }}"
|
|
||||||
mode: 0644
|
|
||||||
with_filetree: "templates/harbor"
|
|
||||||
when: item.state == 'file' and item.src is not match('.*\.j2$')
|
|
||||||
tags:
|
|
||||||
- update_config
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: "Check if harbor tarball exists"
|
|
||||||
stat:
|
|
||||||
path: '{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz'
|
|
||||||
register: harbor_tarball
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Download harbor offline installer
|
|
||||||
ansible.builtin.get_url:
|
|
||||||
url: https://github.com/goharbor/harbor/releases/download/{{ harbor_version }}/harbor-offline-installer-{{ harbor_version }}.tgz
|
|
||||||
dest: "{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz"
|
|
||||||
when:
|
|
||||||
- not harbor_tarball.stat.exists
|
|
||||||
|
|
||||||
- name: "Check if {{ inventory_hostname }}/harbor/docker-compose.yml exists"
|
|
||||||
stat:
|
|
||||||
path: '{{ service_base_path }}/{{ inventory_hostname }}/harbor/docker-compose.yml'
|
|
||||||
register: harbor_installation
|
|
||||||
|
|
||||||
- name: Extract harbor-offline-installer-{{ harbor_version }}.tgz into {{ service_base_path }}/{{ inventory_hostname }}
|
|
||||||
ansible.builtin.unarchive:
|
|
||||||
src: "{{ service_base_path }}/{{ inventory_hostname }}/harbor-offline-installer-{{ harbor_version }}.tgz"
|
|
||||||
dest: "{{ service_base_path }}/{{ inventory_hostname }}"
|
|
||||||
remote_src: yes
|
|
||||||
when:
|
|
||||||
- not harbor_installation.stat.exists
|
|
||||||
|
|
||||||
- name: "Check if {{ inventory_hostname }}/harbor/docker-compose.yml exists"
|
|
||||||
stat:
|
|
||||||
path: '{{ service_base_path }}/harbor/{{ inventory_hostname }}/docker-compose.yml'
|
|
||||||
register: check_docker_compose_file
|
|
||||||
tags:
|
|
||||||
- update_deployment
|
|
||||||
|
|
||||||
- name: "Ensure harbor is running"
|
|
||||||
systemd:
|
|
||||||
name: harbor
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
||||||
daemon_reload: yes
|
|
||||||
|
|||||||
Loading…
Reference in New Issue