Skip to content

Creating Linkding Deployment with FluxCD

Ever since I started tinkering with FluxCD in my homelab Kubernetes cluster, I've been on a kick with maximizing both best practices with it, and also automating the orchestration of my self-hosted services.

It's quite a ride! But as this post is my process for getting the Linkding bookmark service deployed, I will not be going into detail on how to get FluxCD setup and configured. That's a prerequisite you have hopefully already gone through.

For a full breakdown of this structure and the files you can check out my homelab GitHub repository at https://github.com/cyberwatchdoug/homelab/tree/main

Architecture

My FluxCD is organized by folders for my apps labeled apps/base and apps/staging where Staging is currently my testing environment, while the Base holds all the standard templates that work in either a testing environment or eventually a production environment. This primarily saves me from duplicating yaml configuration files, and allows me to reuse the base configurations or adjust them as necessary for the given environment.

Here'a visual of my folder setup:

homelab
└──apps
   ├── base
   │   └── linkding
   │       ├── deployment.yaml
   │       ├── kustomization.yaml
   │       ├── namespace.yaml
   │       └── storage.yaml
   └── staging
       └── linkding
           └── kustomization.yaml

Staging Files

Currently, I only have the one kustomization.yaml file in my staging directory. This points to my apps/base/linkding directory, and informs Flux to then read the kustomization.yaml file in that directory.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: linkding
resources:
  - ../../base/linkding/

Base files

The base files are where the magic happens. Again, I have created a kustomization.yaml file, which then lists out each of the other YAML files in this directory, informing Flux to read and apply them:

kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: linkding
resources:
  - namespace.yaml
  - storage.yaml
  - deployment.yaml

Going down that list, the next file is namespace.yaml where I create the namespace I will be using to group my linkding deployment and related resources:

namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: linkding

Up next is storage.yaml which creates the PersistentVolumeClaim (PVC) I will be using for linkding's /etc/linkding/data directory. This is where the linkding service stores all of its configuration files and most critcally the database file for user accounts. I'm using a PVC so that when this Deployment get's recreated the data will persist.

storage.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: linkding-data-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Next is deployment.yaml. This file describes the linkding Deployment and associated configurations I want for the Pod and Containers inside it.

A note on security: I've ensured that the user, group, and filesystem are all specified as the linkding user, known as Unprivileged. Without those changes, the Container would be running as root, which is known as Privileged and we don't want our Containers running as Privileged.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: linkding
  name: linkding
  namespace: linkding
spec:
  replicas: 1
  selector:
    matchLabels:
      app: linkding
  template:
    metadata:
      labels:
        app: linkding
    spec:
      securityContext:
        runAsUser: 33   # www-data user ID
        runAsGroup: 33  # www-data group ID
        fsGroup: 33     # www-data group ID
      volumes:
        - name: linkding-data
          persistentVolumeClaim:
            claimName: linkding-data-pvc
      containers:
        - name: linkding
          image: sissbruecker/linkding:1.41.0
          ports:
            - containerPort: 9090
          securityContext:
            allowPrivilegeEscalation: false
          volumeMounts:
            - name: linkding-data
              mountPath: "/etc/linkding/data"

With everything in place, deploying Linkding with FluxCD becomes a seamless, repeatable process that fits into my homelab workflow. Not only does this approach keep my configurations tidy, but it also gives me the flexibility to tweak, upgrade, and scale as my needs evolve. If you're looking to bring order and automation to your self-hosted services, I hope showing you my process for deploying Linkding helps get you started or inspires you to refine your own setup.

Happy homelabing folks!