= Implementation

#show raw.where(block: false): box.with(
  fill: luma(240),
  inset: (x: 3pt, y: 0pt),
  outset: (y: 3pt),
  radius: 2pt,
)

== Development Environment Setup

The development of the One-Click Deployment system necessitates a specifically configured environment to support the technologies used. This setup includes a Kubernetes cluster, which is central to deploying and managing containerized applications. Developers need to install Docker to containerize the application, ensuring consistent operation across different environments. The backend development leverages Go, requiring a Go environment setup, while the frontend uses Node.js and SvelteKit #footnote[https://kit.svelte.dev/], necessitating the installation of Node.js and the appropriate npm packages. \
The development environment setup involves:
- A Kubernetes cluster either locally via Minikube #footnote[https://minikube.sigs.k8s.io/docs/] or as a Managed Service at Natron Tech AG #footnote[https://natron.ch].
- Docker #footnote[https://docker.com] installation for building and managing containers.
- Node.js #footnote[https://nodejs.org/en] and npm #footnote[https://www.npmjs.com/] to handle various frontend dependencies and build processes.
- Go #footnote[https://go.dev/] environment for backend development, set to the appropriate version to ensure compatibility with all dependencies and libraries used.

These tools and setups form the backbone of the development infrastructure, providing a robust platform for building, testing, and deploying the system components efficiently.

Generally, the development environment are described in detail in the corresponding *README* files of the respective repositories.

== Core Functionality Implementation

=== Design Goals

The main goal of the One-Click Deployment system is to put *convention over configuration*. This means that the user should not have to deal with the details of Kubernetes resources like Deployments, Services, Ingresses, etc. The user should only have to define highly abstracted values like the amount of replicas, the container image, the environment variables, etc. To make it even easier for the user, the system provides a blueprint functionality of these abstracted values for certain use cases. The user can then create a new deployment based on a blueprint and only has to adjust the values which are different from the blueprint. For example, the user can create a blueprint for a Node-RED deployment and then create a new deployment based on this blueprint and only has to adjust minor things like the URL where the Node-RED instance should be available. This way the user can deploy complex applications with only a few clicks.

The system also provides a real time monitoring of the deployed application. The user can see the current CPU and memory usage of the pods and can also see the Kubernetes resources generated by the deployment like pods, services, ingresses, etc. The user can also interact with these resources like viewing logs, events, and yaml configurations.

The system also provides a rollback functionality. Each time the user changes the deployment configuration a new rollout gets triggered. The user can then see the old rollouts and the current one. The user can also rollback to a previous rollout. This functionality is like a snapshot of the deployment configuration at a specific time.

With the implementation of the Kubernetes Operator, the system can by design be easily extended with new resources and functionalities. The system is also designed to be highly scalable and reliable. In the end the CRD (Custom Resource Definition #footnote[https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/]) Rollout is the core abstraction of the system. Then the Kubernetes Operator takes care of the rest. To make this level of abstraction more accessible to the user, the system provides a web interface where the user can interact with the system and which it's core functionality is to create and manage Rollout resources.

With this design goals in mind, the core functionality of the system was implemented.

#pagebreak()

=== Deployment Module (Kubernetes Operator)

The Kubernetes Operator within the One-Click Deployment platform acts as a core component, designed to simplify the management of deployments within the Kubernetes ecosystem. It automates the process of deploying, updating, and maintaining containerized applications. Using Custom Resource Definitions (CRDs), the operator allows users to define their applications in a declarative manner. \

The development of this module involved using the Operator SDK #footnote[https://sdk.operatorframework.io/], which provides tools and libraries to build Kubernetes operators in Go. This SDK facilitates the monitoring of resource states within the cluster, handling events such as creation, update, and deletion of resources.

In the #emph("controllers") directory of the #emph("one-click-operator repository") #footnote[https://github.com/janlauber/one-click-operator] on GitHub, the core functionality of the operator is implemented. This includes the reconciliation loop, which continuously monitors the state of resources and ensures that the desired state is maintained. The operator interacts with the Kubernetes API to create and manage resources, such as Deployments, Services, and ConfigMaps, based on the user-defined specifications. \ \
*Kubernetes Resources managed by the operator include:*
- *ServiceAccount* #footnote[https://kubernetes.io/docs/concepts/security/service-accounts/]: A service account provides an identity for processes that run in a Pod.
- *PersistentVolumeClaim (PVC)* #footnote[https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims]: A PVC is a request for storage by a user.
- *Secret* #footnote[https://kubernetes.io/docs/concepts/configuration/secret/]: A Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key.
- *Deployment* #footnote[https://kubernetes.io/docs/concepts/workloads/controllers/deployment/]: A Deployment provides declarative updates to Pods and ReplicaSets.
- *Service* #footnote[https://kubernetes.io/docs/concepts/services-networking/service/]: A Service is a networking Layer 3/4 load balancer which exposes the pods within the Kubernetes cluster.
- *Ingress* #footnote[https://kubernetes.io/docs/concepts/services-networking/ingress/]: An Ingress is similar to a Reverse Proxy and exposes HTTP and HTTPS routes from outside the cluster to services within the cluster.
- *HorizontalPodAutoscaler (HPA)* #footnote[https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]: An HPA automatically scales the number of pods in a deployment based on observed CPU utilization.
- *CronJob* #footnote[https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/]: A CronJob creates Jobs on a repeating schedule.

All these resources are managed by the operator based on the user-defined specifications in the Rollout resource explained in the @crd.

==== Rollout Controller

The *rollout_controller.go* @OneclickoperatorControllersRollout_controller is the primary controller responsible for managing Rollout resources.
The following code snippets illustrate the core functionality of the deployment module:

#set text(8pt)
#show raw.where(block: true): block.with(
  fill: luma(240),
  inset: 10pt,
  radius: 4pt,
)

```go
// RolloutReconciler reconciles a Rollout object
func (r *RolloutReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	log := log.FromContext(ctx)

	// Fetch the Rollout instance
	var rollout oneclickiov1alpha1.Rollout
	if err := r.Get(ctx, req.NamespacedName, &rollout); err != nil {
		if errors.IsNotFound(err) {
			// Object not found
			log.Info("Rollout resource not found.")
			return ctrl.Result{}, nil
		}
		// Error reading the object - requeue the request.
		log.Error(err, "Failed to get Rollout.")
		return ctrl.Result{}, err
	}

	// Reconcile ServiceAccount
	if err := r.reconcileServiceAccount(ctx, &rollout); err != nil {
		log.Error(err, "Failed to reconcile ServiceAccount.")
		return ctrl.Result{}, err
	}

	// Reconcile PVCs, Secrets, Deployment, Service, Ingress, HPA, CronJobs
  [...]

	// Update status of the Rollout
	if err := r.updateStatus(ctx, &rollout); err != nil {
		if errors.IsConflict(err) {
			log.Info("Conflict while updating status. Retrying.")
			return ctrl.Result{Requeue: true}, nil
		}
		log.Error(err, "Failed to update status.")
		return ctrl.Result{}, err
	}

	return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *RolloutReconciler) SetupWithManager(mgr ctrl.Manager) error {
	if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &batchv1.CronJob{}, "metadata.ownerReferences.uid", func(rawObj client.Object) []string {
		cronJob := rawObj.(*batchv1.CronJob)
		ownerRefs := cronJob.GetOwnerReferences()
		ownerUIDs := make([]string, len(ownerRefs))
		for i, ownerRef := range ownerRefs {
			ownerUIDs[i] = string(ownerRef.UID)
		}
		return ownerUIDs
	}); err != nil {
		return err
	}

	return ctrl.NewControllerManagedBy(mgr).
		For(&oneclickiov1alpha1.Rollout{}).
		Owns(&appsv1.Deployment{}).
		Owns(&corev1.Service{}).
		Owns(&networkingv1.Ingress{}).
		Owns(&corev1.Secret{}).
		Owns(&corev1.PersistentVolumeClaim{}).
		Owns(&autoscalingv2.HorizontalPodAutoscaler{}).
		Owns(&corev1.ServiceAccount{}).
		Owns(&batchv1.CronJob{}).
		Complete(r)
}
```

#set text(12pt)

The reconciliation loop continuously monitors the state of Rollout resources, ensuring that the desired state is maintained. The controller reconciles various resources, such as ServiceAccounts, PVCs, Secrets, Deployments, Cronjobs, Services, Ingress, and HPAs, based on the user-defined specifications. The *SetupWithManager* function sets up the controller with the Manager, instructing the manager to start the controller when the Manager is started.

#pagebreak()

==== Rollout Resource Specification <crd>

The core abstraction happens in the Rollout specification definition. This yaml structure was designed with our design goals in mind. The user or web interface then only has to interact with this structure to deploy and manage applications. The following yaml snippet illustrates the Rollout resource specification:

#set text(8pt)
#show raw.where(block: true): block.with(
  fill: luma(240),
  inset: 10pt,
  radius: 4pt,
)

```yaml
apiVersion: one-click.dev/v1alpha1 # current version of the CRD
kind: Rollout # name of the CRD
metadata:
  name: nginx # name of the Rollout
  namespace: test # namespace where the Rollout should be created
spec:
  args: ["nginx", "-g", "daemon off;"] # (optional) arguments for the container
  command: ["nginx"] # (optional) command for the container
  rolloutStrategy: rollingUpdate # or "recreate" (if not specified then "rollingUpdate" is used)
  nodeSelector: # (optional) set specific nodes where the pods should be scheduled
    kubernetes.io/hostname: minikube 
  tolerations: # (optional) set specific tolerations for the pods
    - key: "storage"
      operator: "Equal"
      value: "ssd"
      effect: "NoSchedule"
  image: # container image
    registry: "docker.io"
    repository: "nginx"
    tag: "latest"
    username: "test"
    password: "<PASSWORD>"
  securityContext: # (optional) security context for the container
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    allowPrivilegeEscalation: false
    runAsNonRoot: true
    readOnlyRootFilesystem: true
    privileged: false
    capabilities:
      drop:
        - ALL
      add:
        - NET_BIND_SERVICE
  horizontalScale: # the horizontal scaling configuration
    minReplicas: 1
    maxReplicas: 3
    targetCPUUtilizationPercentage: 80
  resources: # the resource configuration like CPU and memory limits and requests
    requests:
      cpu: "100m"
      memory: "128Mi"
    limits:
      cpu: "200m"
      memory: "256Mi"
  env: # environment variables for the container
    - name: "USERNAME"
      value: "admin"
    - name: DEBUG
      value: "true"
  secrets: # secret environment variables for the container
    - name: "PASSWORD"
      value: "<PASSWORD>"
    - name: "ANOTHER_SECRET"
      value: "122"
  volumes: # persistent volumes for the container
    - name: "data"
      mountPath: "/data"
      size: "2Gi"
      storageClass: "standard"
  interfaces: # the network interfaces for the container
    - name: "http"
      port: 80
    - name: "https"
      port: 443
      ingress:
        ingressClass: "nginx"
        annotations:
          nginx.ingress.kubernetes.io/rewrite-target: /
          nginx.ingress.kubernetes.io/ssl-redirect: "false"
        rules:
          - host: "reflex.oneclickapps.dev"
            path: "/"
            tls: true
            tlsSecretName: "wildcard-tls-secret"
          - host: "reflex.oneclickapps.dev"
            path: "/test"
            tls: false
  cronjobs: # cronjobs for the container
    - name: some-bash-job
      suspend: false
      image:
        password: ""
        registry: docker.io
        repository: library/busybox
        tag: latest
        username: ""
      schedule: "*/1 * * * *"
      command: ["echo", "hello"]
      maxRetries: 3
      backoffLimit: 2
      env:
        - name: SOME_ENV
          value: "some-value"
      resources:
        limits:
          cpu: 500m
          memory: 512Mi
        requests:
          cpu: 100m
          memory: 256Mi
  serviceAccountName: "nginx"
```

#set text(12pt)

Here's a brief overview of the key components:

