kube/src/kube_deploy/blocks.clj

394 lines
18 KiB
Clojure

(ns kube-deploy.blocks
(:require [clojure.java.io :as io]
[kube-deploy.helpers :as lkh]
[lambdakube.core :as lk]))
(def resources-mini
{:requests
{:cpu "100m" :memory "64Mi"}
:limits
{:cpu "200m" :memory "256Mi"}})
(def resources-small
{:requests
{:cpu "100m" :memory "100Mi"}
:limits
{:cpu "200m" :memory "400Mi"}})
(def resources-medium
{:requests
{:cpu "100m" :memory "500Mi"}
:limits
{:cpu "200m" :memory "1Gi"}})
(defn mosquitto-mqtt [kube-injector]
(-> kube-injector
(lk/rule :mosquitto-master-rule []
(fn []
(-> (lk/pod
:mosquitto-master
{:app :footprint :role :master :env :production :tier :database})
(lk/add-container :mosquitto "eclipse-mosquitto"
(-> {}
(lkh/add-to-spec :resources resources-mini)
(lkh/add-readiness-probe-cmd ["pg_isready"])
(lkh/add-liveness-probe-cmd ["pg_isready"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 1)
(lk/expose-cluster-ip :mosquitto-master
(lk/port :mosquitto :mosquitto 1883 1883)))))))
(defn test-block [kube-injector]
(-> kube-injector
(lk/rule :test-rule []
(fn []
(-> (lk/pod
:test-pod
{:app :test})
(lk/add-container :busybox "busybox"
(-> {}
(lkh/add-to-spec :resources resources-mini)
(lkh/add-to-spec :command ["sleep 3600"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 1))))))
(defn ldap
([kube-injector]
(ldap kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "ldap")
app-pod-name (str app-name "-pod")
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-service-name (keyword (str app-name "-service"))
app-labels (get settings :labels {:app "ldap"})
app-image (get settings :image "osixia/openldap:1.2.0")
app-resources (get settings :resources resources-small)]
(-> kube-injector
(lk/rule app-rule-name []
(fn []
(-> (lk/pod app-pod-name app-labels)
(lk/add-container
app-container-name
app-image
(-> {}
(lkh/add-to-spec :resources app-resources)))
(lk/deployment 1)
(lk/expose-cluster-ip
app-service-name
(lk/port app-container-name :ldap 389 389)))))))))
#_(defn aq-schedular
([kube-injector]
(aq-schedular kube-injector {}))
([kube-injector settings])
(let [app-name (get settings :app-name "aq-schedular")
app-pod-name (str app-name "-pod")
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-service-name (keyword (str app-name "-service"))
app-labels (get settings :labels {:app "aq-schedular"})
app-image (get settings :image "aq-schedular")
app-resources (get settings :resources resources-small)]
(lk/rule :footprint-aqscheduler-master []
(fn []
(-> (lk/pod :footprint-scheduler
{:app :footprint
:env :production
:tier :scheduler}
{:imagePullSecrets [{:name "docker-registry"}]})
(lk/add-container
:scheduler
app-image
(-> {}
(lkh/add-to-spec :imagePullPolicy "Always")
(lkh/add-to-spec :resources resources-mini)
(lkh/add-to-spec :command ["/usr/local/bin/dramatiq_apscheduler" "/app/tasks.yml" "--debug"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(add-volume "scheduler-config" {:configMap
{:name "scheduler-tasks"}}
{:scheduler
{:name "scheduler-config"
:mountPath "/app/tasks.yml"
:subPath "tasks.yml"}})
(lk/deployment 1))))))
(defn redis
([kube-injector]
(redis kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "redis")
app-pod-name (str app-name "-pod")
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-service-name (keyword (str app-name "-service"))
app-labels (get settings :labels {:app "redis"})
app-image (get settings :image "redis")
app-resources (get settings :resources resources-small)]
(-> kube-injector
(lk/rule app-rule-name []
(fn []
(-> (lk/pod app-pod-name app-labels)
(lk/add-container
app-container-name
app-image
(-> {}
(lkh/add-to-spec :resources app-resources)
(lkh/add-readiness-probe-cmd ["redis-cli" "--version"])
(lkh/add-liveness-probe-cmd ["redis-cli" "--version"])))
(lk/deployment 1)
(lk/expose-cluster-ip
app-service-name
(lk/port app-container-name :redis 6379 6379)))))))))
(defn rabbitmq
([kube-injector]
(rabbitmq kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "postgres")
app-pod-name (str app-name "-pod")
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-service-name (keyword (str app-name "-service"))
app-dependencies (get settings :dependencies [])
app-containers 1
app-labels (get settings :labels {:app "postgres"})
app-image (get settings :image "postgres")
app-resources (get settings :resources resources-small)]
(-> kube-injector
(lk/rule app-rule-name []
(fn []
(-> (lk/pod
app-pod-name
app-labels)
(lk/add-container
app-container-name
app-image
(-> {}
(lkh/add-to-spec :resources app-resources)
(lkh/add-liveness-probe-cmd ["rabbitmq-diagnostics" "ping" "-q"])))
(lk/deployment app-containers)
(lk/expose-cluster-ip
app-service-name
(lk/port app-container-name :rabbit 5672 5672)))))))))
(defn postgres
([kube-injector]
(postgres kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "postgres")
app-pod-name (str app-name "-pod")
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-service-name (keyword (str app-name "-service"))
app-dependencies (get settings :dependencies [])
app-containers 1
app-labels (get settings :labels {:app "postgres"})
app-image (get settings :image "postgres")
app-resources (get settings :resources resources-small)]
(-> kube-injector
(lk/rule app-rule-name []
(fn []
(-> (lk/pod
app-pod-name
app-labels)
(lk/add-container app-container-name app-image
(-> {}
(lkh/add-to-spec :resources app-resources)
(lkh/add-readiness-probe-cmd ["pg_isready"])
(lkh/add-liveness-probe-cmd ["pg_isready"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/stateful-set 1)
(lk/add-volume-claim-template :postgres-volume
{:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "1Gi"}}}
{:bar "/var/lib/postgresql/data"})
(lk/expose-cluster-ip app-service-name
(lk/port app-container-name :postgres 5432 5432)))))))))
(defn gunicorn
([kube-injector]
(gunicorn kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "gunicorn")
app-pod-name (keyword (str app-name "-pod"))
app-rule-name (str app-name "-rule")
app-gunicorn-container-name (keyword (str app-name "-container"))
app-nginx-container-name (keyword (str app-name "-nginx-container"))
app-nginx-pod-name (str app-name "-pod")
app-annotations (get settings :annotations {})
app-dependencies [] ;(get settings :dependencies [])
app-containers 1
app-labels (get settings :labels {:app app-name})
app-image (get settings :image "python:3")
app-resources (get settings :resources resources-small)
app-service-name "gunicorn-service"
app-nginx-service-name "nginx-service"
app-serve-static (get settings :serve-static true)]
(-> kube-injector
(lk/rule (keyword (str app-name "-rule")) app-dependencies
(fn []
(as->
(lk/pod
app-pod-name
app-labels
{:imagePullSecrets [{:name "docker-registry"}]})
pod
; Add containers to the pod, one for frontend assets and one for backend
(lk/add-annotation pod :linkerd.io/inject "enabled")
(lk/add-container
pod
app-gunicorn-container-name
app-image
{:resources app-resources
:imagePullPolicy "Always"
:command (get settings :command ["/usr/bin/gunicorn"
"wsgi"
"--workers" "2"
"-k" "gevent"
"--worker-connections" "100"
"--max-requests" "300"
"--keep-alive" "1000"
"-b" "0.0.0.0:5000"
"--chdir=/app"])
;:ports [{:containerPort 5000 :name "gunicorn-port"}]
:envFrom [{:secretRef {:name "environment"}}]
#_(lkh/add-readiness-probe-cmd ["wget" "127.0.0.1:5000"])
#_(lkh/add-liveness-probe-cmd ["wget" "127.0.0.1:5000"])})
#_(lk/add-init-container
pod
(keyword (str app-name "-init-migrations"))
app-image
(-> {}
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])
(lkh/add-to-spec :command ["./manage.py" "migrate"])))
(if (nil? app-serve-static)
pod
(-> pod
(lk/add-container
app-nginx-container-name
"nginx:alpine"
(-> {}
(lkh/add-to-spec :resources resources-mini)
(lkh/add-to-spec :imagePullPolicy "Always")
;(lkh/add-to-spec :ports [{:containerPort 80 :name "nginx-port"}])
#_(lkh/add-readiness-probe-get "127.0.0.1/static/images/favicon.ico" 80)
(lkh/add-liveness-probe-get "http://127.0.0.1/static/admin/css/responsive.css" 80)))
(lk/add-init-container
(keyword (str app-name "-init-static-files"))
app-image
(-> {}
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])
(lkh/add-to-spec :command ["./manage.py" "collectstatic" "--no-input"])))
(lk/add-volume :static-files
{:emptyDir {}}
{app-nginx-container-name "/usr/share/nginx/html/static/"
app-gunicorn-container-name "/app/staticfiles"})))
; order does matter here, deployment after initcontainers
;(lku/wait-for-service-port postgres :postgres)
;(lku/wait-for-service-port redis :redis)
; wrap in a deployment
(lk/deployment pod 1)
(if (nil? app-serve-static)
pod
(lk/expose-cluster-ip
pod
app-nginx-service-name
(lk/port app-nginx-container-name :nginx-port 80 80)))
(lk/expose-cluster-ip
pod
app-service-name
(lk/port app-gunicorn-container-name :gunicorn-port 5000 5000)))))
; inject the ingress required to serve to gunicorn app
(lk/rule (keyword (str app-name "-ingress-rule")) []
(fn []
(let [ingress-name (str app-name "-ingress")
paths []]
(-> (lkh/ingress ingress-name {:app :nginx-ingress :env :production :tier :ingress})
(lkh/add-spec :tls [{:hosts [(:ingress-host settings)]
:secretName (str app-name "-tls")}])
(lkh/add-spec :rules [{:host (:ingress-host settings)
:http {:paths
(remove nil?
[{:path "/"
:backend
{:serviceName app-service-name
:servicePort 5000}}
(when app-serve-static
{:path "/static/"
:backend
{:serviceName app-nginx-service-name
:servicePort 80}})])}}])
(lk/add-annotation :kubernetes.io/tls-acme "true")
; (lk/add-annotation :certmanager.k8s.io/cluster-issuer "letsencrypt-production")
(lk/add-annotation :kubernetes.io/ingress.class "nginx")))))))))
(defn django-huey
([kube-injector]
(gunicorn kube-injector {}))
([kube-injector settings]
(let [app-name (get settings :app-name "huey")
app-pod-name (keyword (str app-name "-pod"))
app-rule-name (keyword (str app-name "-rule"))
app-container-name (keyword (str app-name "-container"))
app-dependencies [] ;(get settings :dependencies [])
app-containers 1
app-labels (get settings :labels {:app app-name})
app-image (get settings :image "python:3")
app-resources (get settings :resources resources-small)]
(-> kube-injector
(lk/rule app-rule-name []
(fn []
(-> (lk/pod app-pod-name
{:app :hackspace
:env :stage
:role :master
:tier :queue}
{:imagePullSecrets [{:name "docker-registry"}]})
(lk/add-container
app-container-name
app-image
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-to-spec :command ["/app/manage.py" "run_huey"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 2))))))))
;; (into [] (flatten ["c" [:b 2]] ))
;; ;; (bulk-add )
;; ;; (apply lk/add-annotation (list ["a"] (first {:a 1 :b 2})))
;; ;; (defn bulk-add [func obj values]
;; ;; (println (first func))
;; ;; (if (= 0 (count values))
;; ;; (recur
;; ;; func
;; ;; (apply func (into [] (flatten [obj (first values)])))
;; ;; (rest values))
;; ;; obj))
;; ;; (as-> (lk/pod :foo {})
;; ;; pod
;; ;; (bulk-add lk/add-annotation pod {:a 1 :b 2}))
;; ;(apply lk/add-annotation pod (first {:a 1 :b 2}))