Is there something like Swarm's Task-Slot in Kubernetes?

12/21/2017

I am working to get an existing application consisting of a bunch of stateless, scalable microservices (and of course also a few stateful ones serving as backends) running on Docker Swarm and Kubernetes. Changing the code of the application is mostly out of the question, so I have to make some existing mechanisms that we have for, e.g., service discovery, work in the Swarm and K8s contexts.

One thing that helped me a lot with getting things up and running with Docker Swarm was the template feature of Swarm's "service create" command (https://docs.docker.com/engine/reference/commandline/service_create/#create-services-using-templates), where I can do something like

-e my_env_var=foo{{.Task.Slot}}

Inside each container that is part of my Swarm service, this will set the env var my_env_var to a value of the form fooX, where "X" is the container's "slot number". To grasp what a slot number is, consider a service with N instances (i.e., scale=N). Each container occupies one slot, and the slots are numbered from 1 to N.

That way, I can get a ID inside my container that is unique among all currently alive containers of my service, but at the same time, it is NOT totally random. If I scale a service from, e.g., 1 to 5, the five containers in my service will get the slots 1, 2, 3, 4, and 5. If I scale it down to, e.g., 3, two containers will be stopped (e.g., 2 and 4, leaving me with 1, 3, and 5). But if I scale it up again to 5, the slot numbers will (in general) again be 1 to 5 (and even if they were, e.g., 2-6, that is still better than being totally random).

This has proven to be very useful for Swarm-enabling my application and I am desperately looking for something similar in K8s (in particular in the context of K8s deployments, which I am using for our stateless microservices as they seem to be the most suitable K8s concept). I found the possibility to pass the pod name into the container with

    env:
    - name: metadata_name
      valueFrom:
        fieldRef:
          fieldPath: metadata.name

Alas, the name of a container is a) rather lengthy b) random (i.e., scaling down and up will NOT reuse names), e.g. the pods of a deployment named foo-deployment will be named something like

foo-deployment-64db944b84-bwrxx

foo-deployment-64db944b84-5jf7c

etc. So as far as I understand, the last five characters are guaranteed by K8s to be unique among all active pods of a deployment, but they are NOT reused (rare collisions nonwithstanding) when scaling up and down.

Is there any mechanism that corresponds to Swarm's "slot" concept?

Regards PalatinateJ

-- PalatinateJ
docker-swarm
kubernetes

1 Answer

12/12/2018

11 Months late, but here is the solution:

To get stable container (pod) names within K8S you must use a StatefulSet. StatefulSets are designed for applications that must maintain state, however, if you aren't using K8S volumes for state (keeping them ephemeral) you can use StatefulSets without an issue. There is a simple process of converting your Deployment to a StatefulSet:

  1. Change your apiVersion: to apps/v1
  2. Change the kind: to StatefulSet
  3. Under spec: add the selector: tag. This tag will contain everything you use to select the appropriate service. In addition you must ensure that any items you have under spec:template:metadata:labels match those under spec:selector:matchLabels (This will make more sense in the provided example)
  4. If you have any sort of update strategy, called strategy in a Deployment, change this to updateStrategy. For future reference, if you do not update this, you will end up with both a StatefulSet and a ReplicaSet being deployed as K8S is trying to fill the strategy and your StatefulSet requirements.

After applying these changes, you will have your StatefulSet deployed. How do we get task slots from this? The hostname.

Since K8S is maintaining stable pod names, you will have names such as:

pod/mypod-0                             1/1     Running   0          10m
pod/mypod-1                             1/1     Running   0          9m

when running kubetctl. After that, it is a simple matter of parsing the number out of your pod name.

Below is the YAML for a StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myStatefulSetName
  labels:
    app: SomeLabel1
    label2: SomeLabel2
spec:
  replicas: 100
  selector:
    matchLabels:
        app: SomeLabel1
        label2: SomeLabel2
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: SomeLabel1
        label2: SomeLabel2
    spec:
      containers:
      - name: myPodName
        image: myPod:latest
        imagePullPolicy: Always
        ports:
        - name: myPodPort
          containerPort: 8080

The differences become apparent on a equivalent Deployment:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myDeploymentName
  labels:
    app: SomeLabel1
    label2: SomeLabel2
spec:
  replicas: 100
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: SomeLabel1
        label2: SomeLabel2
    spec:
      containers:
      - name: myPodName
        image: myPod:latest
        imagePullPolicy: Always
        ports:
        - name: myPodPort
          containerPort: 8080
-- Tanishq dubey
Source: StackOverflow