Deployment

Requirements

You must have a Kubernetes cluster, which must have:

  • a namespace called emmental-platform (if you want to rename it, you must adapt all manifests)

  • a namespace called emmental-challenges (cannot be changed for now)

  • an Ingress controller enabled. For exemple, with Minikube, use minikube addons enable ingress

  • a networking plugin supporting Network Policies, like Calico (if using Minikube, it may be necessary to use --network-plugin=cni --extra-config=kubeadm.pod-network-cidr=${POD_CIDR} \

with minikube start, see this issue).

Downloadable manifests

Kubernetes manifests can be downloaded here:

namespaces.yaml authorization.yaml back.yaml front.yaml mongo.yaml

Use these manifests one by one by using kubectl apply -f <filename.yaml> or apply an entire manifest folder with kubectl apply -f <path/to/yaml/folder>

Note

To shut down what you just created, just replace apply by delete in above commands

Set up Namespaces

namespaces.yaml

You need to have two namespaces, emmental-platform and emmental-challenges. You may use this manifest to create them:

---
apiVersion: v1
kind: Namespace
metadata:
  name: emmental-platform
---
apiVersion: v1
kind: Namespace
metadata:
  name: emmental-challenges

Set up Network Policies

Warning

These manifests assume you use calico as a networking plugin.

Set up Role Service Bindings

authorization.yaml

We need to allow the platform to manage deployments and services. This manifest defines a ServiceAccount, then a ClusterRole and then bind them with a ClusterRoleBinding:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: api-emmental
  namespace: emmental-platform
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: challenge-instance-controller
rules:
  - apiGroups: ["", "apps", "networking.k8s.io", "extensions"] # "" indicates the core API group
    resources: ["services", "deployments", "configmaps", "pods", "networkpolicies"]
    verbs: ["create", "patch", "read", "get", "list", "delete", "deletecollection"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: emmental-api-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: challenge-instance-controller
subjects:
  - kind: ServiceAccount
    name: api-emmental
    namespace: emmental-platform

Platform deployment

back.yaml front.yaml mongo.yaml

Warning

This will expose the platform as a HTTP service. In production, you must deploy it in HTTPS!

First you need to clone the platform repository, and build the back and front images:

git clone <plateform adress>
cd plateform
make build-prod

Note

This creates two images named front and back.

Then, create a Kubernetes Deployment and Service to deploy the back:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: emmental-platform
  name: back
spec:
  replicas: 1
  selector:
    matchLabels:
      app: back
      tier: backend
      track: stable
  template:
    metadata:
      labels:
        app: back
        tier: backend
        track: stable
    spec:
      containers:
        - name: back
          image: back
          imagePullPolicy: Never
          ports:
            - containerPort: 5000
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
              name: configmap-back
      serviceAccountName: api-emmental
---
apiVersion: v1
kind: Service
metadata:
  namespace: emmental-platform
  name: back
spec:
  selector:
    app: back
    tier: backend
  ports:
    - protocol: TCP
      port: 5000
      targetPort: 5000

Note

You should adapt the number of replicas to your needs.

Do the same for the front, which is exposed by an ingress:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: emmental-platform
  name: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: emmental
      tier: frontend
      track: stable
  template:
    metadata:
      labels:
        app: emmental
        tier: frontend
        track: stable
    spec:
      containers:
        - name: front
          image: front
          imagePullPolicy: Never
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: emmental-platform
  name: front
spec:
  selector:
    app: emmental
    tier: frontend
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  namespace: emmental-platform
  name: front-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: front
    servicePort: 8080

To deploy a mongo database, add the next ressources, do not forget to customize the storage size and location on disk:

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mongo-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/mnt/data/mongo"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: emmental-platform
  name: mongo-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: emmental-platform
  name: mongo
spec:
  selector:
    matchLabels:
      app: mongo
      role: master
      tier: backend
  replicas: 1
  template:
    metadata:
      labels:
        app: mongo
        role: master
        tier: backend
    spec:
      containers:
        - name: mongo
          image: mongo
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: data
              mountPath: /data/db
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: mongo-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  namespace: emmental-platform
  name: mongo
  labels:
    app: mongo
    role: master
    tier: backend
spec:
  ports:
    - port: 27017
      targetPort: 27017
  selector:
    app: mongo
    role: master
    tier: backend

Warning

Using local storage will not work on multi-node clusters.