Stage deploy.
This commit is contained in:
commit
b3ba803631
|
@ -0,0 +1,62 @@
|
||||||
|
{:registry ""
|
||||||
|
:images {:django "registry.gitlab.com/maidstone-hackspace/maidstone-hackspace-website:latest"
|
||||||
|
:nginx-ingress "nginx/nginx-ingress"
|
||||||
|
:nginx "nginx:alpine"
|
||||||
|
:redis "redis:5.0-rc"
|
||||||
|
:rabbitmq "rabbitmq:management-alpine"
|
||||||
|
:postgres "postgres"}
|
||||||
|
:environment "stage"
|
||||||
|
:vars
|
||||||
|
{:MY_DOMAIN_NAME "stage.maidstone-hackspace.org.uk"
|
||||||
|
:COMPOSE_PROJECT_NAME "hackstage"
|
||||||
|
:GUNICORN "/stage-gunicorn-mhackspace.sh"
|
||||||
|
:POSTGRES_PASSWORD "mysecretpass"
|
||||||
|
:POSTGRES_USER "postgresuser"
|
||||||
|
:DATABASE_URL "postgres://postgresuser:mysecretpass@postgres:5432/postgresuser"
|
||||||
|
:DJANGO_ADMIN_URL "trustee/"
|
||||||
|
:DJANGO_SETTINGS_MODULE "config.settings.stage"
|
||||||
|
:DJANGO_SECRET_KEY "iud%k99yw!e+z+c12uatugbn \"&lsdyd(t_byk9)@dp@lj6*c*n"
|
||||||
|
:DJANGO_ALLOWED_HOSTS "stage.maidstone-hackspace.org.uk,165.227.230.86"
|
||||||
|
:DJANGO_DEBUG "False"
|
||||||
|
:BUCKET_PREFIX_PATH "stage/"
|
||||||
|
:DJANGO_AWS_ACCESS_KEY_ID ""
|
||||||
|
:DJANGO_AWS_SECRET_ACCESS_KEY ""
|
||||||
|
:DJANGO_AWS_STORAGE_BUCKET_NAME ""
|
||||||
|
:REDIS_URL "redis://redis:6379"
|
||||||
|
:CELERY_BROKER_URL "redis://redis:6379"
|
||||||
|
:CELERY_RESULT_BACKEND "redis://redis:6379"
|
||||||
|
:DJANGO_MAILGUN_API_KEY ""
|
||||||
|
:DJANGO_SERVER_EMAIL "support@digitaloctave.com"
|
||||||
|
:MAILGUN_SENDER_DOMAIN ""
|
||||||
|
:EMAIL_USER "no-reply@digitaloctave.com"
|
||||||
|
:EMAIL_PASSWORD "5fere5V.9quQe"
|
||||||
|
:DJANGO_ACCOUNT_ALLOW_REGISTRATION "True"
|
||||||
|
:COMPRESS_ENABLED ""
|
||||||
|
:PAYMENT_ENVIRONMENT "sandbox"
|
||||||
|
:PAYMENT_REDIRECT_URL "https://test.maidstone-hackspace.org.uk"
|
||||||
|
:BRAINTREE_MERCHANT_ID "b3sdmyczd3fz6b3p"
|
||||||
|
:BRAINTREE_PUBLIC_KEY "rxb7yffm3tk758rq"
|
||||||
|
:BRAINTREE_PRIVATE_KEY "62f92d2b00a451c40fdf5fbca54f0421"
|
||||||
|
:PAYPAL_CLIENT_ID "AaGlNEvd26FiEJiJi53nfpXh19_oKetteV1NGkBi4DDYZSqBexKVgaz9Lp0SI82gYFSAYpsmxO4iDtxU"
|
||||||
|
:PAYPAL_CLIENT_SECRET "EMcIuDJE_VDNSNZS7C7NLi9DEHaDvVu9jlIYyCCHaLmrLuy_VQ6C0bbcRnyF-7B6CcN__Dn6HqUwsgMG"
|
||||||
|
:GOCARDLESS_APP_ID "MNHBS3C4X4ZG211SM70WSS7WCN8B3X1KAWZBKV9S8N6KH2RNH6YZ5Z5865RFD3H6"
|
||||||
|
:GOCARDLESS_APP_SECRET "NE4NWYDQY4FNN1B47VT9SZ318GPQND130DW7QGQ73JMVTZQZHJQNF23ZFNP48GKV"
|
||||||
|
:GOCARDLESS_ACCESS_TOKEN "CJ7G7V36VAH5KVAHTYXD8VE8M4M0S41EQXH2E1HTGV5AN5TAZBER36ERAF4CG2NR"
|
||||||
|
;:GOCARDLESS_ACCESS_TOKEN "sandbox_-ATBL3jeCXroOBM2nhvwjNzr1utQ7UN5esbB4vIc"
|
||||||
|
:GOCARDLESS_MERCHANT_ID "11QFXD7TTA"
|
||||||
|
:MATRIX_ROOM "fmCpNwqgIiuwATlcdw:matrix.org"
|
||||||
|
:MATRIX_USERNAME "mhackspace"
|
||||||
|
:MATRIX_PASSWORD "AjwsoD952vdOo"
|
||||||
|
:BUCKET_NAME "mhackspace"
|
||||||
|
:BUCKET_ACCESS_KEY "UGCVGOUYW2XER4UNV62W"
|
||||||
|
:BUCKET_SECRET_KEY "bWB6H/LQuPUuZSAOvQuei0gtDSR4BQYz/gBOYUn+VIU"
|
||||||
|
:LDAP_ORGANISATION "Maidstone Hackspace Test"
|
||||||
|
:LDAP_DOMAIN "stage.maidstone-hackspace.org.uk"
|
||||||
|
:LDAP_ADMIN_PASSWORD "NSNZ8xjXwVxis"
|
||||||
|
:LDAP_SERVER "directory"
|
||||||
|
:LDAP_ROOT "dc \"stage, dc \"maidstone-hackspace, dc \"org, dc \"uk"
|
||||||
|
:TWITTER_CONSUMER_KEY "ZdLvlgNBiTNfTWkkKY0ub9F1j"
|
||||||
|
:TWITTER_CONSUMER_SECRET "z3q5mANhNnIHEO6pXhz5Onex41WHObbZRGZ6MS9WchoTA29qQ7"
|
||||||
|
:TWITTER_ACCESS_TOKEN "2756146621-3vJvbfIaeHMMoghaPy7D587xls3QmukyXkC4OGh"
|
||||||
|
:TWITTER_ACCESS_SECRET "PWc6oZFZCXuYxf9VWZxBidPw2AKj69gSvZX0qSz8JQFPu"
|
||||||
|
:RFID_SECRET "jkhgfkjghjhjgf,kjknsfdkjjadjhglaskjnfjvysyjhbfsckjkbh"}}
|
|
@ -0,0 +1,12 @@
|
||||||
|
(defproject kube-deploy "0.1.0-SNAPSHOT"
|
||||||
|
:description "FIXME: write description"
|
||||||
|
:url "http://example.com/FIXME"
|
||||||
|
:license {:name "Eclipse Public License"
|
||||||
|
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||||
|
:dependencies [[org.clojure/clojure "1.8.0"]
|
||||||
|
[org.clojure/data.codec "0.1.1"]
|
||||||
|
[nano-id "0.9.3"]
|
||||||
|
[brosenan/lambdakube "0.7.0"]]
|
||||||
|
:plugins [[lein-auto "0.1.3"]]
|
||||||
|
:auto {:default {:file-pattern #"\.(clj|cljs|cljx|cljc|edn)$"}}
|
||||||
|
:main kube-deploy.core)
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Auto deploy script
|
||||||
|
|
||||||
|
Based on (https://github.com/brosenan/lambdakube-example) using (https://github.com/brosenan/lambda-kube) library.
|
|
@ -0,0 +1,331 @@
|
||||||
|
(ns kube-deploy.core
|
||||||
|
(:require [lambdakube.core :as lk]
|
||||||
|
[kube-deploy.helpers :as lkh]
|
||||||
|
[lambdakube.util :as lku]
|
||||||
|
[clojure.java.shell :as sh]
|
||||||
|
[clojure.java.io :as io]))
|
||||||
|
|
||||||
|
(def conf (atom {}))
|
||||||
|
(def config {:num-be-slaves 3 :num-fe-replicas 3})
|
||||||
|
|
||||||
|
(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 "200m" :memory "400Mi"}
|
||||||
|
:limits
|
||||||
|
{:cpu "500m" :memory "1Gi"}})
|
||||||
|
|
||||||
|
; will not be needed soon
|
||||||
|
(defn kube-apply-namespace
|
||||||
|
([content file]
|
||||||
|
(kube-apply-namespace content file nil nil))
|
||||||
|
([content file namespace]
|
||||||
|
(kube-apply-namespace content namespace nil))
|
||||||
|
([content file kube-namespace kube-config]
|
||||||
|
(let [namespace-param (if (nil? namespace) nil (str "--namespace=" kube-namespace))
|
||||||
|
config-param (if (nil? 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 :redis
|
||||||
|
:role :master
|
||||||
|
:tier :backend})
|
||||||
|
(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 database [kube-injector]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule :postgres-master-rule []
|
||||||
|
(fn []
|
||||||
|
(-> (lk/pod
|
||||||
|
:postgres-master
|
||||||
|
{:app :postgres :role :master :tier :backend})
|
||||||
|
(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/deployment 1)
|
||||||
|
(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 :rabbit :role :master :tier :backend})
|
||||||
|
|
||||||
|
(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 :backend}
|
||||||
|
{: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 ["/gunicorn.sh"])
|
||||||
|
(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
|
||||||
|
:role :master
|
||||||
|
:tier :backend}
|
||||||
|
{: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" "huey"])
|
||||||
|
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
|
||||||
|
(lk/deployment 2))))))
|
||||||
|
|
||||||
|
(defn footprint [kube-injector]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule :footprint-backend-master [:postgres-master-rule :redis-master-rule :rabbit-master-rule]
|
||||||
|
(fn [postgres redis rabbit]
|
||||||
|
(-> (lk/pod :footprint-master {:app :footprint
|
||||||
|
:role :master
|
||||||
|
:tier :backend}
|
||||||
|
{:imagePullSecrets [{:name "docker-registry"}]})
|
||||||
|
|
||||||
|
; Add containers to the pod, one for frontend assets and one for backend
|
||||||
|
(lk/add-container
|
||||||
|
:footprint-backend
|
||||||
|
(get-in @conf [:images :footprint])
|
||||||
|
(-> {}
|
||||||
|
(lkh/add-to-spec :resources resources-medium)
|
||||||
|
(lkh/add-to-spec :command ["/gunicorn.sh"])
|
||||||
|
(lkh/add-to-spec :ports [{:containerPort 5000 :name "gunicorn-port"}])
|
||||||
|
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])
|
||||||
|
#_(lkh/add-readiness-probe-get "http://127.0.0.1" 5000)
|
||||||
|
(lkh/add-liveness-probe-get "http://127.0.0.1" 5000)))
|
||||||
|
|
||||||
|
(lk/add-container
|
||||||
|
:footprint-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-get "127.0.0.1/static/images/favicon.ico" 80)
|
||||||
|
(lkh/add-liveness-probe-get "http://127.0.0.1/static/images/favicon.ico" 80)))
|
||||||
|
|
||||||
|
(lk/add-volume "static-files" {:emptyDir {}}
|
||||||
|
{:footprint-backend "/app/staticfiles"
|
||||||
|
:footprint-frontend "/usr/share/nginx/html/static/"})
|
||||||
|
|
||||||
|
; order does matter here, deployment after initcontainers
|
||||||
|
(lku/wait-for-service-port postgres :postgres)
|
||||||
|
(lku/wait-for-service-port redis :redis)
|
||||||
|
(lku/wait-for-service-port rabbit :rabbit)
|
||||||
|
|
||||||
|
; wrap in a deployment
|
||||||
|
(lk/deployment 2)
|
||||||
|
(lk/expose-cluster-ip :footprint-backend
|
||||||
|
(lk/port :footprint-master :gunicorn-port 5000 5000))
|
||||||
|
(lk/expose-cluster-ip :footprint-frontend
|
||||||
|
(lk/port :footprint-master :nginx-port 80 80)))))
|
||||||
|
(lk/rule :footprint-queue-master []
|
||||||
|
(fn []
|
||||||
|
(-> (lk/pod :footprint-queue
|
||||||
|
{:app :footprint
|
||||||
|
:role :master
|
||||||
|
:tier :backend}
|
||||||
|
{:imagePullSecrets [{:name "docker-registry"}]})
|
||||||
|
|
||||||
|
(lk/add-container
|
||||||
|
:footprint
|
||||||
|
(get-in @conf [:images :footprint])
|
||||||
|
(-> {}
|
||||||
|
(lkh/add-to-spec :resources resources-small)
|
||||||
|
(lkh/add-to-spec :command ["/app/manage.py" "rundramatiq" "-p" "1" "-t" "1"])
|
||||||
|
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
|
||||||
|
|
||||||
|
(lk/deployment 2))))))
|
||||||
|
|
||||||
|
(defn make-secrets [kube-injector name data]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule :secrets []
|
||||||
|
(fn []
|
||||||
|
(-> (lkh/secrets (keyword name) data))))))
|
||||||
|
|
||||||
|
(defn make-registry-secrets [kube-injector name data]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule
|
||||||
|
:secrets-registry []
|
||||||
|
(fn []
|
||||||
|
(lkh/secrets-registry name {} (lkh/encode-secret-map data))))))
|
||||||
|
|
||||||
|
(defn make-namespace [kube-injector name]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule :namespace []
|
||||||
|
(fn []
|
||||||
|
(lkh/kube-namespace (keyword name))))))
|
||||||
|
|
||||||
|
(defn make-environment-secrets [kube-injector name data]
|
||||||
|
(-> kube-injector
|
||||||
|
(lk/rule :secrets-environment []
|
||||||
|
(fn []
|
||||||
|
(lkh/secrets name {}
|
||||||
|
(lkh/encode-secret-map data))))))
|
||||||
|
|
||||||
|
(defn make-ingress [kube-injector]
|
||||||
|
(lk/rule kube-injector :lkube-ingress []
|
||||||
|
(fn []
|
||||||
|
(-> (lkh/ingress "lkube-ingress" {:app :nginx-ingress})
|
||||||
|
(lkh/add-spec :tls [{:hosts [:lkube-ingress] :secretName "lkube-tls"}])
|
||||||
|
(lkh/add-spec :rules [{:host "lkube-ingress.35.197.252.20.nip.io"
|
||||||
|
: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]
|
||||||
|
(reset! conf (clojure.edn/read-string (slurp (str namespace "-config.edn"))))
|
||||||
|
; run deployment in default namespace to create a namespace called footprint
|
||||||
|
(-> (lk/injector)
|
||||||
|
(make-namespace namespace)
|
||||||
|
lk/standard-descs
|
||||||
|
(lk/get-deployable config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
|
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) nil kube-config))
|
||||||
|
|
||||||
|
; run deployment under footprint namespace
|
||||||
|
(-> (lk/injector)
|
||||||
|
(make-environment-secrets :environment (:vars @conf))
|
||||||
|
(make-registry-secrets :docker-registry {:.dockerconfigjson (:registry @conf)})
|
||||||
|
make-ingress
|
||||||
|
rabbitmq
|
||||||
|
database
|
||||||
|
redis
|
||||||
|
footprint
|
||||||
|
lk/standard-descs
|
||||||
|
(lk/get-deployable config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
|
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) "footprint" kube-config)))
|
||||||
|
|
||||||
|
(defn hackspace-deployment [namespace kube-config]
|
||||||
|
(reset! conf (clojure.edn/read-string (slurp (str namespace "-config.edn"))))
|
||||||
|
; run deployment in default namespace to create a namespace called footprint
|
||||||
|
(-> (lk/injector)
|
||||||
|
(make-namespace namespace)
|
||||||
|
;lk/standard-descs
|
||||||
|
(lk/get-deployable config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
|
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) nil kube-config))
|
||||||
|
|
||||||
|
; run deployment under footprint namespace
|
||||||
|
(-> (lk/injector)
|
||||||
|
(make-environment-secrets :environment (:vars @conf))
|
||||||
|
;(make-registry-secrets :docker-registry {:.dockerconfigjson (:registry @conf)})
|
||||||
|
make-ingress
|
||||||
|
database
|
||||||
|
redis
|
||||||
|
hackspace
|
||||||
|
lk/standard-descs
|
||||||
|
(lk/get-deployable config)
|
||||||
|
(lkh/to-yaml-store (str namespace "-store.yaml"))
|
||||||
|
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) namespace kube-config)))
|
||||||
|
|
||||||
|
(defn -main []
|
||||||
|
(hackspace-deployment "maidstone-hackspace" "/home/oly/.kube/dke.yml")
|
||||||
|
(footprint-deployment "footprint" "/home/oly/.kube/ake.yml"))
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
(ns kube-deploy.helpers
|
||||||
|
(:require [lambdakube.core :as lk]
|
||||||
|
[clojure.data.codec.base64 :as b64]))
|
||||||
|
|
||||||
|
(defn kube-namespace
|
||||||
|
([name]
|
||||||
|
{:apiVersion "v1"
|
||||||
|
:kind "Namespace"
|
||||||
|
:metadata {:name name}}))
|
||||||
|
|
||||||
|
(defn secrets
|
||||||
|
([name labels options]
|
||||||
|
{:apiVersion "v1"
|
||||||
|
:kind "Secret"
|
||||||
|
:type "Opaque"
|
||||||
|
:metadata {:name name :labels labels}
|
||||||
|
:data options}))
|
||||||
|
|
||||||
|
(defn secrets-registry
|
||||||
|
([name labels options]
|
||||||
|
{:apiVersion "v1"
|
||||||
|
:kind "Secret"
|
||||||
|
:type "kubernetes.io/dockerconfigjson"
|
||||||
|
:metadata {:name name :labels labels}
|
||||||
|
:data options}))
|
||||||
|
|
||||||
|
(defn ingress
|
||||||
|
([name labels]
|
||||||
|
(ingress name labels {}))
|
||||||
|
([name labels spec]
|
||||||
|
{:apiVersion "networking.k8s.io/v1beta1"
|
||||||
|
:kind "Ingress"
|
||||||
|
:metadata {:name name :labels labels}
|
||||||
|
:spec spec}))
|
||||||
|
|
||||||
|
(defn add-to-spec
|
||||||
|
([container name value]
|
||||||
|
(-> container
|
||||||
|
(assoc name value))))
|
||||||
|
|
||||||
|
(defn add-readiness-probe-get
|
||||||
|
([container url port]
|
||||||
|
(add-readiness-probe-get container url port 60 60))
|
||||||
|
([container url port delay period]
|
||||||
|
(-> container
|
||||||
|
(assoc :readinessProbe
|
||||||
|
{:periodSeconds period
|
||||||
|
:initialDelaySeconds delay
|
||||||
|
:failureThreshold 5
|
||||||
|
:httpGet {:path url :port port}}))))
|
||||||
|
|
||||||
|
(defn add-readiness-probe-cmd
|
||||||
|
([container command]
|
||||||
|
(add-readiness-probe-cmd container command 60 60))
|
||||||
|
([container command delay period]
|
||||||
|
(-> container
|
||||||
|
(assoc :readinessProbe
|
||||||
|
{:periodSeconds period
|
||||||
|
:initialDelaySeconds delay
|
||||||
|
:failureThreshold 5
|
||||||
|
:exec {:command command}}))))
|
||||||
|
|
||||||
|
(defn add-liveness-probe-get
|
||||||
|
([container url port]
|
||||||
|
(add-liveness-probe-get container url port 60 60))
|
||||||
|
([container url port delay period]
|
||||||
|
(-> container
|
||||||
|
(assoc :livenessProbe
|
||||||
|
{:periodSeconds period
|
||||||
|
:initialDelaySeconds delay
|
||||||
|
:failureThreshold 5
|
||||||
|
:httpGet {:path url :port port}}))))
|
||||||
|
|
||||||
|
(defn add-liveness-probe-cmd
|
||||||
|
([container command]
|
||||||
|
(add-liveness-probe-cmd container command 60 60))
|
||||||
|
([container command delay period]
|
||||||
|
(-> container
|
||||||
|
(assoc :livenessProbe
|
||||||
|
{:periodSeconds delay
|
||||||
|
:initialDelaySeconds period
|
||||||
|
:failureThreshold 5
|
||||||
|
:exec {:command command}}))))
|
||||||
|
|
||||||
|
(defn add-tls [obj key val]
|
||||||
|
(-> obj
|
||||||
|
(update-in [:spec :tls] assoc key val)))
|
||||||
|
|
||||||
|
(defn add-rules [obj key val]
|
||||||
|
(-> obj
|
||||||
|
(update-in [:spec :rules] assoc key val)))
|
||||||
|
|
||||||
|
;; livenessProbe:
|
||||||
|
;; exec:
|
||||||
|
;; command:
|
||||||
|
;; - cat
|
||||||
|
;; - /tmp/healthy
|
||||||
|
;; initialDelaySeconds: 5
|
||||||
|
;; periodSeconds: 5
|
||||||
|
|
||||||
|
;; (defn add-spec [obj key val]
|
||||||
|
;; (-> obj
|
||||||
|
;; (update-in [:spec] assoc key val)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-spec [obj key val]
|
||||||
|
(-> obj
|
||||||
|
(update-in [:spec] assoc key val)))
|
||||||
|
|
||||||
|
(defn encode-secret [value]
|
||||||
|
(b64/encode (.getBytes value)))
|
||||||
|
|
||||||
|
(defn encode-secret-map [data]
|
||||||
|
(reduce-kv
|
||||||
|
(fn [m k v] (assoc m k (encode-secret v)))
|
||||||
|
{}
|
||||||
|
data))
|
||||||
|
|
||||||
|
(defn to-yaml-store [$ filename]
|
||||||
|
(let [y (lk/to-yaml $)]
|
||||||
|
(spit filename y) y))
|
||||||
|
|
||||||
|
(defn to-yaml [$]
|
||||||
|
(let [y (lk/to-yaml $)]
|
||||||
|
(spit "test.yaml" y)
|
||||||
|
y))
|
||||||
|
|
||||||
|
|
||||||
|
;; (defn add-init-container
|
||||||
|
;; ([pod name image options]
|
||||||
|
;; (let [container (-> options
|
||||||
|
;; (merge {:name name
|
||||||
|
;; :image image}))]
|
||||||
|
;; (update pod :spec field-conj :initContainers container)))
|
||||||
|
;; ([pod name image]
|
||||||
|
;; (add-init-container pod name image {})))
|
||||||
|
|
||||||
|
;; (defn update-container [pod cont-name f & args]
|
||||||
|
;; (let [update-cont (fn [cont]
|
||||||
|
;; (if (= (:name cont) cont-name)
|
||||||
|
;; (apply f cont args)
|
||||||
|
;; ;; else
|
||||||
|
;; cont))]
|
||||||
|
;; (-> pod
|
||||||
|
;; (update-in [:spec :containers] #(map update-cont %))
|
||||||
|
;; (update-in [:spec :initContainers] #(map update-cont %))
|
||||||
|
;; (update :spec #(if (empty? (:initContainers %))
|
||||||
|
;; (dissoc % :initContainers)
|
||||||
|
;; ;; else
|
||||||
|
;; %)))))
|
||||||
|
|
||||||
|
|
||||||
|
;; (defn wait-for-service-port
|
||||||
|
;; ([pod dep portname]
|
||||||
|
;; (let [{:keys [hostname ports]} dep
|
||||||
|
;; cont (keyword (str "wait-for-" (name hostname) "-" (name portname)))]
|
||||||
|
;; (-> pod
|
||||||
|
;; (lk/add-init-container cont "busybox"
|
||||||
|
;; {:command ["sh"
|
||||||
|
;; "-c"
|
||||||
|
;; (str "while ! nc -z " hostname " " (ports portname) "; do sleep 1; done")]}))))
|
||||||
|
;; ([pod dep]
|
||||||
|
;; (when-not (= (-> dep :ports count) 1)
|
||||||
|
;; (throw (Exception. "Port name must be specified when waiting for a service exposing more than one port.")))
|
||||||
|
;; (let [portname (-> dep :ports first first)]
|
||||||
|
;; (wait-for-service-port pod dep portname))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
(ns kube-deploy.core-test
|
||||||
|
(require [clojure.test :refer :all]
|
||||||
|
[kube-deploy.core :as lke]
|
||||||
|
[lambdakube.core :as lk]
|
||||||
|
[lambdakube.util :as lku]
|
||||||
|
[lambdakube.testing :as lkt]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-module [$]
|
||||||
|
(-> $
|
||||||
|
;; Tests that the master-slave configuration works. We set a
|
||||||
|
;; value in the master, and then read it from the slave,
|
||||||
|
;; expecting it to be the same.
|
||||||
|
(lkt/test :redis-slave-configured
|
||||||
|
{:num-be-slaves 1}
|
||||||
|
[:backend-master :backend-slave]
|
||||||
|
(fn [master slave]
|
||||||
|
(-> (lk/pod :test {})
|
||||||
|
;; Wait for both the master and slave to be up
|
||||||
|
(lku/wait-for-service-port master :redis)
|
||||||
|
(lku/wait-for-service-port slave :redis)
|
||||||
|
;; We use midje for the tests
|
||||||
|
(lku/add-midje-container
|
||||||
|
:test
|
||||||
|
'[[org.clojure/clojure "1.8.0"]
|
||||||
|
;; Carmine is a Redis client library for Clojure
|
||||||
|
[com.taoensso/carmine "2.18.1"]]
|
||||||
|
;; We pass the connection details for the Redis
|
||||||
|
;; master and slave, as provided by our
|
||||||
|
;; dependencies as constants to the test.
|
||||||
|
{:master-conn {:pool {} :spec {:host (:hostname master)
|
||||||
|
:port (-> master :ports :redis)}}
|
||||||
|
:slave-conn {:pool {} :spec {:host (:hostname slave)
|
||||||
|
:port (-> slave :ports :redis)}}}
|
||||||
|
'[(ns main-test
|
||||||
|
(:require [midje.sweet :refer :all]
|
||||||
|
[taoensso.carmine :as car]))
|
||||||
|
(fact
|
||||||
|
;; Set the value in the master.
|
||||||
|
(car/wcar master-conn
|
||||||
|
(car/with-replies
|
||||||
|
(car/set "foo" "bar")) => "OK")
|
||||||
|
;; Wait for value to propagate to slave
|
||||||
|
(Thread/sleep 1000)
|
||||||
|
;; Get the value from the slave.
|
||||||
|
(car/wcar slave-conn
|
||||||
|
(car/with-replies
|
||||||
|
(car/get "foo")) => "bar"))]))))
|
||||||
|
;; This tests the PHP code in the frontent. It sets value to a
|
||||||
|
;; key and then queries it.
|
||||||
|
(lkt/test :frontend-set-and-get
|
||||||
|
{:num-be-slaves 1
|
||||||
|
:num-fe-replicas 1}
|
||||||
|
[:frontend]
|
||||||
|
(fn [frontend]
|
||||||
|
(-> (lk/pod :test {})
|
||||||
|
;; We wait for the frontend to come up
|
||||||
|
(lku/wait-for-service-port frontend :web)
|
||||||
|
(lku/add-midje-container
|
||||||
|
:test
|
||||||
|
'[[org.clojure/clojure "1.8.0"]
|
||||||
|
;; We use clj-http to query the PHP page.
|
||||||
|
[clj-http "3.9.1"]]
|
||||||
|
;; We pass the `base-url` to the PHP page as a
|
||||||
|
;; constant. Values are based on the `frontend`
|
||||||
|
;; dependency.
|
||||||
|
{:base-url (str "http://"
|
||||||
|
(:hostname frontend)
|
||||||
|
":"
|
||||||
|
(-> frontend :ports :web)
|
||||||
|
"/guestbook.php")}
|
||||||
|
'[(ns main-test
|
||||||
|
(:require [midje.sweet :refer :all]
|
||||||
|
[clj-http.client :as client]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
;; A function that makes a query to the PHP
|
||||||
|
;; page, by constructing a URL and making a
|
||||||
|
;; GET request.
|
||||||
|
(defn wget [query]
|
||||||
|
(let [resp (client/get (str base-url "?" (str/join "&" (for [[k v] query]
|
||||||
|
(str k "=" v)))))]
|
||||||
|
(when-not (= (:status resp) 200)
|
||||||
|
(throw (Exception. (str "Bad status" (:status resp) ": " (:body resp)))))
|
||||||
|
(:body resp)))
|
||||||
|
|
||||||
|
;; Set a value.
|
||||||
|
(fact
|
||||||
|
(wget {"cmd" "set"
|
||||||
|
"key" "foo"
|
||||||
|
"value" "bar"}) => "{\"message\": \"Updated\"}")
|
||||||
|
;; Query that value.
|
||||||
|
(fact
|
||||||
|
(wget {"cmd" "get"
|
||||||
|
"key" "foo"}) => "{\"data\": \"bar\"}")]))))))
|
||||||
|
|
||||||
|
(deftest kubetests
|
||||||
|
(is (= (-> (lk/injector)
|
||||||
|
(lke/module)
|
||||||
|
(lk/standard-descs)
|
||||||
|
(test-module)
|
||||||
|
(lkt/kube-tests "lk-ex")) "")))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue