start of more modularity
This commit is contained in:
parent
1bcb0fecde
commit
bfd71627d2
|
@ -7,6 +7,7 @@
|
||||||
[org.clojure/data.codec "0.1.1"]
|
[org.clojure/data.codec "0.1.1"]
|
||||||
[nano-id "0.9.3"]
|
[nano-id "0.9.3"]
|
||||||
[cli-matic "0.3.8"]
|
[cli-matic "0.3.8"]
|
||||||
|
[cheshire "5.9.0"]
|
||||||
[io.forward/yaml "1.0.9"]
|
[io.forward/yaml "1.0.9"]
|
||||||
[brosenan/lambdakube "0.7.0"]]
|
[brosenan/lambdakube "0.7.0"]]
|
||||||
:plugins [[lein-auto "0.1.3"]]
|
:plugins [[lein-auto "0.1.3"]]
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
(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 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 (str app-name "-rule")
|
||||||
|
app-container-name (str app-name "-container")
|
||||||
|
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 :postgres-master-rule []
|
||||||
|
(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-pod-name
|
||||||
|
(lk/port :postgres :postgres 5432 5432)))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn django-gunicorn
|
||||||
|
([kube-injector]
|
||||||
|
(django-gunicorn kube-injector {}))
|
||||||
|
([kube-injector settings]
|
||||||
|
(let [app-name (get settings :app-name "django-gunicorn")
|
||||||
|
app-pod-name (str app-name "-pod")
|
||||||
|
app-rule-name (str app-name "-rule")
|
||||||
|
app-gunicorn-container-name (str app-name "-container")
|
||||||
|
app-nginx-container-name (str app-name "-nginx-container")
|
||||||
|
app-dependencies (get settings :dependencies [])
|
||||||
|
app-containers 1
|
||||||
|
app-labels (get settings :labels {:app "django-gunicorn"})
|
||||||
|
app-image (get settings :image "python:3")
|
||||||
|
app-resources (get settings :resources resources-small)]
|
||||||
|
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule (keyword (str app-name "-rule")) app-dependencies
|
||||||
|
(fn []
|
||||||
|
(-> (lk/pod
|
||||||
|
app-pod-name
|
||||||
|
app-labels
|
||||||
|
{:imagePullSecrets [{:name "docker-registry"}]})
|
||||||
|
; Add containers to the pod, one for frontend assets and one for backend
|
||||||
|
(lk/add-container
|
||||||
|
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-volume "static-files" {:emptyDir {}}
|
||||||
|
{app-pod-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 app-containers)
|
||||||
|
(lk/expose-cluster-ip app-gunicorn-container-name
|
||||||
|
(lk/port app-pod-name :gunicorn-port 5000 5000))
|
||||||
|
(lk/expose-cluster-ip app-nginx-container-name
|
||||||
|
(lk/port app-pod-name :nginx-port 80 80)))))
|
||||||
|
|
||||||
|
; 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")]
|
||||||
|
(-> (lkh/ingress ingress-name {:app :nginx-ingress :env :production :tier :ingress})
|
||||||
|
(lkh/add-spec :tls [{:hosts [(:ingress-host settings)]
|
||||||
|
:secretName "letsencrypt-production"}])
|
||||||
|
(lkh/add-spec :rules [{:host (:ingress-host settings)
|
||||||
|
:http {:paths
|
||||||
|
[{:path "/"
|
||||||
|
:backend
|
||||||
|
{:serviceName "gunicorn-port"
|
||||||
|
:servicePort 5000}}
|
||||||
|
{:path "/static/"
|
||||||
|
:backend
|
||||||
|
{:serviceName "nginx-port"
|
||||||
|
:servicePort 80}}]}}])
|
||||||
|
(lk/add-annotation :certmanager.k8s.io/cluster-issuer "letsencrypt-production")
|
||||||
|
(lk/add-annotation :kubernetes.io/ingress.class "nginx")))))))))
|
|
@ -3,17 +3,18 @@
|
||||||
[clojure.java.shell :as sh]
|
[clojure.java.shell :as sh]
|
||||||
[cli-matic.core :refer [run-cmd]]
|
[cli-matic.core :refer [run-cmd]]
|
||||||
[yaml.core :as yaml]
|
[yaml.core :as yaml]
|
||||||
|
[cheshire.core :as json]
|
||||||
[kube-deploy.from-yaml :as lky]
|
[kube-deploy.from-yaml :as lky]
|
||||||
[kube-deploy.data :as data]
|
[kube-deploy.data :as data]
|
||||||
[kube-deploy.helpers :as lkh]
|
[kube-deploy.helpers :as lkh]
|
||||||
[lambdakube.core :as lk]
|
[lambdakube.core :as lk]
|
||||||
|
[kube-deploy.blocks :as block]
|
||||||
[lambdakube.util :as lku]))
|
[lambdakube.util :as lku]))
|
||||||
|
|
||||||
(def conf (atom {}))
|
(def conf (atom {}))
|
||||||
(def services (atom {}))
|
(def services (atom {}))
|
||||||
(reset! services (clojure.edn/read-string (slurp "config.edn")))
|
(reset! services (clojure.edn/read-string (slurp "config.edn")))
|
||||||
|
(def deployment-config {:num-be-slaves 2 :num-fe-replicas 2})
|
||||||
(def config {:num-be-slaves 2 :num-fe-replicas 2})
|
|
||||||
|
|
||||||
(def resources-mini
|
(def resources-mini
|
||||||
{:requests
|
{:requests
|
||||||
|
@ -34,6 +35,24 @@
|
||||||
{:cpu "200m" :memory "1Gi"}})
|
{:cpu "200m" :memory "1Gi"}})
|
||||||
|
|
||||||
; will not be needed soon
|
; will not be needed soon
|
||||||
|
|
||||||
|
(defn kube-get-namespaces [kube-config]
|
||||||
|
(into #{} (->> (lkh/kube-namespaces kube-config)
|
||||||
|
(map :metadata)
|
||||||
|
(map :name))))
|
||||||
|
|
||||||
|
(defn kube-does-namespace-exists [namespace]
|
||||||
|
(some namespace
|
||||||
|
(into #{} (->> (lkh/kube-namespaces "/home/oly/.kube/dke.yml")
|
||||||
|
(map :metadata)
|
||||||
|
(map :name)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; will not be needed soon
|
||||||
|
|
||||||
|
|
||||||
(defn kube-apply
|
(defn kube-apply
|
||||||
([content file]
|
([content file]
|
||||||
(kube-apply content file nil nil))
|
(kube-apply content file nil nil))
|
||||||
|
@ -84,6 +103,23 @@
|
||||||
(lk/expose-cluster-ip :redis-slave
|
(lk/expose-cluster-ip :redis-slave
|
||||||
(lk/port :redis :redis 6379 6379)))))))
|
(lk/port :redis :redis 6379 6379)))))))
|
||||||
|
|
||||||
|
(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 database [kube-injector]
|
(defn database [kube-injector]
|
||||||
(-> kube-injector
|
(-> kube-injector
|
||||||
(lk/rule :postgres-master-rule []
|
(lk/rule :postgres-master-rule []
|
||||||
|
@ -320,17 +356,18 @@
|
||||||
(-> (lkh/secrets (keyword name) data))))))
|
(-> (lkh/secrets (keyword name) data))))))
|
||||||
|
|
||||||
(defn make-registry-secrets [kube-injector name data]
|
(defn make-registry-secrets [kube-injector name data]
|
||||||
(-> kube-injector
|
(if (nil? (:.dockerconfigjson data))
|
||||||
(lk/rule
|
kube-injector
|
||||||
:secrets-registry []
|
(-> kube-injector
|
||||||
(fn []
|
(lk/rule
|
||||||
(lkh/secrets-registry name {} (lkh/encode-secret-map data))))))
|
:secrets-registry []
|
||||||
|
(fn []
|
||||||
|
(lkh/secrets-registry name {} (lkh/encode-secret-map data)))))))
|
||||||
|
|
||||||
(defn make-namespace [kube-injector name]
|
(defn make-namespace [kube-injector name]
|
||||||
(-> kube-injector
|
(lk/rule kube-injector :namespace []
|
||||||
(lk/rule :namespace []
|
(fn []
|
||||||
(fn []
|
(lkh/kube-namespace (keyword name)))))
|
||||||
(lkh/kube-namespace (keyword name))))))
|
|
||||||
|
|
||||||
(defn make-environment-secrets [kube-injector name data]
|
(defn make-environment-secrets [kube-injector name data]
|
||||||
(-> kube-injector
|
(-> kube-injector
|
||||||
|
@ -403,7 +440,7 @@
|
||||||
(add-config "scheduler-tasks" (get-in @conf [:config]))
|
(add-config "scheduler-tasks" (get-in @conf [:config]))
|
||||||
footprint
|
footprint
|
||||||
lk/standard-descs
|
lk/standard-descs
|
||||||
(lk/get-deployable config)
|
(lk/get-deployable deployment-config)
|
||||||
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
(kube-apply (io/file (str namespace "-deploy.yaml")) "footprint" kube-config)))
|
(kube-apply (io/file (str namespace "-deploy.yaml")) "footprint" kube-config)))
|
||||||
|
|
||||||
|
@ -414,7 +451,7 @@
|
||||||
(-> (lk/injector)
|
(-> (lk/injector)
|
||||||
(make-namespace namespace)
|
(make-namespace namespace)
|
||||||
;lk/standard-descs
|
;lk/standard-descs
|
||||||
(lk/get-deployable config)
|
(lk/get-deployable deployment-config)
|
||||||
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
(kube-apply (io/file (str namespace "-deploy.yaml")) nil kube-config))
|
(kube-apply (io/file (str namespace "-deploy.yaml")) nil kube-config))
|
||||||
|
|
||||||
|
@ -427,18 +464,65 @@
|
||||||
redis
|
redis
|
||||||
hackspace
|
hackspace
|
||||||
lk/standard-descs
|
lk/standard-descs
|
||||||
(lk/get-deployable config)
|
(lk/get-deployable deployment-config)
|
||||||
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
(kube-apply (io/file (str namespace "-deploy.yaml")) namespace kube-config)))
|
(kube-apply (io/file (str namespace "-deploy.yaml")) namespace kube-config)))
|
||||||
|
|
||||||
(defn deploy [{:keys [service]}]
|
;(map lk/injector 'database)
|
||||||
(let [namespace (get-in data/services [(keyword service) :namespace])
|
|
||||||
config (get-in data/services [(keyword service) :config])]
|
(defn create-namespace-if-not-exists [{:keys [config namespace blocks]}]
|
||||||
|
(when-not (kube-does-namespace-exists (keyword namespace))
|
||||||
|
(println (str "Namespace " namespace " not found creating"))
|
||||||
|
(-> (lk/injector)
|
||||||
|
(make-namespace namespace)
|
||||||
|
(lk/get-deployable deployment-config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-namespace.yaml"))
|
||||||
|
(kube-apply (io/file (str namespace "-deploy.yaml")) nil config))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn apply-blocks [kube-injector func settings]
|
||||||
|
(if (= 0 (count func))
|
||||||
|
kube-injector
|
||||||
|
(recur
|
||||||
|
(case (first func)
|
||||||
|
"database" (database kube-injector)
|
||||||
|
"postgres" (block/postgres kube-injector)
|
||||||
|
"django-gunicorn" (block/django-gunicorn kube-injector (get-in settings [(keyword (first func))]))
|
||||||
|
kube-injector)
|
||||||
|
(rest func)
|
||||||
|
settings
|
||||||
|
)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn build [{:keys [config namespace blocks] :as service}]
|
||||||
|
(println "Deploying" config namespace)
|
||||||
|
(if (.exists (io/file (str namespace "-config.edn")))
|
||||||
|
(do (reset! conf (clojure.edn/read-string (slurp (str namespace "-config.edn"))))
|
||||||
|
(create-namespace-if-not-exists service)
|
||||||
|
(let [injector (lk/injector)]
|
||||||
|
(-> injector
|
||||||
|
;(make-environment-secrets :environment (:vars @conf))
|
||||||
|
;(make-registry-secrets :docker-registry {:.dockerconfigjson (:registry @conf)})
|
||||||
|
;; make-ingress-hackspace
|
||||||
|
;; database
|
||||||
|
;; redis
|
||||||
|
;; hackspace
|
||||||
|
(apply-blocks blocks @conf)
|
||||||
|
lk/standard-descs
|
||||||
|
(lk/get-deployable deployment-config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
|
(kube-apply (io/file (str namespace "-deploy.yaml")) namespace config))))
|
||||||
|
(println "No config found " (str namespace "-config.yaml"))))
|
||||||
|
|
||||||
|
(defn deploy [{:keys [namespace] :as ns-config}]
|
||||||
|
(let [config (get-in data/services [(keyword namespace) :config])
|
||||||
|
blocks (get-in data/services [(keyword namespace) :blocks])]
|
||||||
(cond
|
(cond
|
||||||
(= service "hackspace") (hackspace-deployment "maidstone-hackspace" "/home/oly/.kube/dke.yml")
|
(= namespace "hackspace") (hackspace-deployment "maidstone-hackspace" "/home/oly/.kube/dke.yml")
|
||||||
(= service "footprint-production") (footprint-deployment "footprint-production" "/home/oly/.kube/ake.yml")
|
(= namespace "footprint-production") (footprint-deployment "footprint-production" "/home/oly/.kube/ake.yml")
|
||||||
(= service "footprint-stage") (footprint-deployment "footprint" "/home/oly/.kube/ake.yml")
|
(= namespace "footprint-stage") (footprint-deployment "footprint" "/home/oly/.kube/ake.yml")
|
||||||
:else (println (str "Service " service " not found.")))))
|
(= (nil? blocks)) (build {:namespace namespace :config config :blocks blocks})
|
||||||
|
:else (println (str "Namespace " namespace " not found.")))))
|
||||||
|
|
||||||
(def CONFIGURATION
|
(def CONFIGURATION
|
||||||
{:app {:command "Kubernetes deploy"
|
{:app {:command "Kubernetes deploy"
|
||||||
|
@ -447,7 +531,7 @@
|
||||||
; :global-opts []
|
; :global-opts []
|
||||||
:commands [{:command "deploy"
|
:commands [{:command "deploy"
|
||||||
:description "Deploy app out to cluster"
|
:description "Deploy app out to cluster"
|
||||||
:opts [{:option "service" :as "Service to deploy" :type :string :spec string?}]
|
:opts [{:option "namespace" :as "Namespace to deploy" :type :string :spec string?}]
|
||||||
:runs deploy}
|
:runs deploy}
|
||||||
{:command "secrets"
|
{:command "secrets"
|
||||||
:description "Display secrests"
|
:description "Display secrests"
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
(ns kube-deploy.helpers
|
(ns kube-deploy.helpers
|
||||||
(:require [lambdakube.core :as lk]
|
(:require [lambdakube.core :as lk]
|
||||||
|
[cheshire.core :as json]
|
||||||
|
[clojure.java.shell :as sh]
|
||||||
|
|
||||||
[clojure.data.codec.base64 :as b64]))
|
[clojure.data.codec.base64 :as b64]))
|
||||||
|
|
||||||
|
(defn kube-namespaces
|
||||||
|
([]
|
||||||
|
(kube-namespaces nil))
|
||||||
|
([kube-config]
|
||||||
|
(let [config-param (if (nil? kube-config) nil (str "--kubeconfig=" kube-config))]
|
||||||
|
(let [res (apply sh/sh (remove nil? ["kubectl" config-param "get" "namespaces" "-o=json"]))]
|
||||||
|
(if (= (:exit res) 0)
|
||||||
|
(-> (json/parse-string (:out res) true)
|
||||||
|
:items)
|
||||||
|
(throw (Exception. (:err res))))))))
|
||||||
|
|
||||||
(defn kube-namespace
|
(defn kube-namespace
|
||||||
([name]
|
([name]
|
||||||
{:apiVersion "v1"
|
{:apiVersion "v1"
|
||||||
|
|
Loading…
Reference in New Issue