Skip to content

How to deploy and set up BaGet Server in Kubernetes

Last updated on September 30, 2024

BaGet is an open-source NuGet server implementation. It provides a lightweight and performant solution to host your own NuGet repository. In this tutorial, I will walk you through deploying BaGet in a Kubernetes cluster using manifests for a persistent volume, deployment, service, and ingress with basic authentication.

Prerequisites

  • A running Kubernetes cluster
  • kubectl installed and configured
  • NGINX Ingress Controller installed (for ingress with authentication)

Step 1: Create Directory for BaGet Storage

On your Kubernetes node, create the directory where BaGet will store its packages and database files. For this example, the directory will be /home/user/baget/.

mkdir -p /home/user/baget

Step 2: Create a BaGet Environment Config

To configure BaGet, we’ll use environment variables stored in a secret. First, create a baget.env file with the necessary environment variables.

cat <<EOF > baget.env
# The following config is the API Key used to publish packages.
# You should change this to a secret value to secure your server.
ApiKey=NUGET-SERVER-API-KEY
Storage__Type=FileSystem
Storage__Path=/var/baget/packages
Database__Type=Sqlite
Database__ConnectionString=Data Source=/var/baget/baget.db
Search__Type=Database
EOF

Next, create a Kubernetes secret using the baget.env file:

kubectl create secret generic baget-env --from-env-file=baget.env

This secret will provide BaGet with the necessary configuration values.

Step 3: Create Persistent Volume (PV) and Persistent Volume Claim (PVC)

We will define a persistent volume (PV) and a persistent volume claim (PVC) to store BaGet’s data. The following pv.yaml and pvc.yaml manifests define these resources:

pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: baget-pv
spec:
  storageClassName: baget
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: /home/user/baget/baget-data

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: baget-pvc
spec:
  storageClassName: baget
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

Apply these manifests to your Kubernetes cluster:

kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml

Step 4: Create a StorageClass

Since we are using a local storage directory on the node, we need to create a storage class with the no-provisioner type. Here’s the sc.yaml for the storage class:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: baget
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Apply the storage class manifest:

kubectl apply -f sc.yaml

Step 5: Deploy BaGet

Next, we’ll create a deployment for the BaGet server. The deployment uses the BaGet Docker image and mounts the persistent volume where the data will be stored.

deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: baget
  labels:
    app: baget
spec:
  replicas: 1
  selector:
    matchLabels:
      app: baget
  template:
    metadata:
      labels:
        app: baget
    spec:
      containers:
      - name: baget
        image: loicsharma/baget:latest
        envFrom:
          - secretRef:
             name: baget-env
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: baget-data
          mountPath: "/var/baget"
      volumes:
      - name: baget-data
        persistentVolumeClaim:
          claimName: baget-pvc

Apply the deployment manifest:

kubectl apply -f deploy.yaml

Service Definition

To expose the BaGet service, we define a NodePort service in the deploy.yaml to map traffic to the BaGet container:

---
apiVersion: v1
kind: Service
metadata:
  name: baget
spec:
  selector:
    app: baget
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 32555
  type: NodePort

This exposes the BaGet service on port 32555.

Step 6: Secure BaGet with Basic Authentication

To add a layer of security to your BaGet instance, we will use basic authentication. First, generate an htpasswd file to store user credentials:

sudo apt install apache2-utils

htpasswd -c auth foo

Convert the auth file into a Kubernetes secret:

kubectl create secret generic basic-auth --from-file=auth

Verify the secret creation:

kubectl get secret basic-auth -o yaml

Step 7: Configure Ingress with Authentication

Create an ingress resource to route traffic to the BaGet service, and configure it to use the basic-auth secret for authentication. Below is the ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: baget-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
spec:
  ingressClassName: nginx
  rules:
  - host: baget.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: baget
            port:
              number: 80

Apply the ingress manifest:

kubectl apply -f ingress.yaml

Make sure the DNS for baget.example.com points to your cluster.

Step 8: Publish packages

Publish your first package with:

dotnet nuget push -s http://localhost:32555/v3/index.json -k NUGET-SERVER-API-KEY package.1.0.0.nupkg

Step 9: Access BaGet

You can now access your BaGet server through the configured ingress URL with basic authentication at http://baget.example.com. Use the credentials you generated with htpasswd to log in.


With this setup, you now have a fully functional, self-hosted NuGet server running on Kubernetes. The combination of persistent storage, environmental configuration via secrets, and basic authentication ensures your server is robust and secure.

Published inKubernetesLinux