Who am I

- Benjamin APPREDERISSE 🇫🇷

- Lead Engineering @KintoHub

 

- FullStack Backend Engineer

- ~5 years XP with Kubernetes

 

Worth mentioning:

- I ❤️ 🧀

Who are we

"All-in-one platform to combine and deploy your backend services, websites, cronjobs, databases and everything your app needs in one place."

Kubernetes 101

apiVersion: v1
kind: Service
metadata:
  name: example
spec:
  selector:
    app: example
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example
spec:
  selector:
    matchLabels:
      app: example
  replicas: 1
  template:
    metadata:
      labels:
        app: example
    spec:
      containers:
        - name: example
          image: "example:latest"
          ports:
            - name: http
              containerPort: 80

target

Proxy-Serverless

proxy

proxless

example

scale

target

target

proxless

example

example

apiVersion: v1
kind: Service
metadata:
  name: example
  annotations:
    proxless/deployment: example
spec:
  selector:
    app: example
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
  • Annotation `proxless/deployment` required on the `example` service
     
  • Create "Route" in proxless in-memory store
     
  • Proxless automatically creates an `ExternalName` service targeting proxless service - You must only use this new service to connect to your `example` app
     
  • Proxless labelizes the `example` deployment with `proxless=true`
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example
  labels:
    proxless: true
spec:
  selector:
    matchLabels:
      app: example
  replicas: 1
  template:
    metadata:
      labels:
        app: example
    spec:
      containers:
        - name: example
          image: "example:latest"
          ports:
            - name: http
              containerPort: 80

Basics

Basics

proxy

proxless

example

labelize & scale

target

target

proxless

example

example-proxless

CNAME

create

example

apiVersion: v1
kind: Service
metadata:
  name: example
  annotations:
    proxless/deployment: example
    proxless/domains: "example.io,www.example.io"
spec:
  selector:
    app: example
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
  • Annotation `proxless/domains` only required if you want to expose your service publicly
  • Not bound to any ingress controller / service mesh
  • List of domain names separated with `,`

External Access

External Name

proxy

proxless

example

labelize & scale

target

target

proxless

example

example-proxless

CNAME

create

expose

example.io,www.example.io

example

More

apiVersion: v1
kind: Service
metadata:
  name: example
  annotations:
    proxless/domains: "example.io,www.example.io"
    proxless/deployment: "example"
    proxless/ttl-seconds: "120"
    proxless/readiness-timeout-seconds: "30"
spec:
  selector:
    app: example
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
  • Annotation `proxless/ttls-seconds` (optional) - without requests, the `example` deployment will be scaled down after this amount of time
     
  • Annotation `proxless/readiness-timeout-seconds` (optional) - when scaling up, proxless will timeout if the `example` deployment is not ready after this amount of time

High Availability

  • Need to sync-up the in-memory store of all the proxless instances so that one instance does not shutdown the `example`
     
  • Using Redis Pub/Sub
    • No need persistent volume
    • No HA - if Redis dies, proxless continues working properly but the stores are not synced up
       
  • All proxless instances subscribe to redis channels (1 channel per service)
     
  • When a proxless instance receive a request, it updates its in-memory store and publish a message to redis - all other instances received the message and update their in-memory store

High Availability

proxless

proxless-sjskj

proxless-dfjsi

proxless-liowj

proxless

request received and sent to 1 pod

push "lastUsed" time on the correct channel

receive the new "lastUsed" time and update their store

Core Components

  • In-Memory Store
    • In-Memory Map containing the information for each "route" (service uid, namespace, service name, deployment name, domain names, `lastUsed` time)
    • Keys are `[svcuid]`, `[svc]`, `[svc].[ns]`, `[svc].[ns].svc.cluster.local`, `[domainname]`, `[deployment]` - they all target the same route object (pointer)
    • (Optional) Synced-up by Redis Pub/Sub if HA is enabled

       
  • Proxy
    • Responsible for forwarding the requests to the correct backend
    • Scale up the deployment if needed

Core Components

  • Service Engine
    • Responsible for retrieving the configuration from the services and configuring the deployments.
    • Watch (using `k8s informer`) the services creation/update/deletion
      • Create/update/delete route in the in-memory store
      • Create the `ExternalName` service
      • Labelizes the deployment

         
  • Downscaler
    • Responsible for downscaling the deployments when they are not used
    • Pull all the deployments with label `proxless=true` every N seconds
      • Retrieve the associated route from the in-memory store
      • If `lastUsed > ttlSeconds` -> scale down the deployment

Advanced

apiVersion: v1
kind: Service
metadata:
  name: example
  annotations:
    proxless/deployment: example
    proxless/service: example-proxless
spec:
  type: "ExternalName"
  externalName: example-proxless
---
apiVersion: v1
kind: Service
metadata:
  name: example-proxless
spec:
  selector:
    app: example
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
  • Create yourself the `ExternalName` service
    • Allows you to define the name of the service by yourself
    • Annotations must be added on this service
       
  • Annotation `proxless/service` (optional) - name of the service targeting the `example` pod

{DemoTime}

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
      tier: backend
      track: stable
  replicas: 0
  template:
    metadata:
      labels:
        app: hello
        tier: backend
        track: stable
    spec:
      containers:
        - name: hello
          image: "gcr.io/google-samples/hello-go-gke:1.0"
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello
  annotations:
    proxless/deployment: "hello"
spec:
  selector:
    app: hello
    tier: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: hello
      tier: frontend
      track: stable
  replicas: 0
  template:
    metadata:
      labels:
        app: hello
        tier: frontend
        track: stable
    spec:
      containers:
        - name: nginx
          image: "bappr/proxless-nginx-example"
          env:
            - name: BACKEND_HOST
              value: "http://hello-proxless"
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
  annotations:
    proxless/domains: "example.io,www.example.io"
    proxless/deployment: "frontend"
    proxless/ttl-seconds: "120"
    proxless/readiness-timeout-seconds: "30"
spec:
  selector:
    app: hello
    tier: frontend
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
Made with Slides.com