- `apiVersion` and `kind`: These fields specify the version and type of the Kubernetes Custom Resource Definition (CRD). In this case, the CRD is a *Rollout*.
- `metadata`: This section includes the name of the Rollout and the namespace where it will be created. There are also optional fields for labels and annotations. #footnote[https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata]
- `spec`: This is the heart of the Rollout, containing all the configuration details for the deployment. It includes:
  - `args` and `command`: These optional fields specify the arguments and command for the container.
  - `rolloutStrategy`: This field determines the strategy for updating the pods. It can be either *rollingUpdate* or *recreate*.
  - `nodeSelector` and `tolerations`: These optional fields allow you to control where the pods are scheduled and what conditions they can tolerate.
  - `image`: This section specifies the container image details, including the registry, repository, tag, and credentials.
  - `securityContext`: This optional section defines the security settings for the container.
  - `horizontalScale`: This section configures the horizontal scaling of the pods.
  - `resources`: This section sets the CPU and memory limits and requests for the container.
  - `env` and `secrets`: These sections define the environment variables and secret environment variables for the container.
  - `volumes`: This section configures persistent volumes for the container.
  - `interfaces`: This section sets up the network interfaces for the container.
  - `cronjobs`: This section allows you to define cronjobs for the container.
  - `serviceAccountName`: This field specifies the service account associated with the Rollout.

The deployment module is a critical component of the One-Click Deployment system, automating the deployment and management of containerized applications within the Kubernetes environment. The operator simplifies complex tasks, streamlining the deployment process and ensuring efficient system operations.

#pagebreak()

== Backend Implementation

The backend of the One-Click Deployment system is built using Pocketbase #footnote[https://pocketbase.io], an open-source platform that simplifies backend development and deployment. The backend system handles user authentication, data storage, and interactions with the Kubernetes cluster. The backend codebase is written in Go, leveraging the flexibility and performance of the language to manage the system's core functionalities. Also go is the language of the whole Kubernetes ecosystem, so it was a natural choice to use it for the backend because all the standard libraries and tools are available in go.

The backend interacts with the Kubernetes API to creates and manages the logical resources required to deploy the Rollout objects, which then trigger the Kubernetes Operator to handle the deployment process. The backend also manages user authentication, ensuring secure access to the system's functionalities.

The backend codebase is structured to handle various API endpoints, each responsible for specific operations, such as user authentication, project creation, and Rollout management. The backend interacts with the frontend through RESTful APIs, processing requests and returning appropriate responses based on the system's state and user input.

The following code snippet of the *main.go* @OneclickPocketbaseMain demonstrates the implementation of a backend API endpoint for creating a new project:

#set text(8pt)
#show raw.where(block: true): block.with(
  fill: luma(240),
  inset: 10pt,
  radius: 4pt,
)

```go
[...]
func main() {
	// Initialize the Pocketbase app
	app := pocketbase.New()

	[...]

	// Listen for incommint requests to create a new rollout and trigger the rollout creation process in the Kubernetes cluster
	app.OnRecordBeforeCreateRequest().Add(func(e *core.RecordCreateEvent) error {
		switch e.Collection.Name {
		case "rollouts":
			return controller.HandleRolloutCreate(e, app)
		}
		return nil
	})

	[...]
}
```

#set text(12pt)

The code snippet demonstrates the event handling mechanism in Pocketbase, where the backend listens for incoming requests to create a new Rollout object. Upon receiving the request, the backend triggers the Rollout creation process in the Kubernetes cluster, initiating the deployment of the specified application.

The backend implementation is designed to provide a robust and efficient foundation for the One-Click Deployment system, enabling seamless interactions between the frontend, backend, and Kubernetes environment.

== User Interface Implementation

The user interface of the One-Click Deployment system is developed using Svelte #footnote[https://svelte.dev/], a modern web framework that simplifies frontend development and enhances user experience. The frontend interface serves as the primary interaction point for users, allowing them to define and manage deployment projects easily.

The frontend codebase is structured to provide a dynamic and intuitive user experience, with components designed to facilitate project creation, application deployment, and configuration. The frontend interacts with the backend through RESTful APIs with the Pocketbase Javascript SDK #footnote[https://pocketbase.io]Jssdk2024, enabling seamless communication between the user interface and the backend system. The frontend leverages Tailwind CSS #footnote[https://tailwindcss.com/] for styling and Flowbite-Svelte #footnote[https://flowbite-svelte.com/] for UI components, ensuring a consistent and visually appealing design.

With SvelteKit #footnote[https://kit.svelte.dev/] as the frontend framework, the One-Click Deployment system benefits from Svelte's reactivity and SvelteKit's versatility, enabling the development of fast, responsive, and accessible web applications. TypeScript is used to enhance code reliability and maintainability, providing type safety and early error detection during development.

