From 95cd785e4b317b7d6ff2c75c3e2e267e8a7e8c0f Mon Sep 17 00:00:00 2001 From: Damien Duportal Date: Thu, 13 Feb 2025 08:54:32 +0100 Subject: [PATCH] feat: introduce docker-registry chart Signed-off-by: Damien Duportal --- charts/docker-registry/.helmignore | 23 ++++ charts/docker-registry/Chart.yaml | 13 ++ charts/docker-registry/templates/_helpers.tpl | 113 ++++++++++++++++ .../docker-registry/templates/configmap.yaml | 9 ++ charts/docker-registry/templates/secret.yaml | 16 +++ charts/docker-registry/templates/service.yaml | 20 +++ .../templates/statefulset.yaml | 121 ++++++++++++++++++ charts/docker-registry/values.yaml | 121 ++++++++++++++++++ 8 files changed, 436 insertions(+) create mode 100644 charts/docker-registry/.helmignore create mode 100644 charts/docker-registry/Chart.yaml create mode 100644 charts/docker-registry/templates/_helpers.tpl create mode 100644 charts/docker-registry/templates/configmap.yaml create mode 100644 charts/docker-registry/templates/secret.yaml create mode 100644 charts/docker-registry/templates/service.yaml create mode 100644 charts/docker-registry/templates/statefulset.yaml create mode 100644 charts/docker-registry/values.yaml diff --git a/charts/docker-registry/.helmignore b/charts/docker-registry/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/docker-registry/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/docker-registry/Chart.yaml b/charts/docker-registry/Chart.yaml new file mode 100644 index 000000000..b7d9c1245 --- /dev/null +++ b/charts/docker-registry/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +description: Docker Registry for Jenkins Infrastructure +name: docker-registry +type: application +version: 1.0.0 +home: https://hub.docker.com/_/registry/ +icon: https://helm.twun.io/docker-registry.png +maintainers: +- email: jenkins-infra-team@googlegroups.com + name: Jenkins Infra Team + url: https://www.jenkins.io/projects/infrastructure/ +sources: +- https://github.com/jenkins-infra/helm-charts diff --git a/charts/docker-registry/templates/_helpers.tpl b/charts/docker-registry/templates/_helpers.tpl new file mode 100644 index 000000000..4e78f6426 --- /dev/null +++ b/charts/docker-registry/templates/_helpers.tpl @@ -0,0 +1,113 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "docker-registry.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "docker-registry.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "docker-registry.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "docker-registry.labels" -}} +helm.sh/chart: {{ include "docker-registry.chart" . }} +{{ include "docker-registry.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "docker-registry.selectorLabels" -}} +app.kubernetes.io/name: {{ include "docker-registry.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + +*/}} +{{- define "docker-registry.dataVolumeName" -}} +{{- end }} + +{{/* + +*/}} +{{- define "docker-registry.dataVolumeMountPath" -}} +/var/lib/registry +{{- end }} + +{{/* +Registry configuration through environment variables +*/}} +{{- define "docker-registry.envs" -}} +- name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: haSharedSecret +- name: REGISTRY_HTTP_ADDR + value: "0.0.0.0:{{ .Values.port }}" + +{{- if .Values.tlsSecretName }} +- name: REGISTRY_HTTP_TLS_CERTIFICATE + value: /etc/ssl/docker/tls.crt +- name: REGISTRY_HTTP_TLS_KEY + value: /etc/ssl/docker/tls.key +{{- end -}} + +# Proxy mode (eg. registry mirror) requires a filesystem (as file or object storage do not provide expected consistency required by proxy mode) +- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY + value: "{{ include "docker-registry.dataVolumeMountPath" . }}" + +{{- if .Values.proxy.enabled }} +- name: REGISTRY_PROXY_REMOTEURL + value: {{ required ".Values.proxy.remoteurl is required" .Values.proxy.remoteurl }} +- name: REGISTRY_PROXY_USERNAME + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: proxyUsername +- name: REGISTRY_PROXY_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: proxyPassword +{{- end -}} + +{{- if .Values.persistence.deleteEnabled }} +- name: REGISTRY_STORAGE_DELETE_ENABLED + value: "true" +{{- end -}} + +{{- with .Values.extraEnvVars }} +{{ toYaml . }} +{{- end -}} + +{{- end -}} diff --git a/charts/docker-registry/templates/configmap.yaml b/charts/docker-registry/templates/configmap.yaml new file mode 100644 index 000000000..48173cc07 --- /dev/null +++ b/charts/docker-registry/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "docker-registry.fullname" . }}-config + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: {{ include "docker-registry.labels" . | nindent 4 }} +data: + config.yml: |- +{{ toYaml .Values.configData | indent 4 }} diff --git a/charts/docker-registry/templates/secret.yaml b/charts/docker-registry/templates/secret.yaml new file mode 100644 index 000000000..6272941ef --- /dev/null +++ b/charts/docker-registry/templates/secret.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "docker-registry.fullname" . }}-secret + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "docker-registry.labels" . | nindent 4 }} +type: Opaque +data: + {{- if .Values.secrets.haSharedSecret }} + haSharedSecret: {{ .Values.secrets.haSharedSecret | b64enc | quote }} + {{- else }} + haSharedSecret: {{ randAlphaNum 16 | b64enc | quote }} + {{- end }} + proxyUsername: {{ .Values.proxy.username | default "" | b64enc | quote }} + proxyPassword: {{ .Values.proxy.password | default "" | b64enc | quote }} diff --git a/charts/docker-registry/templates/service.yaml b/charts/docker-registry/templates/service.yaml new file mode 100644 index 000000000..a7f8d3776 --- /dev/null +++ b/charts/docker-registry/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "docker-registry.fullname" . }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "docker-registry.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + protocol: TCP + name: {{ if .Values.tlsSecretName }}https{{ else }}http{{ end }} + targetPort: {{ .Values.port }} + selector: + {{- include "docker-registry.selectorLabels" . | nindent 4 }} diff --git a/charts/docker-registry/templates/statefulset.yaml b/charts/docker-registry/templates/statefulset.yaml new file mode 100644 index 000000000..637fdbaf5 --- /dev/null +++ b/charts/docker-registry/templates/statefulset.yaml @@ -0,0 +1,121 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "docker-registry.fullname" . }} + labels: + {{- include "docker-registry.labels" . | nindent 4 }} +spec: + serviceName: {{ include "docker-registry.fullname" . }} + replicas: {{ .Values.replicaCount }} + strategy: {} + selector: + matchLabels: + {{- include "docker-registry.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "docker-registry.selectorLabels" . | nindent 8 }} + spec: + automountServiceAccountToken: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: {{ include "docker-registry.envs" . | nindent 12 }} + ports: + - name: http + containerPort: {{ .Values.port }} + protocol: TCP + # livenessProbe: + # httpGet: + # path: / + # port: {{ .Values.port }} + # {{- if .Values.tlsSecretName }} + # scheme: HTTPS + # {{- end }} + # readinessProbe: + # httpGet: + # path: / + # port: {{ .Values.port }} + # {{- if .Values.tlsSecretName }} + # scheme: HTTPS + # {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ include "docker-registry.dataVolumeMountPath" . }} + - name: "{{ template "docker-registry.fullname" . }}-config" + mountPath: "/etc/docker/registry" + {{- if .Values.tlsSecretName }} + - mountPath: /etc/ssl/docker + name: tls-cert + readOnly: true + {{- end }} + {{- with .Values.extraVolumeMounts }} + {{ toYaml . | nindent 10 }} + {{- end }} + volumes: + - name: {{ template "docker-registry.fullname" . }}-config + configMap: + name: {{ template "docker-registry.fullname" . }}-config + {{- if .Values.tlsSecretName }} + - name: tls-cert + secret: + secretName: {{ .Values.tlsSecretName }} + {{- end }} + {{- with .Values.extraVolumes }} + {{ toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + spec: + {{- with .Values.persistence.storageClass }} + storageClassName: {{ . }} + {{- end }} + accessModes: + - {{ required ".Values.persistence.accessMode is required" .Values.persistence.accessMode }} + resources: + requests: + storage: "{{ required ".Values.persistence.size is required" .Values.persistence.size }}" + {{- else }} + - name: data + emptyDir: {} + {{- end }} diff --git a/charts/docker-registry/values.yaml b/charts/docker-registry/values.yaml new file mode 100644 index 000000000..db6879b6c --- /dev/null +++ b/charts/docker-registry/values.yaml @@ -0,0 +1,121 @@ +# Default values for docker-registry. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +replicaCount: 1 + +image: + repository: registry + tag: 2.8.3 + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +podAnnotations: {} + +containerSecurityContext: + enabled: true + seLinuxOptions: {} + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +securityContext: + enabled: true + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1000 + +port: 5000 + +service: + type: ClusterIP + port: 5000 + annotations: {} + # foo.io/bar: "true" + labels: {} + # foo.io/baz: "false" + + ### TODO: to expose metrics + +resources: {} +# limits: +# cpu: 100m +# memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi + +### TODO: Datadog Integration +# datadog: +# metricsCollection: +# enabled: true +# logCollection: +# enabled: true + +nodeSelector: {} +tolerations: [] +affinity: {} + +initContainers: [] +## Init containers to add to the Deployment +# - name: init +# image: busybox +# command: [] + +configData: + version: 0.1 + log: + fields: + service: registry + storage: + cache: + blobdescriptor: inmemory + http: + # headers: + # X-Content-Type-Options: [nosniff] + # debug: + # addr: :5001 + # prometheus: + # enabled: false + # path: /metrics + health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +# Set this to name of secret for tls certs +# tlsSecretName: registry.docker.example.com + +### TODO +# secrets: +# haSharedSecret: "" + +# https://docs.docker.com/registry/recipes/mirror/ +proxy: + enabled: false + remoteurl: https://registry-1.docker.io + username: "" + password: "" + +persistence: + enabled: false + accessMode: "ReadWriteOnce" + size: 10Gi + # deleteEnabled: true + # storageClass: "-" + +extraEnvVars: [] +## Additional ENV variables to set +# - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY +# value: "/var/lib/example"