Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Helm chart for hosting container on Kubernetes #4

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions helm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v2
name: crushftp
description: Share your files securely with FTP, Implicit FTPS, SFTP, HTTP, or HTTPS using CrushFTP
type: application
version: 1.0.3
appVersion: 10.4.0
101 changes: 101 additions & 0 deletions helm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# CrushFTP for Kubernetes

Share your files securely with FTP, Implicit FTPS, SFTP, HTTP, or HTTPS using CrushFTP using Helm and docker.

This Helm chart will perform the following actions:
1. Create the desired number of CrushFTP instances.
2. Create a Persistent Volume Claim for all of the instances to store config data.
3. Create a secret that stores Azure File Share account information.
4. Mount a directory on each container instance that connects to the Azure File Share. This is used for FTP files.
5. Create an Ingress for the K8s cluster that can handle certificates.
6. Create LoadBalancer instance and setup CrushFTP ports.

# Getting started with helm

Prerequisites:
1. Create Azure Storage Account and Azure File Share. Note the Storage Account Key.
2. Create a DNS record for the desired host name of CrushFTP (ftp.company.com). This should be an A record that points to the K8s Ingress controller.

Install the chart.

```
helm install crushftp . -f values.yaml -n namespace --create-namespace --set azure.client.default.key=foo
```

## Helm chart values

Override helm chart values with the settings you want.

| Parameter | Description | Default |
| ---------------------------- | ------------------------------------------------------------------------------------------------------- | ------------ |
| admin.username | Username for the initial admin account. | crushadmin |
| admin.password | Password for the initial admin account. | *generated* |
| admin.protocol | Protocol for health checks and probs. | http |
| admin.port | Port for health checks and probs. | 8080 |
| features.enableFtp | Used to enable FTP protocol if needed. | false |
| tls.secretName | Name of the secret to use for the TLS certificate. | crushftp-tls |
| volumes | Volume to mount for FTP root folder. | /ftproot |
| configVolume.size | Size of the CrushFTP configuration volume. | 8Gi |
| loadBalancerIp | IP address of the ingress to use. | 127.0.0.1 |
| shared.hosts.crushFtp.root | Root domain of the sftp site. | .local.com |
| shared.hosts.crushFtp.prefix | Prefix or sub-domain of the sftp site. | \ ftp |
| shared.ingress.clusterIssuer | Used to enable a cluster certificate issuer such as cert-manager and lets-encrypt. | '' |
| shared.storageClassName | Sets the storage class to use for the config volume. | default |

## Volumes

| Volume | Required | Function | Example |
| --------------------- | -------- | ---------------------------------------------------------- | ----------------------------------------------------- |
| `/var/opt/crushftp` | Yes | Persistent storage for CrushFTP config | `/your/config/path/:/var/opt/crushftp`. |
| `/ftproot` | No | Mounts Azure File Share to this directory in the container | `/StorageAccount/FileShare/ShareName/:/ftproot` |

* You can add as many volumes as you want between host and the container and change their mount location within the container. You will configure individual folder access and permissions for each user in CrushFTPs User Manager.

## Ports

| Port | Proto | Required | Function | Example |
| ----------- | ----- | -------- | ----------------- | --------------------- |
| `21` | TCP | Yes | FTP Port | `21:21` |
| `443` | TCP | Yes | HTTPS Port | `443:443` |
| `2000-2100` | TCP | Yes | Passive FTP Ports | `2000-2100:2000-2100` |
| `2222` | TCP | Yes | SFTP Port | `2222:2222` |
| `8080` | TCP | Yes | HTTP Port | `8080:8080` |
| `9090` | TCP | Yes | HTTP Alt Port | `9090:9090` |

* If you wish to run certain protocols on different ports you will need to change these to match the CrushFTP config. If you enable implicit or explicit FTPS those ports will also need to be opened.

## Environment Variables

| Variable | Description | Default |
| :--------------------- | :------------------------ | :----------- |
| `CRUSH_ADMIN_USER` | Admin user of CrushFTP | `crushadmin` |
| `CRUSH_ADMIN_PASSWORD` | Password for admin user | `crushadmin` |
| `CRUSH_ADMIN_PROTOCOL` | Protocol for health cecks | `http` |
| `CRUSH_ADMIN_PORT` | Port for health cecks | `8080` |

## Installation

Run this container and mount the containers `/var/opt/crushftp` volume to the host to keep CrushFTP's configuration persistent. Open a browser and go to `http://<IP>:8080`. Note that the default username and password are both `crushadmin` unless the default environment variables are changed.

This command will create a new container and expose all ports. Remember to change the `<volume>` to a location on your host machine.

```
docker run -p 21:21 -p 443:443 -p 2000-2100:2000-2100 -p 2222:2222 -p 8080:8080 -p 9090:9090 -v <volume>:/var/opt/crushftp netlah/crushftp:latest
```

# CrushFTP Configuration