#pagebreak()

=== User Interaction

The user interface of the One-Click Deployment system features a clean and intuitive design, allowing users to create projects, manage deployments, and configure application settings easily. The following screenshots showcase the key components of the user interface.

==== Projects Overview
In One-Click the user can create a new project or manage existing ones. Each project will get a unique *ID* which will be used to identify the project inside the Kubernetes cluster. The project will also get a unique *namespace* in the Kubernetes cluster which has the same name as the project *ID*.

#figure(
  image("../figures/projects-overview.png", width: 100%),
  caption: "One-Click Deployment System Projects Overview"
)

There will be a Kubernetes namespace each One-Click project with certain labels:

#set align(center)
#table(
  columns: 2,
  [*Label*], [*Description*],
  [`one-click.dev/displayName`], [The users display name in pocketbase.],
	[`one-click.dev/projectId`], [The unique ID of the project.],
	[`one-click.dev/userId`], [The users ID of the project.],
	[`one-click.dev/username`], [The username of the project.]
)
#set align(left)

#pagebreak()

==== Deployments Overview
In the project overview, the user can see all the deployments in this project. He can also navigate to the Blueprints, create a new Deployment or make some project settings. In the listed deployments, he can see the deployment name, status, URL (if configured), the last rollout time, number of replicas, and current deployed docker image.

#figure(
  image("../figures/deployments-overview.png", width: 100%),
  caption: "One-Click Deployment System Deployments Overview"
)

\

==== Blueprints
Blueprints are stored configurations of a One-Click CRD (@crd). With these blueprints the user can easily bootstrap new projects with no effort. The use cases are for example to predifine some enhanced configurations in his rollout crd yaml file which then get automatically applied when creating a new project out of this blueprint.

#figure(
  image("../figures/blueprints.png", width: 100%),
  caption: "One-Click Deployment System Blueprints"
)

#pagebreak()

==== Deployment Overview
When selecting or creating a new deployment within a project, users will land on the deployment overview page, as shown in the following screenshot:

#figure(
  image("../figures/deployment-overview.png", width: 100%),
  caption: "One-Click Deployment System Streamlit Deployment Overview"
)

The deployment overview page displays high level information and stats about the deployment configuration, such as amount of rollouts, instances, interfaces, volumes, environment variables, secret variables and the current docker image. There is also real time CPU and memory usage monitoring.

#pagebreak()


==== Deployment Map
The map shows real time Kubernetes resources generated by the deployment, such as pods, services, ingresses, and persistent volume claims etc.

#figure(
  image("../figures/map.png", width: 100%),
  caption: "One-Click Deployment System Map"
)

The map feature in a deployment uses svelte-flow #footnote[https://svelteflow.dev/] to graphically show the resources of the current rollout in the selected deployment. Everything gets updated in real time via a websocket endpoint to the backend.

#pagebreak()

The user can move the components with his mouse, zoom in and out and dig into its `manifests` / `logs` / `events` when click on a component.

#figure(
  image("../figures/map-drawer.png", width: 100%),
  caption: "One-Click Deployment System Map Drawer"
)

#pagebreak()

==== Rollouts
Each time the user edits and changes something in a deployment a new rollout will get created. This is like a *snapshot* of the CRD configuration. This gives the user the power to undo any changes he did to his deployment configuration like changing the port of an interface or updating the container image tag. He can see every rollout in the rollouts table. Through the frontend the user can either delete or hide a rollout snapshot. If he deletes a rollout then it won't pop up on the overview page anymore. If he hides a rollout then it will still be there but not visible on the rollouts table.

#figure(
  image("../figures/rollouts.png", width: 100%),
  caption: "One-Click Deployment System Rollouts Table"
)

#pagebreak()

When selecting a previous rollout the user can click on "rollback" and then a diff shows up which diffs the CRD files and show you exactly what will change.
This is a powerful feature because the user can see what will change before he actually rolls back to a previous rollout. He can also refer to a previous rollout if he wants to see what was the configuration at that time.

#figure(
	image("../figures/rollouts-diff.png", width: 100%),
	caption: "One-Click Deployment System Diff"
)

