---
apiVersion: v1
kind: Namespace
metadata:
  name: woolyai
---
# etcd ConfigMap for cluster configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: etcd-config
  namespace: woolyai
data:
  ETCD_INITIAL_CLUSTER: "etcd-0=http://etcd-0.etcd:2380,etcd-1=http://etcd-1.etcd:2380,etcd-2=http://etcd-2.etcd:2380"
  ETCD_INITIAL_CLUSTER_STATE: "new"
  ETCD_INITIAL_CLUSTER_TOKEN: "etcd-cluster"
---
# etcd Service
apiVersion: v1
kind: Service
metadata:
  name: etcd
  namespace: woolyai
  labels:
    app: etcd
spec:
  clusterIP: None
  ports:
    - port: 2379
      targetPort: 2379
      name: client
    - port: 2380
      targetPort: 2380
      name: peer
  selector:
    app: etcd
---
# etcd StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: etcd
  namespace: woolyai
spec:
  serviceName: etcd
  replicas: 3
  selector:
    matchLabels:
      app: etcd
  template:
    metadata:
      labels:
        app: etcd
    spec:
      containers:
        - name: etcd
          image: quay.io/coreos/etcd:v3.6.5
          ports:
            - containerPort: 2379
              name: client
            - containerPort: 2380
              name: peer
          env:
            - name: ETCD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: ETCD_INITIAL_ADVERTISE_PEER_URLS
              value: "http://$(ETCD_NAME).etcd:2380"
            - name: ETCD_LISTEN_PEER_URLS
              value: "http://0.0.0.0:2380"
            - name: ETCD_LISTEN_CLIENT_URLS
              value: "http://0.0.0.0:2379"
            - name: ETCD_ADVERTISE_CLIENT_URLS
              value: "http://$(ETCD_NAME).etcd:2379"
            - name: ETCD_INITIAL_CLUSTER
              valueFrom:
                configMapKeyRef:
                  name: etcd-config
                  key: ETCD_INITIAL_CLUSTER
            - name: ETCD_INITIAL_CLUSTER_STATE
              valueFrom:
                configMapKeyRef:
                  name: etcd-config
                  key: ETCD_INITIAL_CLUSTER_STATE
            - name: ETCD_INITIAL_CLUSTER_TOKEN
              valueFrom:
                configMapKeyRef:
                  name: etcd-config
                  key: ETCD_INITIAL_CLUSTER_TOKEN
          volumeMounts:
            - name: etcd-data
              mountPath: /etcd-data
          command:
            - /usr/local/bin/etcd
            - --data-dir=/etcd-data
            - --log-level=info
  volumeClaimTemplates:
    - metadata:
        name: etcd-data
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 10Gi
---
# NATS Service
apiVersion: v1
kind: Service
metadata:
  name: nats
  namespace: woolyai
  labels:
    app: nats
spec:
  clusterIP: None
  ports:
    - port: 4222
      targetPort: 4222
      name: client
    - port: 6222
      targetPort: 6222
      name: cluster
    - port: 8222
      targetPort: 8222
      name: monitor
  selector:
    app: nats
---
# NATS ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nats-config
  namespace: woolyai
data:
  nats.conf: |
    server_name: $POD_NAME
    port: 4222
    monitor_port: 8222

    cluster {
      name: nats-cluster
      port: 6222

      routes = [
        "nats://nats-0.nats:6222"
        "nats://nats-1.nats:6222"
        "nats://nats-2.nats:6222"
      ]

      cluster_advertise: $CLUSTER_ADVERTISE
      connect_retries: 30
    }

    jetstream {
      store_dir: /data/jetstream
      max_mem_store: 1GB
      max_file_store: 10GB
    }

    max_payload: 1MB
    max_connections: 64K
    max_control_line: 4KB

    lame_duck_duration: 30s
---
# NATS StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nats
  namespace: woolyai
spec:
  serviceName: nats
  replicas: 3
  selector:
    matchLabels:
      app: nats
  template:
    metadata:
      labels:
        app: nats
    spec:
      containers:
        - name: nats
          image: nats:2.12.1-alpine
          ports:
            - containerPort: 4222
              name: client
            - containerPort: 6222
              name: cluster
            - containerPort: 8222
              name: monitor
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: CLUSTER_ADVERTISE
              value: "$(POD_NAME).nats"
          volumeMounts:
            - name: nats-config
              mountPath: /etc/nats
            - name: nats-data
              mountPath: /data
          command:
            - nats-server
          args:
            - --server_name
            - $(POD_NAME)
            - --config
            - /etc/nats/nats.conf
          livenessProbe:
            httpGet:
              path: /
              port: 8222
            initialDelaySeconds: 10
            timeoutSeconds: 5
          readinessProbe:
            httpGet:
              path: /
              port: 8222
            initialDelaySeconds: 10
            timeoutSeconds: 5
      volumes:
        - name: nats-config
          configMap:
            name: nats-config
  volumeClaimTemplates:
    - metadata:
        name: nats-data
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 5Gi
---
# Controller Service
apiVersion: v1
kind: Service
metadata:
  name: controller
  namespace: woolyai
  labels:
    app: controller
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: 8080
      name: http
  selector:
    app: controller
---
# Controller Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: controller
  namespace: woolyai
spec:
  replicas: 2
  selector:
    matchLabels:
      app: controller
  template:
    metadata:
      labels:
        app: controller
    spec:
      containers:
        - name: controller
          image: woolyai/controller:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8080
              name: http
          env:
            - name: SERVER_ADDRESS
              value: "0.0.0.0:8080"
            - name: ETCD_ENDPOINTS
              value: "http://etcd-0.etcd:2379"
            - name: NATS_URL
              value: "nats://nats-0.nats:4222"
          livenessProbe:
            httpGet:
              path: /livez
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
          resources:
            requests:
              memory: "256Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
---
# Ingress for Controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: controller-ingress
  namespace: woolyai
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  ingressClassName: nginx
  rules:
    - host: controller.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: controller
                port:
                  number: 8080
