From 276e7c3c35f251eefcbc04f448428de2fe162921 Mon Sep 17 00:00:00 2001 From: mengkzhaoyun Date: Sun, 7 Apr 2019 00:35:12 +0800 Subject: [PATCH] update --- .helmignore | 4 + CONTRIBUTING.md | 2 +- Chart.yaml | 14 +- Deploy.md | 77 +++ docs/High Availability.md | 63 ++ docs/Upgrade.md | 48 ++ docs/img/ha.png | Bin 0 -> 156076 bytes logo.png | Bin 62422 -> 0 bytes package.json | 4 - readme.md | 340 ++++++++--- templates/NOTES.txt | 4 +- templates/_helpers.tpl | 209 +++++-- templates/adminserver/configmap.yaml | 60 -- templates/adminserver/secret.yaml | 21 - templates/adminserver/service.yaml | 14 - templates/adminserver/statefulset.yaml | 94 --- templates/chartmuseum/chartmuseum-cm.yaml | 99 +++ templates/chartmuseum/chartmuseum-dpl.yaml | 85 +++ templates/chartmuseum/chartmuseum-secret.yaml | 26 + .../{service.yaml => chartmuseum-svc.yaml} | 7 +- templates/chartmuseum/configmap.yaml | 33 - templates/chartmuseum/secret.yaml | 12 - templates/chartmuseum/statefulset.yaml | 74 --- .../clair/{configmap.yaml => clair-cm.yaml} | 8 +- templates/clair/clair-dpl.yaml | 88 +++ templates/clair/clair-svc.yaml | 17 + templates/clair/deployment.yaml | 60 -- templates/clair/service.yaml | 18 - templates/common/certificate-secret.yaml | 23 + templates/core/core-cm.yaml | 47 ++ templates/core/core-dpl.yaml | 125 ++++ templates/core/core-secret.yaml | 20 + .../service.yaml => core/core-svc.yaml} | 10 +- .../{secret.yaml => database-secret.yaml} | 4 +- templates/database/database-ss.yaml | 83 +++ .../{service.yaml => database-svc.yaml} | 7 +- templates/database/statefulset.yaml | 88 --- templates/ingress/ingress.yaml | 92 ++- templates/ingress/notary-ingress.yaml | 33 + templates/ingress/secret.yaml | 19 - templates/istio/notary.gateway.yaml | 32 - templates/istio/ui.gateway.yaml | 32 - templates/jobservice/configmap.yaml | 21 - templates/jobservice/deployment.yaml | 66 -- templates/jobservice/jobservice-cm.yaml | 39 ++ templates/jobservice/jobservice-dpl.yaml | 94 +++ templates/jobservice/jobservice-secrets.yaml | 9 + .../jobservice-svc.yaml} | 7 +- templates/jobservice/secret.yaml | 11 - templates/nginx/configmap-http.yaml | 132 ++++ templates/nginx/configmap-https.yaml | 175 ++++++ templates/nginx/deployment.yaml | 85 +++ templates/nginx/service.yaml | 63 ++ .../notary/{configmap.yaml => notary-cm.yaml} | 33 +- templates/notary/notary-server.yaml | 46 +- templates/notary/notary-signer.yaml | 54 +- .../notary/{service.yaml => notary-svc.yaml} | 11 +- templates/portal/deployment.yaml | 64 ++ templates/portal/service.yaml | 16 + templates/redis/deployment.yml | 37 -- templates/redis/{service.yml => service.yaml} | 13 +- templates/redis/statefulset.yaml | 67 +++ templates/registry/configmap.yaml | 162 ----- templates/registry/registry-cm.yaml | 55 ++ templates/registry/registry-dpl.yaml | 145 +++++ templates/registry/registry-secret.yaml | 34 ++ .../{service.yaml => registry-svc.yaml} | 8 +- templates/registry/secret.yaml | 31 - templates/registry/statefulset.yaml | 126 ---- templates/ui/configmap.yaml | 14 - templates/ui/deployment.yaml | 117 ---- templates/ui/secret.yaml | 15 - values-aliyun.yaml | 145 +++-- values.yaml | 564 +++++++++++------- 74 files changed, 2878 insertions(+), 1677 deletions(-) create mode 100644 .helmignore create mode 100644 Deploy.md create mode 100644 docs/High Availability.md create mode 100644 docs/Upgrade.md create mode 100644 docs/img/ha.png delete mode 100644 logo.png delete mode 100644 package.json delete mode 100644 templates/adminserver/configmap.yaml delete mode 100644 templates/adminserver/secret.yaml delete mode 100644 templates/adminserver/service.yaml delete mode 100644 templates/adminserver/statefulset.yaml create mode 100644 templates/chartmuseum/chartmuseum-cm.yaml create mode 100644 templates/chartmuseum/chartmuseum-dpl.yaml create mode 100644 templates/chartmuseum/chartmuseum-secret.yaml rename templates/chartmuseum/{service.yaml => chartmuseum-svc.yaml} (64%) delete mode 100644 templates/chartmuseum/configmap.yaml delete mode 100644 templates/chartmuseum/secret.yaml delete mode 100644 templates/chartmuseum/statefulset.yaml rename templates/clair/{configmap.yaml => clair-cm.yaml} (78%) create mode 100644 templates/clair/clair-dpl.yaml create mode 100644 templates/clair/clair-svc.yaml delete mode 100644 templates/clair/deployment.yaml delete mode 100644 templates/clair/service.yaml create mode 100644 templates/common/certificate-secret.yaml create mode 100644 templates/core/core-cm.yaml create mode 100644 templates/core/core-dpl.yaml create mode 100644 templates/core/core-secret.yaml rename templates/{jobservice/service.yaml => core/core-svc.yaml} (54%) rename templates/database/{secret.yaml => database-secret.yaml} (58%) create mode 100644 templates/database/database-ss.yaml rename templates/database/{service.yaml => database-svc.yaml} (62%) delete mode 100644 templates/database/statefulset.yaml create mode 100644 templates/ingress/notary-ingress.yaml delete mode 100644 templates/ingress/secret.yaml delete mode 100644 templates/istio/notary.gateway.yaml delete mode 100644 templates/istio/ui.gateway.yaml delete mode 100644 templates/jobservice/configmap.yaml delete mode 100644 templates/jobservice/deployment.yaml create mode 100644 templates/jobservice/jobservice-cm.yaml create mode 100644 templates/jobservice/jobservice-dpl.yaml create mode 100644 templates/jobservice/jobservice-secrets.yaml rename templates/{ui/service.yaml => jobservice/jobservice-svc.yaml} (65%) delete mode 100644 templates/jobservice/secret.yaml create mode 100644 templates/nginx/configmap-http.yaml create mode 100644 templates/nginx/configmap-https.yaml create mode 100644 templates/nginx/deployment.yaml create mode 100644 templates/nginx/service.yaml rename templates/notary/{configmap.yaml => notary-cm.yaml} (58%) rename templates/notary/{service.yaml => notary-svc.yaml} (61%) create mode 100644 templates/portal/deployment.yaml create mode 100644 templates/portal/service.yaml delete mode 100644 templates/redis/deployment.yml rename templates/redis/{service.yml => service.yaml} (55%) create mode 100644 templates/redis/statefulset.yaml delete mode 100644 templates/registry/configmap.yaml create mode 100644 templates/registry/registry-cm.yaml create mode 100644 templates/registry/registry-dpl.yaml create mode 100644 templates/registry/registry-secret.yaml rename templates/registry/{service.yaml => registry-svc.yaml} (58%) delete mode 100644 templates/registry/secret.yaml delete mode 100644 templates/registry/statefulset.yaml delete mode 100644 templates/ui/configmap.yaml delete mode 100644 templates/ui/deployment.yaml delete mode 100644 templates/ui/secret.yaml diff --git a/.helmignore b/.helmignore new file mode 100644 index 0000000..632a574 --- /dev/null +++ b/.helmignore @@ -0,0 +1,4 @@ +docs/* +.git/* +.gitignore +CONTRIBUTING.md \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94c8333..30ec8be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Helm Chart for Harbor -Please follow [Harbor contributing guide](https://github.com/vmware/harbor/blob/master/CONTRIBUTING.md) to learn how to make code contribution. +Please follow [Harbor contributing guide](https://github.com/goharbor/harbor/blob/master/CONTRIBUTING.md) to learn how to make code contribution. # Contributers diff --git a/Chart.yaml b/Chart.yaml index f28ab58..41bb684 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -1,16 +1,16 @@ name: harbor -version: 0.2.0 -appVersion: 1.5.0 -description: An Enterprise-class Docker Registry by VMware +version: dev +appVersion: dev +description: An open source trusted cloud native registry that stores, signs, and scans content keywords: -- vmware - docker - registry - harbor -home: https://github.com/vmware/harbor -icon: https://raw.githubusercontent.com/vmware/harbor/master/docs/img/harbor_logo.png +home: https://goharbor.io +icon: https://raw.githubusercontent.com/goharbor/harbor/master/docs/img/harbor_logo.png sources: -- https://github.com/vmware/harbor/tree/master/contrib/helm/harbor +- https://github.com/goharbor/harbor +- https://github.com/goharbor/harbor-helm maintainers: - name: Jesse Hu email: huh@vmware.com diff --git a/Deploy.md b/Deploy.md new file mode 100644 index 0000000..cc8835b --- /dev/null +++ b/Deploy.md @@ -0,0 +1,77 @@ +# harbor + +## install + +```bash +# 1.install + +# label node +kubectl label node harbor=enabled + +helm install \ +/etc/kubernetes/helm/harbor \ +--name=harbor \ +--namespace=devops \ +-f /etc/kubernetes/helm/harbor/values-overrides.yaml + +# uninstall +helm delete harbor --purge + +# update +helm upgrade harbor /etc/kubernetes/helm/harbor \ +-f /etc/kubernetes/helm/harbor/values-overrides.yaml +``` + +## images + +```bash +# goharbor/harbor-portal +docker pull goharbor/harbor-portal:v1.7.5 && \ +docker tag goharbor/harbor-portal:v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-portal:v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-portal:v1.7.5 + +# goharbor/harbor-core +docker pull goharbor/harbor-core:v1.7.5 && \ +docker tag goharbor/harbor-core:v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-core:v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-core:v1.7.5 + +# goharbor/harbor-jobservice +docker pull goharbor/harbor-jobservice:v1.7.5 && \ +docker tag goharbor/harbor-jobservice:v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-jobservice:v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-jobservice:v1.7.5 + +# goharbor/registry-photon +docker pull goharbor/registry-photon:v2.6.2-v1.7.5 && \ +docker tag goharbor/registry-photon:v2.6.2-v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/registry-photon:v2.6.2-v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/registry-photon:v2.6.2-v1.7.5 + +# goharbor/harbor-registryctl +docker pull goharbor/harbor-registryctl:v1.7.5 && \ +docker tag goharbor/harbor-registryctl:v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-registryctl:v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-registryctl:v1.7.5 + +# goharbor/chartmuseum-photon +docker pull goharbor/chartmuseum-photon:v0.8.1-v1.7.5 && \ +docker tag goharbor/chartmuseum-photon:v0.8.1-v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/chartmuseum-photon:v0.8.1-v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/chartmuseum-photon:v0.8.1-v1.7.5 + +# goharbor/clair-photon +docker pull goharbor/clair-photon:v2.0.8-v1.7.5 && \ +docker tag goharbor/clair-photon:v2.0.8-v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/clair-photon:v2.0.8-v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/clair-photon:v2.0.8-v1.7.5 + +# goharbor/notary-server-photon +docker pull goharbor/notary-server-photon:v0.6.1-v1.7.5 && \ +docker tag goharbor/notary-server-photon:v0.6.1-v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-server-photon:v0.6.1-v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-server-photon:v0.6.1-v1.7.5 + +# goharbor/notary-signer-photon +docker pull goharbor/notary-signer-photon:v0.6.1-v1.7.5 && \ +docker tag goharbor/notary-signer-photon:v0.6.1-v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-signer-photon:v0.6.1-v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-signer-photon:v0.6.1-v1.7.5 + +# goharbor/harbor-db +docker pull goharbor/harbor-db:v1.7.5 && \ +docker tag goharbor/harbor-db:v1.7.5 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-db:v1.7.5 && \ +docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-db:v1.7.5 +``` \ No newline at end of file diff --git a/docs/High Availability.md b/docs/High Availability.md new file mode 100644 index 0000000..6bd48f1 --- /dev/null +++ b/docs/High Availability.md @@ -0,0 +1,63 @@ +# Harbor High Availability Guide + +## Goal +Deploy Harbor on K8S via helm to make it highly available, that is, if one of node that has Harbor's container running becomes un accessible. Users does not experience interrupt of service of Harbor. + +## Prerequisites +- Kubernetes cluster 1.10+ +- Helm 2.8.0+ +- High available ingress controller (Harbor does not manage the external endpoint) +- High available PostgreSQL database (Harbor does not handle the deployment of HA of database) +- High available Redis (Harbor does not handle the deployment of HA of Redis) +- PVC that can be shared across nodes or external object storage + +## Architecture +Most of Harbor's components are stateless now. So we can simply increase the replica of the pods to make sure the components are distributed to multiple worker nodes, and leverage the "Service" mechanism of K8S to ensure the connectivity across pods. + +As for storage layer, it is expected that the user provide high available PostgreSQL, Redis cluster for application data and PVCs or object storage for storing images and charts. + +![HA](img/ha.png) + +## Installation + +### Download Chart +Download Harbor helm chart code. +```bash +git clone https://github.com/goharbor/harbor-helm +cd harbor-helm +``` + +### Configuration +Configure the followings items in `values.yaml`, you can also set them as parameters via `--set` flag during running `helm install`: +- **Ingress rule** + Configure the `expose.ingress.hosts.core` and `expose.ingress.hosts.notary`. +- **External URL** + Configure the `externalURL`. +- **External PostgreSQL** + Set the `database.type` to `external` and fill the information in `database.external` section. + + Four empty databases should be created manually for `Harbor core`, `Clair`, `Notary server` and `Notary signer` and configure them in the section. Harbor will create tables automatically when starting up. +- **External Redis** + Set the `redis.type` to `external` and fill the information in `redis.external` section. + + As the Redis client used by Harbor's upstream projects doesn't support `Sentinel`, Harbor can only work with a single entry point Redis. You can refer to this [guide](https://community.pivotal.io/s/article/How-to-setup-HAProxy-and-Redis-Sentinel-for-automatic-failover-between-Redis-Master-and-Slave-servers) to setup a HAProxy before the Redis to expose a single entry point. +- **Storage** + By default, a default `StorageClass` is needed in the K8S cluster to provision volumes to store images, charts and job logs. + + If you want to specify the `StorageClass`, set `persistence.persistentVolumeClaim.registry.storageClass`, `persistence.persistentVolumeClaim.chartmuseum.storageClass` and `persistence.persistentVolumeClaim.jobservice.storageClass`. + + If you use `StorageClass`, for both default or specified one, set `persistence.persistentVolumeClaim.registry.accessMode`, `persistence.persistentVolumeClaim.chartmuseum.accessMode` and `persistence.persistentVolumeClaim.jobservice.accessMode` as `ReadWriteMany`, and make sure that the persistent volumes must can be shared cross different nodes. + + You can also use the existing PVCs to store data, set `persistence.persistentVolumeClaim.registry.existingClaim`, `persistence.persistentVolumeClaim.chartmuseum.existingClaim` and `persistence.persistentVolumeClaim.jobservice.existingClaim`. + + If you have no PVCs that can be shared across nodes, you can use external object storage to store images and charts and store the job logs in database. Set the `persistence.imageChartStorage.type` to the value you want to use and fill the corresponding section and set `jobservice.jobLogger` to `database`. + +- **Replica** + Set `portal.replicas`, `core.replicas`, `jobservice.replicas`, `registry.replicas`, `chartmuseum.replicas`, `clair.replicas`, `notary.server.replicas` and `notary.signer.replicas` to `n`(`n`>=2). + +### Installation +Install the Harbor helm chart with a release name `my-release`: +```bash +helm install --name my-release . +``` + diff --git a/docs/Upgrade.md b/docs/Upgrade.md new file mode 100644 index 0000000..3ba2689 --- /dev/null +++ b/docs/Upgrade.md @@ -0,0 +1,48 @@ +# Upgrade Guide + +This guide is used to upgrade Harbor deployed by chart since version 0.3.0. + +**Notes**: +- As the database schema may change between different versions of Harbor, there is a progress to migrate the schema during the upgrade and the downtime cannot be avoid +- The database schema cannot be downgraded automatically, so the `helm rollback` is not supported + +## Upgrade +1. **Backup database** +Backup the database used by Harbor in case the upgrade process fails. +2. **Download new chart** +Download the latest version of Harbor chart. +3. **Configure new chart** +Configure the new chart to make sure that the configuration items have the same values with the old one. + + **Note**: if TLS is enabled and the certificate is generated by chart automatically, a new certificate will be generated and overwrite the old one during the upgrade, this may cause some issues if you have distributed the certificate. You can follow the below steps to configure the new chart to use the old certificate: + + 1) Get the secret name which certificate is stored in: + ``` + kubectl get secret + ``` + Find the secret whose name ends with `-harbor-ingress`(expose service via `Ingress`) or `-harbor-nginx`(expose service via `ClusterIP` or `NodePort`) + + 2) Export the secret as yaml file: + ``` + kubectl get secret secret-name -o yaml > secret.yaml + ``` + Replace the `secret-name` with the one got in step i + + 3) Rename the secret by setting `metadata.name` in `secret.yaml` + + 4) Create a new secret: + ``` + kubectl create -f secret.yaml + ``` + + 5) Configure the chart to use the new secret by setting `expose.tls.secretName` as the value you set in step iii + +4. **Upgrade** +Run upgrade command: + ``` + helm upgrade release-name --force . + ``` + The `--force` is necessary if upgrade from version 0.3.0 due to issue [#30](https://github.com/goharbor/harbor-helm/issues/30). + +## Known issues +- The job logs will be lost if you upgrade from version 0.3.0 as the logs are store in a `emptyDir` in 0.3.0. diff --git a/docs/img/ha.png b/docs/img/ha.png new file mode 100644 index 0000000000000000000000000000000000000000..6f063c2bba21e05934307b5c5d699cc2211c7f8f GIT binary patch literal 156076 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 Hd&m6=0W1T$ literal 0 HcmV?d00001 diff --git a/logo.png b/logo.png deleted file mode 100644 index 45df310f3df8a2d02038772449ed6bab59ff8891..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62422 zcmV)PK()V#P)4Tx07!|IR|iy6$r_$pQb}lm2uKON2~wm>386(0kSf>+Ng$!bm=Hwl%A$g6 z7ZI?bt0Ic71(3C3FNUAu^OTHZ7e+dITuI1U5(D%HzwW?D+T?0A-;6r@XxZ5M_VWMalK!_-lXq1@W-_{K-lT?SMn( zH$2(@;LIH4!ZnttLM=LQ6 z;%-T1Y#hY;5Wg1-RQ3>~RFNVoS#6J+^5q;@Gr)w{O~4C_hS(J12uWUSj7FcCC63@i z3|9zRBrf14Y342z%EJ>ioHeq^32_5BOU7Yq<~HzTD!)qmlZxDAwub+fNXQ-Fe^V?< zN>#^u@GxR%#`OQMyqWwn_>|scECoaNKnRa1F^qQ5*e!I$0laUA`&$AvV8eK zzSu&Mm>a9XRRyA?C=Jg}K2H_D5yZ_x2|Ia!M<^c~Gmwiw7#6P19lI=)Bx~};I-~`m z37WaDqoFi&W~ZAU2g3CTiy5K?QI@s`>F)X+eCFI!-(@hc_x-9S>dvVgLt( z0TxiemI)?<93XD%Zt8}=)FTmq2V@`{2!V@6GcY4nH6nq}L{JR=f=CGDgY!aFqe4&! z^`8f|>Zc3HQjHd>X5@k=5a)wvkOzM&RI?<5-crCHP$T}qJ0HfH2b*&2M;#k#Vl*1X z053~tz>*kF3?oJnBZ!W;2_A$8;4$zS0-Fc!i~9{k`_-QCgwRfSM7U1qAl#lLo+tY* z9~Kx5I-rLLP0pF$=8W4xRxdmh4}|=X8)xDszy%)xJ+bj%=-UfwIhx3o*?-Udj~u?K zy2g&;MnNefKQ&~y5TfJMC+b8u{fv`xq zKLXBV=`@)*TU5Ye!<}Eq;!60g!&n|}?r_&uen-^X)N7{d`+zXdf7Q*m1R!u)e}Dg> zue#{V0PH&q0QJsSoqZ?V4$cE`b`4)4D^%-n<%0mIKnK22#=sm{0|%Io2k-^~AOwVi zQ6LT^fiy4?R#^nsvkXiHGr(L>3d+GUuo_f>4PZ0a4t9aPpa~oT$H8fE0bB;x!Ckm| zI>B?$1Kxr@1VKm$9bq8Ghy`McI3pg2FA{`=BQZzEM?28xXfFmZEsTj-VlJ33#=+vSbSw*#VY9F@tOBdW8n71lKVQWLk1+5{XQrJ<$igjcLRj;&kF-;yU7P;xS@7@iDQNL?RiJoJoPCI1-Ok zKq@7zCG8{~C0!wPlHQZG$QEP|as)Y@EFsS$SCDs*kC3mBpOX71x)fWAKP8SLpiHAI zrEHpwK_o%P6w6v_W{ItesiM8fvRch_gI;-_i z>jO=n=0xMr#?utECA4j{W3=0}*K|7Fjvhi!rx(zd(Cg?Y=nv@cwHey3+FWgc_H6BH z?MCe@+Ank{I<`7&oryZdIu$zmbS~+1>r!;>bUC^_-C4TTx(9V{>h|g}^xXC0^z!u< z>+R4xr}s>sq;IDmt}oCp(ci3pLjN%XV^}jd3_fE%V+-RHqtk$BU~j-R$T284*k#aW z&||1?IKnW+u*k65@UUSA6Jy#jxy(G~Qs!Rf4d%xoW<%IRghLh$X&7>4$UCEH^EJuOvac@HCbdikdo^ zCYVk)-E4Z%wAaksEYeJBw$|)~S+_aUJj6W5e3khT^DYa9MUaKqVwJ^Fi$7V0EH*2T zRmnQZ>ajGnjIvZ%ZnA8%?6b1BO17G3wcF~xHPzbJI?H;Mb*pucjfKrx4-8=cL;Wv;!x{w&5`Kn>zM1f&hfGn z>g44la;kQ^BE-~KQsJ`o0nUj+ZMOG?)vVd+~>KsxWDpn^5A<^dtCFRdq#N9_H6ciIl_5_aK!o% zx4al$qrDb*wR(N__VJc^H+XmX*!X1l)cD-=HSmr1UF>_-kKh;TH{0)!-v@th{{sKL z{(lF!1mp(n2zWNqexz{ZmXVJGtpa(0n*uw6SV0*<8-qH6ErWT%wZV@5<2x z2vN~d%cE{`&A5DS9k*wc�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�T45$u0de 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 harbor=enabled +## Prerequisites -helm install \ -/etc/kubernetes/helm/harbor \ ---name=harbor \ ---namespace=devops \ --f /etc/kubernetes/helm/harbor/values-overrides.yaml +- Kubernetes cluster 1.10+ +- Helm 2.8.0+ -# uninstall -helm delete harbor --purge +## Installation -# update -helm upgrade harbor /etc/kubernetes/helm/harbor \ --f /etc/kubernetes/helm/harbor/values-overrides.yaml +### Download the chart + +Download Harbor helm chart code. + +```bash +git clone https://github.com/goharbor/harbor-helm ``` -## overrides +Checkout the branch. ```bash -cat /etc/kubernetes/helm/harbor/values-overrides.yaml +cd harbor-helm +git checkout branch_name ``` -### 有持久化存储Storage +### Configure the chart + +The following items can be configured in `values.yaml` or set via `--set` flag during installation. + +#### Configure the way how to expose Harbor service: + +- **Ingress**: The ingress controller must be installed in the Kubernetes cluster. + **Notes:** if the TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to issue [#5291](https://github.com/goharbor/harbor/issues/5291) for the detail. +- **ClusterIP**: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from within the cluster. +- **NodePort**: Exposes the service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the NodePort service, from outside the cluster, by requesting `NodeIP:NodePort`. +- **LoadBalancer**: Exposes the service externally using a cloud provider’s load balancer. + +#### Configure the external URL + +The external URL for Harbor core service is used to: + +1. populate the docker/helm commands showed on portal +2. populate the token service URL returned to docker/notary client + +Format: `protocol://domain[:port]`. Usually: -参考values-storage.yaml +- if expose the service via `Ingress`, the `domain` should be the value of `expose.ingress.hosts.core` +- if expose the service via `ClusterIP`, the `domain` should be the value of `expose.clusterIP.name` +- if expose the service via `NodePort`, the `domain` should be the IP address of one Kubernetes node +- if expose the service via `LoadBalancer`, set the `domain` as your own domain name and add a CNAME record to map the domain name to the one you got from the cloud provider -### 使用HostPath存储数据 +If Harbor is deployed behind the proxy, set it as the URL of proxy. -在此之前规划一下哪台服务器存储什么内容 +#### Configure the way how to persistent data: +- **Disable**: The data does not survive the termination of a pod. +- **Persistent Volume Claim(default)**: A default `StorageClass` is needed in the Kubernetes cluster to dynamic provision the volumes. Specify another StorageClass in the `storageClass` or set `existingClaim` if you have already existing persistent volumes to use. +- **External Storage(only for images and charts)**: For images and charts, the external storages are supported: `azure`, `gcs`, `s3` `swift` and `oss`. + +#### Configure the secrets + +- **Secret keys**: Secret keys are used for secure communication between components. Fill `core.secret`, `jobservice.secret` and `registry.secret` to configure. +- **Certificates**: + - *notary*: Used for authentication during communications. Fill `notary.secretName` to configure. Notary server certificate must be issued with notary service name as subject alternative name. + - *core*: Used for token encryption/decryption. Fill `core.secretName` to configure. + +Secrets and certificates must be setup to avoid changes on every Helm upgrade (see: [#107](https://github.com/goharbor/harbor-helm/issues/107)). + + +#### Configure the other items listed in [configuration](#configuration) section. + +### Install the chart + +Install the Harbor helm chart with a release name `my-release`: + +```bash +helm install --name my-release . ``` -harbor: enabled -kubectl label node harbor=enabled -# kubectl label node harbor- +## Uninstallation + +To uninstall/delete the `my-release` deployment: + +```bash +helm delete --purge my-release ``` -参考values-hostpath.yaml +## Configuration +The following table lists the configurable parameters of the Harbor chart and the default values. -# images +| Parameter | Description | Default | +| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | +| **Expose** | +| `expose.type` | The way how to expose the service: `ingress`, `clusterIP`, `nodePort` or `loadBalancer` | `ingress` | +| `expose.tls.enabled` | Enable the tls or not | `true` | +| `expose.tls.secretName` | Fill the name of secret if you want to use your own TLS certificate. The secret must contain keys named: +`tls.crt` - the certificate, `tls.key` - the private key, `ca.crt` - the certificate of CA.These files will be generated automatically if the `secretName` is not set || +| `expose.tls.commonName` | The common name used to generate the certificate, it's necessary when the `expose.type` is `clusterIP` or `nodePort` and `expose.tls.secretName` is null | | +| `expose.ingress.host` | The host of Harbor service in ingress rule | `harbor.local` | +| `expose.ingress.controller` | The ingress controller type. Currently supports `default` and `gce` | `default` | +| `expose.ingress.annotations` | The annotations used in ingress | | +| `expose.ingress.rewriteAnnotation` | The name of the `rewrite-target` annotation| `nginx.ingress.kubernetes.io/rewrite-target` | +| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` | +| `expose.clusterIP.ports.http` | The service port Harbor listens on when serving with HTTP | `80` | +| `expose.clusterIP.ports.https` | The service port Harbor listens on when serving with HTTPS | `443` | +| `expose.nodePort.name` | The name of NodePort service | `harbor` | +| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving with HTTP | `80` | +| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving with HTTP | `30002` | +| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving with HTTPS | `443` | +| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving with HTTPS | `30003` | +| `expose.loadBalancer.name` | The name of service |`harbor`| +| `expose.loadBalancer.ports.http` | The service port Harbor listens on when serving with HTTP |`80`| +| `expose.loadBalancer.ports.https` | The service port Harbor listens on when serving with HTTP |`30002`| +| **Persistence** | +| `persistence.enabled` | Enable the data persistence or not | `true` | +| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted | `keep` | +| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.chartmuseum.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.chartmuseum.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.chartmuseum.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.chartmuseum.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.chartmuseum.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.jobservice.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.jobservice.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.jobservice.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.jobservice.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.jobservice.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` | +| `persistence.imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more information about the detail | `false` | +| `persistence.imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry and chartmuseum. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more information about the detail | `filesystem` | +| **General** | +| `externalURL` | The external URL for Harbor service | `https://harbor.local` | +| `imagePullPolicy` | The image pull policy | `IfNotPresent` | +| `logLevel` | The log level | `debug` | +| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` | +| `secretkey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` | +| **Nginx** (if expose the service via `ingress`, the Nginx will not be used) | +| `nginx.image.repository` | Image repository | `goharbor/nginx-photon` | +| `nginx.image.tag` | Image tag | `dev` | +| `nginx.replicas` | The replica count | `1` | +| `nginx.resources` | The [resources] to allocate for container | undefined | +| `nginx.nodeSelector` | Node labels for pod assignment | `{}` | +| `nginx.tolerations` | Tolerations for pod assignment | `[]` | +| `nginx.affinity` | Node/Pod affinities | `{}` | +| `nginx.podAnnotations` | Annotations to add to the nginx pod | `{}` | +| **Portal** | +| `portal.image.repository` | Repository for portal image | `goharbor/harbor-portal` | +| `portal.image.tag` | Tag for portal image | `dev` | +| `portal.replicas` | The replica count | `1` | +| `portal.resources` | The [resources] to allocate for container | undefined | +| `portal.nodeSelector` | Node labels for pod assignment | `{}` | +| `portal.tolerations` | Tolerations for pod assignment | `[]` | +| `portal.affinity` | Node/Pod affinities | `{}` | +| `portal.podAnnotations` | Annotations to add to the portal pod | `{}` | +| **Core** | +| `core.image.repository` | Repository for Harbor core image | `goharbor/harbor-core` | +| `core.image.tag` | Tag for Harbor core image | `dev` | +| `core.replicas` | The replica count | `1` | +| `core.resources` | The [resources] to allocate for container | undefined | +| `core.nodeSelector` | Node labels for pod assignment | `{}` | +| `core.tolerations` | Tolerations for pod assignment | `[]` | +| `core.affinity` | Node/Pod affinities | `{}` | +| `core.podAnnotations` | Annotations to add to the core pod | `{}` | +| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `core.secret` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named `tls.tokenServiceRootCertBundle` and `tls.tokenServicePrivateKey` that contain the certificate and private key. They will be automatically generated if not set. | | +| **Jobservice** | +| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` | +| `jobservice.image.tag` | Tag for jobservice image | `dev` | +| `jobservice.replicas` | The replica count | `1` | +| `jobservice.maxJobWorkers` | The max job workers | `10` | +| `jobservice.jobLogger` | The logger for jobs: `file`, `database` or `stdout` | `file` | +| `jobservice.resources` | The [resources] to allocate for container | undefined | +| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` | +| `jobservice.tolerations` | Tolerations for pod assignment | `[]` | +| `jobservice.affinity` | Node/Pod affinities | `{}` | +| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` | +| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| **Registry** | +| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` | +| `registry.registry.image.tag` | Tag for registry image | +| `registry.registry.resources` | The [resources] to allocate for container | undefined | | `dev` | +| `registry.controller.image.repository` | Repository for registry controller image | `goharbor/harbor-registryctl` | +| `registry.controller.image.tag` | Tag for registry controller image | +| `registry.controller.resources` | The [resources] to allocate for container | undefined | | `dev` | +| `registry.replicas` | The replica count | `1` | +| `registry.nodeSelector` | Node labels for pod assignment | `{}` | +| `registry.tolerations` | Tolerations for pod assignment | `[]` | +| `registry.affinity` | Node/Pod affinities | `{}` | +| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` | +| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See: https://github.com/docker/distribution/blob/master/docs/configuration.md#http. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| **Chartmuseum** | +| `chartmuseum.enabled` | Enable chartmusuem to store chart | `true` | +| `chartmuseum.image.repository` | Repository for chartmuseum image | `goharbor/chartmuseum-photon` | +| `chartmuseum.image.tag` | Tag for chartmuseum image | `dev` | +| `chartmuseum.replicas` | The replica count | `1` | +| `chartmuseum.resources` | The [resources] to allocate for container | undefined | +| `chartmuseum.nodeSelector` | Node labels for pod assignment | `{}` | +| `chartmuseum.tolerations` | Tolerations for pod assignment | `[]` | +| `chartmuseum.affinity` | Node/Pod affinities | `{}` | +| `chartmuseum.podAnnotations` | Annotations to add to the chart museum pod | `{}` | +| **Clair** | +| `clair.enabled` | Enable Clair | `true` | +| `clair.image.repository` | Repository for clair image | `goharbor/clair-photon` | +| `clair.image.tag` | Tag for clair image | `dev` | +| `clair.replicas` | The replica count | `1` | +| `clair.httpProxy` | The HTTP proxy used to update vulnerabilities database from internet | | +| `clair.httpsProxy` | The HTTPS proxy used to update vulnerabilities database from internet | | +| `clair.updatersInterval` | The interval of clair updaters, the unit is hour, set to 0 to disable the updaters | `12` | +| `clair.resources` | The [resources] to allocate for container | undefined | +| `clair.nodeSelector` | Node labels for pod assignment | `{}` | +| `clair.tolerations` | Tolerations for pod assignment | `[]` | +| `clair.affinity` | Node/Pod affinities | `{}` | +| `clair.podAnnotations` | Annotations to add to the clair pod | `{}` | +| **Notary** | +| `notary.enabled` | Enable Notary? | `true` | +| `notary.server.image.repository` | Repository for notary server image | `goharbor/notary-server-photon` | +| `notary.server.image.tag` | Tag for notary server image | `dev` | +| `notary.server.replicas` | The replica count | +| `notary.server.resources` | The [resources] to allocate for container | undefined | | `1` | +| `notary.signer.image.repository` | Repository for notary signer image | `goharbor/notary-signer-photon` | +| `notary.signer.image.tag` | Tag for notary signer image | `dev` | +| `notary.signer.replicas` | The replica count | +| `notary.signer.resources` | The [resources] to allocate for container | undefined | | `1` | +| `notary.nodeSelector` | Node labels for pod assignment | `{}` | +| `notary.tolerations` | Tolerations for pod assignment | `[]` | +| `notary.affinity` | Node/Pod affinities | `{}` | +| `notary.podAnnotations` | Annotations to add to the notary pod | `{}` | +| `notary.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate authority, certificate and private key for notary communications. The secret must contain keys named `tls.ca`, `tls.crt` and `tls.key` that contain the CA, certificate and private key. They will be generated if not set. | | +| **Database** | +| `database.type` | If external database is used, set it to `external` | `internal` | +| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` | +| `database.internal.image.tag` | Tag for database image | `dev` | +| `database.internal.password` | The password for database | `changeit` | +| `database.internal.resources` | The [resources] to allocate for container | undefined | +| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `database.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `database.internal.affinity` | Node/Pod affinities | `{}` | +| `database.external.host` | The hostname of external database | `192.168.0.1` | +| `database.external.port` | The port of external database | `5432` | +| `database.external.username` | The username of external database | `user` | +| `database.external.password` | The password of external database | `password` | +| `database.external.coreDatabase` | The database used by core service | `registry` | +| `database.external.clairDatabase` | The database used by clair | `clair` | +| `database.external.notaryServerDatabase` | The database used by Notary server | `notary_server` | +| `database.external.notarySignerDatabase` | The database used by Notary signer | `notary_signer` | +| `database.external.sslmode` | Connection method of external database (require | prefer | disable) | `disable` | +| `database.podAnnotations` | Annotations to add to the database pod | `{}` | +| **Redis** | +| `redis.type` | If external redis is used, set it to `external` | `internal` | +| `redis.internal.image.repository` | Repository for redis image | `goharbor/redis-photon` | +| `redis.internal.image.tag` | Tag for redis image | `dev` | +| `redis.internal.resources` | The [resources] to allocate for container | undefined | +| `redis.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `redis.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `redis.internal.affinity` | Node/Pod affinities | `{}` | +| `redis.external.host` | The hostname of external Redis | `192.168.0.2` | +| `redis.external.port` | The port of external Redis | `6379` | +| `redis.external.coreDatabaseIndex` | The database index for core | `0` | +| `redis.external.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.external.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.external.chartmuseumDatabaseIndex` | The database index for chartmuseum | `3` | +| `redis.external.password` | The password of external Redis | | +| `redis.podAnnotations` | Annotations to add to the redis pod | `{}` | -```bash -# harbor-ui -docker pull goharbor/harbor-ui:v1.6.3 && \ -docker tag goharbor/harbor-ui:v1.6.3 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-ui:v1.6.3 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-ui:v1.6.3 - -# harbor-adminserver -docker pull goharbor/harbor-adminserver:v1.6.3 && \ -docker tag goharbor/harbor-adminserver:v1.6.3 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-adminserver:v1.6.3 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-adminserver:v1.6.3 - -# harbor-jobservice -docker pull goharbor/harbor-jobservice:v1.6.3 && \ -docker tag goharbor/harbor-jobservice:v1.6.3 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-jobservice:v1.6.3 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-jobservice:v1.6.3 - -# harbor-db -docker pull goharbor/harbor-db:v1.6.3 && \ -docker tag goharbor/harbor-db:v1.6.3 registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-db:v1.6.3 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/harbor-db:v1.6.3 - -# chartmuseum -docker pull chartmuseum/chartmuseum:v0.7.1 && \ -docker tag chartmuseum/chartmuseum:v0.7.1 registry-vpc.cn-qingdao.aliyuncs.com/wod/chartmuseum:v0.7.1 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/chartmuseum:v0.7.1 - -# clair -docker pull quay.io/coreos/clair:v2.0.6 && \ -docker tag quay.io/coreos/clair:v2.0.6 registry-vpc.cn-qingdao.aliyuncs.com/wod/clair:v2.0.6 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/clair:v2.0.6 - -# notary:server -docker pull notary:server-0.5.0 && \ -docker tag notary:server-0.5.0 registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-server:0.5.0 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-server:0.5.0 - -# notary:signer -docker pull notary:signer-0.5.0 && \ -docker tag notary:signer-0.5.0 registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-signer:0.5.0 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/notary-signer:0.5.0 - -# registry -docker pull registry:2.7.1 && \ -docker tag registry:2.7.1 registry-vpc.cn-qingdao.aliyuncs.com/wod/registry:2.7.1 && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/registry:2.7.1 - -# redis -docker pull redis:4.0.1-alpine && \ -docker tag redis:4.0.1-alpine registry-vpc.cn-qingdao.aliyuncs.com/wod/redis:4.0.1-alpine && \ -docker push registry-vpc.cn-qingdao.aliyuncs.com/wod/redis:4.0.1-alpine -``` \ No newline at end of file +[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ diff --git a/templates/NOTES.txt b/templates/NOTES.txt index ce11208..6378bf3 100644 --- a/templates/NOTES.txt +++ b/templates/NOTES.txt @@ -1,3 +1,3 @@ Please wait for several minutes for Harbor deployment to complete. -Then you should be able to visit the UI portal at {{ template "harbor.externalURL" . }}. -For more details, please visit https://github.com/vmware/harbor. \ No newline at end of file +Then you should be able to visit the Harbor portal at {{ .Values.externalURL }}. +For more details, please visit https://github.com/goharbor/harbor. \ No newline at end of file diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 08e34e4..9021d29 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -13,52 +13,34 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this */}} {{- define "harbor.fullname" -}} {{- $name := default "harbor" .Values.nameOverride -}} -{{- printf "%s" .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* Helm required labels */}} {{- define "harbor.labels" -}} heritage: {{ .Release.Service }} release: {{ .Release.Name }} -chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" {{- end -}} {{/* matchLabels */}} {{- define "harbor.matchLabels" -}} release: {{ .Release.Name }} +app: "{{ template "harbor.name" . }}" {{- end -}} -{{- define "harbor.externalURL" -}} -{{- if .Values.externalPort -}} -{{- printf "%s://%s:%s" .Values.externalProtocol .Values.externalDomain (toString .Values.externalPort) -}} -{{- else -}} -{{- printf "%s://%s" .Values.externalProtocol .Values.externalDomain -}} -{{- end -}} -{{- end -}} - -{{/* -Use *.domain.com as the Common Name in the certificate, -so it can match Harbor service FQDN and Notary service FQDN. -*/}} -{{- define "harbor.certCommonName" -}} -{{- $list := splitList "." .Values.externalDomain -}} -{{- $list := prepend (rest $list) "*" -}} -{{- $cn := join "." $list -}} -{{- printf "%s" $cn -}} -{{- end -}} - -{{/* The external FQDN of Notary server. */}} -{{- define "harbor.notaryFQDN" -}} -{{- printf "notary-%s" .Values.externalDomain -}} -{{- end -}} - -{{- define "harbor.notaryServiceName" -}} -{{- printf "%s-notary-server" (include "harbor.fullname" .) -}} +{{- define "harbor.autoGenCert" -}} + {{- if and .Values.expose.tls.enabled (not .Values.expose.tls.secretName) -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} {{- end -}} {{- define "harbor.database.host" -}} {{- if eq .Values.database.type "internal" -}} - {{- template "harbor.fullname" . }}-database + {{- template "harbor.database" . }} {{- else -}} {{- .Values.database.external.host -}} {{- end -}} @@ -80,14 +62,6 @@ so it can match Harbor service FQDN and Notary service FQDN. {{- end -}} {{- end -}} -{{- define "harbor.database.password" -}} - {{- if eq .Values.database.type "internal" -}} - {{- .Values.database.internal.password | b64enc | quote -}} - {{- else -}} - {{- .Values.database.external.password | b64enc | quote -}} - {{- end -}} -{{- end -}} - {{- define "harbor.database.rawPassword" -}} {{- if eq .Values.database.type "internal" -}} {{- .Values.database.internal.password -}} @@ -96,6 +70,10 @@ so it can match Harbor service FQDN and Notary service FQDN. {{- end -}} {{- end -}} +{{- define "harbor.database.encryptedPassword" -}} + {{- include "harbor.database.rawPassword" . | b64enc | quote -}} +{{- end -}} + {{- define "harbor.database.coreDatabase" -}} {{- if eq .Values.database.type "internal" -}} {{- printf "%s" "registry" -}} @@ -128,58 +106,95 @@ so it can match Harbor service FQDN and Notary service FQDN. {{- end -}} {{- end -}} +{{- define "harbor.database.sslmode" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "disable" -}} + {{- else -}} + {{- .Values.database.external.sslmode -}} + {{- end -}} +{{- end -}} + {{- define "harbor.database.clair" -}} -postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.clairDatabase" . }}?sslmode=disable +postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.clairDatabase" . }}?sslmode={{ template "harbor.database.sslmode" . }} {{- end -}} {{- define "harbor.database.notaryServer" -}} -postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.notaryServerDatabase" . }}?sslmode=disable +postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.notaryServerDatabase" . }}?sslmode={{ template "harbor.database.sslmode" . }} {{- end -}} {{- define "harbor.database.notarySigner" -}} -postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.notarySignerDatabase" . }}?sslmode=disable +postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.database.rawPassword" . }}@{{ template "harbor.database.host" . }}:{{ template "harbor.database.port" . }}/{{ template "harbor.database.notarySignerDatabase" . }}?sslmode={{ template "harbor.database.sslmode" . }} {{- end -}} {{- define "harbor.redis.host" -}} - {{- if .Values.redis.external.enabled -}} - {{- .Values.redis.external.host -}} + {{- if eq .Values.redis.type "internal" -}} + {{- template "harbor.redis" . -}} {{- else -}} - {{- .Release.Name }}-redis + {{- .Values.redis.external.host -}} {{- end -}} {{- end -}} {{- define "harbor.redis.port" -}} - {{- if .Values.redis.external.enabled -}} + {{- if eq .Values.redis.type "internal" -}} + {{- printf "%s" "6379" -}} + {{- else -}} {{- .Values.redis.external.port -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.coreDatabaseIndex" -}} + {{- if eq .Values.redis.type "internal" -}} + {{- printf "%s" "0" }} {{- else -}} - 6379 + {{- .Values.redis.external.coreDatabaseIndex -}} {{- end -}} {{- end -}} -{{- define "harbor.redis.databaseIndex" -}} - {{- if .Values.redis.external.enabled -}} - {{- .Values.redis.external.databaseIndex -}} +{{- define "harbor.redis.jobserviceDatabaseIndex" -}} + {{- if eq .Values.redis.type "internal" -}} + {{- printf "%s" "1" }} {{- else -}} - {{- printf "%s" "0" }} + {{- .Values.redis.external.jobserviceDatabaseIndex -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.registryDatabaseIndex" -}} + {{- if eq .Values.redis.type "internal" -}} + {{- printf "%s" "2" }} + {{- else -}} + {{- .Values.redis.external.registryDatabaseIndex -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.chartmuseumDatabaseIndex" -}} + {{- if eq .Values.redis.type "internal" -}} + {{- printf "%s" "3" }} + {{- else -}} + {{- .Values.redis.external.chartmuseumDatabaseIndex -}} {{- end -}} {{- end -}} -{{- define "harbor.redis.password" -}} - {{- if and .Values.redis.external.enabled .Values.redis.external.usePassword -}} +{{- define "harbor.redis.rawPassword" -}} + {{- if and (eq .Values.redis.type "external") .Values.redis.external.password -}} {{- .Values.redis.external.password -}} - {{- else if and (not .Values.redis.external.enabled) .Values.redis.usePassword -}} - {{- .Values.redis.password -}} {{- end -}} {{- end -}} {{/*the username redis is used for a placeholder as no username needed in redis*/}} {{- define "harbor.redisForJobservice" -}} - {{- if and .Values.redis.external.enabled .Values.redis.external.usePassword -}} - redis:{{ template "harbor.redis.password" . }}@{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}/{{ template "harbor.redis.databaseIndex" }} - {{- else if and (not .Values.redis.external.enabled) .Values.redis.usePassword -}} - redis:{{ template "harbor.redis.password" . }}@{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}/{{ template "harbor.redis.databaseIndex" }} + {{- if (include "harbor.redis.rawPassword" . ) -}} + {{- printf "redis://redis:%s@%s:%s/%s" (include "harbor.redis.rawPassword" . ) (include "harbor.redis.host" . ) (include "harbor.redis.port" . ) (include "harbor.redis.jobserviceDatabaseIndex" . ) }} {{- else }} - {{- template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}/{{ template "harbor.redis.databaseIndex" }} + {{- template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}/{{ template "harbor.redis.jobserviceDatabaseIndex" . }} + {{- end -}} +{{- end -}} + +{{/*the username redis is used for a placeholder as no username needed in redis*/}} +{{- define "harbor.redisForGC" -}} + {{- if (include "harbor.redis.rawPassword" . ) -}} + {{- printf "redis://redis:%s@%s:%s/%s" (include "harbor.redis.rawPassword" . ) (include "harbor.redis.host" . ) (include "harbor.redis.port" . ) (include "harbor.redis.registryDatabaseIndex" . ) }} + {{- else }} + {{- printf "redis://%s:%s/%s" (include "harbor.redis.host" . ) (include "harbor.redis.port" . ) (include "harbor.redis.registryDatabaseIndex" . ) -}} {{- end -}} {{- end -}} @@ -187,6 +202,80 @@ postgres://{{ template "harbor.database.username" . }}:{{ template "harbor.datab host:port,pool_size,password 100 is the default value of pool size */}} -{{- define "harbor.redisForUI" -}} - {{- template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }},100,{{ template "harbor.redis.password" . }} +{{- define "harbor.redisForCore" -}} + {{- template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }},100,{{ template "harbor.redis.rawPassword" . }} +{{- end -}} + +{{- define "harbor.portal" -}} + {{- printf "%s-portal" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.core" -}} + {{- printf "%s-core" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.redis" -}} + {{- printf "%s-redis" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.jobservice" -}} + {{- printf "%s-jobservice" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registry" -}} + {{- printf "%s-registry" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.chartmuseum" -}} + {{- printf "%s-chartmuseum" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.database" -}} + {{- printf "%s-database" (include "harbor.fullname" .) -}} {{- end -}} + +{{- define "harbor.clair" -}} + {{- printf "%s-clair" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.notary-server" -}} + {{- printf "%s-notary-server" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.notary-signer" -}} + {{- printf "%s-notary-signer" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.nginx" -}} + {{- printf "%s-nginx" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.ingress.core" -}} + {{- printf "%s-ingress-core" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.ingress.notary" -}} + {{- printf "%s-ingress-notary" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.certificate" -}} + {{- printf "%s-certificate" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.certificate-secret" -}} + {{- $tls := .Values.expose.tls -}} + {{- if $tls.secretName }} + {{- printf "%s" $tls.secretName -}} + {{- else }} + {{- printf "%s" (include "harbor.certificate" .) -}} + {{- end }} +{{- end -}} + +{{- define "harbor.common-name" -}} + {{- $expose := .Values.expose }} + {{- if and (eq $expose.type "ingress") $expose.ingress.host }} + {{- printf "%s" $expose.ingress.host -}} + {{- else }} + {{- printf "%s" $expose.tls.commonName -}} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/templates/adminserver/configmap.yaml b/templates/adminserver/configmap.yaml deleted file mode 100644 index 08da284..0000000 --- a/templates/adminserver/configmap.yaml +++ /dev/null @@ -1,60 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "{{ template "harbor.fullname" . }}-adminserver" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-adminserver -data: - POSTGRESQL_HOST: "{{ template "harbor.database.host" . }}" - POSTGRESQL_PORT: "{{ template "harbor.database.port" . }}" - POSTGRESQL_USERNAME: "{{ template "harbor.database.username" . }}" - POSTGRESQL_DATABASE: "{{ template "harbor.database.coreDatabase" . }}" - EMAIL_HOST: "{{ .Values.email.host }}" - EMAIL_PORT: "{{ .Values.email.port }}" - EMAIL_USR: "{{ .Values.email.username }}" - EMAIL_SSL: "{{ .Values.email.ssl }}" - EMAIL_FROM: "{{ .Values.email.from }}" - EMAIL_IDENTITY: "{{ .Values.email.identity }}" - EMAIL_INSECURE: "{{ .Values.email.insecure }}" - EXT_ENDPOINT: "{{ template "harbor.externalURL" . }}" - UI_URL: "http://{{ template "harbor.fullname" . }}-ui" - JOBSERVICE_URL: "http://{{ template "harbor.fullname" . }}-jobservice" - REGISTRY_URL: "http://{{ template "harbor.fullname" . }}-registry:5000" - TOKEN_SERVICE_URL: "http://{{ template "harbor.fullname" . }}-ui/service/token" - WITH_NOTARY: "{{ .Values.notary.enabled }}" - NOTARY_URL: "http://{{ template "harbor.notaryServiceName" . }}:4443" - LOG_LEVEL: "info" - IMAGE_STORE_PATH: "/" # This is a temporary hack. - AUTH_MODE: "{{ .Values.authenticationMode }}" - SELF_REGISTRATION: "{{ .Values.selfRegistration }}" - LDAP_URL: "{{ .Values.ldap.url }}" - LDAP_SEARCH_DN: "{{ .Values.ldap.searchDN }}" - LDAP_BASE_DN: "{{ .Values.ldap.baseDN }}" - LDAP_FILTER: "{{ .Values.ldap.filter }}" - LDAP_UID: "{{ .Values.ldap.uid }}" - LDAP_SCOPE: "{{ .Values.ldap.scope }}" - LDAP_TIMEOUT: "{{ .Values.ldap.timeout }}" - LDAP_VERIFY_CERT: "{{ .Values.ldap.verifyCert }}" - DATABASE_TYPE: "postgresql" - PROJECT_CREATION_RESTRICTION: "everyone" - VERIFY_REMOTE_CERT: "off" - MAX_JOB_WORKERS: "3" - TOKEN_EXPIRATION: "30" - CFG_EXPIRATION: "5" - GODEBUG: "netdns=cgo" - ADMIRAL_URL: "NA" - RESET: "false" - WITH_CLAIR: "{{ .Values.clair.enabled }}" - CLAIR_DB_HOST: "{{ template "harbor.database.host" . }}" - CLAIR_DB_PORT: "{{ template "harbor.database.port" . }}" - CLAIR_DB_USERNAME: "{{ template "harbor.database.username" . }}" - CLAIR_DB: "{{ template "harbor.database.clairDatabase" . }}" - CLAIR_URL: "http://{{ template "harbor.fullname" . }}-clair:6060" - UAA_ENDPOINT: "" - UAA_CLIENTID: "" - UAA_CLIENTSECRET: "" - UAA_VERIFY_CERT: "True" - REGISTRY_STORAGE_PROVIDER_NAME: "{{ .Values.registry.storage.type }}" - WITH_CHARTMUSEUM: "{{ .Values.chartmuseum.enabled }}" - CHART_REPOSITORY_URL: "http://{{ template "harbor.fullname" . }}-chartmuseum" \ No newline at end of file diff --git a/templates/adminserver/secret.yaml b/templates/adminserver/secret.yaml deleted file mode 100644 index fac8645..0000000 --- a/templates/adminserver/secret.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-adminserver" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-adminserver -type: Opaque -data: - secretKey: {{ .Values.secretKey | b64enc | quote }} - EMAIL_PWD: {{ .Values.email.password | b64enc | quote }} - HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} - POSTGRESQL_PASSWORD: {{ template "harbor.database.password" . }} - JOBSERVICE_SECRET: {{ .Values.jobservice.secret | b64enc | quote }} - UI_SECRET: {{ .Values.ui.secret | b64enc | quote }} -{{- if eq .Values.authenticationMode "ldap_auth" }} - LDAP_SEARCH_PWD: {{ .Values.ldap.searchPassword | b64enc | quote }} -{{- end }} -{{ if .Values.clair.enabled }} - CLAIR_DB_PASSWORD: {{ template "harbor.database.password" . }} -{{ end }} diff --git a/templates/adminserver/service.yaml b/templates/adminserver/service.yaml deleted file mode 100644 index 14fd00b..0000000 --- a/templates/adminserver/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: "{{ template "harbor.fullname" . }}-adminserver" - labels: -{{ include "harbor.labels" . | indent 4 }} -spec: - ports: - - name: http - port: 80 - targetPort: 8080 - selector: -{{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-adminserver \ No newline at end of file diff --git a/templates/adminserver/statefulset.yaml b/templates/adminserver/statefulset.yaml deleted file mode 100644 index e3cd3a2..0000000 --- a/templates/adminserver/statefulset.yaml +++ /dev/null @@ -1,94 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: "{{ template "harbor.fullname" . }}-adminserver" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-adminserver - version: {{ .Values.adminserver.image.tag }} -spec: - replicas: 1 - serviceName: "{{ template "harbor.fullname" . }}-adminserver" - selector: - matchLabels: -{{ include "harbor.matchLabels" . | indent 6 }} - app: harbor-adminserver - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-adminserver - version: {{ .Values.adminserver.image.tag }} - spec: - containers: - - name: adminserver - image: "{{ .Values.adminserver.image.repository }}:{{ .Values.adminserver.image.tag }}" - imagePullPolicy: "{{ .Values.adminserver.image.pullPolicy }}" - resources: -{{ toYaml .Values.adminserver.resources | indent 10 }} - envFrom: - - configMapRef: - name: "{{ template "harbor.fullname" . }}-adminserver" - - secretRef: - name: "{{ template "harbor.fullname" . }}-adminserver" - env: - - name: PORT - value: "8080" - - name: JSON_CFG_STORE_PATH - value: /etc/adminserver/config/config.json - - name: KEY_PATH - value: /etc/adminserver/key - ports: - - containerPort: 8080 - volumeMounts: - - name: data - mountPath: /etc/adminserver/config - - name: adminserver-key - mountPath: /etc/adminserver/key - subPath: key - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - {{- if not .Values.persistence.enabled }} - - name: data - hostPath: - path: /data/{{ .Release.Namespace }}/{{ .Release.Name }}/adminserver - {{- end }} - - name: adminserver-key - secret: - secretName: "{{ template "harbor.fullname" . }}-adminserver" - items: - - key: secretKey - path: key - {{- with .Values.adminserver.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.adminserver.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.adminserver.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - {{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [{{ .Values.adminserver.volumes.config.accessMode | quote }}] - {{- if .Values.adminserver.volumes.config.storageClass }} - {{- if (eq "-" .Values.adminserver.volumes.config.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.adminserver.volumes.config.storageClass }}" - {{- end }} - {{- end }} - resources: - requests: - storage: {{ .Values.adminserver.volumes.config.size | quote }} - {{- end -}} diff --git a/templates/chartmuseum/chartmuseum-cm.yaml b/templates/chartmuseum/chartmuseum-cm.yaml new file mode 100644 index 0000000..272c515 --- /dev/null +++ b/templates/chartmuseum/chartmuseum-cm.yaml @@ -0,0 +1,99 @@ +{{- if .Values.chartmuseum.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.chartmuseum" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + PORT: "9999" + CACHE: "redis" + CACHE_REDIS_ADDR: "{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}" + CACHE_REDIS_DB: "{{ template "harbor.redis.chartmuseumDatabaseIndex" . }}" + BASIC_AUTH_USER: "chart_controller" + DEPTH: "1" +{{- if eq .Values.logLevel "debug" }} + DEBUG: "true" +{{- else }} + DEBUG: "false" +{{- end }} + LOG_JSON: "true" + DISABLE_METRICS: "false" + DISABLE_API: "false" + DISABLE_STATEFILES: "false" + ALLOW_OVERWRITE: "true" + #CHART_URL: {{ .Values.externalURL }}/chartrepo + AUTH_ANONYMOUS_GET: "false" + TLS_CERT: + TLS_KEY: + CONTEXT_PATH: + INDEX_LIMIT: "0" + MAX_STORAGE_OBJECTS: "0" + MAX_UPLOAD_SIZE: "20971520" + CHART_POST_FORM_FIELD_NAME: "chart" + PROV_POST_FORM_FIELD_NAME: "prov" +{{- $storage := .Values.persistence.imageChartStorage }} +{{- $storageType := $storage.type }} +{{- if eq $storageType "filesystem" }} + STORAGE: "local" + STORAGE_LOCAL_ROOTDIR: "/chart_storage" +{{- else if eq $storageType "azure" }} + STORAGE: "microsoft" + STORAGE_MICROSOFT_CONTAINER: {{ $storage.azure.container }} + AZURE_STORAGE_ACCOUNT: {{ $storage.azure.accountname }} + STORAGE_MICROSOFT_PREFIX: "/azure/harbor/charts" +{{- else if eq $storageType "gcs" }} + STORAGE: "google" + STORAGE_GOOGLE_BUCKET: {{ $storage.gcs.bucket }} + GOOGLE_APPLICATION_CREDENTIALS: /etc/chartmuseum/gcs-key.json + {{- if $storage.gcs.rootdirectory }} + STORAGE_GOOGLE_PREFIX: {{ $storage.gcs.rootdirectory }} + {{- end }} +{{- else if eq $storageType "s3" }} + STORAGE: "amazon" + STORAGE_AMAZON_BUCKET: {{ $storage.s3.bucket }} + {{- if $storage.s3.rootdirectory }} + STORAGE_AMAZON_PREFIX: {{ $storage.s3.rootdirectory }} + {{- end }} + STORAGE_AMAZON_REGION: {{ $storage.s3.region }} + {{- if $storage.s3.regionendpoint }} + STORAGE_AMAZON_ENDPOINT: {{ $storage.s3.regionendpoint }} + {{- end }} + {{- if $storage.s3.accesskey }} + AWS_ACCESS_KEY_ID: {{ $storage.s3.accesskey }} + {{- end }} +{{- else if eq $storageType "swift" }} + STORAGE: "openstack" + STORAGE_OPENSTACK_CONTAINER: {{ $storage.swift.container }} + {{- if $storage.swift.secretkey }} + STORAGE_OPENSTACK_PREFIX: {{ $storage.swift.prefix }} + {{- end }} + {{- if $storage.swift.secretkey }} + STORAGE_OPENSTACK_REGION: {{ $storage.swift.region }} + {{- end }} + OS_AUTH_URL: {{ $storage.swift.authurl }} + OS_USERNAME: {{ $storage.swift.username }} + {{- if $storage.swift.secretkey }} + OS_PROJECT_ID: {{ $storage.swift.tenantid }} + {{- end }} + {{- if $storage.swift.secretkey }} + OS_PROJECT_NAME: {{ $storage.swift.tenant }} + {{- end }} + {{- if $storage.swift.secretkey }} + OS_DOMAIN_ID: {{ $storage.swift.domainid }} + {{- end }} + {{- if $storage.swift.secretkey }} + OS_DOMAIN_NAME: {{ $storage.swift.domain }} + {{- end }} +{{- else if eq $storageType "oss" }} + STORAGE: "alibaba" + STORAGE_ALIBABA_BUCKET: {{ $storage.oss.bucket }} + {{- if $storage.oss.secretkey }} + STORAGE_ALIBABA_PREFIX: {{ $storage.oss.rootdirectory }} + {{- end }} + {{- if $storage.oss.secretkey }} + STORAGE_ALIBABA_ENDPOINT: {{ $storage.oss.endpoint }} + {{- end }} + ALIBABA_CLOUD_ACCESS_KEY_ID: {{ $storage.oss.accesskeyid }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/chartmuseum/chartmuseum-dpl.yaml b/templates/chartmuseum/chartmuseum-dpl.yaml new file mode 100644 index 0000000..6957978 --- /dev/null +++ b/templates/chartmuseum/chartmuseum-dpl.yaml @@ -0,0 +1,85 @@ +{{- if .Values.chartmuseum.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.chartmuseum" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: chartmuseum +spec: + replicas: {{ .Values.chartmuseum.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: chartmuseum + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: chartmuseum + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/chartmuseum/chartmuseum-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/chartmuseum/chartmuseum-secret.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if .Values.chartmuseum.podAnnotations }} +{{ toYaml .Values.chartmuseum.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: chartmuseum + image: {{ .Values.chartmuseum.image.repository }}:{{ .Values.chartmuseum.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /health + port: 9999 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /health + port: 9999 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.chartmuseum.resources }} + resources: +{{ toYaml .Values.chartmuseum.resources | indent 10 }} +{{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.chartmuseum" . }}" + - secretRef: + name: "{{ template "harbor.chartmuseum" . }}" + env: + - name: BASIC_AUTH_PASS + valueFrom: + secretKeyRef: + name: {{ template "harbor.core" . }} + key: secret + ports: + - containerPort: 9999 + volumeMounts: + - name: chartmuseum-data + mountPath: /chart_storage + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: chartmuseum-data + hostPath: + path: /data/{{ .Release.Namespace }}/{{ .Release.Name }}/chartmuseum + {{- with .Values.chartmuseum.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.chartmuseum.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.chartmuseum.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} diff --git a/templates/chartmuseum/chartmuseum-secret.yaml b/templates/chartmuseum/chartmuseum-secret.yaml new file mode 100644 index 0000000..cc19867 --- /dev/null +++ b/templates/chartmuseum/chartmuseum-secret.yaml @@ -0,0 +1,26 @@ +{{- if .Values.chartmuseum.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.chartmuseum" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + CACHE_REDIS_PASSWORD: {{ include "harbor.redis.rawPassword" . | b64enc | quote }} +{{- $storage := .Values.persistence.imageChartStorage }} +{{- $storageType := $storage.type }} +{{- if eq $storageType "azure" }} + AZURE_STORAGE_ACCESS_KEY: {{ $storage.azure.accountkey | b64enc | quote }} +{{- else if eq $storageType "gcs" }} + # TODO support the keyfile of gcs +{{- else if eq $storageType "s3" }} + {{- if $storage.s3.secretkey }} + AWS_SECRET_ACCESS_KEY: {{ $storage.s3.secretkey | b64enc | quote }} + {{- end }} +{{- else if eq $storageType "swift" }} + OS_PASSWORD: {{ $storage.swift.password | b64enc | quote }} +{{- else if eq $storageType "oss" }} + ALIBABA_CLOUD_ACCESS_KEY_SECRET: {{ $storage.oss.accesskeysecret | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/chartmuseum/service.yaml b/templates/chartmuseum/chartmuseum-svc.yaml similarity index 64% rename from templates/chartmuseum/service.yaml rename to templates/chartmuseum/chartmuseum-svc.yaml index 1034fc1..49a3bb5 100644 --- a/templates/chartmuseum/service.yaml +++ b/templates/chartmuseum/chartmuseum-svc.yaml @@ -2,15 +2,14 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "harbor.fullname" . }}-chartmuseum" + name: "{{ template "harbor.chartmuseum" . }}" labels: {{ include "harbor.labels" . | indent 4 }} spec: ports: - - name: http - port: 80 + - port: 80 targetPort: 9999 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-chartmuseum + component: chartmuseum {{- end }} \ No newline at end of file diff --git a/templates/chartmuseum/configmap.yaml b/templates/chartmuseum/configmap.yaml deleted file mode 100644 index a6d2015..0000000 --- a/templates/chartmuseum/configmap.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.chartmuseum.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: "{{ template "harbor.fullname" . }}-chartmuseum" - labels: -{{ include "harbor.labels" . | indent 4 }} -data: - PORT: "9999" - CACHE: "redis" - CACHE_REDIS_ADDR: "{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}" - CACHE_REDIS_DB: "{{ template "harbor.redis.databaseIndex" }}" - BASIC_AUTH_USER: "chart_controller" - DEPTH: "1" - STORAGE: "local" - STORAGE_LOCAL_ROOTDIR: "/chart_storage" - DEBUG: "false" - LOG_JSON: "true" - DISABLE_METRICS: "false" - DISABLE_API: "false" - DISABLE_STATEFILES: "false" - ALLOW_OVERWRITE: "true" - CHART_URL: "" - AUTH_ANONYMOUS_GET: "false" - TLS_CERT: "" - TLS_KEY: "" - CONTEXT_PATH: "" - INDEX_LIMIT: "0" - MAX_STORAGE_OBJECTS: "0" - MAX_UPLOAD_SIZE: "20971520" - CHART_POST_FORM_FIELD_NAME: "chart" - PROV_POST_FORM_FIELD_NAME: "prov" -{{- end }} \ No newline at end of file diff --git a/templates/chartmuseum/secret.yaml b/templates/chartmuseum/secret.yaml deleted file mode 100644 index 8266171..0000000 --- a/templates/chartmuseum/secret.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.chartmuseum.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-chartmuseum" - labels: -{{ include "harbor.labels" . | indent 4 }} -type: Opaque -data: - CACHE_REDIS_PASSWORD: "{{ template "harbor.redis.password" }}" - BASIC_AUTH_PASS: {{ .Values.ui.secret | b64enc | quote }} -{{- end }} \ No newline at end of file diff --git a/templates/chartmuseum/statefulset.yaml b/templates/chartmuseum/statefulset.yaml deleted file mode 100644 index 5699109..0000000 --- a/templates/chartmuseum/statefulset.yaml +++ /dev/null @@ -1,74 +0,0 @@ -{{- if .Values.chartmuseum.enabled }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: "{{ template "harbor.fullname" . }}-chartmuseum" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-chartmuseum - version: {{ .Values.chartmuseum.image.tag }} -spec: - replicas: 1 - serviceName: "{{ template "harbor.fullname" . }}-chartmuseum" - selector: - matchLabels: -{{ include "harbor.matchLabels" . | indent 6 }} - app: harbor-chartmuseum - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-chartmuseum - version: {{ .Values.chartmuseum.image.tag }} - spec: - containers: - - name: chartmuseum - image: {{ .Values.chartmuseum.image.repository }}:{{ .Values.chartmuseum.image.tag }} - imagePullPolicy: {{ .Values.chartmuseum.image.pullPolicy }} - resources: -{{ toYaml .Values.chartmuseum.resources | indent 10 }} - envFrom: - - configMapRef: - name: "{{ template "harbor.fullname" . }}-chartmuseum" - - secretRef: - name: "{{ template "harbor.fullname" . }}-chartmuseum" - ports: - - containerPort: 9999 - # TODO: update it after moving the storage out of registry scope - {{- if (.Values.persistence.enabled) and eq .Values.registry.storage.type "filesystem" }} - volumeMounts: - - name: data - mountPath: /chart_storage - {{- end }} - {{- with .Values.chartmuseum.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.chartmuseum.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.chartmuseum.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - {{- if (.Values.persistence.enabled) and eq .Values.registry.storage.type "filesystem" }} - volumeClaimTemplates: - - metadata: - name: data - labels: -{{ include "harbor.labels" . | indent 8 }} - spec: - accessModes: [{{ .Values.chartmuseum.volumes.data.accessMode | quote }}] - {{- if .Values.chartmuseum.volumes.data.storageClass }} - {{- if (eq "-" .Values.chartmuseum.volumes.data.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.chartmuseum.volumes.data.storageClass }}" - {{- end }} - {{- end }} - resources: - requests: - storage: {{ .Values.chartmuseum.volumes.data.size | quote }} - {{- end -}} -{{- end }} \ No newline at end of file diff --git a/templates/clair/configmap.yaml b/templates/clair/clair-cm.yaml similarity index 78% rename from templates/clair/configmap.yaml rename to templates/clair/clair-cm.yaml index f707b28..f2ada30 100644 --- a/templates/clair/configmap.yaml +++ b/templates/clair/clair-cm.yaml @@ -2,10 +2,10 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ template "harbor.fullname" . }}-clair + name: {{ template "harbor.clair" . }} labels: {{ include "harbor.labels" . | indent 4 }} - app: harbor-clair + component: clair data: config.yaml: | clair: @@ -25,11 +25,11 @@ data: # Deadline before an API request will respond with a 503 timeout: 300s updater: - interval: 12h + interval: {{ .Values.clair.updatersInterval }}h notifier: attempts: 3 renotifyinterval: 2h http: - endpoint: "http://{{ template "harbor.fullname" . }}-ui/service/notifications/clair" + endpoint: "http://{{ template "harbor.core" . }}/service/notifications/clair" {{ end }} diff --git a/templates/clair/clair-dpl.yaml b/templates/clair/clair-dpl.yaml new file mode 100644 index 0000000..4893477 --- /dev/null +++ b/templates/clair/clair-dpl.yaml @@ -0,0 +1,88 @@ +{{ if .Values.clair.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.clair" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: clair +spec: + replicas: {{ .Values.clair.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: clair + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: clair + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/clair/clair-cm.yaml") . | sha256sum }} +{{- if .Values.clair.podAnnotations }} +{{ toYaml .Values.clair.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: clair + image: {{ .Values.clair.image.repository }}:{{ .Values.clair.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /health + port: 6061 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /health + port: 6061 + initialDelaySeconds: 30 + periodSeconds: 10 + args: ["-log-level", "{{ .Values.logLevel }}"] + env: + {{- if .Values.clair.httpProxy }} + - name: HTTP_PROXY + value: {{ .Values.clair.httpProxy }} + {{- end }} + {{- if .Values.clair.httpsProxy }} + - name: HTTPS_PROXY + value: {{ .Values.clair.httpsProxy }} + {{- end }} + - name: NO_PROXY + value: "{{ template "harbor.registry" . }},{{ template "harbor.core" . }}" +{{- if .Values.clair.resources }} + resources: +{{ toYaml .Values.clair.resources | indent 10 }} +{{- end }} + ports: + - containerPort: 6060 + volumeMounts: + - name: clair-config + mountPath: /etc/clair/config.yaml + subPath: config.yaml + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: clair-config + configMap: + name: "{{ template "harbor.clair" . }}" + items: + - key: config.yaml + path: config.yaml + {{- with .Values.clair.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.clair.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.clair.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{ end }} diff --git a/templates/clair/clair-svc.yaml b/templates/clair/clair-svc.yaml new file mode 100644 index 0000000..c4923bf --- /dev/null +++ b/templates/clair/clair-svc.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clair.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.clair" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: clair + port: 6060 + - name: health + port: 6061 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: clair +{{ end }} diff --git a/templates/clair/deployment.yaml b/templates/clair/deployment.yaml deleted file mode 100644 index 973e278..0000000 --- a/templates/clair/deployment.yaml +++ /dev/null @@ -1,60 +0,0 @@ -{{ if .Values.clair.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "harbor.fullname" . }}-clair - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-clair - version: {{ .Values.clair.image.tag }} -spec: - replicas: 1 - selector: - matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-clair - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-clair - version: {{ .Values.clair.image.tag }} - spec: - containers: - - name: clair - image: {{ .Values.clair.image.repository }}:{{ .Values.clair.image.tag }} - imagePullPolicy: {{ .Values.clair.image.pullPolicy }} - args: ["-insecure-tls", "-config", "/etc/clair/config.yaml"] - resources: -{{ toYaml .Values.clair.resources | indent 10 }} - ports: - - containerPort: 6060 - volumeMounts: - - name: clair-config - mountPath: /etc/clair/config.yaml - subPath: config.yaml - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - - name: clair-config - configMap: - name: "{{ template "harbor.fullname" . }}-clair" - items: - - key: config.yaml - path: config.yaml - {{- with .Values.clair.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.clair.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.clair.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} -{{ end }} diff --git a/templates/clair/service.yaml b/templates/clair/service.yaml deleted file mode 100644 index fb9adf5..0000000 --- a/templates/clair/service.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{ if .Values.clair.enabled }} -# clair host isn't configurable yet. this creates a service -# to get it working for now. -# see https://github.com/vmware/harbor/issues/3250 -apiVersion: v1 -kind: Service -metadata: - name: "{{ template "harbor.fullname" . }}-clair" - labels: -{{ include "harbor.labels" . | indent 4 }} -spec: - ports: - - name: http - port: 6060 - selector: -{{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-clair -{{ end }} diff --git a/templates/common/certificate-secret.yaml b/templates/common/certificate-secret.yaml new file mode 100644 index 0000000..a93dd2f --- /dev/null +++ b/templates/common/certificate-secret.yaml @@ -0,0 +1,23 @@ +{{- if eq (include "harbor.autoGenCert" .) "true" }} +{{- $cn := (required "The \"expose.tls.commonName\" is required!" (include "harbor.common-name" .)) }} +{{- $ca := genCA "harbor-ca" 365 }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.certificate" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + {{- if regexMatch `^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` $cn }} + {{- $cert := genSignedCert $cn (list $cn) nil 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- else }} + {{- $cert := genSignedCert $cn nil (list $cn) 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/core/core-cm.yaml b/templates/core/core-cm.yaml new file mode 100644 index 0000000..e7508bb --- /dev/null +++ b/templates/core/core-cm.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + app.conf: |+ + appname = Harbor + runmode = dev + enablegzip = true + + [dev] + httpport = 8080 + DATABASE_TYPE: "postgresql" + POSTGRESQL_HOST: "{{ template "harbor.database.host" . }}" + POSTGRESQL_PORT: "{{ template "harbor.database.port" . }}" + POSTGRESQL_USERNAME: "{{ template "harbor.database.username" . }}" + POSTGRESQL_DATABASE: "{{ template "harbor.database.coreDatabase" . }}" + POSTGRESQL_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + EXT_ENDPOINT: "{{ .Values.externalURL }}" + CORE_URL: "http://{{ template "harbor.core" . }}" + JOBSERVICE_URL: "http://{{ template "harbor.fullname" . }}-jobservice" + REGISTRY_URL: "http://{{ template "harbor.registry" . }}:5000" + TOKEN_SERVICE_URL: "http://{{ template "harbor.core" . }}/service/token" + WITH_NOTARY: "{{ .Values.notary.enabled }}" + NOTARY_URL: "http://{{ template "harbor.notary-server" . }}:4443" + CFG_EXPIRATION: "5" + WITH_CLAIR: "{{ .Values.clair.enabled }}" + CLAIR_DB_HOST: "{{ template "harbor.database.host" . }}" + CLAIR_DB_PORT: "{{ template "harbor.database.port" . }}" + CLAIR_DB_USERNAME: "{{ template "harbor.database.username" . }}" + CLAIR_DB: "{{ template "harbor.database.clairDatabase" . }}" + CLAIR_DB_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + CLAIR_URL: "http://{{ template "harbor.fullname" . }}-clair:6060" + REGISTRY_STORAGE_PROVIDER_NAME: "{{ .Values.persistence.imageChartStorage.type }}" + WITH_CHARTMUSEUM: "{{ .Values.chartmuseum.enabled }}" + CHART_REPOSITORY_URL: "http://{{ template "harbor.chartmuseum" . }}" + LOG_LEVEL: "{{ .Values.logLevel }}" + CONFIG_PATH: "/etc/core/app.conf" + SYNC_REGISTRY: "false" + CHART_CACHE_DRIVER: "redis" + _REDIS_URL: "{{ template "harbor.redisForCore" . }}" + _REDIS_URL_REG: "{{ template "harbor.redisForGC" . }}" + PORTAL_URL: "http://{{ template "harbor.portal" . }}" + REGISTRYCTL_URL: "http://{{ template "harbor.registry" . }}:8080" + CLAIR_HEALTH_CHECK_SERVER_URL: "http://{{ template "harbor.clair" . }}:6061" \ No newline at end of file diff --git a/templates/core/core-dpl.yaml b/templates/core/core-dpl.yaml new file mode 100644 index 0000000..5d4d8d0 --- /dev/null +++ b/templates/core/core-dpl.yaml @@ -0,0 +1,125 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: core +spec: + replicas: {{ .Values.core.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: core + template: + metadata: + labels: +{{ include "harbor.matchLabels" . | indent 8 }} + component: core + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/core/core-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} +{{- if .Values.core.podAnnotations }} +{{ toYaml .Values.core.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: core + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/ping + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/ping + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ template "harbor.core" . }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: "{{ template "harbor.jobservice" . }}" + key: secret + ports: + - containerPort: 8080 + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + - name: secret-key + mountPath: /etc/core/key + subPath: key + - name: token-service-private-key + mountPath: /etc/core/private_key.pem + subPath: tokenServicePrivateKey + - name: etc-localtime + mountPath: /etc/localtime + {{- if .Values.expose.tls.enabled }} + - name: ca-download + mountPath: /etc/core/ca/ca.crt + subPath: ca.crt + {{- end }} + - name: psc + mountPath: /etc/core/token +{{- if .Values.core.resources }} + resources: +{{ toYaml .Values.core.resources | indent 10 }} +{{- end }} + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: config + configMap: + name: {{ template "harbor.core" . }} + - name: secret-key + secret: + secretName: {{ template "harbor.core" . }} + items: + - key: secretKey + path: key + - name: token-service-private-key + secret: + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: ca-download + secret: + secretName: "{{ template "harbor.certificate-secret" . }}" + items: + - key: ca.crt + path: ca.crt + {{- end }} + - name: psc + emptyDir: {} + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} \ No newline at end of file diff --git a/templates/core/core-secret.yaml b/templates/core/core-secret.yaml new file mode 100644 index 0000000..860f433 --- /dev/null +++ b/templates/core/core-secret.yaml @@ -0,0 +1,20 @@ +{{- $cert := genSelfSignedCert "harbor" nil nil 365 }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + secretKey: {{ .Values.secretKey | b64enc | quote }} + secret: {{ .Values.core.secret | default (randAlphaNum 16) | b64enc | quote }} +{{- if not .Values.core.secretName }} + tokenServiceRootCertBundle: {{ $cert.Cert | b64enc | quote }} + tokenServicePrivateKey: {{ $cert.Key | b64enc | quote }} +{{- end }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} + POSTGRESQL_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{ if .Values.clair.enabled }} + CLAIR_DB_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{ end }} diff --git a/templates/jobservice/service.yaml b/templates/core/core-svc.yaml similarity index 54% rename from templates/jobservice/service.yaml rename to templates/core/core-svc.yaml index 99cc683..84b68f6 100644 --- a/templates/jobservice/service.yaml +++ b/templates/core/core-svc.yaml @@ -1,14 +1,16 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "harbor.fullname" . }}-jobservice" + name: {{ template "harbor.core" . }} labels: {{ include "harbor.labels" . | indent 4 }} spec: +{{- if (eq .Values.expose.ingress.controller "gce") }} + type: NodePort +{{- end }} ports: - - name: http - port: 80 + - port: 80 targetPort: 8080 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-jobservice + component: core diff --git a/templates/database/secret.yaml b/templates/database/database-secret.yaml similarity index 58% rename from templates/database/secret.yaml rename to templates/database/database-secret.yaml index 0e2e2fe..864aff4 100644 --- a/templates/database/secret.yaml +++ b/templates/database/database-secret.yaml @@ -2,10 +2,10 @@ apiVersion: v1 kind: Secret metadata: - name: "{{ template "harbor.fullname" . }}-database" + name: "{{ template "harbor.database" . }}" labels: {{ include "harbor.labels" . | indent 4 }} type: Opaque data: - POSTGRES_PASSWORD: {{ template "harbor.database.password" . }} + POSTGRES_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} {{- end -}} diff --git a/templates/database/database-ss.yaml b/templates/database/database-ss.yaml new file mode 100644 index 0000000..0565b6a --- /dev/null +++ b/templates/database/database-ss.yaml @@ -0,0 +1,83 @@ +{{- if eq .Values.database.type "internal" -}} +{{- $database := .Values.persistence.persistentVolumeClaim.database -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: database +spec: + replicas: 1 + serviceName: "{{ template "harbor.database" . }}" + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: database + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: database + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/database/database-secret.yaml") . | sha256sum }} +{{- if .Values.database.podAnnotations }} +{{ toYaml .Values.database.podAnnotations | indent 8 }} +{{- end }} + spec: + initContainers: + - name: "remove-lost-found" + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: ["rm", "-Rf", "/var/lib/postgresql/data/lost+found"] + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + containers: + - name: database + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.database.internal.resources }} + resources: +{{ toYaml .Values.database.internal.resources | indent 10 }} +{{- end }} + envFrom: + - secretRef: + name: "{{ template "harbor.database" . }}" + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: "database-data" + hostPath: + path: /data/{{ .Release.Namespace }}/{{ .Release.Name }}/database + {{- with .Values.database.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- end -}} diff --git a/templates/database/service.yaml b/templates/database/database-svc.yaml similarity index 62% rename from templates/database/service.yaml rename to templates/database/database-svc.yaml index 27eb417..6475048 100644 --- a/templates/database/service.yaml +++ b/templates/database/database-svc.yaml @@ -2,14 +2,13 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "harbor.fullname" . }}-database" + name: "{{ template "harbor.database" . }}" labels: {{ include "harbor.labels" . | indent 4 }} spec: ports: - - name: postgre - port: 5432 + - port: 5432 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-database + component: database {{- end -}} \ No newline at end of file diff --git a/templates/database/statefulset.yaml b/templates/database/statefulset.yaml deleted file mode 100644 index 9eae891..0000000 --- a/templates/database/statefulset.yaml +++ /dev/null @@ -1,88 +0,0 @@ -{{- if eq .Values.database.type "internal" -}} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: "{{ template "harbor.fullname" . }}-database" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-database - version: {{ .Values.database.internal.image.tag }} -spec: - replicas: 1 - serviceName: "{{ template "harbor.fullname" . }}-database" - selector: - matchLabels: -{{ include "harbor.matchLabels" . | indent 6 }} - app: harbor-database - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-database - version: {{ .Values.database.internal.image.tag }} - spec: - initContainers: - - name: "remove-lost-found" - image: "{{ .Values.busybox.image.repository }}:{{ .Values.busybox.image.tag }}" - command: - - /bin/sh - - "-c" - - "rm -Rf /var/lib/postgresql/data/lost+found" - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - containers: - - name: database - image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} - imagePullPolicy: {{ .Values.database.internal.image.pullPolicy }} - resources: -{{ toYaml .Values.database.internal.resources | indent 10 }} - envFrom: - - secretRef: - name: "{{ template "harbor.fullname" . }}-database" - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - {{- if not .Values.persistence.enabled }} - - name: data - hostPath: - path: /data/{{ .Release.Namespace }}/{{ .Release.Name }}/database - {{- end -}} - {{- with .Values.database.internal.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.database.internal.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.database.internal.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - {{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: "data" - labels: -{{ include "harbor.labels" . | indent 8 }} - spec: - accessModes: [{{ .Values.database.internal.volumes.data.accessMode | quote }}] - {{- if .Values.database.internal.volumes.data.storageClass }} - {{- if (eq "-" .Values.database.internal.volumes.data.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.database.internal.volumes.data.storageClass }}" - {{- end }} - {{- end }} - resources: - requests: - storage: {{ .Values.database.internal.volumes.data.size | quote }} - {{- end -}} - {{- end -}} diff --git a/templates/ingress/ingress.yaml b/templates/ingress/ingress.yaml index 3deffa4..d0e891d 100644 --- a/templates/ingress/ingress.yaml +++ b/templates/ingress/ingress.yaml @@ -1,37 +1,83 @@ -{{ if .Values.ingress.enabled }} +{{- if eq .Values.expose.type "ingress" }} +{{- $ingress := .Values.expose.ingress -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: - name: "{{ template "harbor.fullname" . }}" + name: "{{ template "harbor.ingress.core" . }}" labels: {{ include "harbor.labels" . | indent 4 }} annotations: -{{ toYaml .Values.ingress.annotations | indent 4 }} +{{ toYaml $ingress.annotations | indent 4 }} spec: -# {{ if eq .Values.externalProtocol "https" }} -# tls: -# - hosts: -# - "{{ .Values.externalDomain }}" -# - "{{ template "harbor.notaryFQDN" . }}" -# {{ if eq .Values.ingress.tls.secretName "" }} -# secretName: "{{ template "harbor.fullname" . }}-ingress" -# {{ else }} -# secretName: {{ .Values.ingress.tls.secretName }} -# {{ end }} -# {{ end }} + {{- if .Values.expose.tls.enabled }} + tls: + - secretName: {{ template "harbor.certificate-secret" . }} + {{- if $ingress.host }} + hosts: + - {{ $ingress.host }} + {{- end }} + {{- end }} +{{- if eq .Values.expose.ingress.controller "gce" }} rules: - - host: "{{ .Values.externalDomain }}" - http: + - http: paths: - - path: / + - path: /* + backend: + serviceName: {{ template "harbor.portal" . }} + servicePort: 80 + - path: /api/* + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /service/* + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /v2/* + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /chartrepo/* backend: - serviceName: {{ template "harbor.fullname" . }}-ui + serviceName: {{ template "harbor.core" . }} servicePort: 80 - - host: "{{ template "harbor.notaryFQDN" . }}" - http: + - path: /c/* + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + {{- if $ingress.host }} + host: {{ $ingress.host }} + {{- end }} +{{- else }} + rules: + - http: paths: - path: / backend: - serviceName: {{ template "harbor.notaryServiceName" . }} - servicePort: 4443 -{{ end }} \ No newline at end of file + serviceName: {{ template "harbor.portal" . }} + servicePort: 80 + - path: /api/ + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /service/ + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /v2/ + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /chartrepo/ + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + - path: /c/ + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: 80 + {{- if $ingress.host }} + host: {{ $ingress.host }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/ingress/notary-ingress.yaml b/templates/ingress/notary-ingress.yaml new file mode 100644 index 0000000..17a436d --- /dev/null +++ b/templates/ingress/notary-ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.notary.enabled }} +{{- if eq .Values.expose.type "ingress" }} +{{- $ingress := .Values.expose.ingress -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: "{{ template "harbor.ingress.notary" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + annotations: +{{ toYaml $ingress.annotations | indent 4 }} + {{ printf "%s: /" $ingress.rewriteAnnotation }} +spec: + {{- if .Values.expose.tls.enabled }} + tls: + - secretName: {{ template "harbor.certificate-secret" . }} + {{- if $ingress.host }} + hosts: + - {{ $ingress.host }} + {{- end }} + {{- end }} + rules: + - http: + paths: + - path: /notary/ + backend: + serviceName: {{ template "harbor.notary-server" . }} + servicePort: 4443 + {{- if $ingress.host }} + host: {{ $ingress.host }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/ingress/secret.yaml b/templates/ingress/secret.yaml deleted file mode 100644 index 33d13ee..0000000 --- a/templates/ingress/secret.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{ if eq .Values.externalProtocol "https" }} -{{ if .Values.ingress.enabled }} -{{ if eq .Values.ingress.tls.secretName "" }} -{{ $ca := genCA "harbor-ca" 3650 }} -{{ $cert := genSignedCert (include "harbor.certCommonName" .) nil nil 3650 $ca }} -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-ingress" - labels: -{{ include "harbor.labels" . | indent 4 }} -type: kubernetes.io/tls -data: - tls.crt: {{ .Values.tlsCrt | default $cert.Cert | b64enc | quote }} - tls.key: {{ .Values.tlsKey | default $cert.Key | b64enc | quote }} - ca.crt: {{ .Values.caCrt | default $ca.Cert | b64enc | quote }} -{{ end }} -{{ end }} -{{ end }} \ No newline at end of file diff --git a/templates/istio/notary.gateway.yaml b/templates/istio/notary.gateway.yaml deleted file mode 100644 index 73bae82..0000000 --- a/templates/istio/notary.gateway.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{ if .Values.istio.enabled }} -apiVersion: networking.istio.io/v1alpha3 -kind: Gateway -metadata: - name: {{ template "harbor.fullname" . }}-notary -spec: - selector: - istio: ingressgateway # use istio default controller - servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - "{{ template "harbor.notaryFQDN" . }}" ---- -apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: {{ template "harbor.fullname" . }}-notary -spec: - hosts: - - "{{ template "harbor.notaryFQDN" . }}" - gateways: - - {{ template "harbor.fullname" . }}-notary - http: - - route: - - destination: - host: {{ template "harbor.notaryServiceName" . }} - port: - number: 4443 -{{ end }} diff --git a/templates/istio/ui.gateway.yaml b/templates/istio/ui.gateway.yaml deleted file mode 100644 index 31be8f5..0000000 --- a/templates/istio/ui.gateway.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{ if .Values.istio.enabled }} -apiVersion: networking.istio.io/v1alpha3 -kind: Gateway -metadata: - name: {{ template "harbor.fullname" . }}-ui -spec: - selector: - istio: ingressgateway # use istio default controller - servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - "{{ .Values.externalDomain }}" ---- -apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: {{ template "harbor.fullname" . }}-ui -spec: - hosts: - - "{{ .Values.externalDomain }}" - gateways: - - {{ template "harbor.fullname" . }}-ui - http: - - route: - - destination: - host: {{ template "harbor.fullname" . }}-ui - port: - number: 80 -{{ end }} diff --git a/templates/jobservice/configmap.yaml b/templates/jobservice/configmap.yaml deleted file mode 100644 index b52c03f..0000000 --- a/templates/jobservice/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "{{ template "harbor.fullname" . }}-jobservice" - labels: -{{ include "harbor.labels" . | indent 4 }} -data: - config.yml: |+ - protocol: "http" - port: 8080 - worker_pool: - workers: {{ .Values.jobservice.maxWorkers }} - backend: "redis" - redis_pool: - redis_url: "{{ template "harbor.redisForJobservice" . }}" - namespace: "harbor_job_service_namespace" - logger: - path: "/var/log/jobs" - level: "INFO" - archive_period: 14 #days - admin_server: "http://{{ template "harbor.fullname" . }}-adminserver" diff --git a/templates/jobservice/deployment.yaml b/templates/jobservice/deployment.yaml deleted file mode 100644 index ee27e26..0000000 --- a/templates/jobservice/deployment.yaml +++ /dev/null @@ -1,66 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ template "harbor.fullname" . }}-jobservice" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-jobservice - version: {{ .Values.jobservice.image.tag }} -spec: - replicas: 1 - selector: - matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-jobservice - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-jobservice - version: {{ .Values.jobservice.image.tag }} - spec: - containers: - - name: jobservice - image: {{ .Values.jobservice.image.repository }}:{{ .Values.jobservice.image.tag }} - imagePullPolicy: {{ .Values.jobservice.image.pullPolicy }} - resources: -{{ toYaml .Values.jobservice.resources | indent 10 }} - envFrom: - - secretRef: - name: "{{ template "harbor.fullname" . }}-jobservice" - env: - - name: LOG_LEVEL - value: debug - - name: GODEBUG - value: netdns=cgo - ports: - - containerPort: 8080 - volumeMounts: - - name: jobservice-config - mountPath: /etc/jobservice/config.yml - subPath: config.yml - - name: job-logs - mountPath: /var/log/jobs - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - - name: jobservice-config - configMap: - name: "{{ template "harbor.fullname" . }}-jobservice" - - name: job-logs - emptyDir: {} - {{- with .Values.jobservice.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.jobservice.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.jobservice.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} diff --git a/templates/jobservice/jobservice-cm.yaml b/templates/jobservice/jobservice-cm.yaml new file mode 100644 index 0000000..2faa9cc --- /dev/null +++ b/templates/jobservice/jobservice-cm.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + protocol: "http" + port: 8080 + worker_pool: + workers: {{ .Values.jobservice.maxJobWorkers }} + backend: "redis" + redis_pool: + redis_url: "{{ template "harbor.redisForJobservice" . }}" + namespace: "harbor_job_service_namespace" + job_loggers: + {{- if eq .Values.jobservice.jobLogger "file" }} + - name: "FILE" + level: {{ .Values.logLevel | upper }} + settings: # Customized settings of logger + base_dir: "/var/log/jobs" + sweeper: + duration: 14 #days + settings: # Customized settings of sweeper + work_dir: "/var/log/jobs" + {{- else if eq .Values.jobservice.jobLogger "database" }} + - name: "DB" + level: {{ .Values.logLevel | upper }} + sweeper: + duration: 14 #days + {{- else }} + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + {{- end }} + #Loggers for the job service + loggers: + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} \ No newline at end of file diff --git a/templates/jobservice/jobservice-dpl.yaml b/templates/jobservice/jobservice-dpl.yaml new file mode 100644 index 0000000..58d492a --- /dev/null +++ b/templates/jobservice/jobservice-dpl.yaml @@ -0,0 +1,94 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice +spec: + replicas: {{ .Values.jobservice.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: jobservice + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: jobservice + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if .Values.jobservice.podAnnotations }} +{{ toYaml .Values.jobservice.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: jobservice + image: {{ .Values.jobservice.image.repository }}:{{ .Values.jobservice.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/v1/stats + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v1/stats + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 +{{- if .Values.jobservice.resources }} + resources: +{{ toYaml .Values.jobservice.resources | indent 10 }} +{{- end }} + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ template "harbor.core" . }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: "{{ template "harbor.jobservice" . }}" + key: secret + - name: CORE_URL + value: "http://{{ template "harbor.core" . }}" + - name: REGISTRY_CONTROLLER_URL + value: "http://{{ template "harbor.registry" . }}:8080" + - name: LOG_LEVEL + value: debug + ports: + - containerPort: 8080 + volumeMounts: + - name: jobservice-config + mountPath: /etc/jobservice/config.yml + subPath: config.yml + - name: job-logs + mountPath: /var/log/jobs + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: jobservice-config + configMap: + name: "{{ template "harbor.jobservice" . }}" + - name: job-logs + emptyDir: {} + {{- with .Values.jobservice.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/templates/jobservice/jobservice-secrets.yaml b/templates/jobservice/jobservice-secrets.yaml new file mode 100644 index 0000000..e08f7ce --- /dev/null +++ b/templates/jobservice/jobservice-secrets.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + secret: {{ .Values.jobservice.secret | default (randAlphaNum 16) | b64enc | quote }} diff --git a/templates/ui/service.yaml b/templates/jobservice/jobservice-svc.yaml similarity index 65% rename from templates/ui/service.yaml rename to templates/jobservice/jobservice-svc.yaml index fbd75ee..2b5d47f 100644 --- a/templates/ui/service.yaml +++ b/templates/jobservice/jobservice-svc.yaml @@ -1,14 +1,13 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "harbor.fullname" . }}-ui" + name: "{{ template "harbor.jobservice" . }}" labels: {{ include "harbor.labels" . | indent 4 }} spec: ports: - - name: http - port: 80 + - port: 80 targetPort: 8080 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-ui + component: jobservice diff --git a/templates/jobservice/secret.yaml b/templates/jobservice/secret.yaml deleted file mode 100644 index 6426480..0000000 --- a/templates/jobservice/secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-jobservice" - labels: -{{ include "harbor.labels" . | indent 4 }} -type: Opaque -data: - secretKey: {{ .Values.secretKey | b64enc | quote }} - JOBSERVICE_SECRET: {{ .Values.jobservice.secret | b64enc | quote }} - UI_SECRET: {{ .Values.ui.secret | b64enc | quote }} \ No newline at end of file diff --git a/templates/nginx/configmap-http.yaml b/templates/nginx/configmap-http.yaml new file mode 100644 index 0000000..2cd02fa --- /dev/null +++ b/templates/nginx/configmap-http.yaml @@ -0,0 +1,132 @@ +{{- if and (ne .Values.expose.type "ingress") (not .Values.expose.tls.enabled) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + + events { + worker_connections 1024; + use epoll; + multi_accept on; + } + + http { + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server {{ template "harbor.core" . }}; + } + + upstream portal { + server {{ template "harbor.portal" . }}; + } + + log_format timed_combined '$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + server { + listen 80; + server_tokens off; + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + location / { + proxy_pass http://portal/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass http://core/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass http://core/chartrepo/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass http://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass http://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/ { + proxy_pass http://core/service/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + } +{{- end }} + \ No newline at end of file diff --git a/templates/nginx/configmap-https.yaml b/templates/nginx/configmap-https.yaml new file mode 100644 index 0000000..e962eb2 --- /dev/null +++ b/templates/nginx/configmap-https.yaml @@ -0,0 +1,175 @@ +{{- if and (ne .Values.expose.type "ingress") .Values.expose.tls.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + + events { + worker_connections 1024; + use epoll; + multi_accept on; + } + + http { + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server {{ template "harbor.core" . }}; + } + + upstream portal { + server {{ template "harbor.portal" . }}; + } + + {{- if .Values.notary.enabled }} + upstream notary-server { + server {{ template "harbor.notary-server" . }}:4443; + } + {{- end }} + + log_format timed_combined 'remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + server { + listen 443 ssl; + # server_name harbordomain.com; + server_tokens off; + # SSL + ssl_certificate /etc/nginx/cert/tls.crt; + ssl_certificate_key /etc/nginx/cert/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.1 TLSv1.2; + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + location / { + proxy_pass http://portal/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + # Add Secure flag when serving HTTPS + proxy_cookie_path / "/; secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass http://core/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass http://core/chartrepo/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass http://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass http://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/ { + proxy_pass http://core/service/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + {{- if .Values.notary.enabled }} + location /notary/ { + proxy_pass http://notary-server; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + + rewrite /notary/(.*) /$1 break; + } + {{- end }} + } + server { + listen 80; + #server_name harbordomain.com; + return 301 https://$host$request_uri; + } + } +{{- end }} \ No newline at end of file diff --git a/templates/nginx/deployment.yaml b/templates/nginx/deployment.yaml new file mode 100644 index 0000000..f8cd6ff --- /dev/null +++ b/templates/nginx/deployment.yaml @@ -0,0 +1,85 @@ +{{- if ne .Values.expose.type "ingress" }} +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: nginx +spec: + replicas: 1 + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: nginx + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: nginx + annotations: + {{- if not .Values.expose.tls.enabled }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-http.yaml") . | sha256sum }} + {{- else }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-https.yaml") . | sha256sum }} + {{- end }} + {{- if eq (include "harbor.autoGenCert" .) "true" }} + checksum/secret: {{ include (print $.Template.BasePath "/common/certificate-secret.yaml") . | sha256sum }} + {{- end }} +{{- if .Values.nginx.podAnnotations }} +{{ toYaml .Values.nginx.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: nginx + image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.nginx.resources }} + resources: +{{ toYaml .Values.nginx.resources | indent 10 }} +{{- end }} + ports: + - containerPort: 80 + - containerPort: 443 + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.expose.tls.enabled }} + - name: certificate + mountPath: /etc/nginx/cert + {{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.nginx" . }} + {{- if .Values.expose.tls.enabled }} + - name: certificate + secret: + secretName: {{ template "harbor.certificate-secret" . }} + {{- end }} + {{- with .Values.nginx.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/nginx/service.yaml b/templates/nginx/service.yaml new file mode 100644 index 0000000..d919d78 --- /dev/null +++ b/templates/nginx/service.yaml @@ -0,0 +1,63 @@ +{{- if ne .Values.expose.type "ingress" }} +apiVersion: v1 +kind: Service +metadata: +{{- if eq .Values.expose.type "clusterIP" }} +{{- $clusterIP := .Values.expose.clusterIP }} + name: {{ $clusterIP.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: {{ $clusterIP.ports.http }} + targetPort: 80 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $clusterIP.ports.https }} + targetPort: 443 + {{- end }} +{{- else if eq .Values.expose.type "nodePort" }} +{{- $nodePort := .Values.expose.nodePort }} + name: {{ $nodePort.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + type: NodePort + ports: + - name: http + port: {{ $nodePort.ports.http.port }} + targetPort: 80 + {{- if $nodePort.ports.http.nodePort }} + nodePort: {{ $nodePort.ports.http.nodePort }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $nodePort.ports.https.port }} + targetPort: 443 + {{- if $nodePort.ports.https.nodePort }} + nodePort: {{ $nodePort.ports.https.nodePort }} + {{- end }} + {{- end }} +{{- else if eq .Values.expose.type "loadBalancer" }} +{{- $loadBalancer := .Values.expose.loadBalancer }} + name: {{ $loadBalancer.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + type: LoadBalancer + ports: + - name: http + port: {{ $loadBalancer.ports.http }} + targetPort: 80 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $loadBalancer.ports.https }} + targetPort: 443 + {{- end }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: nginx +{{- end }} \ No newline at end of file diff --git a/templates/notary/configmap.yaml b/templates/notary/notary-cm.yaml similarity index 58% rename from templates/notary/configmap.yaml rename to templates/notary/notary-cm.yaml index c2b35d0..4ba8a3b 100644 --- a/templates/notary/configmap.yaml +++ b/templates/notary/notary-cm.yaml @@ -2,19 +2,21 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ template "harbor.fullname" . }}-notary + name: {{ template "harbor.notary-server" . }} labels: {{ include "harbor.labels" . | indent 4 }} - app: harbor-notary + component: notary data: - {{ $ca := genCA "harbor-notary-ca" 3650 }} - {{ $cert := genSignedCert (printf "%s-notary-signer" (include "harbor.fullname" .)) nil nil 3650 $ca }} + {{ $ca := genCA "harbor-notary-ca" 365 }} + {{ $cert := genSignedCert (include "harbor.notary-signer" .) nil nil 365 $ca }} + {{- if not .Values.notary.secretName }} notary-signer-ca.crt: | -{{ .Values.notary.signer.caCrt | default $ca.Cert | indent 4 }} +{{ $ca.Cert | indent 4 }} notary-signer.crt: | -{{ .Values.notary.signer.tlsCrt | default $cert.Cert | indent 4 }} +{{ $cert.Cert | indent 4 }} notary-signer.key: | -{{ .Values.notary.signer.tlsKey | default $cert.Key | indent 4 }} +{{ $cert.Key | indent 4 }} + {{- end }} server-config.postgres.json: | { "server": { @@ -22,13 +24,17 @@ data: }, "trust_service": { "type": "remote", - "hostname": "{{ template "harbor.fullname" . }}-notary-signer", + "hostname": "{{ template "harbor.notary-signer" . }}", "port": "7899", +{{- if not .Values.notary.secretName }} "tls_ca_file": "./notary-signer-ca.crt", +{{- else }} + "tls_ca_file": "/etc/ssl/notary/cert/notary-signer-ca.crt", +{{- end }} "key_algorithm": "ecdsa" }, "logging": { - "level": "debug" + "level": "{{ .Values.logLevel }}" }, "storage": { "backend": "postgres", @@ -37,7 +43,7 @@ data: "auth": { "type": "token", "options": { - "realm": "{{ template "harbor.externalURL" . }}/service/token", + "realm": "{{ .Values.externalURL }}/service/token", "service": "harbor-notary", "issuer": "harbor-token-issuer", "rootcertbundle": "/root.crt" @@ -48,11 +54,16 @@ data: { "server": { "grpc_addr": ":7899", +{{- if not .Values.notary.secretName }} "tls_cert_file": "./notary-signer.crt", "tls_key_file": "./notary-signer.key" +{{- else }} + "tls_cert_file": "/etc/ssl/notary/cert/notary-signer.crt", + "tls_key_file": "/etc/ssl/notary/cert/notary-signer.key" +{{- end }} }, "logging": { - "level": "debug" + "level": "{{ .Values.logLevel }}" }, "storage": { "backend": "postgres", diff --git a/templates/notary/notary-server.yaml b/templates/notary/notary-server.yaml index a1befe1..b96c9df 100644 --- a/templates/notary/notary-server.yaml +++ b/templates/notary/notary-server.yaml @@ -2,30 +2,36 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ template "harbor.fullname" . }}-notary-server + name: {{ template "harbor.notary-server" . }} labels: {{ include "harbor.labels" . | indent 4 }} - app: harbor-notary-server - version: {{ .Values.notary.server.image.tag }} + component: notary-server spec: - replicas: 1 + replicas: {{ .Values.notary.server.replicas }} selector: matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-notary-server +{{ include "harbor.matchLabels" . | indent 6 }} + component: notary-server template: metadata: labels: {{ include "harbor.labels" . | indent 8 }} - app: harbor-notary-server - version: {{ .Values.notary.server.image.tag }} + component: notary-server + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/notary/notary-cm.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if .Values.notary.podAnnotations }} +{{ toYaml .Values.notary.podAnnotations | indent 8 }} +{{- end }} spec: containers: - name: notary-server image: {{ .Values.notary.server.image.repository }}:{{ .Values.notary.server.image.tag }} - imagePullPolicy: {{ .Values.notary.server.image.pullPolicy }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.notary.server.resources }} resources: {{ toYaml .Values.notary.server.resources | indent 10 }} +{{- end }} env: - name: MIGRATIONS_PATH value: migrations/server/postgresql @@ -34,21 +40,35 @@ spec: volumeMounts: - name: notary-config mountPath: /etc/notary + - name: etc-localtime + mountPath: /etc/localtime - name: root-certificate mountPath: /root.crt subPath: tokenServiceRootCertBundle - - name: etc-localtime - mountPath: /etc/localtime + {{- if .Values.notary.secretName }} + - name: notary-ca + mountPath: /etc/ssl/notary/cert/notary-signer-ca.crt + subPath: ca + {{- end }} volumes: - name: etc-localtime hostPath: path: /etc/localtime - name: notary-config configMap: - name: "{{ template "harbor.fullname" . }}-notary" + name: "{{ template "harbor.notary-server" . }}" - name: root-certificate secret: - secretName: "{{ template "harbor.fullname" . }}-ui" + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + {{- if .Values.notary.secretName }} + - name: notary-ca + secret: + secretName: {{ .Values.notary.secretName }} + {{- end }} {{- with .Values.notary.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} diff --git a/templates/notary/notary-signer.yaml b/templates/notary/notary-signer.yaml index f562971..5af3fbe 100644 --- a/templates/notary/notary-signer.yaml +++ b/templates/notary/notary-signer.yaml @@ -2,47 +2,77 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ template "harbor.fullname" . }}-notary-signer + name: {{ template "harbor.notary-signer" . }} labels: {{ include "harbor.labels" . | indent 4 }} - app: harbor-notary-signer - version: {{ .Values.notary.signer.image.tag }} + component: notary-signer spec: - replicas: 1 + replicas: {{ .Values.notary.signer.replicas }} selector: matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-notary-signer +{{ include "harbor.matchLabels" . | indent 6 }} + component: notary-signer template: metadata: labels: {{ include "harbor.labels" . | indent 8 }} - app: harbor-notary-signer - version: {{ .Values.notary.signer.image.tag }} + component: notary-signer + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/notary/notary-cm.yaml") . | sha256sum }} spec: containers: - name: notary-signer image: {{ .Values.notary.signer.image.repository }}:{{ .Values.notary.signer.image.tag }} - imagePullPolicy: {{ .Values.notary.signer.image.pullPolicy }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.notary.signer.resources }} resources: {{ toYaml .Values.notary.signer.resources | indent 10 }} +{{- end }} env: - name: MIGRATIONS_PATH value: migrations/signer/postgresql - name: DB_URL value: {{ template "harbor.database.notarySigner" . }} - name: NOTARY_SIGNER_DEFAULTALIAS - value: {{ .Values.notary.signer.env.NOTARY_SIGNER_DEFAULTALIAS }} + value: defaultalias volumeMounts: - name: notary-config mountPath: /etc/notary - name: etc-localtime - mountPath: /etc/localtime + mountPath: /etc/localtime + {{- if .Values.notary.secretName }} + - name: notary-cert + mountPath: /etc/ssl/notary/cert/notary-signer-ca.crt + subPath: ca + - name: notary-cert + mountPath: /etc/ssl/notary/cert/notary-signer.crt + subPath: crt + - name: notary-cert + mountPath: /etc/ssl/notary/cert/notary-signer.key + subPath: key + {{- end }} volumes: - name: etc-localtime hostPath: path: /etc/localtime - name: notary-config configMap: - name: "{{ template "harbor.fullname" . }}-notary" + name: "{{ template "harbor.notary-server" . }}" + {{- if .Values.notary.secretName }} + - name: notary-cert + secret: + secretName: {{ .Values.notary.secretName }} + {{- end }} + {{- with .Values.notary.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.notary.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.notary.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} {{ end }} diff --git a/templates/notary/service.yaml b/templates/notary/notary-svc.yaml similarity index 61% rename from templates/notary/service.yaml rename to templates/notary/notary-svc.yaml index 37cda55..f02ba3c 100644 --- a/templates/notary/service.yaml +++ b/templates/notary/notary-svc.yaml @@ -2,21 +2,24 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "harbor.notaryServiceName" . }} + name: {{ template "harbor.notary-server" . }} labels: {{ include "harbor.labels" . | indent 4 }} spec: +{{- if (eq .Values.expose.ingress.controller "gce") }} + type: NodePort +{{- end }} ports: - port: 4443 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-notary-server + component: notary-server --- apiVersion: v1 kind: Service metadata: - name: {{ template "harbor.fullname" . }}-notary-signer + name: {{ template "harbor.notary-signer" . }} labels: {{ include "harbor.labels" . | indent 4 }} spec: @@ -24,5 +27,5 @@ spec: - port: 7899 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-notary-signer + component: notary-signer {{ end }} \ No newline at end of file diff --git a/templates/portal/deployment.yaml b/templates/portal/deployment.yaml new file mode 100644 index 0000000..7ddef54 --- /dev/null +++ b/templates/portal/deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: portal +spec: + replicas: {{ .Values.portal.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: portal + template: + metadata: + labels: +{{ include "harbor.matchLabels" . | indent 8 }} + component: portal + annotations: +{{- if .Values.portal.podAnnotations }} +{{ toYaml .Values.portal.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: portal + image: {{ .Values.portal.image.repository }}:{{ .Values.portal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.portal.resources }} + resources: +{{ toYaml .Values.portal.resources | indent 10 }} +{{- end }} + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 1 + periodSeconds: 10 + ports: + - containerPort: 80 + volumeMounts: + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + {{- with .Values.portal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/templates/portal/service.yaml b/templates/portal/service.yaml new file mode 100644 index 0000000..045de36 --- /dev/null +++ b/templates/portal/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if (eq .Values.expose.ingress.controller "gce") }} + type: NodePort +{{- end }} + ports: + - port: 80 + targetPort: 80 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: portal diff --git a/templates/redis/deployment.yml b/templates/redis/deployment.yml deleted file mode 100644 index 00be599..0000000 --- a/templates/redis/deployment.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "harbor.fullname" . }}-redis - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-redis - version: {{ .Values.redis.image.tag }} -spec: - replicas: 1 - selector: - matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-redis - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-redis - version: {{ .Values.redis.image.tag }} - spec: - containers: - - name: redis - image: {{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }} - imagePullPolicy: {{ .Values.redis.image.pullPolicy }} - args: ["--save","''","--appendonly","no"] - ports: - - name: redis - containerPort: 6379 - volumeMounts: - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime \ No newline at end of file diff --git a/templates/redis/service.yml b/templates/redis/service.yaml similarity index 55% rename from templates/redis/service.yml rename to templates/redis/service.yaml index 0d308d3..79c95c3 100644 --- a/templates/redis/service.yml +++ b/templates/redis/service.yaml @@ -1,15 +1,14 @@ ---- +{{- if eq .Values.redis.type "internal" -}} apiVersion: v1 kind: Service metadata: - name: {{ template "harbor.fullname" . }}-redis + name: {{ template "harbor.redis" . }} labels: {{ include "harbor.labels" . | indent 4 }} - app: harbor-redis spec: + ports: + - port: 6379 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-redis - ports: - - name: redis - port: 6379 \ No newline at end of file + component: redis +{{- end -}} \ No newline at end of file diff --git a/templates/redis/statefulset.yaml b/templates/redis/statefulset.yaml new file mode 100644 index 0000000..712efde --- /dev/null +++ b/templates/redis/statefulset.yaml @@ -0,0 +1,67 @@ +{{- if eq .Values.redis.type "internal" -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.redis" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: redis +spec: + replicas: 1 + serviceName: {{ template "harbor.redis" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: redis + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: redis +{{- if .Values.redis.podAnnotations }} + annotations: +{{ toYaml .Values.redis.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: redis + image: {{ .Values.redis.internal.image.repository }}:{{ .Values.redis.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.redis.internal.resources }} + resources: +{{ toYaml .Values.redis.internal.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /var/lib/redis + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: data + emptyDir: {} + {{- with .Values.redis.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end -}} diff --git a/templates/registry/configmap.yaml b/templates/registry/configmap.yaml deleted file mode 100644 index d579f1c..0000000 --- a/templates/registry/configmap.yaml +++ /dev/null @@ -1,162 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "{{ template "harbor.fullname" . }}-registry" - labels: -{{ include "harbor.labels" . | indent 4 }} -data: - config.yml: |+ - version: 0.1 - log: - level: {{ .Values.registry.logLevel }} - fields: - service: registry - storage: - {{- $storage := .Values.registry.storage }} - {{- $type := $storage.type }} - {{- if eq $type "filesystem" }} - filesystem: - rootdirectory: {{ $storage.filesystem.rootdirectory }} - {{- if $storage.filesystem.maxthreads }} - maxthreads: {{ $storage.filesystem.maxthreads }} - {{- end }} - {{- else if eq $type "azure" }} - azure: - accountname: {{ $storage.azure.accountname }} - container: {{ $storage.azure.container }} - {{- if $storage.azure.realm }} - realm: {{ $storage.azure.realm }} - {{- end }} - {{- else if eq $type "gcs" }} - gcs: - bucket: {{ $storage.gcs.bucket }} - {{- if $storage.gcs.rootdirectory }} - rootdirectory: {{ $storage.gcs.rootdirectory }} - {{- end }} - {{- if $storage.gcs.chunksize }} - chunksize: {{ $storage.gcs.chunksize }} - {{- end }} - {{- else if eq $type "s3" }} - s3: - region: {{ $storage.s3.region }} - bucket: {{ $storage.s3.bucket }} - {{- if $storage.s3.regionendpoint }} - regionendpoint: {{ $storage.s3.regionendpoint }} - {{- end }} - {{- if $storage.s3.encrypt }} - encrypt: {{ $storage.s3.encrypt }} - {{- end }} - {{- if $storage.s3.secure }} - secure: {{ $storage.s3.secure }} - {{- end }} - {{- if $storage.s3.v4auth }} - v4auth: {{ $storage.s3.v4auth }} - {{- end }} - {{- if $storage.s3.chunksize }} - chunksize: {{ $storage.s3.chunksize }} - {{- end }} - {{- if $storage.s3.rootdirectory }} - rootdirectory: {{ $storage.s3.rootdirectory }} - {{- end }} - {{- if $storage.s3.storageclass }} - storageclass: {{ $storage.s3.storageclass }} - {{- end }} - {{- else if eq $type "swift" }} - swift: - authurl: {{ $storage.swift.authurl }} - username: {{ $storage.swift.username }} - container: {{ $storage.swift.container }} - {{- if $storage.swift.region }} - region: {{ $storage.swift.region }} - {{- end }} - {{- if $storage.swift.tenant }} - tenant: {{ $storage.swift.tenant }} - {{- end }} - {{- if $storage.swift.tenantid }} - tenantid: {{ $storage.swift.tenantid }} - {{- end }} - {{- if $storage.swift.domain }} - domain: {{ $storage.swift.domain }} - {{- end }} - {{- if $storage.swift.domainid }} - domainid: {{ $storage.swift.domainid }} - {{- end }} - {{- if $storage.swift.trustid }} - trustid: {{ $storage.swift.trustid }} - {{- end }} - {{- if $storage.swift.insecureskipverify }} - insecureskipverify: {{ $storage.swift.insecureskipverify }} - {{- end }} - {{- if $storage.swift.chunksize }} - chunksize: {{ $storage.swift.chunksize }} - {{- end }} - {{- if $storage.swift.prefix }} - prefix: {{ $storage.swift.prefix }} - {{- end }} - {{- if $storage.swift.authversion }} - authversion: {{ $storage.swift.authversion }} - {{- end }} - {{- if $storage.swift.endpointtype }} - endpointtype: {{ $storage.swift.endpointtype }} - {{- end }} - {{- if $storage.swift.tempurlcontainerkey }} - tempurlcontainerkey: {{ $storage.swift.tempurlcontainerkey }} - {{- end }} - {{- if $storage.swift.tempurlmethods }} - tempurlmethods: {{ $storage.swift.tempurlmethods }} - {{- end }} - {{- else if eq $type "oss" }} - oss: - accesskeyid: {{ $storage.oss.accesskeyid }} - region: {{ $storage.oss.region }} - bucket: {{ $storage.oss.bucket }} - {{- if $storage.oss.endpoint }} - endpoint: {{ $storage.oss.endpoint }} - {{- end }} - {{- if $storage.oss.internal }} - internal: {{ $storage.oss.internal }} - {{- end }} - {{- if $storage.oss.encrypt }} - encrypt: {{ $storage.oss.encrypt }} - {{- end }} - {{- if $storage.oss.secure }} - secure: {{ $storage.oss.secure }} - {{- end }} - {{- if $storage.oss.chunksize }} - chunksize: {{ $storage.oss.chunksize }} - {{- end }} - {{- if $storage.oss.rootdirectory }} - rootdirectory: {{ $storage.oss.rootdirectory }} - {{- end }} - {{- end }} - cache: - layerinfo: redis - maintenance: - uploadpurging: - enabled: false - delete: - enabled: true - redis: - addr: "{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}" - password: {{ template "harbor.redis.password" . }} - db: {{ template "harbor.redis.databaseIndex" . }} - http: - addr: :5000 - # set via environment variable - # secret: placeholder - debug: - addr: localhost:5001 - auth: - token: - issuer: harbor-token-issuer - realm: "{{ template "harbor.externalURL" . }}/service/token" - rootcertbundle: /etc/registry/root.crt - service: harbor-registry - notifications: - endpoints: - - name: harbor - disabled: false - url: http://{{ template "harbor.fullname" . }}-ui/service/notifications - timeout: 3000ms - threshold: 5 - backoff: 1s diff --git a/templates/registry/registry-cm.yaml b/templates/registry/registry-cm.yaml new file mode 100644 index 0000000..9793df7 --- /dev/null +++ b/templates/registry/registry-cm.yaml @@ -0,0 +1,55 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + version: 0.1 + log: + level: {{ .Values.logLevel }} + fields: + service: registry + storage: + filesystem: + rootdirectory: /data + cache: + layerinfo: redis + maintenance: + uploadpurging: + enabled: false + delete: + enabled: true + redirect: + disable: false + redis: + addr: "{{ template "harbor.redis.host" . }}:{{ template "harbor.redis.port" . }}" + db: {{ template "harbor.redis.registryDatabaseIndex" . }} + http: + addr: :5000 + # set via environment variable + # secret: placeholder + debug: + addr: localhost:5001 + auth: + token: + issuer: harbor-token-issuer + realm: "{{ .Values.externalURL }}/service/token" + rootcertbundle: /etc/registry/root.crt + service: harbor-registry + validation: + disabled: true + notifications: + endpoints: + - name: harbor + disabled: false + url: http://{{ template "harbor.core" . }}/service/notifications + timeout: 3000ms + threshold: 5 + backoff: 1s + ctl-config.yml: |+ + --- + protocol: "http" + port: 8080 + log_level: {{ .Values.logLevel }} diff --git a/templates/registry/registry-dpl.yaml b/templates/registry/registry-dpl.yaml new file mode 100644 index 0000000..7ac3638 --- /dev/null +++ b/templates/registry/registry-dpl.yaml @@ -0,0 +1,145 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry +spec: + replicas: {{ .Values.registry.replicas }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: registry + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: registry + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/registry/registry-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/registry/registry-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if .Values.registry.podAnnotations }} +{{ toYaml .Values.registry.podAnnotations | indent 8 }} +{{- end }} + spec: + containers: + - name: registry + image: {{ .Values.registry.registry.image.repository }}:{{ .Values.registry.registry.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + port: 5000 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5000 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.registry.resources }} + resources: +{{ toYaml .Values.registry.registry.resources | indent 10 }} +{{- end }} + args: ["serve", "/etc/registry/config.yml"] + envFrom: + - secretRef: + name: "{{ template "harbor.registry" . }}" + ports: + - containerPort: 5000 + - containerPort: 5001 + volumeMounts: + - name: registry-data + mountPath: /data + - name: registry-root-certificate + mountPath: /etc/registry/root.crt + subPath: tokenServiceRootCertBundle + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + - name: etc-localtime + mountPath: /etc/localtime + - name: registryctl + image: {{ .Values.registry.controller.image.repository }}:{{ .Values.registry.controller.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/health + port: 8080 + initialDelaySeconds: 1 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/health + port: 8080 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.controller.resources }} + resources: +{{ toYaml .Values.registry.controller.resources | indent 10 }} +{{- end }} + args: ["serve", "/etc/registry/config.yml"] + envFrom: + - secretRef: + name: "{{ template "harbor.registry" . }}" + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ template "harbor.core" . }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ template "harbor.jobservice" . }} + key: secret + ports: + - containerPort: 8080 + volumeMounts: + - name: registry-data + mountPath: /data + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + - name: registry-config + mountPath: /etc/registryctl/config.yml + subPath: ctl-config.yml + - name: etc-localtime + mountPath: /etc/localtime + volumes: + - name: etc-localtime + hostPath: + path: /etc/localtime + - name: registry-root-certificate + secret: + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + - name: registry-config + configMap: + name: "{{ template "harbor.registry" . }}" + - name: registry-data + hostPath: + {{- if .Values.registry.hostPath }} + path: {{ .Values.registry.hostPath }} + {{- else }} + path: /data/{{ .Release.Namespace }}/{{ .Release.Name }}/registry + {{- end }} + {{- with .Values.registry.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/templates/registry/registry-secret.yaml b/templates/registry/registry-secret.yaml new file mode 100644 index 0000000..ca7e1df --- /dev/null +++ b/templates/registry/registry-secret.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + REGISTRY_HTTP_SECRET: {{ .Values.registry.secret | default (randAlphaNum 16) | b64enc | quote }} + REGISTRY_REDIS_PASSWORD: {{ (include "harbor.redis.rawPassword" .) | b64enc | quote }} + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if eq $type "azure" }} + REGISTRY_STORAGE_AZURE_ACCOUNTKEY: {{ $storage.azure.accountkey | b64enc | quote }} + {{- else if eq $type "gcs" }} + GCS_KEY_DATA: {{ $storage.gcs.encodedkey | quote }} + {{- else if eq $type "s3" }} + {{- if $storage.s3.accesskey }} + REGISTRY_STORAGE_S3_ACCESSKEY: {{ $storage.s3.accesskey | b64enc | quote }} + {{- end }} + {{- if $storage.s3.secretkey }} + REGISTRY_STORAGE_S3_SECRETKEY: {{ $storage.s3.secretkey | b64enc | quote }} + {{- end }} + {{- else if eq $type "swift" }} + REGISTRY_STORAGE_SWIFT_PASSWORD: {{ $storage.swift.password | b64enc | quote }} + {{- if $storage.swift.secretkey }} + REGISTRY_STORAGE_SWIFT_SECRETKEY: {{ $storage.swift.secretkey | b64enc | quote }} + {{- end }} + {{- if $storage.swift.accesskey }} + REGISTRY_STORAGE_SWIFT_ACCESSKEY: {{ $storage.swift.accesskey | b64enc | quote }} + {{- end }} + {{- else if eq $type "oss" }} + REGISTRY_STORAGE_OSS_ACCESSKEYSECRET: {{ $storage.oss.accesskeysecret | b64enc | quote }} + {{- end }} diff --git a/templates/registry/service.yaml b/templates/registry/registry-svc.yaml similarity index 58% rename from templates/registry/service.yaml rename to templates/registry/registry-svc.yaml index 1dc24b6..6ec6ada 100644 --- a/templates/registry/service.yaml +++ b/templates/registry/registry-svc.yaml @@ -1,13 +1,15 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "harbor.fullname" . }}-registry" + name: "{{ template "harbor.registry" . }}" labels: {{ include "harbor.labels" . | indent 4 }} spec: ports: - - name: http + - name: registry port: 5000 + - name: controller + port: 8080 selector: {{ include "harbor.matchLabels" . | indent 4 }} - app: harbor-registry \ No newline at end of file + component: registry \ No newline at end of file diff --git a/templates/registry/secret.yaml b/templates/registry/secret.yaml deleted file mode 100644 index e13dbfd..0000000 --- a/templates/registry/secret.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-registry" - labels: -{{ include "harbor.labels" . | indent 4 }} -type: Opaque -data: - httpSecret: {{ .Values.registry.httpSecret | b64enc | quote }} - {{- $storage := .Values.registry.storage }} - {{- $type := $storage.type }} - {{- if eq $type "azure" }} - accountkey: {{ $storage.azure.accountkey | b64enc | quote }} - {{- else if eq $type "s3" }} - {{- if $storage.s3.accesskey }} - accesskey: {{ $storage.s3.accesskey | b64enc | quote }} - {{- end }} - {{- if $storage.s3.secretkey }} - secretkey: {{ $storage.s3.secretkey | b64enc | quote }} - {{- end }} - {{- else if eq $type "swift" }} - password: {{ $storage.swift.password }} - {{- if $storage.swift.secretkey }} - secretkey: {{ $storage.swift.secretkey }} - {{- end }} - {{- if $storage.swift.accesskey }} - accesskey: {{ $storage.swift.accesskey }} - {{- end }} - {{- else if eq $type "oss" }} - accesskeysecret: {{ $storage.oss.accesskeysecret }} - {{- end }} \ No newline at end of file diff --git a/templates/registry/statefulset.yaml b/templates/registry/statefulset.yaml deleted file mode 100644 index a08fa68..0000000 --- a/templates/registry/statefulset.yaml +++ /dev/null @@ -1,126 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: "{{ template "harbor.fullname" . }}-registry" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-registry - version: {{ .Values.registry.image.tag }} -spec: - replicas: 1 - serviceName: "{{ template "harbor.fullname" . }}-registry" - selector: - matchLabels: -{{ include "harbor.matchLabels" . | indent 6 }} - app: harbor-registry - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-registry - version: {{ .Values.registry.image.tag }} - spec: - containers: - - name: registry - image: {{ .Values.registry.image.repository }}:{{ .Values.registry.image.tag }} - imagePullPolicy: {{ .Values.registry.image.pullPolicy }} - resources: -{{ toYaml .Values.registry.resources | indent 10 }} - args: ["serve", "/etc/registry/config.yml"] - env: - - name: REGISTRY_HTTP_SECRET - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: httpSecret - {{- $storage := .Values.registry.storage }} - {{- $type := $storage.type }} - {{- if eq $type "azure" }} - - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: accountkey - {{- else if eq $type "s3" }} - {{- if $storage.s3.accesskey }} - - name: REGISTRY_STORAGE_S3_ACCESSKEY - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: accesskey - {{- end }} - {{- if $storage.s3.secretkey }} - - name: REGISTRY_STORAGE_S3_SECRETKEY - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: secretkey - {{- end }} - {{- else if eq $type "swift" }} - - name: REGISTRY_STORAGE_SWIFT_PASSWORD - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: password - {{- if $storage.swift.secretkey }} - - name: REGISTRY_STORAGE_SWIFT_SECRETKEY - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: secretkey - {{- end }} - {{- if $storage.swift.accesskey }} - - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: accesskey - {{- end }} - {{- else if eq $type "oss" }} - - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-registry" - key: accesskeysecret - {{- end }} - ports: - - containerPort: 5000 - - containerPort: 5001 - volumeMounts: - {{- if eq .Values.registry.storage.type "filesystem" }} - - name: registry-data - mountPath: {{ .Values.registry.storage.filesystem.rootdirectory }} - {{- end }} - - name: registry-root-certificate - mountPath: /etc/registry/root.crt - subPath: tokenServiceRootCertBundle - - name: registry-config - mountPath: /etc/registry/config.yml - subPath: config.yml - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - - name: registry-root-certificate - secret: - secretName: "{{ template "harbor.fullname" . }}-ui" - - name: registry-config - configMap: - name: "{{ template "harbor.fullname" . }}-registry" - - name: registry-data - hostPath: - path: {{ .Values.registry.hostpath }} - {{- with .Values.registry.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.registry.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.registry.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} diff --git a/templates/ui/configmap.yaml b/templates/ui/configmap.yaml deleted file mode 100644 index 6cd0b05..0000000 --- a/templates/ui/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "{{ template "harbor.fullname" . }}-ui" - labels: -{{ include "harbor.labels" . | indent 4 }} -data: - app.conf: |+ - appname = Harbor - runmode = prod - enablegzip = true - - [prod] - httpport = 8080 diff --git a/templates/ui/deployment.yaml b/templates/ui/deployment.yaml deleted file mode 100644 index 6ddabfd..0000000 --- a/templates/ui/deployment.yaml +++ /dev/null @@ -1,117 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ template "harbor.fullname" . }}-ui" - labels: -{{ include "harbor.labels" . | indent 4 }} - app: harbor-ui - version: {{ .Values.ui.image.tag }} -spec: - replicas: 1 - selector: - matchLabels: -{{ include "harbor.labels" . | indent 6 }} - app: harbor-ui - template: - metadata: - labels: -{{ include "harbor.labels" . | indent 8 }} - app: harbor-ui - version: {{ .Values.ui.image.tag }} - spec: - containers: - - name: ui - image: {{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag }} - imagePullPolicy: {{ .Values.ui.image.pullPolicy }} - env: - - name: UI_SECRET - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-ui" - key: secret - - name: JOBSERVICE_SECRET - valueFrom: - secretKeyRef: - name: "{{ template "harbor.fullname" . }}-ui" - key: jobserviceSecret - - name: _REDIS_URL - value: {{ template "harbor.redisForUI" . }} - - name: GODEBUG - value: netdns=cgo - - name: LOG_LEVEL - value: info - - name: CONFIG_PATH - value: /etc/ui/app.conf - - name: ENABLE_HARBOR_SCAN_ON_PUSH - value: "1" - - name: ADMINSERVER_URL - value: "http://{{ template "harbor.fullname" . }}-adminserver" - - name: CHART_CACHE_DRIVER - value: "redis" - ports: - - containerPort: 8080 - volumeMounts: - - name: ui-config - mountPath: /etc/ui/app.conf - subPath: app.conf - - name: ui-secrets-key - mountPath: /etc/ui/key - subPath: key - - name: ui-secrets-private-key - mountPath: /etc/ui/private_key.pem - subPath: tokenServicePrivateKey - {{- if eq .Values.externalProtocol "https" }} - {{- if .Values.ingress.enabled }} - {{- if eq .Values.ingress.tls.secretName "" }} - - name: ca-download - mountPath: /etc/ui/ca/ca.crt - subPath: ca.crt - {{- end }} - {{- end }} - {{- end }} - - name: psc - mountPath: /etc/ui/token - - name: etc-localtime - mountPath: /etc/localtime - volumes: - - name: etc-localtime - hostPath: - path: /etc/localtime - - name: ui-config - configMap: - name: "{{ template "harbor.fullname" . }}-ui" - - name: ui-secrets-key - secret: - secretName: "{{ template "harbor.fullname" . }}-ui" - items: - - key: secretKey - path: key - - name: ui-secrets-private-key - secret: - secretName: "{{ template "harbor.fullname" . }}-ui" - {{- if eq .Values.externalProtocol "https" }} - {{- if .Values.ingress.enabled }} - {{- if eq .Values.ingress.tls.secretName "" }} - - name: ca-download - secret: - secretName: "{{ template "harbor.fullname" . }}-ingress" - items: - - key: ca.crt - path: ca.crt - {{- end }} - {{- end }} - {{- end }} - - name: psc - emptyDir: {} - {{- with .Values.ui.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.ui.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.ui.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} diff --git a/templates/ui/secret.yaml b/templates/ui/secret.yaml deleted file mode 100644 index 7433543..0000000 --- a/templates/ui/secret.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- $cert := genSelfSignedCert "harbor" nil nil 365 }} -apiVersion: v1 -kind: Secret -metadata: - name: "{{ template "harbor.fullname" . }}-ui" - labels: -{{ include "harbor.labels" . | indent 4 }} -type: Opaque -data: - secretKey: {{ .Values.secretKey | b64enc | quote }} - secret: {{ .Values.ui.secret | b64enc | quote }} - jobserviceSecret: {{ .Values.jobservice.secret | b64enc | quote }} - tokenServiceRootCertBundle: {{ $cert.Cert | b64enc | quote }} - tokenServicePrivateKey: {{ $cert.Key | b64enc | quote }} - \ No newline at end of file diff --git a/values-aliyun.yaml b/values-aliyun.yaml index 9d72278..f16da71 100644 --- a/values-aliyun.yaml +++ b/values-aliyun.yaml @@ -1,102 +1,115 @@ +expose: + type: ingress + tls: + enabled: false + ingress: + host: harbor.wodcloud.local + controller: default + annotations: + ingress.kubernetes.io/ssl-redirect: "true" + rewriteAnnotation: traefik.ingress.kubernetes.io/rewrite-target + +externalURL: https://harbor.wodcloud.local + persistence: enabled: false -externalProtocol: https -externalDomain: hub.wodcloud.local -harborAdminPassword: "passwd" -ingress: - enabled: true +imagePullPolicy: IfNotPresent -adminserver: - image: - repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-adminserver - tag: v1.6.3 - nodeSelector: - harbor: enabled +logLevel: debug +harborAdminPassword: "changeit" +secretKey: "IpTIscRIgmerlare" -jobservice: +portal: image: - repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-jobservice - tag: v1.6.3 + repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-portal + tag: v1.7.5 + replicas: 1 -ui: +core: image: - repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-ui - tag: v1.6.3 + repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-core + tag: v1.7.5 + replicas: 1 -busybox: +jobservice: image: - repository: registry.cn-qingdao.aliyuncs.com/wod/busybox - tag: "1.30" + repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-jobservice + tag: v1.7.5 + replicas: 1 + maxJobWorkers: 10 + jobLogger: file -database: - internal: +registry: + registry: image: - repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-db - tag: v1.6.3 + repository: registry.cn-qingdao.aliyuncs.com/wod/registry + tag: v2.7.1 resources: limits: memory: 4Gi - cpu: 1000m + cpu: 1000m requests: memory: 256Mi - cpu: 100m - password: "passwd" - nodeSelector: - harbor: enabled - -registry: - image: - repository: registry.cn-qingdao.aliyuncs.com/wod/registry - tag: 2.7.1 - hostpath: /data/registry - resources: - limits: - memory: 4Gi - cpu: 1000m - requests: - memory: 256Mi - cpu: 100m + cpu: 100m nodeSelector: harbor: enabled + controller: + image: + repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-registryctl + tag: v1.7.5 + replicas: 1 chartmuseum: enabled: true image: - repository: registry.cn-qingdao.aliyuncs.com/wod/chartmuseum - tag: v0.7.1 + repository: registry.cn-qingdao.aliyuncs.com/wod/chartmuseum-photon + tag: v0.8.1-v1.7.5 + replicas: 1 + nodeSelector: + harbor: enabled clair: enabled: true image: - repository: registry.cn-qingdao.aliyuncs.com/wod/clair - tag: v2.0.6 - resources: - limits: - memory: 1Gi - cpu: 1000m - requests: - memory: 128Mi - cpu: 100m - -redis: - image: - repository: registry.cn-qingdao.aliyuncs.com/wod/redis - tag: 4.0.11-alpine - usePassword: false - cluster: - enabled: false - master: - persistence: - enabled: false + repository: registry.cn-qingdao.aliyuncs.com/wod/clair-photon + tag: v2.0.8-v1.7.5 + replicas: 1 + updatersInterval: 12 notary: enabled: true server: image: repository: registry.cn-qingdao.aliyuncs.com/wod/notary-server-photon - tag: dev + tag: v0.6.1-v1.7.5 + replicas: 1 signer: image: repository: registry.cn-qingdao.aliyuncs.com/wod/notary-signer-photon - tag: dev \ No newline at end of file + tag: v0.6.1-v1.7.5 + replicas: 1 + +database: + type: internal + internal: + image: + repository: registry.cn-qingdao.aliyuncs.com/wod/harbor-db + tag: v1.7.5 + password: "changeit" + resources: + limits: + memory: 4Gi + cpu: 1000m + requests: + memory: 256Mi + cpu: 100m + nodeSelector: + harbor: enabled + +redis: + type: internal + internal: + image: + repository: registry.cn-qingdao.aliyuncs.com/wod/redis + tag: 4.0.11-alpine \ No newline at end of file diff --git a/values.yaml b/values.yaml index 33ef0c4..d24bb93 100644 --- a/values.yaml +++ b/values.yaml @@ -1,154 +1,155 @@ -persistence: - enabled: true -externalProtocol: https -# The FQDN for Harbor service -externalDomain: hub.wodcloud.local -# The Port for Harbor service, leave empty if the service -# is to be bound to port 80/443 -externalPort: -harborAdminPassword: "passwd" -authenticationMode: "db_auth" -selfRegistration: "on" -ldap: - url: "ldaps://ldapserver" - searchDN: "" - searchPassword: "" - baseDN: "" - filter: "(objectClass=person)" - uid: "uid" - scope: "2" - timeout: "5" - verifyCert: "True" -email: - host: "smtp.mydomain.com" - port: "25" - username: "sample_admin@mydomain.com" - password: "password" - ssl: "false" - insecure: "false" - from: "admin " - identity: "" - -# The secret key used for encryption. Must be a string of 16 chars. -secretKey: "nQImBn5SVCHL7ehq" - -# These annotations allow the registry to work behind the nginx -# ingress controller. -ingress: - enabled: true - annotations: +expose: + # Set the way how to expose the service. Set the type as "ingress", + # "clusterIP", "nodePort" or "loadBalancer" and fill the information + # in the corresponding section + type: ingress tls: - # Fill the secretName if you want to use the certificate of - # yourself when Harbor serves with HTTPS. A certificate will - # be generated automatically by the chart if leave it empty + # Enable the tls or not. Note: if the type is "ingress" and the tls + # is disabled, the port must be included in the command when pull/push + # images. Refer to https://github.com/goharbor/harbor/issues/5291 + # for the detail. + enabled: true + # Fill the name of secret if you want to use your own TLS certificate. + # The secret must contain keys named: + # "tls.crt" - the certificate + # "tls.key" - the private key + # "ca.crt" - the certificate of CA + # These files will be generated automatically if the "secretName" is not set secretName: "" + # The commmon name used to generate the certificate, it's necessary + # when the type isn't "ingress" and "secretName" is null + commonName: "" + ingress: + host: harbor.local + # set to the type of ingress controller if it has specific requirements. + # leave as `default` for most ingress controllers. + # set to `gce` if using the GCE ingress controller + controller: default + annotations: + ingress.kubernetes.io/ssl-redirect: "true" + ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + # The annotation name for "rewrite-target", only needed when Notary + # service is enabled + rewriteAnnotation: nginx.ingress.kubernetes.io/rewrite-target + clusterIP: + # The name of ClusterIP service + name: harbor + ports: + # The service port Harbor listens on when serving with HTTP + http: 80 + # The service port Harbor listens on when serving with HTTPS + https: 443 + nodePort: + # The name of NodePort service + name: harbor + ports: + http: + # The service port Harbor listens on when serving with HTTP + port: 80 + # The node port Harbor listens on when serving with HTTP + nodePort: 30002 + https: + # The service port Harbor listens on when serving with HTTPS + port: 443 + # The node port Harbor listens on when serving with HTTPS + nodePort: 30003 + loadBalancer: + # The name of LoadBalancer service + name: harbor + ports: + # The service port Harbor listens on when serving with HTTP + http: 80 + # The service port Harbor listens on when serving with HTTPS + https: 443 -istio: - enabled: false +# The external URL for Harbor service. It is used to +# 1) populate the docker/helm commands showed on portal +# 2) populate the token service URL returned to docker/notary client +# +# Format: protocol://domain[:port]. Usually: +# 1) if "expose.type" is "ingress", the "domain" should be +# the value of "expose.ingress.host" +# 2) if "expose.type" is "clusterIP", the "domain" should be +# the value of "expose.clusterIP.name" +# 3) if "expose.type" is "nodePort", the "domain" should be +# the IP address of k8s node +# +# If Harbor is deployed behind the proxy, set it as the URL of proxy +externalURL: https://harbor.local -# The tag for Harbor docker images. -harborImageTag: &harbor_image_tag v1.6.3 - -adminserver: - image: - repository: goharbor/harbor-adminserver - tag: *harbor_image_tag - pullPolicy: IfNotPresent - volumes: - config: - storageClass: "storageos" +# The persistence is enabled by default and a default StorageClass +# is needed in the k8s cluster to provision volumes dynamicly. +# Specify another StorageClass in the "storageClass" or set "existingClaim" +# if you have already existing persistent volumes to use +# +# For storing images and charts, you can also use "azure", "gcs", "s3", +# "swift" or "oss". Set it in the "imageChartStorage" section +persistence: + enabled: true + # Setting it to "keep" to avoid removing PVCs during a helm delete + # operation. Leaving it empty will delete PVCs after the chart deleted + resourcePolicy: "keep" + persistentVolumeClaim: + registry: + # Use the existing PVC which must be created manually before bound, + # and specify the "subPath" if the PVC is shared with other components + existingClaim: "" + # Specify the "storageClass" used to provision the volume. Or the default + # StorageClass will be used(the default). + # Set it to "-" to disable dynamic provisioning + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + chartmuseum: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + jobservice: + existingClaim: "" + storageClass: "" + subPath: "" accessMode: ReadWriteOnce size: 1Gi - # resources: - # requests: - # memory: 256Mi - # cpu: 100m - nodeSelector: {} - tolerations: [] - affinity: {} - -jobservice: - image: - repository: goharbor/harbor-jobservice - tag: *harbor_image_tag - pullPolicy: IfNotPresent - secret: "BBRQwySksiHZqJUh" - maxWorkers: 50 -# resources: -# requests: -# memory: 256Mi -# cpu: 100m - nodeSelector: {} - tolerations: [] - affinity: {} - -ui: - image: - repository: goharbor/harbor-ui - tag: *harbor_image_tag - pullPolicy: IfNotPresent - secret: "BBRQwySksiHZqJUh" -# resources: -# requests: -# memory: 256Mi -# cpu: 100m - nodeSelector: {} - tolerations: [] - affinity: {} - -busybox: - image: - repository: busybox - tag: 1.29 - -# TODO: change the style to be same with redis -database: - # if external database is used, set "type" to "external" - # and fill the connection informations in "external" section - type: internal - internal: - image: - repository: goharbor/harbor-db - tag: *harbor_image_tag - pullPolicy: IfNotPresent - # the superuser password of database - password: "passwd" - volumes: - data: - storageClass: "storageos" - accessMode: ReadWriteOnce - size: 5Gi - # resources: - # requests: - # memory: 256Mi - # cpu: 100m - nodeSelector: {} - tolerations: [] - affinity: {} - external: - host: "192.168.0.1" - port: "5432" - username: "user" - password: "password" - coreDatabase: "registry" - clairDatabase: "clair" - notaryServerDatabase: "notary_server" - notarySignerDatabase: "notary_signer" - -registry: - image: - repository: registry - tag: 2.7.1 - pullPolicy: IfNotPresent - httpSecret: "BBRQwySksiHZqJUh" - logLevel: info - hostpath: /etc/kubernetes/data/registry - storage: - # specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift", - # "oss" and fill the information needed in the corresponding section + # If external database is used, the following settings for database will + # be ignored + database: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + # If external Redis is used, the following settings for Redis will + # be ignored + redis: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + # Define which storage backend is used for registry and chartmuseum to store + # images and charts. Refer to + # https://github.com/docker/distribution/blob/master/docs/configuration.md#storage + # for the detail. + imageChartStorage: + # Specify whether to disable `redirect` for images and chart storage, for + # backends which not supported it (such as using minio for `s3` storage type), please disable + # it. To disable redirects, simply set `disableredirect` to `true` instead. + # Refer to + # https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect + # for the detail. + disableredirect: false + # Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift", + # "oss" and fill the information needed in the corresponding section. The type + # must be "filesystem" if you want to use persistent volumes for registry + # and chartmuseum type: filesystem filesystem: - rootdirectory: /var/lib/registry + rootdirectory: /storage #maxthreads: 100 azure: accountname: accountname @@ -157,10 +158,10 @@ registry: #realm: core.windows.net gcs: bucket: bucketname - # TODO: support the keyfile of gcs - #keyfile: /path/to/keyfile + # The base64 encoded json file which contains the key + encodedkey: base64-encoded-json-key-file #rootdirectory: /gcs/object/name/prefix - #chunksize: 5242880 + #chunksize: "5242880" s3: region: us-west-1 bucket: bucketname @@ -171,7 +172,7 @@ registry: #keyid: mykeyid #secure: true #v4auth: true - #chunksize: 5242880 + #chunksize: "5242880" #rootdirectory: /s3/object/name/prefix #storageclass: STANDARD swift: @@ -205,32 +206,130 @@ registry: #secure: true #chunksize: 10M #rootdirectory: rootdirectory - ## Persist data to a persistent volume - volumes: - data: - # storageClass: "-" - accessMode: ReadWriteOnce - size: 5Gi + +imagePullPolicy: IfNotPresent + +logLevel: debug +# The initial password of Harbor admin. Change it from portal after launching Harbor +harborAdminPassword: "Harbor12345" +# The secret key used for encryption. Must be a string of 16 chars. +secretKey: "not-a-secure-key" + +# If expose the service via "ingress", the Nginx will not be used +nginx: + image: + repository: goharbor/nginx-photon + tag: dev + replicas: 1 # resources: # requests: # memory: 256Mi # cpu: 100m - # nodeSelector: - # kubernetes.io/hostname: 172.31.14.41 + nodeSelector: {} tolerations: [] affinity: {} + ## Additional deployment annotations + podAnnotations: {} + +portal: + image: + repository: goharbor/harbor-portal + tag: dev + replicas: 1 +# resources: +# requests: +# memory: 256Mi +# cpu: 100m + nodeSelector: {} + tolerations: [] + affinity: {} + ## Additional deployment annotations + podAnnotations: {} + +core: + image: + repository: goharbor/harbor-core + tag: dev + replicas: 1 +# resources: +# requests: +# memory: 256Mi +# cpu: 100m + nodeSelector: {} + tolerations: [] + affinity: {} + ## Additional deployment annotations + podAnnotations: {} + # Secret is used when core server communicates with other components. + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + + # Fill the name of a kubernetes secret if you want to use your own + # TLS certificate and private key for token encryption/decryption. + # The secret must contain keys named tls.tokenServiceRootCertBundle and + # tls.tokenServicePrivateKey that contain the certificate and private key. + # They will be automatically generated if not set + secretName: "" + +jobservice: + image: + repository: goharbor/harbor-jobservice + tag: dev + replicas: 1 + maxJobWorkers: 10 + # The logger for jobs: "file", "database" or "stdout" + jobLogger: file +# resources: +# requests: +# memory: 256Mi +# cpu: 100m + nodeSelector: {} + tolerations: [] + affinity: {} + ## Additional deployment annotations + podAnnotations: {} + # Secret is used when job service communicates with other components. + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + +registry: + registry: + image: + repository: goharbor/registry-photon + tag: dev + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + controller: + image: + repository: goharbor/harbor-registryctl + tag: dev + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + replicas: 1 + nodeSelector: {} + tolerations: [] + affinity: {} + ## Additional deployment annotations + podAnnotations: {} + # Secret is used to secure the upload state from client + # and registry storage backend. + # See: https://github.com/docker/distribution/blob/master/docs/configuration.md#http + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" chartmuseum: enabled: true image: - repository: chartmuseum/chartmuseum - tag: v0.7.1 - pullPolicy: IfNotPresent - volumes: - data: - storageClass: "storageos" - accessMode: ReadWriteOnce - size: 5Gi + repository: goharbor/chartmuseum-photon + tag: dev + replicas: 1 # resources: # requests: # memory: 256Mi @@ -238,18 +337,21 @@ chartmuseum: nodeSelector: {} tolerations: [] affinity: {} + ## Additional deployment annotations + podAnnotations: {} clair: enabled: true image: - repository: quay.io/coreos/clair - tag: 2.0.6 - pullPolicy: IfNotPresent - volumes: - pgData: - storageClass: "storageos" - accessMode: ReadWriteOnce - size: 1Gi + repository: goharbor/clair-photon + tag: dev + replicas: 1 + # The http(s) proxy used to update vulnerabilities database from internet + httpProxy: + httpsProxy: + # The interval of clair updaters, the unit is hour, set to 0 to + # disable the updaters + updatersInterval: 12 # resources: # requests: # memory: 256Mi @@ -257,50 +359,96 @@ clair: nodeSelector: {} tolerations: [] affinity: {} - -redis: - image: - repository: redis - tag: 4.0.1-alpine - pullPolicy: IfNotPresent - # if external Redis is used, set "external.enabled" to "true" - # and fill the connection informations in "external" section. - # or the internal Redis will be used - usePassword: false - password: "passwd" - cluster: - enabled: false - master: - persistence: -# TODO: There is a perm issue: Can't open the append-only file: Permission denied -# TODO: Setting it to false is a temp workaround. Will re-visit this problem. - enabled: false - external: - enabled: false - host: "192.168.0.2" - port: "6379" - databaseIndex: "0" - usePassword: false - password: "passwd" + ## Additional deployment annotations + podAnnotations: {} notary: enabled: true server: image: - repository: notary - tag: server-0.5.0 - pullPolicy: IfNotPresent + repository: goharbor/notary-server-photon + tag: dev + replicas: 1 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m signer: image: - repository: notary - tag: signer-0.5.0 - pullPolicy: IfNotPresent - env: - NOTARY_SIGNER_DEFAULTALIAS: defaultalias - # The TLS certificate for Notary Signer. Will auto generate them if unspecified here. - caCrt: - tlsCrt: - tlsKey: + repository: goharbor/notary-signer-photon + tag: dev + replicas: 1 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m nodeSelector: {} tolerations: [] affinity: {} + ## Additional deployment annotations + podAnnotations: {} + # Fill the name of a kubernetes secret if you want to use your own + # TLS certificate authority, certificate and private key for notary + # communications. + # The secret must contain keys named tls.ca, tls.crt and tls.key that + # contain the CA, certificate and private key. + # They will be generated if not set. + secretName: "" + +database: + # if external database is used, set "type" to "external" + # and fill the connection informations in "external" section + type: internal + internal: + image: + repository: goharbor/harbor-db + tag: dev + # The initial superuser password for internal database + password: "changeit" + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + nodeSelector: {} + tolerations: [] + affinity: {} + external: + host: "192.168.0.1" + port: "5432" + username: "user" + password: "password" + coreDatabase: "registry" + clairDatabase: "clair" + notaryServerDatabase: "notary_server" + notarySignerDatabase: "notary_signer" + sslmode: "disable" + ## Additional deployment annotations + podAnnotations: {} + +redis: + # if external Redis is used, set "type" to "external" + # and fill the connection informations in "external" section + type: internal + internal: + image: + repository: goharbor/redis-photon + tag: dev + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + nodeSelector: {} + tolerations: [] + affinity: {} + external: + host: "192.168.0.2" + port: "6379" + # The "coreDatabaseIndex" must be "0" as the library Harbor + # used doesn't support configuring it + coreDatabaseIndex: "0" + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + chartmuseumDatabaseIndex: "3" + password: "" + ## Additional deployment annotations + podAnnotations: {} \ No newline at end of file -- 2.26.0