#pagebreak()

==== Container Image
Under images, the management of the deployment image is possible. Configuration of the registry (e.g., ghcr.io, docker.io), along with specifying username and password for private registries, and the repository/image are supported. Additionally, defining the image tag is an option. For debugging purposes, copying the current rollout ID allows for searching components within the Kubernetes cluster.

#figure(
	image("../figures/image.png", width: 100%),
	caption: "One-Click Deployment System Container Image"
)

*Auto update*
To avoid manual updates of the image tag each time a new version is pushed to the registry, the Auto Update feature can be activated. This feature allows for specifying an interval (1m, 5m, 10m), a pattern, and a policy on how the image registry should be checked and updated.
- *Interval*: The cron ticker, defined as a Pocketbase environment variable, checks the registry at set intervals based on the modulo of the minutes. It is recommended to maintain the default 1-minute tick interval.
- *Pattern*: A regex pattern that parses the image tag, following the default semantic versioning format (x.x.x).
- *Policy*: This dictates the sorting method, which can be either semantic versioning (semver) or timestamp-based, with the latter requiring the image tag to be in unix timestamp format.
The concept and behavior mirror those found in fluxcd, as outlined in their guide to image updates: FluxCD Image Update Guide #footnote[https://fluxcd.io/flux/guides/image-update/] \ \
*Examples*
#set align(center)
#table(
  columns: 3,
  [*Pattern*], [*Policy*], [*Note*],
	[`^\d+.\d+.\d+$`], [semver], [Default x.x.x semver pattern. e.g. 1.2.0 will get updated to 1.2.1],
	[`dev-\d+.\d+.\d+$`], [semver], [Custom pattern for *dev* versions. e.g. dev-1.2.0 will get updated to dev-1.2.1],
	[`.*`], [timestamp], [Any pattern will get updated with a *unix* timestamp.],
	[`preview-*`], [timestamp], [A pattern with the *preview-* prefix which will get updated with a *unix* timestamp.]
)
#set align(left)

#pagebreak()

==== Scaling
On the scale page, configuration options are available for both horizontal and vertical scaling. Horizontal scaling adjusts the number of instances (replicas), while vertical scaling involves setting CPU and memory requests and limits.

#figure(
	image("../figures/scale.png", width: 100%),
	caption: "One-Click Deployment System Scaling"
)

*Horizontal* \
The number of minimum and maximum replicas can be defined. Autoscaling behavior is governed by the *target* *CPU* usage; if the CPU usage exceeds the target, the number of replicas will increase. Current CPU usage can be monitored on the deployment overview page. \ \
*Vertical* \
Vertical scaling involves setting CPU and memory *requests* and *limits*. The request specifies the minimum CPU and memory allocated to the pod, while the limit defines the maximum allowable CPU and memory. Exceeding these limits results in pod *termination* on the *memory* side and *throttling* on the *CPU* side. These measurements are specified in millicores and megabytes, with the limit set at or above the request level. 

Understanding the application's requirements is crucial for setting appropriate values. If the requirements are unknown, starting with default values and monitoring the system's behavior is advisable. Increases to the limits may be necessary if the pod is frequently terminated due to exceeding these thresholds.

==== Networking
Network configuration offers several customization options. An unlimited number of services and ingress interfaces can be configured. Services provide internal Kubernetes connectivity, while ingress interfaces handle external access.
To create a new network interface, select the "New Interface" button. The configurable options include:
-	*name*: Unique identifier within the deployment.
-	*port*: Corresponds to the application port specified in the Dockerfile.
-	*ingress* class: Select from available ingress classes within the Kubernetes cluster via a dropdown menu.
-	*host*: The domain name, such as example.com.
-	*path*: Access path for the interface (e.g., `/api`, `/`).
-	*tls*: Toggle to enable TLS and specify the secret name for the TLS certificate.
	-	*tls secret name*: If left unspecified, defaults to the host name. This setting allows for automatic TLS certificate generation using cert-manager annotations #footnote[https://cert-manager.io/docs/usage/ingress/].

#pagebreak()

The DNS name corresponds to the Kubernetes Service name in the cluster, which other deployments can use for DNS lookups. The DNS name can be copied using the copy icon.
Setting the ingress class to none, removing the host and path, and disabling TLS will result in the deletion of the ingress and creation of the service for internal network exposure only.

#figure(
	image("../figures/network.png", width: 100%),
	caption: "One-Click Deployment System Networking"
)

#pagebreak()

==== Volumes
For persistent storage, volumes are available to store application data. Multiple volumes can be defined as needed. To add a new volume, click the "New Volume" button.
Configurable options for volumes include:
-	*name*: Unique identifier within the deployment.
-	*mount path*: Location where the volume is mounted (e.g., `/data`, `/var/lib/mysql`).
-	*size*: Volume size in GiB (gibibyte).
-	*storage class*: Select from the available storage classes within the Kubernetes cluster using a dropdown menu.
Once created, the size and storage class of a volume cannot be changed. If a change is necessary, a new volume must be created, and the data migrated to it.

#figure(
	image("../figures/volumes.png", width: 100%),
	caption: "One-Click Deployment System Volumes"
)

#pagebreak()

==== Environment Variables and Secrets
On the envs & secrets page, users can configure both environment variables and secrets for their application. Environment variables are key-value pairs injected into the container, while secrets represent sensitive data stored as Kubernetes secrets and are base64 encoded. They can function as environment variables or be mounted as files within the container. Content from a `.env` file or a secret file can be directly pasted into the text area provided.

Environment variables and secrets are accessible within the container as environment going forward.


#figure(
	image("../figures/volumes.png", width: 100%),
	caption: "One-Click Deployment System Environment Variables"
)

#pagebreak()

==== Deployment Settings
In the deployment settings the user can change it's name or avatar. He can also use the advanced editing mode to edit the CRD of the deployment directly. It's also possible to create new blueprint out of the current deployment configuration. The blueprint can then be used to create new deployments with the same configuration. The user can also delete the deployment.

#figure(
	image("../figures/deployment-settings.png", width: 100%),
	caption: "One-Click Deployment System Deployment Settings"
)

#pagebreak()

== Build and Deployment Process
Of course the One-Click System itself needs a deployment process. The core components like the Kubernetes Operator, frontend and backend needs to be accessible for the user to run it on his own. The operator is deployed in the Kubernetes cluster where the user wants to deploy his applications. It doesn't matter if it's a local Minikube cluster, a managed Kubernetes cluster at Natron Tech AG #footnote[https://natron.ch] or a cluster in a hyperscaler like AWS, Azure or Google Cloud.
An example deployment can be found in the *config* directory of the *one-click-operator* #footnote[https://github.com/janlauber/one-click-operator/tree/main/config] repository. 

The frontend and backend are build in a single Docker container and can get deployed either in a Kubernetes cluster or on a server. It only needs a connection and kubeconfig (for authentication) to the Kubernetes cluster where the operator is running. An example to deploy it inside the Kubernetes cluster can be found in the *deployment* directory of the *one-click* #footnote[https://github.com/janlauber/one-click/tree/main/deployment] repository.

== Project Management
To manage the development process efficiently, GitHub Projects was used, which provided a straightforward Kanban board for tracking progress. This tool was instrumental in organizing tasks, collecting feature requests, and prioritizing work based on user feedback and identified requirements. The use of GitHub Projects facilitated a clear and transparent workflow, enabling future contributors to collaborate effectively and stay aligned on project goals.

- *Kanban Board*: The Kanban board in GitHub Projects allowed us to visualize the development process, track the status of tasks, and manage the flow of work. Features and tasks were categorized into columns such as "To Do," "In Progress," "Review," and "Done," providing a clear overview of the project's progress.
- *Feature Collection*: Based on user feedback and requirements analysis, features were collected and added to the backlog. This ensured that user needs were continuously integrated into the development cycle, leading to a more user-centered product.
- *Prioritization*: Tasks were prioritized according to their importance and impact, ensuring that critical features and fixes were addressed promptly. This approach helped maintain a focus on delivering high-value functionality in each iteration.

By leveraging GitHub Projects as a project management tool, it was possible to streamline the development process.

Also the use of GitHub Issues and Pull Requests was essential for tracking bugs, feature requests, and code changes, ensuring a structured and organized development process with a clear transparency for all users and contributors.