Search code examples
kubernetesminikubepersistent-volumes

Minikube: SQL Server running on local kubernetes with a volume on local machine


Context

  • My OS is ubuntu 22.04.
  • I use minikube. But I want something that looks like what I will have to deploy on prod.

What I want

  • SQL server
  • Data of SQL server on a volume that is "binded" to a local directory of the hard drive on my host machine

What I did

sudo mkdir /mnt/mssql
sudo chmod +777 /mnt/mssql
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mon-volume-persistant
spec:
  storageClassName: local-storage
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/mssql
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mon-volume-persistant-claim
spec:
  storageClassName: local-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mssql-deployment
spec:
  replicas: 1
  selector:
     matchLabels:
       app: mssql
  template:
    metadata:
      labels:
        app: mssql
    spec:
      terminationGracePeriodSeconds: 30
      hostname: mssqlinst
      securityContext:
        runAsUser: 10001
      containers:
      - name: mssql
        image: mcr.microsoft.com/mssql/server:2019-latest
        resources:
          requests:
            memory: "2G"
            cpu: "2000m"
          limits:
            memory: "2G"
            cpu: "2000m"
        ports:
        - containerPort: 1433
        env:
        - name: MSSQL_PID
          value: "Developer"
        - name: ACCEPT_EULA
          value: "Y"
        - name: MSSQL_SA_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mssql
              key: MSSQL_SA_PASSWORD
        volumeMounts:
        - name: mssqldb
          mountPath: /var/opt/mssql
      volumes:
      - name: mssqldb
        persistentVolumeClaim:
          claimName: mon-volume-persistant-claim
apiVersion: v1
kind: Secret
metadata:
  name: mssql
type: Opaque
data:
  MSSQL_SA_PASSWORD: {{ .Values.sql_sa_password | b64enc }}
apiVersion: v1
kind: Service
metadata:
  name: mssql-deployment
spec:
  selector:
    app: mssql
  ports:
    - protocol: TCP
      port: 1433
      targetPort: 1433
  type: LoadBalancer

What I get

The pod cannot start successfully.

kubectl describe pvc mon-volume-persistant-claim

Name:          mon-volume-persistant-claim
Namespace:     default
StorageClass:  local-storage
Status:        Bound
Volume:        mon-volume-persistant
Labels:        app.kubernetes.io/managed-by=Helm
Annotations:   meta.helm.sh/release-name: mssql
               meta.helm.sh/release-namespace: default
               pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      10Gi
Access Modes:  RWO
VolumeMode:    Filesystem
Used By:       mssql-deployment-6477c9d6fb-jpbx4
Events:
  Type    Reason                Age   From                         Message
  ----    ------                ----  ----                         -------
  Normal  WaitForFirstConsumer  31m   persistentvolume-controller  waiting for first consumer to be created before binding
kubectl describe pv mon-volume-persistant

Name:            mon-volume-persistant
Labels:          app.kubernetes.io/managed-by=Helm
Annotations:     meta.helm.sh/release-name: mssql
                 meta.helm.sh/release-namespace: default
                 pv.kubernetes.io/bound-by-controller: yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    local-storage
Status:          Bound
Claim:           default/mon-volume-persistant-claim
Reclaim Policy:  Retain
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        10Gi
Node Affinity:   <none>
Message:         
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /mnt/mssql
    HostPathType:  
Events:            <none>
kubectl logs mssql-deployment-6477c9d6fb-jpbx4 --all-containers

SQL Server 2019 will run as non-root by default.
This container is running as user mssql.
To learn more visit https://go.microsoft.com/fwlink/?linkid=2099216.
/opt/mssql/bin/sqlservr: Error: The system directory [/.system] could not be created. File: LinuxDirectory.cpp:420 [Status: 0xC0000022 Access Denied errno = 0xD(13) Permission denied]

I'm sure I am trying to solve a very common and simple problem, but I cannot find any clear and complete way to do it in the official K8S documentation.


Solution

  • Actually, I muist remove the storage class and use standard instead.

    Then I must go in the terminal of minikube container, and make chown -R 10001:0 <my host folder> as actually, from the point of view of kubernetes, the minikube container is the host of kubernetes. (see here: https://mycsharpdeveloper.wordpress.com/2022/10/30/minikube-opt-mssql-bin-sqlservr-error-the-system-directory-system-could-not-be-created/)

    Then, to have this folder mapped as is on my bare metal local folder, I must use minikube mount command from my very machine. (see here: https://minikube.sigs.k8s.io/docs/handbook/mount/)

    If you want to have everything persisting on your baremetal machine

    • on your baremetal host computer, run this command:
    minikube mount /mnt/mssql:/data/mssql --uid=10001
    

    10001 is the user that is mentionned in the deployment. This command actually says to minikube that the container image that hosts kubernetes will map its folder /data/mssql to the very local folder /mnt/mssql, and that its local folder will belong to the user 10001. Then on the volume, the folder that is mentioned as the hostPath is the path of direct host... that is the minikube container. On this minikube container, we just defined that this folder will be /data/mssql

    • deploy your helm chart or you K8S manifests

    If you want to have everything persisting only on your minikube container

    • get the container_id of minikube:
    docker ps
    
    • Open a terminal on the minikube container:
    run docker exec -it -u root <the previously discovered container_id> 
    
    • Give ownership to the user that will run deployed pods
    chown -R 10001:0 /data/mssql
    
    • deploy your helm chart or you K8S manifests
    • expose the service from minikube to the local machine:
    minikube tunnel
    
    • list services:
    kubectl get svc
    
    • the IP address of your SQL Server is the one mentionned in External-IP