diff --git a/apps-helm/samba4/Chart.yaml b/apps-helm/samba4/Chart.yaml new file mode 100644 index 0000000..6da6874 --- /dev/null +++ b/apps-helm/samba4/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "4.8" +description: A Samba Helm chart for Kubernetes +name: samba4 +version: 0.1.2 diff --git a/apps-helm/samba4/conf/smb.conf b/apps-helm/samba4/conf/smb.conf new file mode 100755 index 0000000..cc7ffcc --- /dev/null +++ b/apps-helm/samba4/conf/smb.conf @@ -0,0 +1,36 @@ +[global] + workgroup = {{ .Values.samba.global.workgroup }} + server string = {{ .Values.samba.global.server_string | default "%h server (Samba, Alpine)" }} + security = {{ .Values.samba.global.security | default "user" }} + map to guest = {{ .Values.samba.global.map_to_guest | default "Bad User" }} + encrypt passwords = {{ .Values.samba.global.encrypt_passwords | default "yes" }} + load printers = no + printing = bsd + printcap name = /dev/null + disable spoolss = yes + disable netbios = yes + server role = {{ .Values.samba.global.server_role | default "standalone" }} + server services = -dns, -nbt + smb ports = {{ .Values.samba.global.smb_ports | default "445" }} + log level = {{ .Values.samba.global.log_level | default "3" }} +{{- range .Values.samba.global.extraLines }} + {{ .key }} = {{ .value }} +{{- end }} + +[{{ .Values.samba.share.nameOverride | default "data" }}] + path = /data + comment = {{ .Values.samba.share.comment | default "ZFS" }} + browseable = {{ .Values.samba.share.browseable | default "yes" }} + writable = {{ .Values.samba.share.writable | default "yes" }} +{{- range .Values.samba.share.extraLines }} + {{ .key }} = {{ .value }} +{{- end }} + +{{ range .Values.persistence.extraPVCShares }} +[{{ .name }}] + path = /extras/{{ .name }} + comment = {{ .comment | default "ZFS" }} + browseable = {{ .browseable | default "yes" }} + writable = {{ .writable | default "yes" }} +{{- end }} +;EOF way past actual end of file \ No newline at end of file diff --git a/apps-helm/samba4/scripts/k8s.sh b/apps-helm/samba4/scripts/k8s.sh new file mode 100755 index 0000000..c16abd8 --- /dev/null +++ b/apps-helm/samba4/scripts/k8s.sh @@ -0,0 +1,30 @@ +#!/bin/sh +#passwd files need to be stored on the persistent storage +if [ ! -f /privatepersist/etc/passwd ]; then + mkdir -p /privatepersist/etc + cp /etc/passwd /privatepersist/etc/passwd +fi +rm -f /etc/passwd +ln -s /privatepersist/etc/passwd /etc/passwd +#tdb files need to be stored on the persistent storage +if [ ! -f /privatepersist/varlibsamba/private/passdb.tdb ]; then + mkdir /privatepersist/varlibsamba + tar c -C /var/lib/samba . | tar x -C /privatepersist/varlibsamba +fi +rm -rf /var/lib/samba +ln -s /privatepersist/varlibsamba /var/lib/samba +#create required users +if ! md5sum -c /privatepersist/k8s-users-checksum > /dev/null 2>&1; then + rm /var/lib/samba/private/passdb.tdb + if [ -s /secrets/create-users ]; then + for line in $(cat /secrets/create-users); do + USER=$(echo $line | cut -f1 -d:) + PASS=$(echo $line | cut -f2 -d:) + adduser -s /sbin/nologin -h /home/samba -H -D $USER + yes "$PASS" | smbpasswd -a $USER + done + fi + md5sum /secrets/create-users > /privatepersist/k8s-users-checksum +fi +# bug where smbd stops on "end of input" +ionice -c 3 smbd --foreground --log-stdout < /dev/null \ No newline at end of file diff --git a/apps-helm/samba4/templates/NOTES.txt b/apps-helm/samba4/templates/NOTES.txt new file mode 100644 index 0000000..89f9f47 --- /dev/null +++ b/apps-helm/samba4/templates/NOTES.txt @@ -0,0 +1,25 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "samba4.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo smb://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "samba4.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "samba4.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo smb://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "samba4.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "You will need to ensure samba is not running locally, then you can use smb://127.0.0.1/" + kubectl port-forward $POD_NAME 445:445 + + You can also access the service inside the cluster directly with smb://{{ include "samba4.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local +{{- end }} + +{{ if not .Values.samba.users }} +You have not specified any users to be created, so you will need to create them by hand. Execute the following command and then inside it, the next two : + +kubectl exec -it $POD_NAME sh +$ adduser -s /sbin/nologin -h /home/samba -H -D {username} +$ smbpasswd -a {username} +{{- end }} diff --git a/apps-helm/samba4/templates/_helpers.tpl b/apps-helm/samba4/templates/_helpers.tpl new file mode 100644 index 0000000..31c0377 --- /dev/null +++ b/apps-helm/samba4/templates/_helpers.tpl @@ -0,0 +1,38 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "samba4.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 "samba4.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 "samba4.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "userstocreate" -}} +{{- range .Values.samba.users }} +{{ .username }}:{{ .password }} +{{ end -}} +{{- end -}} diff --git a/apps-helm/samba4/templates/configmap-script.yaml b/apps-helm/samba4/templates/configmap-script.yaml new file mode 100755 index 0000000..54583be --- /dev/null +++ b/apps-helm/samba4/templates/configmap-script.yaml @@ -0,0 +1,14 @@ +{{ if .Values.image.lacksK8sScript -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "samba4.fullname" . }}-packagescripts + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +data: + k8s.sh: |- +{{ tpl (.Files.Get "scripts/k8s.sh") . | indent 6 }} +{{ end -}} \ No newline at end of file diff --git a/apps-helm/samba4/templates/configmap-smbconf.yaml b/apps-helm/samba4/templates/configmap-smbconf.yaml new file mode 100755 index 0000000..1f1a64c --- /dev/null +++ b/apps-helm/samba4/templates/configmap-smbconf.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "samba4.fullname" . }}-smbconf + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +data: + smb.conf: |- +{{ tpl (.Files.Get "conf/smb.conf") . | indent 6 }} \ No newline at end of file diff --git a/apps-helm/samba4/templates/deployment.yaml b/apps-helm/samba4/templates/deployment.yaml new file mode 100644 index 0000000..8ebd424 --- /dev/null +++ b/apps-helm/samba4/templates/deployment.yaml @@ -0,0 +1,176 @@ +{{ $smbconfchecksum := tpl (.Files.Get "conf/smb.conf") . | sha256sum -}} +{{ $userschecksum := include "userstocreate" . | sha256sum -}} +{{ $scriptchecksum := tpl (.Files.Get "scripts/k8s.sh") . | sha256sum -}} +{{ $fullName := include "samba4.fullname" . }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $fullName }} + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + checksum/smbconf: {{ $smbconfchecksum }} + checksum/users: {{ $userschecksum }} +{{ if .Values.image.lacksK8sScript -}} + checksum/script: {{ $scriptchecksum }} +{{- end }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + checksum/smbconf: {{ $smbconfchecksum }} + checksum/users: {{ $userschecksum }} +{{- if .Values.image.lacksK8sScript }} + checksum/script: {{ $scriptchecksum }} +{{- end }} + spec: + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + command: + - /bin/sh + - -c + - cd /scripts ; sh ./k8s.sh + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: cifs + containerPort: 445 + protocol: TCP +{{- if .Values.livenessProbe.enabled | default true }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + - {{ .Values.livenessProbe.command | default "echo | smbclient -L 127.0.0.1" | quote }} +{{- end }} + readinessProbe: + tcpSocket: + port: cifs + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: +{{- if .Values.image.lacksK8sScript }} + - mountPath: /configmaps/scripts + name: scripts +{{- end }} + - mountPath: /secrets + name: users + - mountPath: /etc/samba/smb.conf + name: smbconf + subPath: smb.conf + - mountPath: /data + name: data + {{- range .Values.persistence.extraPVCShares }} + - mountPath: /extras/{{ .name }} + name: {{ .name }} + {{- end }} + - mountPath: /privatepersist + name: private + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: +{{ if .Values.image.lacksK8sScript -}} + - name: scripts + configMap: + name: {{ $fullName }}-packagescripts + defaultMode: 0555 + items: + - key: k8s.sh + path: k8s.sh +{{- end }} + - name: smbconf + configMap: + name: {{ $fullName }}-smbconf + defaultMode: 0644 + items: + - key: smb.conf + path: smb.conf + - name: users + secret: + secretName: {{ $fullName }}-users + defaultMode: 0600 + - name: data +{{ if .Values.persistence.enabled -}} +{{ if eq .Values.persistence.type "pvc" }} + persistentVolumeClaim: + claimName: {{ if .Values.persistence.pvc.existingClaim }}{{ .Values.persistence.pvc.existingClaim }}{{- else }}{{ template "samba4.fullname" . }}-data{{- end }} +{{ else if eq .Values.persistence.type "flexVolume" }} +#{{ required "A valid flexVolume block is required when using flexVolume persistence!" .Values.persistence.flexVolume }} + flexVolume: +{{ .Values.persistence.flexVolume | toYaml | indent 10 }} +{{- else if eq .Values.persistence.type "hostPath" }} +#{{ required "A valid hostPath.path is required when using hostPath persistence!" .Values.persistence.hostPath.path }} + hostPath: + path: {{ .Values.persistence.hostPath.path }} +{{ if .Values.persistence.hostPath.type -}} + type: {{ .Values.persistence.hostPath.type }} +{{ end -}} +{{ else if eq .Values.persistence.type "other" -}} +#{{ required "A valid other block is required when using flexVolume persistence!" .Values.persistence.other }} +{{ .Values.persistence.other | toYaml | indent 8 }} +{{ else -}} +{{ fail "if persistence is enabled, persistence.type must be one of 'pvc','flexVolume','hostPath' or 'other'!" }} +{{ end -}} +{{ else }} + emptyDir: {} +{{ end }} + - name: private +{{ if .Values.privatePersistence.enabled -}} +{{- $p := .Values.persistence -}} +{{- $pp := .Values.privatePersistence -}} +{{- if eq ($pp.type | default $p.type) "pvc" }} + persistentVolumeClaim: + claimName: {{ if $pp.pvc.existingClaim }}{{ $pp.pvc.existingClaim }}{{- else }}{{ template "samba4.fullname" . }}-private{{- end }} +{{ else if eq ($pp.type | default $p.type) "flexVolume" }} +#{{ required "A valid flexVolume block is required when using hostPath persistence!" $pp.flexVolume }} + flexVolume: +{{ $pp.flexVolume | toYaml | indent 10 }} +{{ else if eq ($pp.type | default $p.type) "hostPath" }} +#{{ required "A valid flexVolume block is required when using flexVolume persistence!" .Values.privatePersistence.flexVolume }} + hostPath: + path: {{ if .Values.privatePersistence.hostPath.path }}{{ .Values.privatePersistence.hostPath.path }}{{ else }}{{ .Values.persistence.hostPath.path }}/.smbprivate/{{ end }} +{{ if .Values.privatePersistence.hostPath.type -}} + type: {{ $pp.hostPath.type | $p.hostPath.type | default "Directory" | quote }} +{{ end -}} +{{ else if eq ($pp.type | default $p.type) "other" -}} +#{{ required "A valid other block is required when using flexVolume persistence!" .Values.privatePersistence.other }} +{{ $pp.other | toYaml | indent 8 }} +{{ else -}} +{{ fail "if privatePersistence is enabled, privatePersistence.type must be one of 'pvc','flexVolume','hostPath' or 'other'!" }} +{{ end -}} +{{ else }} + emptyDir: {} +{{ end -}} +{{ if .Values.persistence.enabled }} + {{- range .Values.persistence.extraPVCShares }} + - name: {{ .name }} + persistentVolumeClaim: + claimName: {{ $fullName }}-{{ .name }} + {{- end }} +{{ end -}} \ No newline at end of file diff --git a/apps-helm/samba4/templates/pvc.yaml b/apps-helm/samba4/templates/pvc.yaml new file mode 100755 index 0000000..ba4ba10 --- /dev/null +++ b/apps-helm/samba4/templates/pvc.yaml @@ -0,0 +1,64 @@ +{{ $fullName := include "samba4.fullname" . }} +{{- if and .Values.persistence.enabled ( eq .Values.persistence.type "pvc") -}} + {{- if not .Values.persistence.pvc.existingClaim -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $fullName }}-data +spec: + accessModes: + - {{ .Values.persistence.pvc.accessMode | default "ReadWriteOnce" | quote }} + resources: + requests: + storage: {{ .Values.persistence.pvc.size | default "8Gi" | quote }} + {{- if .Values.persistence.pvc.storageClass }} + {{- if (eq "-" .Values.persistence.pvc.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistence.pvc.storageClass }}" + {{- end }} + {{- end }} + {{- end }} + {{- range .Values.persistence.extraPVCShares }} +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $fullName }}-{{ .name }} +spec: + accessModes: + - {{ .accessMode | default "ReadWriteOnce" | quote }} + resources: + requests: + storage: {{ .size | default "8Gi" | quote }} + {{- if .storageClass }} + {{- if (eq "-" .storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .storageClass }}" + {{- end }} + {{- end }} + {{- end }} +{{- end }} +--- +{{- if .Values.privatePersistence.enabled }} +{{- if and (eq (.Values.privatePersistence.type | default .Values.persistence.type) "pvc") (not .Values.privatePersistence.pvc.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $fullName }}-private +spec: + accessModes: + - {{ .Values.privatePersistence.pvc.accessMode | default .Values.persistence.pvc.accessMode | default "ReadWriteOnce" | quote }} + resources: + requests: + storage: {{ .Values.privatePersistence.pvc.size | default .Values.persistence.pvc.size | default "20Mi" | quote }} +{{- if .Values.privatePersistence.pvc.storageClass }} +{{- if (eq "-" (.Values.privatePersistence.pvc.storageClass | default .Values.persistence.pvc.storageClass)) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.privatePersistence.pvc.storageClass | default .Values.persistence.pvc.storageClass }}" +{{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/apps-helm/samba4/templates/secret.yaml b/apps-helm/samba4/templates/secret.yaml new file mode 100755 index 0000000..f709259 --- /dev/null +++ b/apps-helm/samba4/templates/secret.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "samba4.fullname" . }}-users + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +data: + create-users: {{ include "userstocreate" . | b64enc }} diff --git a/apps-helm/samba4/templates/service.yaml b/apps-helm/samba4/templates/service.yaml new file mode 100644 index 0000000..316c943 --- /dev/null +++ b/apps-helm/samba4/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "samba4.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: cifs + protocol: TCP + name: cifs + selector: + app.kubernetes.io/name: {{ include "samba4.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/apps-helm/samba4/templates/tests/test-connection.yaml b/apps-helm/samba4/templates/tests/test-connection.yaml new file mode 100644 index 0000000..e7ea1a6 --- /dev/null +++ b/apps-helm/samba4/templates/tests/test-connection.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "samba4.fullname" . }}-test-connection" + labels: + app.kubernetes.io/name: {{ include "samba4.name" . }} + helm.sh/chart: {{ include "samba4.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: smbclient + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + command: ['smbclient'] + args: ['-L','{{ include "samba4.fullname" . }}'] + restartPolicy: Never diff --git a/apps-helm/samba4/values.yaml b/apps-helm/samba4/values.yaml new file mode 100644 index 0000000..fa4771b --- /dev/null +++ b/apps-helm/samba4/values.yaml @@ -0,0 +1,74 @@ +# Default values for samba4. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + # note: lots more pulls of stanback/alpine-samba so understandable + # if you want to use that. Just remember it doesn't contain the script + # so set the flag to true also. That said, it only has one tag, and isn't + # an automated build so you might be better with the below image. + repository: imartyn/samba4k8s + lacksK8sScript: false + #repository: stanback/alpine-samba + #lacksK8sScript: true + tag: stable + pullPolicy: IfNotPresent + +nameOverride: "" +fullnameOverride: "" + +podSecurityContext: + fsGroup: 1000 + +samba: + global: + workgroup: WORKGROUP + share: {} + users: [] + +persistence: + enabled: true + type: pvc + pvc: + accessMode: ReadWriteOnce + size: 5Ti + storageClass: "spinny" + other: + emptyDir: {} + extraPVCShares: [] + +privatePersistence: + enabled: false + pvc: + accessMode: ReadWriteOnce + size: 20Mi + storageClass: "-" + other: + emptyDir: {} + +livenessProbe: + enabled: true + +service: + type: ClusterIP + port: 445 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {}