From 4d52c14f93d1f35fafc9b04a9cf23fd176627c0d Mon Sep 17 00:00:00 2001 From: Oly Date: Wed, 6 Nov 2019 17:01:20 +0000 Subject: [PATCH] more clean ups and blog --- src/kube_deploy/blocks.clj | 95 +++++++++++-- src/kube_deploy/core.clj | 281 +++++++------------------------------ src/kube_deploy/data.clj | 18 +++ 3 files changed, 148 insertions(+), 246 deletions(-) diff --git a/src/kube_deploy/blocks.clj b/src/kube_deploy/blocks.clj index 7e68899..754f0fc 100644 --- a/src/kube_deploy/blocks.clj +++ b/src/kube_deploy/blocks.clj @@ -21,7 +21,76 @@ :limits {:cpu "200m" :memory "1Gi"}}) -(defn mosquitto-mqtt [kube-injector] +(defn drone-ci + ([kube-injector] + (drone-ci kube-injector {})) + ([kube-injector settings] + (let [app-name (get settings :app-name "drone-ci") + app-pod-name (str app-name "-pod") + app-runner-pod-name (str app-name "-runner-pod") + app-rule-name (keyword (str app-name "-rule")) + app-runner-rule-name (keyword (str app-name "-runner-rule")) + app-container-name (keyword (str app-name "-container")) + app-runner-container-name (keyword (str app-name "-runner-container")) + app-service-name (keyword (str app-name "-service")) + app-runner-service-name (keyword (str app-name "-runner-service")) + app-labels (get settings :labels {:app "drone-ci"}) + app-image (get settings :image "drone/drone:latest") + app-runner-image (get settings :image "drone/drone-runner-kube:latest") + app-ingress-host (get settings :ingress-host "drone-ci") + 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-to-spec :envFrom [{:secretRef {:name "environment"}}]))) + (lk/deployment 1) + (lk/expose-cluster-ip app-service-name + (lk/port app-container-name :drone-port 80 80))))) + + (lk/rule app-runner-rule-name [] + (fn [] + (-> (lk/pod + app-runner-pod-name + app-labels) + (lk/add-container + app-runner-container-name + app-runner-image + (-> {} + (lkh/add-to-spec :resources app-resources) + (lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}]))) + (lk/deployment 1) + (lk/expose-cluster-ip app-runner-service-name + (lk/port app-runner-container-name :runner-port 3000 3000))))) + + + (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 [app-ingress-host] + :secretName (str app-name "-tls")}]) + (lkh/add-spec :rules [{:host app-ingress-host + :http {:paths [{:path "/" + :backend + {:serviceName app-service-name + :servicePort 80}}]}}]) + (lk/add-annotation :nginx.ingress.kubernetes.io/enable-global-auth "false") + (lk/add-annotation :kubernetes.io/tls-acme "true") + (lk/add-annotation :kubernetes.io/ingress.class "nginx"))))))))) + + +(defn mosquitto-mqtt + ([kube-injector] + (mosquitto-mqtt kube-injector {})) + ([kube-injector settings] (-> kube-injector (lk/rule :mosquitto-master-rule [] (fn [] @@ -39,7 +108,7 @@ (lk/expose-cluster-ip :mosquitto-service-websocket (lk/port :mosquitto :mosquitto-websocket-port 8883 8883)) (lk/expose-cluster-ip :mosquitto-master - (lk/port :mosquitto :mosquitto-service-port 1883 1883))))))) + (lk/port :mosquitto :mosquitto-service-port 1883 1883)))))))) (defn test-block [kube-injector] (-> kube-injector @@ -265,12 +334,12 @@ #_(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"]))) + 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 @@ -286,11 +355,11 @@ (lkh/add-liveness-probe-get "http://127.0.0.1/static/admin/css/responsive.css" 80))) #_(lk/add-init-container pod - (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"]))) + (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 {}} diff --git a/src/kube_deploy/core.clj b/src/kube_deploy/core.clj index 8266a59..13ae0df 100644 --- a/src/kube_deploy/core.clj +++ b/src/kube_deploy/core.clj @@ -47,180 +47,6 @@ ([namespace kube-config] (some #(= (name namespace) %) (kube-get-namespaces kube-config)))) - - - -; will not be needed soon - - -(defn kube-apply - ([content file] - (kube-apply content file nil nil)) - ([content file kube-namespace] - (kube-apply content kube-namespace nil)) - ([content file kube-namespace kube-config] - (let [namespace-param (if (nil? kube-namespace) nil (str "--namespace=" kube-namespace)) - config-param (if (nil? kube-config) nil (str "--kubeconfig=" kube-config))] - (when-not (and (.exists file) - (= (slurp file) content)) - (spit file content) - (let [res (apply sh/sh (remove nil? ["kubectl" "apply" namespace-param config-param "-f" (str file)]))] - (when-not (= (:exit res) 0) - (.delete file) - (throw (Exception. (:err res))))))))) - -(defn redis [kube-injector] - (-> kube-injector - (lk/rule :redis-master-rule [] - (fn [] - (-> (lk/pod :redis-master {:app :footprint - :env :production - :role :master - :tier :redis}) - (lk/add-container :redis (get-in @conf [:images :redis]) - (-> {} - (lkh/add-to-spec :resources resources-small) - (lkh/add-readiness-probe-cmd ["redis-cli" "--version"]) - (lkh/add-liveness-probe-cmd ["redis-cli" "--version"]))) - (lk/deployment 1) - (lk/expose-cluster-ip :redis-master - (lk/port :redis :redis 6379 6379))))) - - #_(lk/rule :redis-slave-rule [:redis-master-rule :num-be-slaves] - (fn [backend-master num-be-slaves] - (-> (lk/pod :redis-slave {:app :redis - :role :slave - :tier :backend}) - (lk/add-container :redis (get-in @conf [:images :redis]) - (-> {} - (lkh/add-to-spec :resources resources-small) - (lkh/add-to-spec - :args ["--slaveof" - (:hostname backend-master) - (-> backend-master :ports :redis str)]) - (lkh/add-liveness-probe-cmd ["redis-cli" "--version"]))) - (lk/deployment num-be-slaves) - (lk/expose-cluster-ip :redis-slave - (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] - (-> kube-injector - (lk/rule :postgres-master-rule [] - (fn [] - (-> (lk/pod - :postgres-master - {:app :footprint :role :master :env :production :tier :database}) - (lk/add-container :postgres (get-in @conf [:images :postgres]) - (-> {} - (lkh/add-to-spec :resources resources-small) - (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 :postgres-master - (lk/port :postgres :postgres 5432 5432))))))) - -(defn rabbitmq [kube-injector] - (-> kube-injector - (lk/rule :rabbit-master-rule [] - (fn [] - (-> (lk/pod - :rabbit-master - {:app :footprint :role :master :env :prodction :tier :rabbit}) - (lk/add-container - :rabbit - (get-in @conf [:images :rabbitmq]) - (-> {} - (lkh/add-to-spec :resources resources-medium) - (lkh/add-liveness-probe-cmd ["rabbitmq-diagnostics" "ping" "-q"]))) - - (lk/deployment 1) - (lk/expose-cluster-ip - :rabbit-master (lk/port :rabbit :rabbit 5672 5672))))))) - -(defn hackspace [kube-injector] - (-> kube-injector - (lk/rule :hackspace-backend-master [:postgres-master-rule :redis-master-rule] - (fn [postgres redis] - (-> (lk/pod :hackspace-master {:app :hackspace - :role :master - :tier :web} - {:imagePullSecrets [{:name "docker-registry"}]}) - - ; Add containers to the pod, one for frontend assets and one for backend - (lk/add-container - :hackspace-backend - (get-in @conf [:images :django]) - (-> {} - (lkh/add-to-spec :resources resources-medium) - ;(lkh/add-to-spec :command ["python" "/app/wsgi_bjoern.py"]) - ;(lkh/add-to-spec :command ["/gunicorn.sh"]) - (lkh/add-to-spec :command ["/usr/local/bin/gunicorn" "config.wsgi" "--workers" "2" "-k" "gevent" "--worker-connections" "100" "--max-requests" "300" "--keep-alive" "1000" "-b" "0.0.0.0:5000" "--chdir=/app"]) - (lkh/add-to-spec :ports [{:containerPort 5000 :name "gunicorn-port"}]) - (lkh/add-to-spec :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-container - :hackspace-frontend - (get-in @conf [:images :nginx]) - (-> {} - (lkh/add-to-spec :resources resources-mini) - (lkh/add-to-spec :ports [{:containerPort 80 :name "nginx-port"}]) - (lkh/add-readiness-probe-cmd ["wget" "127.0.0.1/static/images/favicon.ico"]) - (lkh/add-liveness-probe-cmd ["wget" "127.0.0.1/static/images/favicon.ico"]))) - (lk/add-volume "static-files" {:emptyDir {}} - {:hackspace-backend "/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 2) - (lk/expose-cluster-ip :hackspace-backend - (lk/port :hackspace-master :gunicorn-port 5000 5000)) - (lk/expose-cluster-ip :hackspace-frontend - (lk/port :hackspace-master :nginx-port 80 80))))) - (lk/rule :hackspace-queue-master [] - (fn [] - (-> (lk/pod :hackspace-queue - {:app :hackspace - :env :stage - :role :master - :tier :queue} - {:imagePullSecrets [{:name "docker-registry"}]}) - (lk/add-container - :hackspace - (get-in @conf [:images :django]) - (-> {} - (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)))))) - (defn field-conj [m k v] (if (contains? m k) (update m k conj v) @@ -376,46 +202,28 @@ (lkh/secrets name {} (lkh/encode-secret-map data)))))) -(defn add-config [kube-injector name config] - (lk/rule kube-injector :config-map [] - (fn [] - (lk/config-map name config)))) - -#_(defn make-ingress-hackspace [kube-injector] - (lk/rule kube-injector :lkube-ingress [] - (fn [] - (-> (lkh/ingress "lkube-ingress" {:app :nginx-ingress :env :production :tier :ingress}) - (lkh/add-spec :tls [{:hosts [(:ingress-host @conf)] :secretName "letsencrypt-production"}]) - (lkh/add-spec :rules [{:host (:ingress-host @conf) - :http {:paths - [{:path "/" - :backend - {:serviceName "hackspace-backend" - :servicePort 5000}} - {:path "/static/" - :backend - {:serviceName "hackspace-frontend" - :servicePort 80}}]}}]) - (lk/add-annotation :certmanager.k8s.io/cluster-issuer "letsencrypt-production") - (lk/add-annotation :kubernetes.io/ingress.class "nginx"))))) +#_(defn add-config [kube-injector name config] + (lk/rule kube-injector :config-map [] + (fn [] + (lk/config-map name config)))) #_(defn make-ingress [kube-injector] - (lk/rule kube-injector :lkube-ingress [] - (fn [] - (-> (lkh/ingress "lkube-ingress" {:app :nginx-ingress :env :production :tier :ingress}) - (lkh/add-spec :tls [{:hosts [:lkube-ingress] :secretName "lkube-tls"}]) - (lkh/add-spec :rules [{:host (:ingress-host @conf) - :http {:paths - [{:path "/" - :backend - {:serviceName "footprint-backend" - :servicePort 5000}} - {:path "/static/" - :backend - {:serviceName "footprint-frontend" - :servicePort 80}}]}}]) - (lk/add-annotation :kubernetes.io/tls-acme "true") - (lk/add-annotation :kubernetes.io/ingress.class "nginx"))))) + (lk/rule kube-injector :lkube-ingress [] + (fn [] + (-> (lkh/ingress "lkube-ingress" {:app :nginx-ingress :env :production :tier :ingress}) + (lkh/add-spec :tls [{:hosts [:lkube-ingress] :secretName "lkube-tls"}]) + (lkh/add-spec :rules [{:host (:ingress-host @conf) + :http {:paths + [{:path "/" + :backend + {:serviceName "footprint-backend" + :servicePort 5000}} + {:path "/static/" + :backend + {:serviceName "footprint-frontend" + :servicePort 80}}]}}]) + (lk/add-annotation :kubernetes.io/tls-acme "true") + (lk/add-annotation :kubernetes.io/ingress.class "nginx"))))) #_(defn footprint-deployment [namespace kube-config] (println "deploying footprint") @@ -454,26 +262,32 @@ ; recursive function that processes through each project block + + (defn apply-blocks [kube-injector func settings] (if (some? (first func)) (do - (println "Generating block" (first func)) - (recur + (println "Generating block" (first func)) + (println (get-in settings [(keyword (first func))])) + (recur + (let [block-settings ((keyword (first func)) settings)] (case (first func) - :ldap (block/ldap kube-injector) - :redis (block/redis kube-injector) - :rabbitmq (block/rabbitmq kube-injector) - :postgres (block/postgres kube-injector) - :mosquitto (block/mosquitto-mqtt kube-injector) - :django-huey (block/django-huey kube-injector (get-in settings [(keyword (first func))])) - :django-gunicorn (block/gunicorn kube-injector (get-in settings [(keyword (first func))])) - kube-injector) - (rest func) - settings)) - kube-injector)) + :ldap (block/ldap kube-injector block-settings) + :drone-ci (block/drone-ci kube-injector block-settings) + :redis (block/redis kube-injector block-settings) + :rabbitmq (block/rabbitmq kube-injector block-settings) + :postgres (block/postgres kube-injector block-settings) + :mosquitto (block/mosquitto-mqtt kube-injector block-settings) + :django-huey (block/django-huey kube-injector block-settings) + :django-gunicorn (block/gunicorn kube-injector block-settings) + kube-injector)) + (rest func) + settings)) + kube-injector)) ; build functionality, pass config to apply blocks to generate the map then dump yaml + (defn build [{:keys [config namespace blocks options] :as service}] (println "Deploying to" (or config "default") "namespace" namespace) (println options) @@ -485,7 +299,7 @@ (if (= "t" (:secrets options)) (make-environment-secrets injector :environment (:vars @conf)) injector) - ;(make-registry-secrets injector :docker-registry {:.dockerconfigjson (:registry @conf)}) + ; (make-registry-secrets injector :docker-registry {:.dockerconfigjson (:registry @conf)}) (apply-blocks injector blocks @conf) (lk/standard-descs injector) (lk/get-deployable injector deployment-config) @@ -500,8 +314,6 @@ (let [config (get-in data/services [(keyword namespace) :config]) blocks (get-in data/services [(keyword namespace) :blocks])] (cond - ;(= namespace "footprint-production") (footprint-deployment "footprint-production" "/home/oly/.kube/ake.yml") - ;(= namespace "footprint-stage") (footprint-deployment "footprint" "/home/oly/.kube/ake.yml") (= (nil? blocks)) (build {:namespace namespace :config config :blocks blocks :options ns-config}) :else (println (str "Namespace " namespace " not found."))))) @@ -509,12 +321,14 @@ {:app {:command "Kubernetes deploy" :description "Generate yaml and deploy out to cluster." :version "0.0.1"} -; :global-opts [] :commands [{:command "deploy" :description "Deploy app out to cluster" - :opts [{:short "n" :option "namespace" :as "Namespace to deploy" :type :string :spec string?} - {:short "d" :option "deploy" :as "Deploy with kubectl" :type :string :default nil} - {:short "s" :option "secrets" :as "Include secrets" :type :string :default nil}] + :opts [{:short "n" :option "namespace" + :as "Namespace to deploy" :type :string :spec string?} + {:short "d" :option "deploy" + :as "Deploy with kubectl" :type :string :default nil} + {:short "s" :option "secrets" + :as "Include secrets" :type :string :default nil}] :runs deploy} {:command "secrets" :description "Display secrests" @@ -523,6 +337,7 @@ (defn -main [& args] (if args - (run-cmd args CONFIGURATION))) + (run-cmd args CONFIGURATION) + (println "No args supplied"))) diff --git a/src/kube_deploy/data.clj b/src/kube_deploy/data.clj index bef82f6..2ad6240 100644 --- a/src/kube_deploy/data.clj +++ b/src/kube_deploy/data.clj @@ -1,3 +1,21 @@ (ns kube-deploy.data) (def services (clojure.edn/read-string (slurp "config.edn"))) + +(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"}})