Visit the [CrushFTP 10 Wiki](https://www.crushftp.com/crush10wiki/)


## Publishing docker image

1. Set the `.env` file `DOCKER_TAG` variable to the new version
2. Build the image:

```bash
docker-compose build --no-cache
```

- Docker image based on https://github.com/NetLah/docker-crushftp
- [CrushFTP - Linux Install](https://www.crushftp.com/crush10wiki/Wiki.jsp?page=Linux%20Install)
4 changes: 4 additions & 0 deletions helm/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{ .Chart.Description }}
Crush FTP is now accessible at https://{{ .Values.shared.hosts.crushFtp.prefix }}{{ .Values.shared.hosts.crushFtp.root }}
View the container logs for temporary password.
This will show as deployment and pod {{ template "crushftp.fullname" . }} in namespace {{ .Release.Namespace }}.
70 changes: 70 additions & 0 deletions helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "crushftp.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 "crushftp.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 "crushftp.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "crushftp.labels" -}}
helm.sh/chart: {{ include "crushftp.chart" . }}
{{ include "crushftp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "crushftp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "crushftp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
nodeselector
*/}}
{{- define "crushftp.nodeSelector" -}}
kubernetes.io/os: linux
environment: {{ .Values.nodeselector }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "crushftp.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "crushftp.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
119 changes: 119 additions & 0 deletions helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.clustername | lower }}
labels:
{{- include "crushftp.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "crushftp.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "crushftp.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "crushftp.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: CRUSH_ADMIN_USER
value: {{ .Values.admin.username | quote }}
- name: CRUSH_ADMIN_PASSWORD
value: {{ .Values.admin.password | quote }}
- name: CRUSH_ADMIN_PROTOCOL
value: {{ .Values.admin.protocol | quote }}
- name: CRUSH_ADMIN_PORT
value: {{ .Values.admin.port | quote }}
ports:
- name: http
containerPort: {{ .Values.admin.port }}
protocol: TCP
- name: http-alt
containerPort: 9090
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
- name: sftp
containerPort: 2222
protocol: TCP
{{- if .Values.features.enableFtp }}
- name: ftp
containerPort: 21
protocol: TCP
{{- range (untilStep 0 101 1) }}
- name: 'ftp-pas-{{ . }}'
containerPort: {{ add 2000 . }}
protocol: TCP
{{- end }}
{{- end }}
livenessProbe:
httpGet:
path: /
port: http
timeoutSeconds: 10
failureThreshold: 3
periodSeconds: 10
startupProbe:
httpGet:
path: /
port: http
failureThreshold: 24
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: http
timeoutSeconds: 10
failureThreshold: 3
periodSeconds: 10
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: config-volume
mountPath: /var/opt/crushftp
{{- range .Values.volumes }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- end }}
volumes:
- name: config-volume
persistentVolumeClaim:
claimName: {{ include "crushftp.fullname" . }}
{{- range .Values.volumes }}
- name: {{ .name }}
csi:
driver: file.csi.azure.com
readOnly: false
volumeAttributes:
secretName: {{ $.Values.clustername }}-azurefiles
shareName: share
{{- end }}
nodeSelector:
kubernetes.io/os: linux
{{- if .Values.nodeSelector }}
environment: {{ .Values.nodeSelector }}
tolerations:
- key: environment
operator: Equal
value: {{ .Values.nodeSelector }}
effect: NoExecute
{{- end }}
50 changes: 50 additions & 0 deletions helm/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{{- $fullName := include "crushftp.fullname" . -}}
{{- $rootUrl := printf "%s%s" .Values.shared.hosts.crushFtp.prefix .Values.shared.hosts.crushFtp.root -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "crushftp.labels" . | nindent 4 }}
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/ssl-redirect: "True"
nginx.ingress.kubernetes.io/proxy-body-size: 100m
{{- if .Values.shared.ingress.clusterIssuer }}
cert-manager.io/cluster-issuer: {{ .Values.shared.ingress.clusterIssuer }}
{{- end }}
{{- with .Values.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
tls:
- hosts:
- {{ $rootUrl | quote }}
secretName: {{ .Values.tls.secretName }}
rules:
- host: {{ $rootUrl | quote }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ $fullName }}-cluster
port:
number: 443
13 changes: 13 additions & 0 deletions helm/templates/pvc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "crushftp.fullname" . }}
labels:
{{- include "crushftp.labels" . | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
storageClassName: {{ .Values.shared.storageClassName }}
resources:
requests:
storage: {{ .Values.configVolume.size }}
9 changes: 9 additions & 0 deletions helm/templates/secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{- if .Values.azure.client.default.account }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.clustername | lower }}-azurefiles
data:
azurestorageaccountname: {{ .Values.azure.client.default.account | b64enc }}
azurestorageaccountkey: {{ required "Need to supply storage account access key for .Values.azure.client.default.account via --set azure.client.default.key=foo" .Values.azure.client.default.key | b64enc }}
{{- end }}
15 changes: 15 additions & 0 deletions helm/templates/service-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "crushftp.fullname" . }}-cluster
labels:
{{- include "crushftp.labels" . | nindent 4 }}
spec:
type: ClusterIP
ports:
- name: https
port: 443
targetPort: 443
protocol: TCP
selector:
{{- include "crushftp.selectorLabels" . | nindent 4 }}
Loading