func (k kubernetes) CreateStatefulSet(repoName string, imageId string, ports []int, volumes []titanclient.Volume, environment []string) {
	objectMeta := metav1.ObjectMeta{
		Name:                       repoName,
		Namespace:                  k.namespace,
		Labels:                     map[string]string{"titanRepository": repoName},
	}
	servicePorts := make([]v1.ServicePort, len(ports))
	for _, port := range ports {
		servicePorts = append(servicePorts, v1.ServicePort{
			Name:        "port-" + strconv.Itoa(port),
			Port:        int32(port),
		})
	}
	serviceSpec := v1.ServiceSpec{
		Ports:                    servicePorts,
		Selector:                 map[string]string{"titanRepository": repoName},
		ClusterIP:                "None",
	}
	service := v1.Service{
		ObjectMeta: objectMeta,
		Spec:      	serviceSpec,
		Status:     v1.ServiceStatus{},
	}
	createMetadata := metav1.CreateOptions{
		DryRun:       nil,
		FieldManager: "",
	}
	client.CoreV1().Services(k.namespace).Create(ctx, &service, createMetadata)
	containerPorts := make([]v1.ContainerPort, len(ports))
	for _, port := range ports {
		containerPorts = append(containerPorts, v1.ContainerPort{
			Name:          "port-" + strconv.Itoa(port),
			ContainerPort: int32(port),
		})
	}
	envs := make([]v1.EnvVar, len(environment))
	for _, environment := range environment {
		s := strings.Split(environment, "=")
		envs = append(envs, v1.EnvVar{
			Name:      s[0],
			Value:     s[1],
		})
	}
	volumeMounts := make([]v1.VolumeMount, len(volumes))
	for _, volume := range volumes {
		volumeMounts = append(volumeMounts, v1.VolumeMount{
			Name:             volume.Name,
			MountPath:        volume.Properties["path"].(string),
		})
	}
	container := v1.Container{
		Name:                     repoName,
		Image:                    imageId,
		Ports:                    containerPorts,
		Env:                      envs,
		VolumeMounts:             volumeMounts,
	}
	containers := make([]v1.Container, 1)
	containers = append(containers, container)
	vols := make([]v1.Volume, len(volumes))
	for _, volume := range volumes {
		pvc := v1.PersistentVolumeClaimVolumeSource{
			ClaimName: volume.Properties["pvc"].(string),
		}
		vols = append(vols, v1.Volume{
			Name:         volume.Name,
			VolumeSource: v1.VolumeSource{
				PersistentVolumeClaim: &pvc,
			},
		})
	}
	podSpec := v1.PodSpec{
		Volumes:                       vols,
		Containers:                    containers,
	}
	podTemplate := v1.PodTemplateSpec{
		ObjectMeta: objectMeta,
		Spec:       podSpec,
	}
	replica := int32(1)
	selector := metav1.LabelSelector{
		MatchLabels:      map[string]string{"titanRepository": repoName},
	}
	statefulSpecs := v1Apps.StatefulSetSpec{
		Replicas:             &replica,
		Selector:             &selector,
		Template:             podTemplate,
		ServiceName:          repoName,
	}
	statefulSet := v1Apps.StatefulSet{
		ObjectMeta: objectMeta,
		Spec:       statefulSpecs,
	}
	client.AppsV1().StatefulSets(k.namespace).Create(ctx, &statefulSet, createMetadata)
}
For our repositories, we keep it very simple. There is a single headless service that is responsible for exposing
the ports in the container. We then create a single replica stateful set with the given volumes (each with
existing PVCs) mapped in.
package clients
import (
	"context"
	"errors"
	"fmt"
	titanclient "github.com/titan-data/titan-client-go"
	v1Apps "k8s.io/api/apps/v1"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	k8s "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)
type kubernetes struct {
	namespace string
}
func Kubernetes (n string) kubernetes {
	return kubernetes{n}
}
var client *k8s.Clientset
var ctx = context.Background()
func init() {
	home := homedir.HomeDir()
	kubeconfig := filepath.Join(home, ".kube", "config")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err == nil {
		client, _ = k8s.NewForConfig(config)
	}
}