mirror of
https://github.com/kubesphere/kubekey.git
synced 2025-12-25 17:12:50 +00:00
feat: install image_registry (#2640)
Signed-off-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
parent
9686e047be
commit
8237a2fd88
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.4
|
etcd_version: v3.5.4
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.6.3
|
# harbor_version: v2.6.3
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.6
|
etcd_version: v3.5.6
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: v2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.7.1
|
# harbor_version: v2.7.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.7
|
etcd_version: v3.5.7
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.8.1
|
# harbor_version: v2.8.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.8
|
etcd_version: v3.5.8
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.9.1
|
# harbor_version: v2.9.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.9
|
etcd_version: v3.5.9
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.9
|
etcd_version: v3.5.9
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.10
|
etcd_version: v3.5.10
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.10
|
etcd_version: v3.5.10
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.11
|
etcd_version: v3.5.11
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.11
|
etcd_version: v3.5.11
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
etcd_version: v3.5.11
|
etcd_version: v3.5.11
|
||||||
# ========== image registry ==========
|
# ========== image registry ==========
|
||||||
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
# keepalived image tag. Used for load balancing when there are multiple image registry nodes.
|
||||||
# keepalived_version: stable
|
# keepalived_version: 2.0.20
|
||||||
# ========== image registry: harbor ==========
|
# ========== image registry: harbor ==========
|
||||||
# harbor image tag
|
# harbor image tag
|
||||||
# harbor_version: v2.10.1
|
# harbor_version: v2.10.1
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
- import_playbook: hook/pre_install.yaml
|
- import_playbook: hook/pre_install.yaml
|
||||||
|
|
||||||
- hosts:
|
- hosts:
|
||||||
- localhost
|
- localhost
|
||||||
roles:
|
roles:
|
||||||
- init/init-artifact
|
- init/init-artifact
|
||||||
- init/init-cert
|
- init/init-cert
|
||||||
|
|
||||||
- hosts:
|
- hosts:
|
||||||
- image_registry
|
- image_registry
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@
|
||||||
{{- range .groups.etcd | default list -}}
|
{{- range .groups.etcd | default list -}}
|
||||||
{{- $internalIPv4 := index $.hostvars . "internal_ipv4" | default "" -}}
|
{{- $internalIPv4 := index $.hostvars . "internal_ipv4" | default "" -}}
|
||||||
{{- $internalIPv6 := index $.hostvars . "internal_ipv6" | default "" -}}
|
{{- $internalIPv6 := index $.hostvars . "internal_ipv6" | default "" -}}
|
||||||
{{- if ne $internalIPv4 "" -}}
|
{{- if $internalIPv4 | empty | not -}}
|
||||||
{{- $ips = append $ips $internalIPv4 -}}
|
{{- $ips = append $ips $internalIPv4 -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if ne $internalIPv6 "" -}}
|
{{- if $internalIPv6 | empty | not -}}
|
||||||
{{- $ips = append $ips $internalIPv6 -}}
|
{{- $ips = append $ips $internalIPv6 -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
@ -46,13 +46,16 @@
|
||||||
cn: image_registry
|
cn: image_registry
|
||||||
sans: >-
|
sans: >-
|
||||||
{{- $ips := list -}}
|
{{- $ips := list -}}
|
||||||
|
{{- if .image_registry.ha_vip | empty | not -}}
|
||||||
|
{{- $ips = append $ips .image_registry.ha_vip -}}
|
||||||
|
{{- end -}}
|
||||||
{{- range .groups.image_registry | default list -}}
|
{{- range .groups.image_registry | default list -}}
|
||||||
{{- $internalIPv4 := index $.hostvars . "internal_ipv4" | default "" -}}
|
{{- $internalIPv4 := index $.hostvars . "internal_ipv4" | default "" -}}
|
||||||
{{- $internalIPv6 := index $.hostvars . "internal_ipv6" | default "" -}}
|
{{- $internalIPv6 := index $.hostvars . "internal_ipv6" | default "" -}}
|
||||||
{{- if ne $internalIPv4 "" -}}
|
{{- if $internalIPv4 | empty | not -}}
|
||||||
{{- $ips = append $ips $internalIPv4 -}}
|
{{- $ips = append $ips $internalIPv4 -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if ne $internalIPv6 "" -}}
|
{{- if $internalIPv6 | empty | not -}}
|
||||||
{{- $ips = append $ips $internalIPv6 -}}
|
{{- $ips = append $ips $internalIPv6 -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ image_registry:
|
||||||
nfs_dir: /share/registry
|
nfs_dir: /share/registry
|
||||||
storage:
|
storage:
|
||||||
filesystem:
|
filesystem:
|
||||||
rootdir: /var/lib/registry
|
rootdir: /opt/registry/data
|
||||||
# nfs_mount: /repository/registry # if set. will mount rootdirectory to nfs server in nfs_mount.
|
# nfs_mount: /repository/registry # if set. will mount rootdirectory to nfs server in nfs_mount.
|
||||||
# azure:
|
# azure:
|
||||||
# accountname: accountname
|
# accountname: accountname
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
nc -zv -w 2 localhost 443 > /dev/null 2>&1
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
register: docker_install_version
|
register: docker_install_version
|
||||||
|
|
||||||
- name: Install docker
|
- name: Install docker
|
||||||
when: .docker_install_version.stderr | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not)
|
when: or (.docker_install_version.stderr | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not)
|
||||||
block:
|
block:
|
||||||
- name: Sync docker binary to remote
|
- name: Sync docker binary to remote
|
||||||
copy:
|
copy:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
- name: Sync harbor package to remote
|
- name: Sync harbor package to remote
|
||||||
copy:
|
copy:
|
||||||
src: >-
|
src: >-
|
||||||
{{ .binary_dir }}/image-registry/harbor/{{ .harbor_version }}/{{ .binary_type.stdout }}/harbor-offline-installer-{{ .harbor_version }}.tgz
|
{{ .binary_dir }}/image-registry/harbor/{{ .harbor_version }}/{{ .binary_type }}/harbor-offline-installer-{{ .harbor_version }}.tgz
|
||||||
dest: >-
|
dest: >-
|
||||||
/opt/harbor/{{ .harbor_version }}/harbor-offline-installer-{{ .harbor_version }}.tgz
|
/opt/harbor/{{ .harbor_version }}/harbor-offline-installer-{{ .harbor_version }}.tgz
|
||||||
|
|
||||||
|
|
@ -30,15 +30,6 @@
|
||||||
dest: >-
|
dest: >-
|
||||||
/opt/harbor/{{ .harbor_version }}/harbor/harbor.yml
|
/opt/harbor/{{ .harbor_version }}/harbor/harbor.yml
|
||||||
|
|
||||||
- name: Generate keepalived docker compose
|
|
||||||
template:
|
|
||||||
src: harbor_keepalived.docker-compose
|
|
||||||
dest: >-
|
|
||||||
/opt/harbor/{{ .harbor_version }}/harbor/docker-compose-keepalived.yml
|
|
||||||
when:
|
|
||||||
- .image_registry.ha_vip | empty | not
|
|
||||||
- .image_registry_service.stderr | empty | not
|
|
||||||
|
|
||||||
- name: Install harbor
|
- name: Install harbor
|
||||||
command: |
|
command: |
|
||||||
cd /opt/harbor/{{ .harbor_version }}/harbor && /bin/bash install.sh
|
cd /opt/harbor/{{ .harbor_version }}/harbor && /bin/bash install.sh
|
||||||
|
|
@ -50,3 +41,62 @@
|
||||||
|
|
||||||
- name: Start harbor service
|
- name: Start harbor service
|
||||||
command: systemctl daemon-reload && systemctl start harbor.service && systemctl enable harbor.service
|
command: systemctl daemon-reload && systemctl start harbor.service && systemctl enable harbor.service
|
||||||
|
|
||||||
|
- name: HA harbor sync images
|
||||||
|
when:
|
||||||
|
- .image_registry.ha_vip | empty | not
|
||||||
|
- .groups.image_registry | len | lt 1
|
||||||
|
block:
|
||||||
|
- name: add keepalived service to docker-compose
|
||||||
|
command: |
|
||||||
|
KEEPALIVED_SERVICE='# keepalived is generated by kubekey.
|
||||||
|
keepalived:
|
||||||
|
image: osixia/keepalived:{{ .keepalived_version }}
|
||||||
|
container_name: keepalived
|
||||||
|
command:
|
||||||
|
- --copy-service
|
||||||
|
network_mode: "host"
|
||||||
|
restart: always
|
||||||
|
dns_search: .
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_BROADCAST
|
||||||
|
- NET_RAW
|
||||||
|
- CHOWN
|
||||||
|
- DAC_OVERRIDE
|
||||||
|
depends_on:
|
||||||
|
- proxy
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: /opt/keepalived/{{ .keepalived_version }}/keepalived.conf
|
||||||
|
target: /container/service/keepalived/assets/keepalived.conf
|
||||||
|
- type: bind
|
||||||
|
source: /opt/keepalived/{{ .keepalived_version }}/healthcheck.sh
|
||||||
|
target: /etc/keepalived/healthcheck.sh'
|
||||||
|
TARGET_FILE="/opt/harbor/{{ .harbor_version }}/harbor/docker-compose.yml"
|
||||||
|
TMP_FILE="/opt/harbor/{{ .harbor_version }}/harbor/docker-compose.yml.tmp"
|
||||||
|
awk -v service="$KEEPALIVED_SERVICE" '
|
||||||
|
/^services:/ {
|
||||||
|
print
|
||||||
|
print service
|
||||||
|
next
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' "$TARGET_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$TARGET_FILE"
|
||||||
|
systemctl restart harbor.service
|
||||||
|
- name: wait harbor service ready
|
||||||
|
command: |
|
||||||
|
if ! timeout 300 bash -c 'while ! nc -zv localhost 443; do sleep 2; done'; then
|
||||||
|
echo "ERROR: Harbor did not start within 5 minutes!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: sync harbor-replications scripts to remote
|
||||||
|
template:
|
||||||
|
src: harbor-replications.sh
|
||||||
|
dest: /opt/harbor/scripts/harbor-replications.sh
|
||||||
|
mode: 0755
|
||||||
|
- name: execute harbor-replications.sh
|
||||||
|
command: bash /opt/harbor/scripts/harbor-replications.sh
|
||||||
|
|
||||||
|
|
@ -1,23 +1,65 @@
|
||||||
---
|
---
|
||||||
|
- name: Get interface from ha_vip
|
||||||
|
block:
|
||||||
|
- name: Get all interface with cidr
|
||||||
|
command: |
|
||||||
|
ip -o addr show | awk '
|
||||||
|
BEGIN {
|
||||||
|
printf "[\n";
|
||||||
|
first = 1;
|
||||||
|
}
|
||||||
|
/inet / && !/ lo|docker|br-|veth/ {
|
||||||
|
if (!first) {
|
||||||
|
printf ",\n";
|
||||||
|
}
|
||||||
|
first = 0;
|
||||||
|
printf " {\n";
|
||||||
|
printf " \"interface\": \"%s\",\n", $2;
|
||||||
|
printf " \"cidr\": \"%s\"\n", $4;
|
||||||
|
printf " }";
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
printf "\n]\n";
|
||||||
|
}
|
||||||
|
'
|
||||||
|
register: interface
|
||||||
|
register_type: json
|
||||||
|
- name: filter interface by ha_vip
|
||||||
|
set_fact:
|
||||||
|
ha_vip_interface: >-
|
||||||
|
{{- $interface := "" }}
|
||||||
|
{{- range .interface.stdout | default list -}}
|
||||||
|
{{- if .cidr | ipInCIDR | has $.image_registry.ha_vip -}}
|
||||||
|
{{- $interface = .interface -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{ $interface }}
|
||||||
|
- name: Check if network is exist
|
||||||
|
assert:
|
||||||
|
that: .kube_vip_interface | empty
|
||||||
|
fail_msg: "cannot find network interface to match ha_vip"
|
||||||
|
|
||||||
- name: Sync keepalived image to remote
|
- name: Sync keepalived image to remote
|
||||||
copy:
|
copy:
|
||||||
src: >-
|
src: >-
|
||||||
{{ .binary_dir }}/image-registry/keepalived/{{ .keepalived_version }}/{{ .binary_type.stdout }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type.stdout }}.tgz
|
{{ .binary_dir }}/image-registry/keepalived/{{ .keepalived_version }}/{{ .binary_type }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz
|
||||||
dest: >-
|
dest: >-
|
||||||
/opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type.stdout }}.tgz
|
/opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz
|
||||||
|
|
||||||
- name: Load keeplived image
|
- name: Load keeplived image
|
||||||
command: |
|
command: |
|
||||||
docker load -i /opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type.stdout }}.tgz
|
docker load -i /opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz
|
||||||
|
|
||||||
- name: Sync keeplived config to remote
|
- name: Sync keeplived config to remote
|
||||||
template:
|
template:
|
||||||
src: keeplived.config
|
src: keepalived.conf
|
||||||
dest: >-
|
dest: >-
|
||||||
/opt/keeplived/{{ .keepalived_version }}/keepalived.conf
|
/opt/keepalived/{{ .keepalived_version }}/keepalived.conf
|
||||||
|
mode: 0664
|
||||||
|
|
||||||
- name: Sync healthcheck shell to remote
|
- name: Sync healthcheck shell to remote
|
||||||
template:
|
copy:
|
||||||
src: keepalived.healthcheck
|
src: keepalived/healthcheck.sh
|
||||||
dest: >-
|
dest: >-
|
||||||
/opt/keeplived/{{ .keepalived_version }}/healthcheck.sh
|
/opt/keepalived/{{ .keepalived_version }}/healthcheck.sh
|
||||||
|
mode: 0755
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,8 @@
|
||||||
mount -t nfs {{ $internalIPv6 }}:{{ .image_registry.registry.storage.filesystem.nfs_mount }} {{ .image_registry.registry.storage.filesystem.rootdir }}
|
mount -t nfs {{ $internalIPv6 }}:{{ .image_registry.registry.storage.filesystem.nfs_mount }} {{ .image_registry.registry.storage.filesystem.rootdir }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
when:
|
when:
|
||||||
- and .image_registry.registry.storage.filesystem.nfs_mount (ne .image_registry.registry.storage.filesystem.nfs_mount "")
|
- .image_registry.registry.storage.filesystem.nfs_mount | empty | not
|
||||||
- .groups.nfs | default list | len | eq 1
|
- .groups.nfs | default list | len | eq 1
|
||||||
- .image_registry_service.stderr | empty | not
|
|
||||||
|
|
||||||
- name: Load registry image
|
- name: Load registry image
|
||||||
command: |
|
command: |
|
||||||
|
|
@ -58,9 +57,16 @@
|
||||||
/opt/registry/{{ .registry_version }}/config.yml
|
/opt/registry/{{ .registry_version }}/config.yml
|
||||||
|
|
||||||
- name: Register registry service
|
- name: Register registry service
|
||||||
copy:
|
template:
|
||||||
src: registry.service
|
src: registry.service
|
||||||
dest: /etc/systemd/system/registry.service
|
dest: /etc/systemd/system/registry.service
|
||||||
|
|
||||||
- name: Start registry service
|
- name: Start registry service
|
||||||
command: systemctl daemon-reload && systemctl start registry.service && systemctl enable registry.service
|
command: systemctl daemon-reload && systemctl start registry.service && systemctl enable registry.service
|
||||||
|
|
||||||
|
- name: wait registry service ready
|
||||||
|
command: |
|
||||||
|
if ! timeout 300 bash -c 'while ! nc -zv localhost 443; do sleep 2; done'; then
|
||||||
|
echo "ERROR: Harbor did not start within 5 minutes!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
done
|
done
|
||||||
when: .image_registry.type | eq "harbor"
|
when: .image_registry.type | eq "harbor"
|
||||||
|
|
||||||
- name: Sync images package to harbor
|
- name: Sync images package to image_registry
|
||||||
tags: ["only_image"]
|
tags: ["only_image"]
|
||||||
image:
|
image:
|
||||||
push:
|
push:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
- include_tasks: install_docker_compose.yaml
|
- include_tasks: install_docker_compose.yaml
|
||||||
|
|
||||||
- include_tasks: install_keepalived.yaml
|
- include_tasks: install_keepalived.yaml
|
||||||
when: .image_registry.ha_vip | empty | not
|
when:
|
||||||
|
- .image_registry.ha_vip | empty | not
|
||||||
|
- .groups.image_registry | len | lt 1
|
||||||
|
|
||||||
- name: Install harbor
|
- name: Install harbor
|
||||||
when: .image_registry.type | eq "harbor"
|
when: .image_registry.type | eq "harbor"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function createRegistries() {
|
||||||
|
{{- range .groups.image_registry | default list }}
|
||||||
|
{{- if ne . $.inventory_hostname }}
|
||||||
|
curl -k -u '{{ printf "%s:%s" $.image_registry.auth.username $.image_registry.auth.password }}' -X POST -H "Content-Type: application/json" "https://{{ $.inventory_hostname }}/api/v2.0/registries" -d "{\"name\": \"{{ . }}\", \"type\": \"harbor\", \"url\":\"https://{{ . }}:7443\", \"credential\": {\"access_key\": \"{{ $.image_registry.auth.username }}\", \"access_secret\": \"{{ $.image_registry.auth.password }}\"}, \"insecure\": true}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createReplication() {
|
||||||
|
{{- range $index, $host := .groups.image_registry | default list }}
|
||||||
|
{{- if ne $host $.inventory_hostname }}
|
||||||
|
curl -k -u '{{ printf "%s:%s" $.image_registry.auth.username $.image_registry.auth.password }}' -X POST -H "Content-Type: application/json" "https://{{ $.inventory_hostname }}/api/v2.0/replication/policies" -d "{\"name\": \"{{ printf "%s_%s" $.inventory_hostname $host }}\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": {{ $index }}, \"name\": \"{{ $host }}\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
createRegistries
|
||||||
|
createReplication
|
||||||
|
|
@ -5,7 +5,7 @@ Requires=docker.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/local/bin/docker-compose -p harbor -f /opt/harbor/{{ .harbor_version }}/harbor/docker-compose.yml up{{ if and .image_registry.ha_vip (ne .image_registry.ha_vip "") }} && /usr/local/bin/docker-compose -p harbor -f /opt/harbor/{{ .harbor_version }}/harbor/docker-compose-keepalived.yml up{{ end }}
|
ExecStart=/usr/local/bin/docker-compose -p harbor -f /opt/harbor/{{ .harbor_version }}/harbor/docker-compose.yml up
|
||||||
ExecStop=/usr/local/bin/docker-compose -p harbor down
|
ExecStop=/usr/local/bin/docker-compose -p harbor down
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
[Install]
|
[Install]
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
version: '2.3'
|
|
||||||
services:
|
|
||||||
keepalived:
|
|
||||||
image: osixia/keepalived: {{ .keepalived_version }}
|
|
||||||
container_name: keepalived
|
|
||||||
restart: always
|
|
||||||
dns_search: .
|
|
||||||
cap_drop:
|
|
||||||
- ALL
|
|
||||||
cap_add:
|
|
||||||
- CHOWN
|
|
||||||
- DAC_OVERRIDE
|
|
||||||
- SETGID
|
|
||||||
- SETUID
|
|
||||||
depends_on:
|
|
||||||
- proxy
|
|
||||||
volumes:
|
|
||||||
- type: bind
|
|
||||||
source: /opt/keeplived/{{ .keepalived_version }}/keepalived.conf
|
|
||||||
target: /container/service/keepalived/assets/keepalived.conf
|
|
||||||
- type: bind
|
|
||||||
source: /opt/keeplived/{{ .keepalived_version }}/healthcheck.sh
|
|
||||||
target: /etc/keepalived/healthcheck.sh
|
|
||||||
networks:
|
|
||||||
- harbor
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
vrrp_script healthcheck {
|
||||||
|
script "/etc/keepalived/healthcheck.sh"
|
||||||
|
interval 10
|
||||||
|
fall 2
|
||||||
|
rise 2
|
||||||
|
timeout 5
|
||||||
|
init_fail
|
||||||
|
}
|
||||||
|
global_defs {
|
||||||
|
script_user root
|
||||||
|
router_id harbor-ha
|
||||||
|
enable_script_security
|
||||||
|
}
|
||||||
|
vrrp_instance VI_1 {
|
||||||
|
state {{ if .groups.image_registry | first | eq .inventory_hostname }}MASTER{{ else }}BACKUP{{ end }}
|
||||||
|
interface {{ .ha_vip_interface }}
|
||||||
|
virtual_router_id 31
|
||||||
|
priority 50
|
||||||
|
advert_int 1
|
||||||
|
authentication {
|
||||||
|
auth_type PASS
|
||||||
|
auth_pass k8s-test
|
||||||
|
}
|
||||||
|
virtual_ipaddress {
|
||||||
|
{{ .image_registry.ha_vip }}
|
||||||
|
}
|
||||||
|
track_script {
|
||||||
|
healthcheck
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
vrrp_script healthcheck {
|
|
||||||
script "/etc/keepalived/healthcheck.sh"
|
|
||||||
interval 10
|
|
||||||
fall 2
|
|
||||||
rise 2
|
|
||||||
timeout 5
|
|
||||||
init_fail
|
|
||||||
}
|
|
||||||
global_defs {
|
|
||||||
script_user root
|
|
||||||
router_id harbor-ha
|
|
||||||
enable_script_security
|
|
||||||
lvs_sync_daemon ens3 VI_1
|
|
||||||
}
|
|
||||||
vrrp_instance VI_1 {
|
|
||||||
state BACKUP
|
|
||||||
interface ens3
|
|
||||||
virtual_router_id 31
|
|
||||||
priority 50
|
|
||||||
advert_int 1
|
|
||||||
authentication {
|
|
||||||
auth_type PASS
|
|
||||||
auth_pass k8s-test
|
|
||||||
}
|
|
||||||
virtual_ipaddress {
|
|
||||||
{{ .image_registry.ha_vip }}
|
|
||||||
}
|
|
||||||
track_script {
|
|
||||||
healthcheck
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
{{- if .image_registry.type | eq "registry" }}
|
|
||||||
# registry service
|
|
||||||
service=registry:5000
|
|
||||||
{{- else }}
|
|
||||||
# harbor service
|
|
||||||
service=harbor:80
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
nc -zv -w 2 $service > /dev/null 2>&1
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
@ -22,9 +22,9 @@ log:
|
||||||
# to:
|
# to:
|
||||||
# - errors@example.com
|
# - errors@example.com
|
||||||
storage:
|
storage:
|
||||||
{{- if .image_registry.registry.storage.filesystem.rootdirectory | empty | not }}
|
{{- if .image_registry.registry.storage.filesystem.rootdir | empty | not }}
|
||||||
filesystem:
|
filesystem:
|
||||||
rootdirectory: {{ .image_registry.registry.storage.filesystem.rootdirectory }}
|
rootdirectory: {{ .image_registry.registry.storage.filesystem.rootdir }}
|
||||||
maxthreads: 100
|
maxthreads: 100
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .image_registry.registry.storage.azure }}
|
{{- if .image_registry.registry.storage.azure }}
|
||||||
|
|
@ -71,13 +71,13 @@ storage:
|
||||||
usedualstack: false
|
usedualstack: false
|
||||||
loglevel: debug
|
loglevel: debug
|
||||||
{{- end }}
|
{{- end }}
|
||||||
inmemory: # This driver takes no parameters
|
# inmemory: # This driver takes no parameters
|
||||||
delete:
|
delete:
|
||||||
enabled: false
|
enabled: false
|
||||||
redirect:
|
redirect:
|
||||||
disable: false
|
disable: false
|
||||||
cache:
|
cache:
|
||||||
blobdescriptor: redis
|
blobdescriptor: inmemory
|
||||||
blobdescriptorsize: 10000
|
blobdescriptorsize: 10000
|
||||||
maintenance:
|
maintenance:
|
||||||
uploadpurging:
|
uploadpurging:
|
||||||
|
|
@ -124,7 +124,7 @@ storage:
|
||||||
# options:
|
# options:
|
||||||
# baseurl: https://example.com/
|
# baseurl: https://example.com/
|
||||||
http:
|
http:
|
||||||
addr: localhost:5000
|
addr: 0.0.0.0:5000
|
||||||
# prefix: /my/nested/registry/
|
# prefix: /my/nested/registry/
|
||||||
# host: https://myregistryaddress.org:5000
|
# host: https://myregistryaddress.org:5000
|
||||||
secret: asecretforlocaldevelopment
|
secret: asecretforlocaldevelopment
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ services:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /opt/registry/{{ .registry_version }}/config.yml
|
source: /opt/registry/{{ .registry_version }}/config.yml
|
||||||
target: /etc/docker/registry/config.yml
|
target: /etc/docker/registry/config.yml
|
||||||
port:
|
ports:
|
||||||
- 443:5000
|
- 443:5000
|
||||||
networks:
|
networks:
|
||||||
- registry
|
- registry
|
||||||
|
|
@ -28,26 +28,28 @@ services:
|
||||||
keepalived:
|
keepalived:
|
||||||
image: osixia/keepalived:{{ .keepalived_version }}
|
image: osixia/keepalived:{{ .keepalived_version }}
|
||||||
container_name: keepalived
|
container_name: keepalived
|
||||||
|
command:
|
||||||
|
- --copy-service
|
||||||
|
network_mode: "host"
|
||||||
restart: always
|
restart: always
|
||||||
dns_search: .
|
dns_search: .
|
||||||
cap_drop:
|
cap_drop:
|
||||||
- ALL
|
- ALL
|
||||||
cap_add:
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_BROADCAST
|
||||||
|
- NET_RAW
|
||||||
- CHOWN
|
- CHOWN
|
||||||
- DAC_OVERRIDE
|
- DAC_OVERRIDE
|
||||||
- SETGID
|
|
||||||
- SETUID
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- registry
|
- registry
|
||||||
volumes:
|
volumes:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /opt/keeplived/{{ .keepalived_version }}/keepalived.conf
|
source: /opt/keepalived/{{ .keepalived_version }}/keepalived.conf
|
||||||
target: /container/service/keepalived/assets/keepalived.conf
|
target: /container/service/keepalived/assets/keepalived.conf
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /opt/keeplived/{{ .keepalived_version }}/healthcheck.sh
|
source: /opt/keepalived/{{ .keepalived_version }}/healthcheck.sh
|
||||||
target: /etc/keepalived/healthcheck.sh
|
target: /etc/keepalived/healthcheck.sh
|
||||||
networks:
|
|
||||||
- registry
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
networks:
|
networks:
|
||||||
registry:
|
registry:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=harbor
|
Description=registry
|
||||||
After=docker.service systemd-networkd.service systemd-resolved.service
|
After=docker.service systemd-networkd.service systemd-resolved.service
|
||||||
Requires=docker.service
|
Requires=docker.service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,43 @@
|
||||||
---
|
---
|
||||||
- name: Get network interface for kube_vip
|
- name: Get interface from kube_vip
|
||||||
command: |
|
block:
|
||||||
{{- if .kubernetes.control_plane_endpoint.kube_vip.address | ipFamily | eq "IPv4" }}
|
- name: Get all interface with cidr
|
||||||
ip route | grep '{{ .internal_ipv4 }}' | grep 'proto kernel scope link src' | awk '{print $3}'
|
command: |
|
||||||
{{- else if .kubernetes.control_plane_endpoint.host | ipFamily | eq "IPv6" }}
|
ip -o addr show | awk '
|
||||||
ip route | grep '{{ .internal_ipv6 }}' | grep 'proto kernel scope link src' | awk '{print $3}'
|
BEGIN {
|
||||||
{{- else }}
|
printf "[\n";
|
||||||
echo "kubernetes.control_plane_endpoint.kube_vip.address" should be ipv4 or ipv6
|
first = 1;
|
||||||
exit 1
|
}
|
||||||
{{- end }}
|
/inet / && !/ lo|docker|br-|veth/ {
|
||||||
register: interface
|
if (!first) {
|
||||||
|
printf ",\n";
|
||||||
- name: Check if network is exist
|
}
|
||||||
assert:
|
first = 0;
|
||||||
that:
|
printf " {\n";
|
||||||
- .interface.stderr | empty
|
printf " \"interface\": \"%s\",\n", $2;
|
||||||
- .interface.stdout | empty | not
|
printf " \"cidr\": \"%s\"\n", $4;
|
||||||
fail_msg: "cannot find network interface to match kube_vip"
|
printf " }";
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
printf "\n]\n";
|
||||||
|
}
|
||||||
|
'
|
||||||
|
register: interface
|
||||||
|
register_type: json
|
||||||
|
- name: filter interface by ha_vip
|
||||||
|
set_fact:
|
||||||
|
kube_vip_interface: >-
|
||||||
|
{{- $interface := "" }}
|
||||||
|
{{- range .interface.stdout | default list -}}
|
||||||
|
{{- if .cidr | ipInCIDR | has $.kubernetes.control_plane_endpoint.kube_vip.address -}}
|
||||||
|
{{- $interface = .interface -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{ $interface }}
|
||||||
|
- name: Check if network is exist
|
||||||
|
assert:
|
||||||
|
that: .kube_vip_interface | empty
|
||||||
|
fail_msg: "cannot find network interface to match kube_vip"
|
||||||
|
|
||||||
- name: Generate kube_vip manifest
|
- name: Generate kube_vip manifest
|
||||||
template:
|
template:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
- name: port
|
- name: port
|
||||||
value: "6443"
|
value: "6443"
|
||||||
- name: vip_interface
|
- name: vip_interface
|
||||||
value: {{ .interface.stdout }}
|
value: {{ .kube_vip_interface }}
|
||||||
- name: vip_cidr
|
- name: vip_cidr
|
||||||
value: "32"
|
value: "32"
|
||||||
- name: cp_enable
|
- name: cp_enable
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
- name: port
|
- name: port
|
||||||
value: "6443"
|
value: "6443"
|
||||||
- name: vip_interface
|
- name: vip_interface
|
||||||
value: {{ .interface.stdout }}
|
value: {{ .kube_vip_interface }}
|
||||||
- name: vip_cidr
|
- name: vip_cidr
|
||||||
value: "32"
|
value: "32"
|
||||||
- name: cp_enable
|
- name: cp_enable
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# image_registry is installed by docker_compose
|
||||||
|
- name: docker_version and dockercompose_version should not be empty
|
||||||
|
when: .groups.image_registry | empty | not
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- .docker_version | empty | not
|
||||||
|
- .dockercompose_version | empty | not
|
||||||
|
msg: >-
|
||||||
|
"docker_version" and "dockercompose_version" should not be empty
|
||||||
|
|
||||||
|
- name: keepalived_version should not be empty when image_registry is high availability
|
||||||
|
when:
|
||||||
|
- .image_registry.ha_vip | empty | not
|
||||||
|
- .groups.image_registry | len | lt 1
|
||||||
|
assert:
|
||||||
|
that: .keepalived_version | empty | not
|
||||||
|
msg: >-
|
||||||
|
"keepalived_version" should not be empty when image_registry is high availability
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
- name: Delete arp by kube-vip
|
||||||
|
command: |
|
||||||
|
ip neigh show | grep {{ .image_registry.ha_vip }} | awk '{print $1 " dev " $3}' | xargs -r -L1 ip neigh delete
|
||||||
|
ip -o addr show | grep {{ .image_registry.ha_vip }} | awk '{system("ip addr del "$4" dev "$2)}'
|
||||||
|
|
||||||
- name: Delete residue keepalived files
|
- name: Delete residue keepalived files
|
||||||
command: |
|
command: |
|
||||||
rm -rf /opt/keepalived/
|
rm -rf /opt/keepalived/
|
||||||
|
|
@ -0,0 +1,784 @@
|
||||||
|
{
|
||||||
|
"type": "excalidraw",
|
||||||
|
"version": 2,
|
||||||
|
"source": "https://excalidraw.com",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"id": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 868,
|
||||||
|
"y": 241,
|
||||||
|
"width": 244,
|
||||||
|
"height": 59.99999999999999,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7F",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 865016729,
|
||||||
|
"version": 290,
|
||||||
|
"versionNonce": 326982455,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "Q-e9pr0XedDsE8hLhtxpo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3wbQCkbDLOFDINm5zzTS-",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "LWBWVZxRHzET8YEmPb-f3",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302611172,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Q-e9pr0XedDsE8hLhtxpo",
|
||||||
|
"type": "text",
|
||||||
|
"x": 926.0099983215332,
|
||||||
|
"y": 258.5,
|
||||||
|
"width": 127.9800033569336,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7G",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1864202359,
|
||||||
|
"version": 274,
|
||||||
|
"versionNonce": 2119579319,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302514626,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "harbor service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"originalText": "harbor service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 486,
|
||||||
|
"y": 245.5,
|
||||||
|
"width": 244.00000000000003,
|
||||||
|
"height": 60.000000000000014,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7H",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 1227906551,
|
||||||
|
"version": 335,
|
||||||
|
"versionNonce": 1110807543,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "o1sccqOk7_faggHLFNheO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3wbQCkbDLOFDINm5zzTS-",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "LWBWVZxRHzET8YEmPb-f3",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302607030,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "o1sccqOk7_faggHLFNheO",
|
||||||
|
"type": "text",
|
||||||
|
"x": 544.0099983215332,
|
||||||
|
"y": 263,
|
||||||
|
"width": 127.9800033569336,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7I",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1568638743,
|
||||||
|
"version": 318,
|
||||||
|
"versionNonce": 1300714231,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1750302560040,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "harbor service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"originalText": "harbor service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 484,
|
||||||
|
"y": 126,
|
||||||
|
"width": 624,
|
||||||
|
"height": 78,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#a5d8ff",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7J",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 981932439,
|
||||||
|
"version": 81,
|
||||||
|
"versionNonce": 428276025,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "neXgNEUOhJo1yjimmCiTH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "neXgNEUOhJo1yjimmCiTH",
|
||||||
|
"type": "text",
|
||||||
|
"x": 731.4399948120117,
|
||||||
|
"y": 152.5,
|
||||||
|
"width": 129.12001037597656,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7K",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1816398713,
|
||||||
|
"version": 50,
|
||||||
|
"versionNonce": 212167193,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "Load Blanacer",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"originalText": "Load Blanacer",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 488,
|
||||||
|
"y": 337,
|
||||||
|
"width": 244.00000000000003,
|
||||||
|
"height": 60.000000000000014,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7N",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 271586231,
|
||||||
|
"version": 393,
|
||||||
|
"versionNonce": 1107051063,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "WaP95sXUDIWaHJ8dD3VlR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302607030,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "WaP95sXUDIWaHJ8dD3VlR",
|
||||||
|
"type": "text",
|
||||||
|
"x": 541.75,
|
||||||
|
"y": 354.5,
|
||||||
|
"width": 136.5,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7O",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 511870167,
|
||||||
|
"version": 388,
|
||||||
|
"versionNonce": 1016794583,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1750302602385,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "storage service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"originalText": "storage service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "QnD-8-ujPJygThWv4oRRT",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 872,
|
||||||
|
"y": 336,
|
||||||
|
"width": 244.00000000000003,
|
||||||
|
"height": 60.000000000000014,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7P",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 303174871,
|
||||||
|
"version": 384,
|
||||||
|
"versionNonce": 384514423,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "zvSBobCjWHUzU-fOWcJLi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302611172,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "zvSBobCjWHUzU-fOWcJLi",
|
||||||
|
"type": "text",
|
||||||
|
"x": 925.75,
|
||||||
|
"y": 353.5,
|
||||||
|
"width": 136.5,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7Q",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1388798455,
|
||||||
|
"version": 379,
|
||||||
|
"versionNonce": 1293090647,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1750302598218,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "storage service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "QnD-8-ujPJygThWv4oRRT",
|
||||||
|
"originalText": "storage service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 789.8272747713355,
|
||||||
|
"y": 204.9990705847769,
|
||||||
|
"width": 130.79362370312788,
|
||||||
|
"height": 39.02567346207175,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7R",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 383988983,
|
||||||
|
"version": 166,
|
||||||
|
"versionNonce": 2021834489,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-130.79362370312788,
|
||||||
|
39.02567346207175
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"focus": -0.2888910803214833,
|
||||||
|
"gap": 7
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": -0.2441231343283578,
|
||||||
|
"gap": 5.5
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 862.5126006477127,
|
||||||
|
"y": 204.99907058477686,
|
||||||
|
"width": 142.14928077039178,
|
||||||
|
"height": 33.100855462394435,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7S",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 72016441,
|
||||||
|
"version": 108,
|
||||||
|
"versionNonce": 732067801,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
142.14928077039178,
|
||||||
|
33.100855462394435
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"focus": 0.2194976788477558,
|
||||||
|
"gap": 7
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": 0.6222604211431018,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3wbQCkbDLOFDINm5zzTS-",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 739.5702440443347,
|
||||||
|
"y": 258.96307786317976,
|
||||||
|
"width": 118.85951191133074,
|
||||||
|
"height": 0.014658463536704858,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7T",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 1405197335,
|
||||||
|
"version": 135,
|
||||||
|
"versionNonce": 1501321783,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302560193,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
118.85951191133074,
|
||||||
|
0.014658463536704858
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": -0.5514950166112959,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": 0.3999999999999996,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "LWBWVZxRHzET8YEmPb-f3",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 858.4297559556653,
|
||||||
|
"y": 279.2973724995128,
|
||||||
|
"width": 120.65385031474193,
|
||||||
|
"height": 1.916023220647503,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7U",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 67343543,
|
||||||
|
"version": 140,
|
||||||
|
"versionNonce": 1144521719,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302574470,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-120.65385031474193,
|
||||||
|
1.916023220647503
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": -0.156993339676499,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": 0.24342244771700097,
|
||||||
|
"gap": 7.7759056409233835
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dBCR-0VHhAZrQsuybKfxf",
|
||||||
|
"type": "text",
|
||||||
|
"x": 746,
|
||||||
|
"y": 290,
|
||||||
|
"width": 110.52000427246094,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7V",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1033720663,
|
||||||
|
"version": 68,
|
||||||
|
"versionNonce": 931739607,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302594968,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "sync images",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "sync images",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 610,
|
||||||
|
"y": 313,
|
||||||
|
"width": 0,
|
||||||
|
"height": 15,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7W",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 1108486455,
|
||||||
|
"version": 11,
|
||||||
|
"versionNonce": 745405719,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302607030,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
15
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": -0.016393442622950786,
|
||||||
|
"gap": 7.5
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"focus": 0,
|
||||||
|
"gap": 9
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 1004,
|
||||||
|
"y": 311,
|
||||||
|
"width": 0,
|
||||||
|
"height": 17,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7X",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 572285047,
|
||||||
|
"version": 11,
|
||||||
|
"versionNonce": 1740299351,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302611172,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
17
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": -0.11475409836065573,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "QnD-8-ujPJygThWv4oRRT",
|
||||||
|
"focus": 0.08196721311475404,
|
||||||
|
"gap": 8
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"appState": {
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
|
"gridModeEnabled": false,
|
||||||
|
"viewBackgroundColor": "#ffffff",
|
||||||
|
"lockedMultiSelections": {}
|
||||||
|
},
|
||||||
|
"files": {}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
|
|
@ -0,0 +1,551 @@
|
||||||
|
{
|
||||||
|
"type": "excalidraw",
|
||||||
|
"version": 2,
|
||||||
|
"source": "https://excalidraw.com",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"id": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 868,
|
||||||
|
"y": 241,
|
||||||
|
"width": 244,
|
||||||
|
"height": 59.99999999999999,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7F",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 865016729,
|
||||||
|
"version": 292,
|
||||||
|
"versionNonce": 497225262,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "Q-e9pr0XedDsE8hLhtxpo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750924036450,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Q-e9pr0XedDsE8hLhtxpo",
|
||||||
|
"type": "text",
|
||||||
|
"x": 921.1600036621094,
|
||||||
|
"y": 258.5,
|
||||||
|
"width": 137.67999267578125,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7G",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1864202359,
|
||||||
|
"version": 282,
|
||||||
|
"versionNonce": 697610606,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750924050371,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "registry service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"originalText": "registry service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 486,
|
||||||
|
"y": 245.5,
|
||||||
|
"width": 244.00000000000003,
|
||||||
|
"height": 60.000000000000014,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7H",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 1227906551,
|
||||||
|
"version": 337,
|
||||||
|
"versionNonce": 1529332210,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "o1sccqOk7_faggHLFNheO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750924036450,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "o1sccqOk7_faggHLFNheO",
|
||||||
|
"type": "text",
|
||||||
|
"x": 539.1600036621094,
|
||||||
|
"y": 263,
|
||||||
|
"width": 137.67999267578125,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7I",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1568638743,
|
||||||
|
"version": 328,
|
||||||
|
"versionNonce": 511754546,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1750924033996,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "registry service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"originalText": "registry service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 484,
|
||||||
|
"y": 126,
|
||||||
|
"width": 624,
|
||||||
|
"height": 78,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#a5d8ff",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7J",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 981932439,
|
||||||
|
"version": 81,
|
||||||
|
"versionNonce": 428276025,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "neXgNEUOhJo1yjimmCiTH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "neXgNEUOhJo1yjimmCiTH",
|
||||||
|
"type": "text",
|
||||||
|
"x": 731.4399948120117,
|
||||||
|
"y": 152.5,
|
||||||
|
"width": 129.12001037597656,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7K",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1816398713,
|
||||||
|
"version": 50,
|
||||||
|
"versionNonce": 212167193,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "Load Blanacer",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"originalText": "Load Blanacer",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 488,
|
||||||
|
"y": 383,
|
||||||
|
"width": 628,
|
||||||
|
"height": 60.000000000000014,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7N",
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 271586231,
|
||||||
|
"version": 458,
|
||||||
|
"versionNonce": 1441604658,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "WaP95sXUDIWaHJ8dD3VlR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1750924054994,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "WaP95sXUDIWaHJ8dD3VlR",
|
||||||
|
"type": "text",
|
||||||
|
"x": 733.75,
|
||||||
|
"y": 400.5,
|
||||||
|
"width": 136.5,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7O",
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 511870167,
|
||||||
|
"version": 452,
|
||||||
|
"versionNonce": 81645042,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1750924054994,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "storage service",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 6,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"originalText": "storage service",
|
||||||
|
"autoResize": true,
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "L8_xG3dqum2_YKMebNu2u",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 789.8336419760351,
|
||||||
|
"y": 204.99907058477686,
|
||||||
|
"width": 130.72171598152477,
|
||||||
|
"height": 39.02567346207178,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7R",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 383988983,
|
||||||
|
"version": 167,
|
||||||
|
"versionNonce": 798245042,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750924028531,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-130.72171598152477,
|
||||||
|
39.02567346207178
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"focus": -0.2888910803214833,
|
||||||
|
"gap": 7
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": -0.2441231343283578,
|
||||||
|
"gap": 5.5
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "_oQQMRTunRyo9Zq43ZnJU",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 862.5126006477127,
|
||||||
|
"y": 204.99907058477686,
|
||||||
|
"width": 142.14928077039178,
|
||||||
|
"height": 33.100855462394435,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7S",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 72016441,
|
||||||
|
"version": 108,
|
||||||
|
"versionNonce": 732067801,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750302564064,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
142.14928077039178,
|
||||||
|
33.100855462394435
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "53tMOC8ghJAglooQgD-kW",
|
||||||
|
"focus": 0.2194976788477558,
|
||||||
|
"gap": 7
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": 0.6222604211431018,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cO9D1owMBo5ciGKj9M8W7",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 655.6624775795378,
|
||||||
|
"y": 307.58611094053396,
|
||||||
|
"width": 103.19328237376556,
|
||||||
|
"height": 74.33503752082942,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7W",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 1108486455,
|
||||||
|
"version": 120,
|
||||||
|
"versionNonce": 1804812210,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750924054995,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
103.19328237376556,
|
||||||
|
74.33503752082942
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "KcVtlaVjZmNTnyoeRJBfq",
|
||||||
|
"focus": -0.016393442622950786,
|
||||||
|
"gap": 7.5
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"focus": 0,
|
||||||
|
"gap": 9
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DQu2mOOAST7Qj33GexWWU",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 966.2341709724777,
|
||||||
|
"y": 303.90007395282873,
|
||||||
|
"width": 99.30046503552558,
|
||||||
|
"height": 78.16233299063248,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "#b2f2bb",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "dashed",
|
||||||
|
"roughness": 0,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"index": "b7X",
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 572285047,
|
||||||
|
"version": 91,
|
||||||
|
"versionNonce": 1177844082,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1750924054995,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-99.30046503552558,
|
||||||
|
78.16233299063248
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "o93_Uv5XcZbMQM0H30Zkq",
|
||||||
|
"focus": -0.11475409836065573,
|
||||||
|
"gap": 10
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "edP1PJ_ABStEloX-Syel7",
|
||||||
|
"focus": 0.07278735375547067,
|
||||||
|
"gap": 8
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"elbowed": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"appState": {
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
|
"gridModeEnabled": false,
|
||||||
|
"viewBackgroundColor": "#ffffff",
|
||||||
|
"lockedMultiSelections": {}
|
||||||
|
},
|
||||||
|
"files": {}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
|
|
@ -47,6 +47,8 @@ precheck 集群安装前,对集群节点进行检查是否满足集群安装
|
||||||
- **containerd 版本检查**: 当使用 containerd 作为容器管理器时,验证 containerd 版本是否满足最低版本要求
|
- **containerd 版本检查**: 当使用 containerd 作为容器管理器时,验证 containerd 版本是否满足最低版本要求
|
||||||
**nfs_precheck**: NFS 存储检查,包括:
|
**nfs_precheck**: NFS 存储检查,包括:
|
||||||
- **NFS 服务器数量检查**: 验证集群中只能有一个 NFS 服务器节点,确保 NFS 服务部署的唯一性
|
- **NFS 服务器数量检查**: 验证集群中只能有一个 NFS 服务器节点,确保 NFS 服务部署的唯一性
|
||||||
|
**image_registry_precheck**: 镜像仓库检查,包括:
|
||||||
|
- **镜像仓库必要软件检查**: 需检查 `docker_version` 和 `dockercompose_version` 均已配置且不为空。镜像仓库通过 docker_compose 进行安装,缺少必要软件会导致安装失败。
|
||||||
|
|
||||||
## init
|
## init
|
||||||
|
|
||||||
|
|
@ -61,11 +63,11 @@ init 阶段负责准备和构建集群安装所需的所有资源,包括:
|
||||||
|
|
||||||
install 阶段是 KubeKey 的核心安装阶段,负责在集群节点上实际部署和配置 Kubernetes 集群,包括:
|
install 阶段是 KubeKey 的核心安装阶段,负责在集群节点上实际部署和配置 Kubernetes 集群,包括:
|
||||||
|
|
||||||
**install nfs**: 为 `nfs` 组中的节点安装nfs服务。
|
**install nfs**: 为 `nfs` 组中的节点安装nfs服务。
|
||||||
**install image_registry**: 为 `image_registry` 组中的节点安装镜像仓库。目前支持两种类型的镜像仓库:harbor,registry。
|
**install image_registry**: 为 `image_registry` 组中的节点安装镜像仓库。目前支持两种类型的镜像仓库:harbor,registry。
|
||||||
**install etcd**: 为 `etcd` 组中的节点安装etcd。
|
**install etcd**: 为 `etcd` 组中的节点安装etcd。
|
||||||
**install cri**: 为 `k8s_cluster` 组中的节点安装cri。目前支持两种CRI:docker,containerd。
|
**install cri**: 为 `k8s_cluster` 组中的节点安装cri。目前支持两种CRI:docker,containerd。
|
||||||
**kubernetes_install**: 为 `k8s_cluster` 组中的节点安装kubernetes。
|
**kubernetes_install**: 为 `k8s_cluster` 组中的节点安装kubernetes。
|
||||||
**install helm**: 为已安装好的kubernetes集群安装额外的helm 应用。包含:CNI(calico,cilium,flannel,hybridnet,kubeovn,multus)
|
**install helm**: 为已安装好的kubernetes集群安装额外的helm 应用。包含:CNI(calico,cilium,flannel,hybridnet,kubeovn,multus)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -78,6 +80,6 @@ post_hook 阶段在集群安装完成后执行,负责集群的最终配置和
|
||||||
2. 设置脚本文件权限为 0755
|
2. 设置脚本文件权限为 0755
|
||||||
3. 遍历每个远程节点上 `/etc/kubekey/scripts/` 目录下所有 `post_install_*.sh` 文件,并执行该脚本文件
|
3. 遍历每个远程节点上 `/etc/kubekey/scripts/` 目录下所有 `post_install_*.sh` 文件,并执行该脚本文件
|
||||||
|
|
||||||
> work_dir: 工作目录,默认当前命令执行目录。
|
> **work_dir**: 工作目录,默认当前命令执行目录。
|
||||||
> inventory_hostname: Inventory.yaml 文件中定义的host对应的名称。
|
> **inventory_hostname**: Inventory.yaml 文件中定义的host对应的名称。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
# image_registry
|
||||||
|
|
||||||
|
image_registry允许用户安装镜像仓库。支持harbor和registry两种镜像仓库
|
||||||
|
|
||||||
|
## requirement
|
||||||
|
|
||||||
|
- 一台或多台运行兼容 deb/rpm 的 Linux 操作系统的计算机;例如:Ubuntu 或 CentOS。
|
||||||
|
- 每台机器 8 GB 以上的内存,内存不足时应用会受限制。
|
||||||
|
- 用作控制平面节点的计算机上至少有 4 个 CPU。
|
||||||
|
- 集群中所有计算机之间具有完全的网络连接。你可以使用公共网络或专用网络
|
||||||
|
- 使用本地存储时。计算机需要100G高速存储的磁盘空间。
|
||||||
|
|
||||||
|
## 安装harbor
|
||||||
|
|
||||||
|
### 构建Inventory
|
||||||
|
```yaml
|
||||||
|
apiVersion: kubekey.kubesphere.io/v1
|
||||||
|
kind: Inventory
|
||||||
|
metadata:
|
||||||
|
name: default
|
||||||
|
spec:
|
||||||
|
hosts: # your can set all nodes here. or set nodes on special groups.
|
||||||
|
# node1:
|
||||||
|
# connector:
|
||||||
|
# type: ssh
|
||||||
|
# host: node1
|
||||||
|
# port: 22
|
||||||
|
# user: root
|
||||||
|
# password: 123456
|
||||||
|
groups:
|
||||||
|
# all kubernetes nodes.
|
||||||
|
k8s_cluster:
|
||||||
|
groups:
|
||||||
|
- kube_control_plane
|
||||||
|
- kube_worker
|
||||||
|
# control_plane nodes
|
||||||
|
kube_control_plane:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# worker nodes
|
||||||
|
kube_worker:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# etcd nodes when etcd_deployment_type is external
|
||||||
|
etcd:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
image_registry:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# nfs nodes for registry storage. and kubernetes nfs storage
|
||||||
|
# nfs:
|
||||||
|
# hosts:
|
||||||
|
# - localhost
|
||||||
|
|
||||||
|
```
|
||||||
|
需设置 `image_registry` 组
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
harbor是默认安装的镜像仓库
|
||||||
|
1. 安装前检查
|
||||||
|
```shell
|
||||||
|
kk precheck image_registry -i inventory.yaml --set harbor_version=v2.10.1,docker_version=24.0.7,dockercompose_version=v2.20.3
|
||||||
|
```
|
||||||
|
2. 安装
|
||||||
|
- 单独安装
|
||||||
|
`image_registry` 可以脱离集群单独进行安装。
|
||||||
|
```shell
|
||||||
|
kk init registry -i inventory.yaml --set harbor_version=v2.10.1,docker_version=24.0.7,dockercompose_version=v2.20.3
|
||||||
|
```
|
||||||
|
|
||||||
|
- 在创建集群时,自动安装
|
||||||
|
在创建集群时,会检测 `image_registry` 节点是否安装了harbor, 没有安装时会自动根据配置安装harbor。
|
||||||
|
```shell
|
||||||
|
kk create cluster -i inventory.yaml --set harbor_version=v2.10.1,docker_version=24.0.7, dockercompose_version=v2.20.3
|
||||||
|
```
|
||||||
|
|
||||||
|
### harbor高可用
|
||||||
|
|
||||||
|
harbor高可用有两种实现方式。
|
||||||
|
|
||||||
|
1. 每个harbor共享同一个存储服务。
|
||||||
|
官方做法,适用于在kubernetes集群中安装。需要独立部署PostgreSQL 和 Redis 服务
|
||||||
|
参考:https://goharbor.io/docs/edge/install-config/harbor-ha-helm/
|
||||||
|
|
||||||
|
2. 每个harbor有单独的存储服务。
|
||||||
|
kubekey的做法,适用于在服务器上安装。
|
||||||
|

|
||||||
|
- load balancer: 通过docker compose部署keepalived服务实现。
|
||||||
|
- harbor service: 通过docker compose部署harbor实现。
|
||||||
|
- sync images: 通过harbor的复制管理功能实现。
|
||||||
|
|
||||||
|
安装示例:
|
||||||
|
```shell
|
||||||
|
./kk init registry -i inventory.yaml --set image_registry.ha_vip=xx.xx.xx.xx --set harbor_version=v2.10.1,docker_version=24.0.7,dockercompose_version=v2.20.3 --set keepalived_version=2.0.20,artifact.artifact_url.keepalived.amd64=keepalived-2.0.20-linux-amd64.tgz
|
||||||
|
```
|
||||||
|
1. 在inventory中的image_registry 组中设置多个节点
|
||||||
|
|
||||||
|
2. 设置变量`image_registry.ha_vip` ha_vip 是负载均衡的入口
|
||||||
|
|
||||||
|
3. 设置变量 `keepalived_version` 和 `artifact.artifact_url.keepalived.amd64` keepalived 是用于负载均衡的镜像。目前kubekey并未提供下载地址,可通过手动打包的方式来实现。
|
||||||
|
```shell
|
||||||
|
# download keepalived images
|
||||||
|
docker pull osixia/keepalived:{{ .keepalived_version }}
|
||||||
|
# package image
|
||||||
|
docker save -o keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz osixia/ keepalived:{{ .keepalived_version }}
|
||||||
|
# move image to workdir
|
||||||
|
mv keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz {{ .binary_dir }}/ image-registry/keepalived/{{ .keepalived_version }}/{{ .binary_type }}/
|
||||||
|
```
|
||||||
|
`binary_type`: 是机器的架构(目前支持amd64和arm64,可通过 `gather_fact` 自动获取)
|
||||||
|
`binary_dir`: 软件包存放地址,通常为: `{{ .work_dir}}/kubekey`
|
||||||
|
|
||||||
|
4. 设置变量 `harbor_version`, `docker_version` 和 `dockercompose_version`。harbor通过docker-compose进行安装。
|
||||||
|
|
||||||
|
|
||||||
|
## 安装registry
|
||||||
|
|
||||||
|
### 构建Inventory
|
||||||
|
```yaml
|
||||||
|
apiVersion: kubekey.kubesphere.io/v1
|
||||||
|
kind: Inventory
|
||||||
|
metadata:
|
||||||
|
name: default
|
||||||
|
spec:
|
||||||
|
hosts: # your can set all nodes here. or set nodes on special groups.
|
||||||
|
# node1:
|
||||||
|
# connector:
|
||||||
|
# type: ssh
|
||||||
|
# host: node1
|
||||||
|
# port: 22
|
||||||
|
# user: root
|
||||||
|
# password: 123456
|
||||||
|
groups:
|
||||||
|
# all kubernetes nodes.
|
||||||
|
k8s_cluster:
|
||||||
|
groups:
|
||||||
|
- kube_control_plane
|
||||||
|
- kube_worker
|
||||||
|
# control_plane nodes
|
||||||
|
kube_control_plane:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# worker nodes
|
||||||
|
kube_worker:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# etcd nodes when etcd_deployment_type is external
|
||||||
|
etcd:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
image_registry:
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# nfs nodes for registry storage. and kubernetes nfs storage
|
||||||
|
# nfs:
|
||||||
|
# hosts:
|
||||||
|
# - localhost
|
||||||
|
|
||||||
|
```
|
||||||
|
### 构建 registry 镜像包
|
||||||
|
kubekey暂未提供registry的离线镜像包地址,需通过手动打包的方式来实现。
|
||||||
|
```shell
|
||||||
|
# download registry images
|
||||||
|
docker pull registry:{{ .registry_version }}
|
||||||
|
# package image
|
||||||
|
docker save -o registry-{{ .registry_version }}-linux-{{ .binary_type }}.tgz registry:{{ .registry_version }}
|
||||||
|
# move image to workdir
|
||||||
|
mv registry-{{ .registry_version }}-linux-{{ .binary_type }}.tgz {{ .binary_dir }}/ image-registry/registry/{{ .registry_version }}/{{ .binary_type }}/
|
||||||
|
```
|
||||||
|
`binary_type`: 是机器的架构(目前支持amd64和arm64,可通过 `gather_fact` 自动获取)
|
||||||
|
`binary_dir`: 软件包存放地址,通常为: `{{ .work_dir}}/kubekey`
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
安装registry需要设置`image_registry.type`值为`registry`
|
||||||
|
1. 安装前检查
|
||||||
|
```shell
|
||||||
|
kk precheck image_registry -i inventory.yaml --set image_registry.type=registry --set registry_version=2.8.3,docker_version=24.0.7,dockercompose_version=v2.20.3
|
||||||
|
```
|
||||||
|
2. 安装
|
||||||
|
- 单独安装
|
||||||
|
`image_registry` 可以脱离集群单独进行安装。
|
||||||
|
```shell
|
||||||
|
kk init registry -i inventory.yaml --set image_registry.type=registry --set registry_version=2.8.3,docker_version=24.0.7,dockercompose_version=v2.20.3 --set artifact.artifact_url.registry.amd64=registry-2.8.3-linux.amd64.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
- 在创建集群时,自动安装
|
||||||
|
在创建集群时,会检测 `image_registry` 节点是否安装了harbor, 没有安装时会自动根据配置安装harbor。
|
||||||
|
```shell
|
||||||
|
kk create cluster -i inventory.yaml --set image_registry.type=registry --set registry_version=2.8.3,docker_version=24.0.7,dockercompose_version=v2.20.3 --set artifact.artifact_url.registry.amd64=registry-2.8.3-linux.amd64.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
### registry高可用
|
||||||
|
|
||||||
|

|
||||||
|
- load balancer: 通过docker compose部署keepalived服务实现。
|
||||||
|
- registry service: 通过docker compose部署registry实现。
|
||||||
|
- storage service: registry 高可用可通过共享存储的方式来实现。registry 支持多种存储后端,常见的有:
|
||||||
|
- **filesystem**: 本地存储。默认情况下,registry 使用本地磁盘存储镜像数据。如果需要实现高可用,可以将本地存储目 录挂载到 NFS 等共享存储上。配置示例:
|
||||||
|
```yaml
|
||||||
|
image_registry:
|
||||||
|
registry:
|
||||||
|
storage:
|
||||||
|
filesystem:
|
||||||
|
rootdir: /opt/registry/data
|
||||||
|
nfs_mount: /repository/registry # 可选,将 rootdir 挂载到 NFS 服务器
|
||||||
|
```
|
||||||
|
需要在 `nfs` 节点配置和挂载好共享目录,保证所有 registry 实例的数据一致性。
|
||||||
|
|
||||||
|
- **azure**: 使用 Azure Blob Storage 作为后端存储。适用于部署在 Azure 云环境下的场景。配置示例:
|
||||||
|
```yaml
|
||||||
|
image_registry:
|
||||||
|
registry:
|
||||||
|
storage:
|
||||||
|
azure:
|
||||||
|
accountname: <your-account-name>
|
||||||
|
accountkey: <your-account-key>
|
||||||
|
container: <your-container-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
- **gcs**: 使用 Google Cloud Storage 作为后端存储。适用于部署在 GCP 云环境下的场景。配置示例:
|
||||||
|
```yaml
|
||||||
|
image_registry:
|
||||||
|
registry:
|
||||||
|
storage:
|
||||||
|
gcs:
|
||||||
|
bucket: <your-bucket-name>
|
||||||
|
keyfile: /path/to/keyfile.json
|
||||||
|
```
|
||||||
|
|
||||||
|
- **s3**: 使用 Amazon S3 或兼容 S3 协议的对象存储作为后端存储。适用于 AWS 或支持 S3 协议的私有云。配置示例:
|
||||||
|
```yaml
|
||||||
|
image_registry:
|
||||||
|
registry:
|
||||||
|
storage:
|
||||||
|
s3:
|
||||||
|
accesskey: <your-access-key>
|
||||||
|
secretkey: <your-secret-key>
|
||||||
|
region: <your-region>
|
||||||
|
bucket: <your-bucket-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意:**
|
||||||
|
> 1. 使用共享存储(如 NFS、S3、GCS、Azure Blob)时,建议至少部署 2 个及以上 registry 实例,并通过负载均衡(如 keepalived+nginx)实现高可用访问。
|
||||||
|
> 2. 配置共享存储时,需保证各 registry 节点对存储的读写权限和网络连通性。
|
||||||
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
|
|
||||||
function createRegistries() {
|
|
||||||
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/registries" -d "{\"name\": \"master1_2_master2\", \"type\": \"harbor\", \"url\":\"https://${master2_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/registries" -d "{\"name\": \"master1_2_master3\", \"type\": \"harbor\", \"url\":\"https://${master3_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/registries" -d "{\"name\": \"master2_2_master1\", \"type\": \"harbor\", \"url\":\"https://${master1_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/registries" -d "{\"name\": \"master2_2_master3\", \"type\": \"harbor\", \"url\":\"https://${master3_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/registries" -d "{\"name\": \"master3_2_master1\", \"type\": \"harbor\", \"url\":\"https://${master1_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
# create registry
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/registries" -d "{\"name\": \"master3_2_master2\", \"type\": \"harbor\", \"url\":\"https://${master2_Address}:7443\", \"credential\": {\"access_key\": \"${Harbor_User}\", \"access_secret\": \"${Harbor_Passwd}\"}, \"insecure\": true}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function listRegistries() {
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/registries"
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/registries"
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/registries"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReplication() {
|
|
||||||
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master1_2_master2\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 1, \"name\": \"master1_2_master2\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master1_2_master3\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 2, \"name\": \"master1_2_master3\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master2_2_master1\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 1, \"name\": \"master2_2_master1\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master2_2_master3\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 2, \"name\": \"master2_2_master3\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master3_2_master1\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 1, \"name\": \"master3_2_master1\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
curl -k -u $Harbor_UserPwd -X POST -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/replication/policies" -d "{\"name\": \"master3_2_master2\", \"enabled\": true, \"deletion\":true, \"override\":true, \"replicate_deletion\":true, \"dest_registry\":{ \"id\": 2, \"name\": \"master3_2_master2\"}, \"trigger\": {\"type\": \"event_based\"}, \"dest_namespace_replace_count\":1 }"
|
|
||||||
}
|
|
||||||
|
|
||||||
function listReplications() {
|
|
||||||
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master1_Address}/api/v2.0/replication/policies"
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master2_Address}/api/v2.0/replication/policies"
|
|
||||||
curl -k -u $Harbor_UserPwd -X GET -H "Content-Type: application/json" "https://${Harbor_master3_Address}/api/v2.0/replication/policies"
|
|
||||||
}
|
|
||||||
|
|
||||||
#### main ######
|
|
||||||
Harbor_master1_Address=master1:7443
|
|
||||||
master1_Address=192.168.122.61
|
|
||||||
Harbor_master2_Address=master2:7443
|
|
||||||
master2_Address=192.168.122.62
|
|
||||||
Harbor_master3_Address=master3:7443
|
|
||||||
master3_Address=192.168.122.63
|
|
||||||
Harbor_User=admin #登录Harbor的用户
|
|
||||||
Harbor_Passwd="Harbor12345" #登录Harbor的用户密码
|
|
||||||
Harbor_UserPwd="$Harbor_User:$Harbor_Passwd"
|
|
||||||
|
|
||||||
|
|
||||||
createRegistries
|
|
||||||
listRegistries
|
|
||||||
createReplication
|
|
||||||
listReplications
|
|
||||||
Loading…
Reference in New Issue