diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3fec32c842751033d92c8967eba40c3911333a78
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+tmp/
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a42a6bb76b6ac8eee63469d2be28351f18054da3
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+set -e
+set -x
+
+prefix="tmp/manifests"
+json="tmp/manifests.json"
+
+rm -rf ${prefix}
+mkdir -p $(dirname "${json}")
+jsonnet -J /home/brancz/.jsonnet-bundler/src/git/git@github.com-ksonnet-ksonnet-lib/master jsonnet/kube-prometheus.jsonnet > ${json}
+
+files=$(jq -r 'keys[]' ${json})
+
+for file in ${files}; do
+    dir=$(dirname "${file}")
+    path="${prefix}/${dir}"
+    mkdir -p ${path}
+    jq -r ".[\"${file}\"]" ${json} | yaml2json | json2yaml > "${prefix}/${file}"
+done
diff --git a/jsonnet/alertmanager/alertmanager-main-secret.libsonnet b/jsonnet/alertmanager/alertmanager-main-secret.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..fca165667692cf2cd3fdba34ef527f5e93951b09
--- /dev/null
+++ b/jsonnet/alertmanager/alertmanager-main-secret.libsonnet
@@ -0,0 +1,25 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local secret = k.core.v1.secret;
+
+local plainConfig = "global:
+  resolve_timeout: 5m
+route:
+  group_by: ['job']
+  group_wait: 30s
+  group_interval: 5m
+  repeat_interval: 12h
+  receiver: 'null'
+  routes:
+  - match:
+      alertname: DeadMansSwitch
+    receiver: 'null'
+receivers:
+- name: 'null'";
+
+local config = std.base64(plainConfig);
+
+{
+    new(namespace)::
+        secret.new("alertmanager-main", {"alertmanager.yaml": config}) +
+          secret.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/alertmanager/alertmanager-main-service-account.libsonnet b/jsonnet/alertmanager/alertmanager-main-service-account.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..89ca2f803f40e6819ae36b5c40a5e229f65c79b7
--- /dev/null
+++ b/jsonnet/alertmanager/alertmanager-main-service-account.libsonnet
@@ -0,0 +1,8 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local serviceAccount = k.core.v1.serviceAccount;
+
+{
+    new(namespace)::
+        serviceAccount.new("alertmanager-main") +
+          serviceAccount.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/alertmanager/alertmanager-main-service.libsonnet b/jsonnet/alertmanager/alertmanager-main-service.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..e89f009fa8f8411c107b5ec41e86e0976dbe5f19
--- /dev/null
+++ b/jsonnet/alertmanager/alertmanager-main-service.libsonnet
@@ -0,0 +1,12 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local service = k.core.v1.service;
+local servicePort = k.core.v1.service.mixin.spec.portsType;
+
+local alertmanagerPort = servicePort.newNamed("web", 9093, "web");
+
+{
+    new(namespace)::
+        service.new("alertmanager-main", {app: "alertmanager", alertmanager: "main"}, alertmanagerPort) +
+          service.mixin.metadata.withNamespace(namespace) +
+          service.mixin.metadata.withLabels({alertmanager: "main"})
+}
diff --git a/jsonnet/alertmanager/alertmanager-main.libsonnet b/jsonnet/alertmanager/alertmanager-main.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..63e06a168f6aeb10bfabb2920a94c1475d3ee7ff
--- /dev/null
+++ b/jsonnet/alertmanager/alertmanager-main.libsonnet
@@ -0,0 +1,19 @@
+{
+    new(namespace)::
+        {
+          apiVersion: "monitoring.coreos.com/v1",
+          kind: "Alertmanager",
+          metadata: {
+            name: "main",
+            namespace: namespace,
+            labels: {
+              alertmanager: "main",
+            },
+          },
+          spec: {
+            replicas: 3,
+            version: "v0.14.0",
+            serviceAccountName: "alertmanager-main",
+          },
+        }
+}
diff --git a/jsonnet/alertmanager/alertmanager.libsonnet b/jsonnet/alertmanager/alertmanager.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..ef837abaa58167935257da4f3930e179a4f04fc8
--- /dev/null
+++ b/jsonnet/alertmanager/alertmanager.libsonnet
@@ -0,0 +1,6 @@
+{
+    config:: import "alertmanager-main-secret.libsonnet",
+    serviceAccount:: import "alertmanager-main-service-account.libsonnet",
+    service:: import "alertmanager-main-service.libsonnet",
+    alertmanager:: import "alertmanager-main.libsonnet",
+}
diff --git a/jsonnet/kube-prometheus.jsonnet b/jsonnet/kube-prometheus.jsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..3a0ef2cfc477bc4db79eb6c852c54f77f0f8f582
--- /dev/null
+++ b/jsonnet/kube-prometheus.jsonnet
@@ -0,0 +1,62 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+
+local alertmanager = import "alertmanager/alertmanager.libsonnet";
+local ksm = import "kube-state-metrics/kube-state-metrics.libsonnet";
+local nodeExporter = import "node-exporter/node-exporter.libsonnet";
+local po = import "prometheus-operator/prometheus-operator.libsonnet";
+local prometheus = import "prometheus/prometheus.libsonnet";
+
+local namespace = "monitoring";
+
+local objects = {
+    "alertmanager-main/alertmanager-main-secret.yaml":          alertmanager.config.new(namespace),
+    "alertmanager-main/alertmanager-main-service-account.yaml": alertmanager.serviceAccount.new(namespace),
+    "alertmanager-main/alertmanager-main-service.yaml":         alertmanager.service.new(namespace),
+    "alertmanager-main/alertmanager-main.yaml":                 alertmanager.alertmanager.new(namespace),
+
+    "kube-state-metrics/kube-state-metrics-cluster-role-binding": ksm.clusterRoleBinding.new(namespace),
+    "kube-state-metrics/kube-state-metrics-cluster-role.yaml":    ksm.clusterRole.new(),
+    "kube-state-metrics/kube-state-metrics-deployment.yaml":      ksm.deployment.new(namespace),
+    "kube-state-metrics/kube-state-metrics-role-binding.yaml":    ksm.roleBinding.new(namespace),
+    "kube-state-metrics/kube-state-metrics-role.yaml":            ksm.role.new(namespace),
+    "kube-state-metrics/kube-state-metrics-service-account.yaml": ksm.serviceAccount.new(namespace),
+    "kube-state-metrics/kube-state-metrics-service.yaml":         ksm.service.new(namespace),
+
+    "node-exporter/node-exporter-cluster-role-binding.yaml": nodeExporter.clusterRoleBinding.new(namespace),
+    "node-exporter/node-exporter-cluster-role.yaml": nodeExporter.clusterRole.new(),
+    "node-exporter/node-exporter-daemonset.yaml": nodeExporter.daemonset.new(namespace),
+    "node-exporter/node-exporter-service-account.yaml": nodeExporter.serviceAccount.new(namespace),
+    "node-exporter/node-exporter-service.yaml": nodeExporter.service.new(namespace),
+
+    "prometheus-operator/prometheus-operator-cluster-role-binding.yaml": po.clusterRoleBinding.new(namespace),
+    "prometheus-operator/prometheus-operator-cluster-role.yaml":         po.clusterRole.new(),
+    "prometheus-operator/prometheus-operator-deployment.yaml":           po.deployment.new(namespace),
+    "prometheus-operator/prometheus-operator-service.yaml":              po.service.new(namespace),
+    "prometheus-operator/prometheus-operator-service-account.yaml":      po.serviceAccount.new(namespace),
+
+    "prometheus-k8s/prometheus-k8s-cluster-role-binding.yaml":                    prometheus.clusterRoleBinding.new(namespace),
+    "prometheus-k8s/prometheus-k8s-cluster-role.yaml":                            prometheus.clusterRole.new(),
+    "prometheus-k8s/prometheus-k8s-service-account.yaml":                         prometheus.serviceAccount.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service.yaml":                                 prometheus.service.new(namespace),
+    "prometheus-k8s/prometheus-k8s.yaml":                                         prometheus.prometheus.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-binding-config.yaml":                     prometheus.roleBindingConfig.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-binding-namespace.yaml":                  prometheus.roleBindingNamespace.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-binding-kube-system.yaml":                prometheus.roleBindingKubeSystem.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-binding-default.yaml":                    prometheus.roleBindingDefault.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-config.yaml":                             prometheus.roleConfig.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-namespace.yaml":                          prometheus.roleNamespace.new(namespace),
+    "prometheus-k8s/prometheus-k8s-role-kube-system.yaml":                        prometheus.roleKubeSystem.new(),
+    "prometheus-k8s/prometheus-k8s-role-default.yaml":                            prometheus.roleDefault.new(),
+    "prometheus-k8s/prometheus-k8s-service-monitor-alertmanager.yaml":            prometheus.serviceMonitorAlertmanager.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-apiserver.yaml":               prometheus.serviceMonitorApiserver.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-coredns.yaml":                 prometheus.serviceMonitorCoreDNS.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-kube-controller-manager.yaml": prometheus.serviceMonitorControllerManager.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-kube-scheduler.yaml":          prometheus.serviceMonitorScheduler.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-kube-state-metrics.yaml":      prometheus.serviceMonitorKubeStateMetrics.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-kubelet.yaml":                 prometheus.serviceMonitorKubelet.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-node-exporter.yaml":           prometheus.serviceMonitorNodeExporter.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-prometheus-operator.yaml":     prometheus.serviceMonitorPrometheusOperator.new(namespace),
+    "prometheus-k8s/prometheus-k8s-service-monitor-prometheus.yaml":              prometheus.serviceMonitorPrometheus.new(namespace),
+};
+
+{[path]: std.manifestYamlDoc(objects[path]) for path in std.objectFields(objects)}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role-binding.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..ae150c35933176f62a41abdfd7b9007f27d9e8db
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role-binding.libsonnet
@@ -0,0 +1,12 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+{
+    new(namespace)::
+        clusterRoleBinding.new() +
+          clusterRoleBinding.mixin.metadata.withName("kube-state-metrics") +
+          clusterRoleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+          clusterRoleBinding.mixin.roleRef.withName("kube-state-metrics") +
+          clusterRoleBinding.mixin.roleRef.mixinInstance({kind: "ClusterRole"}) +
+          clusterRoleBinding.withSubjects([{kind: "ServiceAccount", name: "kube-state-metrics", namespace: namespace}])
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..976d850abf7dad1b525c0bee6e832f969954dab6
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-cluster-role.libsonnet
@@ -0,0 +1,75 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRole = k.rbac.v1.clusterRole;
+local policyRule = clusterRole.rulesType;
+
+local coreRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "configmaps",
+    "secrets",
+    "nodes",
+    "pods",
+    "services",
+    "resourcequotas",
+    "replicationcontrollers",
+    "limitranges",
+    "persistentvolumeclaims",
+    "persistentvolumes",
+    "namespaces",
+    "endpoints",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local extensionsRule = policyRule.new() +
+  policyRule.withApiGroups(["extensions"]) +
+  policyRule.withResources([
+    "daemonsets",
+    "deployments",
+    "replicasets",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local appsRule = policyRule.new() +
+  policyRule.withApiGroups(["apps"]) +
+  policyRule.withResources([
+    "statefulsets",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local batchRule = policyRule.new() +
+  policyRule.withApiGroups(["batch"]) +
+  policyRule.withResources([
+    "cronjobs",
+    "jobs",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local autoscalingRule = policyRule.new() +
+  policyRule.withApiGroups(["autoscaling"]) +
+  policyRule.withResources([
+    "horizontalpodautoscalers",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local authenticationRole = policyRule.new() +
+  policyRule.withApiGroups(["authentication.k8s.io"]) +
+  policyRule.withResources([
+    "tokenreviews",
+  ]) +
+  policyRule.withVerbs(["create"]);
+
+local authorizationRole = policyRule.new() +
+  policyRule.withApiGroups(["authorization.k8s.io"]) +
+  policyRule.withResources([
+    "subjectaccessreviews",
+  ]) +
+  policyRule.withVerbs(["create"]);
+
+local rules = [coreRule, extensionsRule, appsRule, batchRule, autoscalingRule, authenticationRole, authorizationRole];
+
+{
+    new()::
+        clusterRole.new() +
+          clusterRole.mixin.metadata.withName("kube-state-metrics") +
+          clusterRole.withRules(rules)
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-deployment.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-deployment.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..e873fa30b0d080d9684d214931c12b97db70d494
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-deployment.libsonnet
@@ -0,0 +1,86 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local deployment = k.apps.v1beta2.deployment;
+
+local deployment = k.apps.v1beta2.deployment;
+local container = k.apps.v1beta2.deployment.mixin.spec.template.spec.containersType;
+local volume = k.apps.v1beta2.deployment.mixin.spec.template.spec.volumesType;
+local containerPort = container.portsType;
+local containerVolumeMount = container.volumeMountsType;
+local podSelector = deployment.mixin.spec.template.spec.selectorType;
+
+local kubeStateMetricsVersion = "v1.3.0";
+local kubeRbacProxyVersion = "v0.3.0";
+local addonResizerVersion = "1.0";
+local podLabels = {"app": "kube-state-metrics"};
+
+local proxyClusterMetrics =
+  container.new("kube-rbac-proxy-main", "quay.io/coreos/kube-rbac-proxy:" + kubeRbacProxyVersion) +
+  container.withArgs([
+	"--secure-listen-address=:8443",
+	"--upstream=http://127.0.0.1:8081/",
+  ]) +
+  container.withPorts(containerPort.newNamed("https-main", 8443)) +
+  container.mixin.resources.withRequests({cpu: "10m", memory: "20Mi"}) +
+  container.mixin.resources.withLimits({cpu: "20m", memory: "40Mi"});
+
+local proxySelfMetrics =
+  container.new("kube-rbac-proxy-self", "quay.io/coreos/kube-rbac-proxy:" + kubeRbacProxyVersion) +
+  container.withArgs([
+	"--secure-listen-address=:9443",
+	"--upstream=http://127.0.0.1:8082/",
+  ]) +
+  container.withPorts(containerPort.newNamed("https-self", 9443)) +
+  container.mixin.resources.withRequests({cpu: "10m", memory: "20Mi"}) +
+  container.mixin.resources.withLimits({cpu: "20m", memory: "40Mi"});
+
+local kubeStateMetrics =
+  container.new("kube-state-metrics", "quay.io/coreos/kube-state-metrics:" + kubeStateMetricsVersion) +
+  container.withArgs([
+	"--host=127.0.0.1",
+	"--port=8081",
+	"--telemetry-host=127.0.0.1",
+	"--telemetry-port=8082",
+  ]) +
+  container.mixin.resources.withRequests({cpu: "102m", memory: "180Mi"}) +
+  container.mixin.resources.withLimits({cpu: "102m", memory: "180Mi"});
+
+local addonResizer =
+  container.new("addon-resizer", "quay.io/coreos/addon-resizer:" + addonResizerVersion) +
+  container.withCommand([
+	"/pod_nanny",
+	"--container=kube-state-metrics",
+	"--cpu=100m",
+	"--extra-cpu=2m",
+	"--memory=150Mi",
+	"--extra-memory=30Mi",
+	"--threshold=5",
+	"--deployment=kube-state-metrics",
+  ]) +
+  container.withEnv([
+	{
+	  name: "MY_POD_NAME",
+      valueFrom: {
+		fieldRef: {apiVersion: "v1", fieldPath: "metadata.name"}
+      }
+	}, {
+	  name: "MY_POD_NAMESPACE",
+      valueFrom: {
+		fieldRef: {apiVersion: "v1", fieldPath: "metadata.namespace"}
+      }
+	}
+  ]) +
+  container.mixin.resources.withRequests({cpu: "10m", memory: "30Mi"}) +
+  container.mixin.resources.withLimits({cpu: "10m", memory: "30Mi"});
+
+local c = [proxyClusterMetrics, proxySelfMetrics, kubeStateMetrics, addonResizer];
+
+{
+    new(namespace)::
+        deployment.new("kube-state-metrics", 1, c, podLabels) +
+          deployment.mixin.metadata.withNamespace(namespace) +
+          deployment.mixin.metadata.withLabels(podLabels) +
+          deployment.mixin.spec.selector.withMatchLabels(podLabels) +
+          deployment.mixin.spec.template.spec.securityContext.withRunAsNonRoot(true) +
+          deployment.mixin.spec.template.spec.securityContext.withRunAsUser(65534) +
+          deployment.mixin.spec.template.spec.withServiceAccountName("kube-state-metrics")
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-role-binding.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..bd9b03ae1b94a22c5c8df9da205e9cfa08993bda
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-role-binding.libsonnet
@@ -0,0 +1,13 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local roleBinding = k.rbac.v1.roleBinding;
+
+{
+    new(namespace)::
+        roleBinding.new() +
+          roleBinding.mixin.metadata.withName("kube-state-metrics") +
+          roleBinding.mixin.metadata.withNamespace(namespace) +
+          roleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+          roleBinding.mixin.roleRef.withName("kube-state-metrics-addon-resizer") +
+          roleBinding.mixin.roleRef.mixinInstance({kind: "Role"}) +
+          roleBinding.withSubjects([{kind: "ServiceAccount", name: "kube-state-metrics"}])
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-role.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..bf80880fb4547ba1d15b3979bcf9252e56d46d9c
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-role.libsonnet
@@ -0,0 +1,28 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local role = k.rbac.v1.role;
+local policyRule = role.rulesType;
+
+local coreRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "pods",
+  ]) +
+  policyRule.withVerbs(["get"]);
+
+local extensionsRule = policyRule.new() +
+  policyRule.withApiGroups(["extensions"]) +
+  policyRule.withResources([
+    "deployments",
+  ]) +
+  policyRule.withVerbs(["get", "update"]) +
+  policyRule.withResourceNames(["kube-state-metrics"]);
+
+local rules = [coreRule, extensionsRule];
+
+{
+    new(namespace)::
+        role.new() +
+          role.mixin.metadata.withName("kube-state-metrics") +
+          role.mixin.metadata.withNamespace(namespace) +
+          role.withRules(rules)
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-service-account.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-service-account.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..6e6904ff01cc8b9b2604fde8370adfd06caff9c7
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-service-account.libsonnet
@@ -0,0 +1,8 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local serviceAccount = k.core.v1.serviceAccount;
+
+{
+    new(namespace)::
+        serviceAccount.new("kube-state-metrics") +
+          serviceAccount.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics-service.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics-service.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..c8eaee18f1e96285d3834e937b60790693fb61b3
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics-service.libsonnet
@@ -0,0 +1,15 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local service = k.core.v1.service;
+local servicePort = k.core.v1.service.mixin.spec.portsType;
+
+local ksmDeployment = import "kube-state-metrics-deployment.libsonnet";
+
+local ksmServicePortMain = servicePort.newNamed("https-main", 8443, "https-main");
+local ksmServicePortSelf = servicePort.newNamed("https-self", 9443, "https-self");
+
+{
+    new(namespace)::
+        service.new("kube-state-metrics", ksmDeployment.new(namespace).spec.selector.matchLabels, [ksmServicePortMain, ksmServicePortSelf]) +
+          service.mixin.metadata.withNamespace(namespace) +
+          service.mixin.metadata.withLabels({"k8s-app": "kube-state-metrics"})
+}
diff --git a/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet b/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..3f9b8ba272432aebe05b57928fb0c99a5aafe746
--- /dev/null
+++ b/jsonnet/kube-state-metrics/kube-state-metrics.libsonnet
@@ -0,0 +1,9 @@
+{
+    clusterRoleBinding:: import "kube-state-metrics-cluster-role-binding.libsonnet",
+    clusterRole:: import "kube-state-metrics-cluster-role.libsonnet",
+    deployment:: import "kube-state-metrics-deployment.libsonnet",
+    roleBinding:: import "kube-state-metrics-role-binding.libsonnet",
+    role:: import "kube-state-metrics-role.libsonnet",
+    serviceAccount:: import "kube-state-metrics-service-account.libsonnet",
+    service:: import "kube-state-metrics-service.libsonnet",
+}
diff --git a/jsonnet/node-exporter/node-exporter-cluster-role-binding.libsonnet b/jsonnet/node-exporter/node-exporter-cluster-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..39f373b526d36f89627aa262c6b7f9f26d0133d8
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter-cluster-role-binding.libsonnet
@@ -0,0 +1,12 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+{
+    new(namespace)::
+        clusterRoleBinding.new() +
+          clusterRoleBinding.mixin.metadata.withName("node-exporter") +
+          clusterRoleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+          clusterRoleBinding.mixin.roleRef.withName("node-exporter") +
+          clusterRoleBinding.mixin.roleRef.mixinInstance({kind: "ClusterRole"}) +
+          clusterRoleBinding.withSubjects([{kind: "ServiceAccount", name: "node-exporter", namespace: namespace}])
+}
diff --git a/jsonnet/node-exporter/node-exporter-cluster-role.libsonnet b/jsonnet/node-exporter/node-exporter-cluster-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..426e0a668f475ec1b26fcba02bf18509dfbd1048
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter-cluster-role.libsonnet
@@ -0,0 +1,26 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRole = k.rbac.v1.clusterRole;
+local policyRule = clusterRole.rulesType;
+
+local authenticationRole = policyRule.new() +
+  policyRule.withApiGroups(["authentication.k8s.io"]) +
+  policyRule.withResources([
+    "tokenreviews",
+  ]) +
+  policyRule.withVerbs(["create"]);
+
+local authorizationRole = policyRule.new() +
+  policyRule.withApiGroups(["authorization.k8s.io"]) +
+  policyRule.withResources([
+    "subjectaccessreviews",
+  ]) +
+  policyRule.withVerbs(["create"]);
+
+local rules = [authenticationRole, authorizationRole];
+
+{
+    new()::
+        clusterRole.new() +
+          clusterRole.mixin.metadata.withName("node-exporter") +
+          clusterRole.withRules(rules)
+}
diff --git a/jsonnet/node-exporter/node-exporter-daemonset.libsonnet b/jsonnet/node-exporter/node-exporter-daemonset.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..ac6428914dbff3ad2cf59741aa294ba53590d6c9
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter-daemonset.libsonnet
@@ -0,0 +1,58 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+
+local daemonset = k.apps.v1beta2.daemonSet;
+local container = daemonset.mixin.spec.template.spec.containersType;
+local volume = daemonset.mixin.spec.template.spec.volumesType;
+local containerPort = container.portsType;
+local containerVolumeMount = container.volumeMountsType;
+local podSelector = daemonset.mixin.spec.template.spec.selectorType;
+
+local nodeExporterVersion = "v0.15.2";
+local kubeRbacProxyVersion = "v0.3.0";
+local podLabels = {"app": "node-exporter"};
+
+local procVolumeName = "proc";
+local procVolume = volume.fromHostPath(procVolumeName, "/proc");
+local procVolumeMount = containerVolumeMount.new(procVolumeName, "/host/proc");
+
+local sysVolumeName = "sys";
+local sysVolume = volume.fromHostPath(sysVolumeName, "/sys");
+local sysVolumeMount = containerVolumeMount.new(sysVolumeName, "/host/sys");
+
+local nodeExporter =
+  container.new("node-exporter", "quay.io/prometheus/node-exporter:" + nodeExporterVersion) +
+  container.withArgs([
+    "--web.listen-address=127.0.0.1:9101",
+    "--path.procfs=/host/proc",
+    "--path.sysfs=/host/sys",
+  ]) +
+  container.withVolumeMounts([procVolumeMount, sysVolumeMount]) +
+  container.mixin.resources.withRequests({cpu: "102m", memory: "180Mi"}) +
+  container.mixin.resources.withLimits({cpu: "102m", memory: "180Mi"});
+
+local proxy =
+  container.new("kube-rbac-proxy", "quay.io/coreos/kube-rbac-proxy:" + kubeRbacProxyVersion) +
+  container.withArgs([
+	"--secure-listen-address=:9100",
+	"--upstream=http://127.0.0.1:9101/",
+  ]) +
+  container.withPorts(containerPort.newNamed("https", 9100)) +
+  container.mixin.resources.withRequests({cpu: "10m", memory: "20Mi"}) +
+  container.mixin.resources.withLimits({cpu: "20m", memory: "40Mi"});
+
+local c = [nodeExporter, proxy];
+
+{
+    new(namespace)::
+        daemonset.new() +
+          daemonset.mixin.metadata.withName("node-exporter") +
+          daemonset.mixin.metadata.withNamespace(namespace) +
+          daemonset.mixin.metadata.withLabels(podLabels) +
+          daemonset.mixin.spec.selector.withMatchLabels(podLabels) +
+          daemonset.mixin.spec.template.metadata.withLabels(podLabels) +
+          daemonset.mixin.spec.template.spec.withContainers(c) +
+          daemonset.mixin.spec.template.spec.withVolumes([procVolume, sysVolume]) +
+          daemonset.mixin.spec.template.spec.securityContext.withRunAsNonRoot(true) +
+          daemonset.mixin.spec.template.spec.securityContext.withRunAsUser(65534) +
+          daemonset.mixin.spec.template.spec.withServiceAccountName("node-exporter")
+}
diff --git a/jsonnet/node-exporter/node-exporter-service-account.libsonnet b/jsonnet/node-exporter/node-exporter-service-account.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..f75a682737762d6e1a9d0633bd93329466e4a478
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter-service-account.libsonnet
@@ -0,0 +1,8 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local serviceAccount = k.core.v1.serviceAccount;
+
+{
+    new(namespace)::
+        serviceAccount.new("node-exporter") +
+          serviceAccount.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/node-exporter/node-exporter-service.libsonnet b/jsonnet/node-exporter/node-exporter-service.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..addbc5983c576d39a140c71b993f4d3f74bf8f22
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter-service.libsonnet
@@ -0,0 +1,14 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local service = k.core.v1.service;
+local servicePort = k.core.v1.service.mixin.spec.portsType;
+
+local nodeExporterDaemonset = import "node-exporter-daemonset.libsonnet";
+
+local nodeExporterPort = servicePort.newNamed("https", 9100, "https");
+
+{
+    new(namespace)::
+        service.new("node-exporter", nodeExporterDaemonset.new(namespace).spec.selector.matchLabels, nodeExporterPort) +
+          service.mixin.metadata.withNamespace(namespace) +
+          service.mixin.metadata.withLabels({"k8s-app": "node-exporter"})
+}
diff --git a/jsonnet/node-exporter/node-exporter.libsonnet b/jsonnet/node-exporter/node-exporter.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..57e67911c336f85f4eb74d5ee09e9fd0b0f5d00b
--- /dev/null
+++ b/jsonnet/node-exporter/node-exporter.libsonnet
@@ -0,0 +1,7 @@
+{
+    clusterRoleBinding:: import "node-exporter-cluster-role-binding.libsonnet",
+    clusterRole:: import "node-exporter-cluster-role.libsonnet",
+    daemonset:: import "node-exporter-daemonset.libsonnet",
+    serviceAccount:: import "node-exporter-service-account.libsonnet",
+    service:: import "node-exporter-service.libsonnet",
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator-cluster-role-binding.libsonnet b/jsonnet/prometheus-operator/prometheus-operator-cluster-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..64453c522dca2ea8812063195ecf17cbcc74bee7
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator-cluster-role-binding.libsonnet
@@ -0,0 +1,12 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+{
+    new(namespace)::
+        clusterRoleBinding.new() +
+          clusterRoleBinding.mixin.metadata.withName("prometheus-operator") +
+          clusterRoleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+          clusterRoleBinding.mixin.roleRef.withName("prometheus-operator") +
+          clusterRoleBinding.mixin.roleRef.mixinInstance({kind: "ClusterRole"}) +
+          clusterRoleBinding.withSubjects([{kind: "ServiceAccount", name: "prometheus-operator", namespace: namespace}])
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator-cluster-role.libsonnet b/jsonnet/prometheus-operator/prometheus-operator-cluster-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..db8bcd7b0f50b95c9fd1493518c42e21d4467f18
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator-cluster-role.libsonnet
@@ -0,0 +1,80 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRole = k.rbac.v1.clusterRole;
+local policyRule = clusterRole.rulesType;
+
+local extensionsRule = policyRule.new() +
+  policyRule.withApiGroups(["extensions"]) +
+  policyRule.withResources([
+    "thirdpartyresources",
+  ]) +
+  policyRule.withVerbs(["*"]);
+
+local apiExtensionsRule = policyRule.new() +
+  policyRule.withApiGroups(["apiextensions.k8s.io"]) +
+  policyRule.withResources([
+    "customresourcedefinitions",
+  ]) +
+  policyRule.withVerbs(["*"]);
+
+local monitoringRule = policyRule.new() +
+  policyRule.withApiGroups(["monitoring.coreos.com"]) +
+  policyRule.withResources([
+    "alertmanagers",
+    "prometheuses",
+    "prometheuses/finalizers",
+    "alertmanagers/finalizers",
+    "servicemonitors",
+  ]) +
+  policyRule.withVerbs(["*"]);
+
+local appsRule = policyRule.new() +
+  policyRule.withApiGroups(["apps"]) +
+  policyRule.withResources([
+    "statefulsets",
+  ]) +
+  policyRule.withVerbs(["*"]);
+
+local coreRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "configmaps",
+    "secrets",
+  ]) +
+  policyRule.withVerbs(["*"]);
+
+local podRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "pods",
+  ]) +
+  policyRule.withVerbs(["list", "delete"]);
+
+local routingRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "services",
+  ]) +
+  policyRule.withVerbs(["get", "create", "update"]);
+
+local nodeRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "nodes",
+  ]) +
+  policyRule.withVerbs(["list", "watch"]);
+
+local namespaceRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "namespaces",
+  ]) +
+  policyRule.withVerbs(["list"]);
+
+local rules = [extensionsRule, apiExtensionsRule, monitoringRule, appsRule, coreRule, podRule, routingRule, nodeRule, namespaceRule];
+
+{
+    new()::
+        clusterRole.new() +
+          clusterRole.mixin.metadata.withName("prometheus-operator") +
+          clusterRole.withRules(rules)
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator-deployment.libsonnet b/jsonnet/prometheus-operator/prometheus-operator-deployment.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..2ad7f5260bebe19fdfd4a3bb3378be61f86d07c9
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator-deployment.libsonnet
@@ -0,0 +1,30 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local rawVersion = importstr "../../../../VERSION";
+
+local removeLineBreaks = function(str) std.join("", std.filter(function(c) c != "\n", std.stringChars(str)));
+local version = removeLineBreaks(rawVersion);
+
+local deployment = k.apps.v1beta2.deployment;
+local container = k.apps.v1beta2.deployment.mixin.spec.template.spec.containersType;
+local containerPort = container.portsType;
+
+local targetPort = 8080;
+local podLabels = {"k8s-app": "prometheus-operator"};
+
+local operatorContainer =
+  container.new("prometheus-operator", "quay.io/coreos/prometheus-operator:v" + version) +
+  container.withPorts(containerPort.newNamed("http", targetPort)) +
+  container.withArgs(["--kubelet-service=kube-system/kubelet", "--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1"]) +
+  container.mixin.resources.withRequests({cpu: "100m", memory: "50Mi"}) +
+  container.mixin.resources.withLimits({cpu: "200m", memory: "100Mi"});
+
+{
+    new(namespace)::
+        deployment.new("prometheus-operator", 1, operatorContainer, podLabels) +
+          deployment.mixin.metadata.withNamespace(namespace) +
+          deployment.mixin.metadata.withLabels(podLabels) +
+          deployment.mixin.spec.selector.withMatchLabels(podLabels) +
+          deployment.mixin.spec.template.spec.securityContext.withRunAsNonRoot(true) +
+          deployment.mixin.spec.template.spec.securityContext.withRunAsUser(65534) +
+          deployment.mixin.spec.template.spec.withServiceAccountName("prometheus-operator")
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator-service-account.libsonnet b/jsonnet/prometheus-operator/prometheus-operator-service-account.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..791ce93cbb57165761f7c811cae5fc57b1039684
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator-service-account.libsonnet
@@ -0,0 +1,8 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local serviceAccount = k.core.v1.serviceAccount;
+
+{
+    new(namespace)::
+        serviceAccount.new("prometheus-operator") +
+          serviceAccount.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator-service.libsonnet b/jsonnet/prometheus-operator/prometheus-operator-service.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..8bbd1477f5b37fe11ae5897688766a582527d25b
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator-service.libsonnet
@@ -0,0 +1,14 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local service = k.core.v1.service;
+local servicePort = k.core.v1.service.mixin.spec.portsType;
+
+local poDeployment = import "prometheus-operator-deployment.libsonnet";
+
+local poServicePort = servicePort.newNamed("http", 8080, "http");
+
+
+{
+    new(namespace)::
+        service.new("prometheus-operator", poDeployment.new(namespace).spec.selector.matchLabels, [poServicePort]) +
+        service.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/prometheus-operator/prometheus-operator.libsonnet b/jsonnet/prometheus-operator/prometheus-operator.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..849acbbfd2ee122bba530b7c4eeb58e020058890
--- /dev/null
+++ b/jsonnet/prometheus-operator/prometheus-operator.libsonnet
@@ -0,0 +1,7 @@
+{
+  clusterRoleBinding:: import "prometheus-operator-cluster-role-binding.libsonnet",
+  clusterRole:: import "prometheus-operator-cluster-role.libsonnet",
+  deployment:: import "prometheus-operator-deployment.libsonnet",
+  serviceAccount:: import "prometheus-operator-service-account.libsonnet",
+  service:: import "prometheus-operator-service.libsonnet",
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-cluster-role-binding.libsonnet b/jsonnet/prometheus/prometheus-k8s-cluster-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..d577bee5619902258b32bc159bb0c1d2bf99bfa1
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-cluster-role-binding.libsonnet
@@ -0,0 +1,12 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+{
+    new(namespace)::
+        clusterRoleBinding.new() +
+          clusterRoleBinding.mixin.metadata.withName("prometheus-k8s") +
+          clusterRoleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+          clusterRoleBinding.mixin.roleRef.withName("prometheus-k8s") +
+          clusterRoleBinding.mixin.roleRef.mixinInstance({kind: "ClusterRole"}) +
+          clusterRoleBinding.withSubjects([{kind: "ServiceAccount", name: "prometheus-k8s", namespace: namespace}])
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-cluster-role.libsonnet b/jsonnet/prometheus/prometheus-k8s-cluster-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..c514624c2e6c2a5ab4c9389d6ce0e7f878b7b750
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-cluster-role.libsonnet
@@ -0,0 +1,21 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local clusterRole = k.rbac.v1.clusterRole;
+local policyRule = clusterRole.rulesType;
+
+local nodeMetricsRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources(["nodes/metrics"]) +
+  policyRule.withVerbs(["get"]);
+
+local metricsRule = policyRule.new() +
+  policyRule.withNonResourceUrls("/metrics") +
+  policyRule.withVerbs(["get"]);
+
+local rules = [nodeMetricsRule, metricsRule];
+
+{
+    new()::
+        clusterRole.new() +
+          clusterRole.mixin.metadata.withName("prometheus-k8s") +
+          clusterRole.withRules(rules)
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-binding-config.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-binding-config.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..2319aa356018ee946a77043820a931d2a9b053a0
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-binding-config.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRoleBinding = import "prometheus-namespace-role-binding.libsonnet";
+
+{
+    new(namespace):: prometheusNamespaceRoleBinding.new(namespace, namespace, "prometheus-k8s-config")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-binding-default.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-binding-default.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..f5d38ce7c8c10b74021e0775b5fc4671c82b4086
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-binding-default.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRoleBinding = import "prometheus-namespace-role-binding.libsonnet";
+
+{
+    new(namespace):: prometheusNamespaceRoleBinding.new(namespace, "default", "prometheus-k8s")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-binding-kube-system.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-binding-kube-system.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..04c481cacfd36443c86582c7a6537ee115e70905
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-binding-kube-system.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRoleBinding = import "prometheus-namespace-role-binding.libsonnet";
+
+{
+    new(namespace):: prometheusNamespaceRoleBinding.new(namespace, "kube-system", "prometheus-k8s")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-binding-namespace.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-binding-namespace.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..7833f78534e4351653f4365d660a92029d0435e0
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-binding-namespace.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRoleBinding = import "prometheus-namespace-role-binding.libsonnet";
+
+{
+    new(namespace):: prometheusNamespaceRoleBinding.new(namespace, namespace, "prometheus-k8s")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-config.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-config.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..abd43433b27d8c0bb42d6d783ff3cd1c47c9f6c8
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-config.libsonnet
@@ -0,0 +1,18 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local role = k.rbac.v1.role;
+local policyRule = role.rulesType;
+
+local configmapRule = policyRule.new() +
+  policyRule.withApiGroups([""]) +
+  policyRule.withResources([
+    "configmaps",
+  ]) +
+  policyRule.withVerbs(["get"]);
+
+{
+    new(namespace)::
+        role.new() +
+          role.mixin.metadata.withName("prometheus-k8s-config") +
+          role.mixin.metadata.withNamespace(namespace) +
+          role.withRules(configmapRule),
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-default.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-default.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..a9abbb1a3a9e003b6a6ea0c3033d93f96972a432
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-default.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRole = import "prometheus-namespace-role.libsonnet";
+
+{
+    new():: prometheusNamespaceRole.new("default")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-kube-system.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-kube-system.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..f1ee9860c984d32749678fc953ef627410aeaecd
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-kube-system.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRole = import "prometheus-namespace-role.libsonnet";
+
+{
+    new():: prometheusNamespaceRole.new("kube-system")
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-role-namespace.libsonnet b/jsonnet/prometheus/prometheus-k8s-role-namespace.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..3149cbf0d97815a844099b7f75dbba371b08d670
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-role-namespace.libsonnet
@@ -0,0 +1,5 @@
+local prometheusNamespaceRole = import "prometheus-namespace-role.libsonnet";
+
+{
+    new(namespace):: prometheusNamespaceRole.new(namespace)
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-account.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-account.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..e816455616208c3660cdf663be8e77feb976b35e
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-account.libsonnet
@@ -0,0 +1,8 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local serviceAccount = k.core.v1.serviceAccount;
+
+{
+    new(namespace)::
+        serviceAccount.new("prometheus-k8s") +
+          serviceAccount.mixin.metadata.withNamespace(namespace)
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-alertmanager.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-alertmanager.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..5f13a2b45a72effbf6c26b8f4c25b740acbb6e3e
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-alertmanager.libsonnet
@@ -0,0 +1,32 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "alertmanager",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "alertmanager"
+                }
+            },
+            "spec": {
+                "selector": {
+                    "matchLabels": {
+                        "alertmanager": "main"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "monitoring"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "web",
+                        "interval": "30s"
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-apiserver.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-apiserver.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..e53ed231e240e89fde9f3e268ea257c9ea962799
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-apiserver.libsonnet
@@ -0,0 +1,40 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "kube-apiserver",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "apiserver"
+                }
+            },
+            "spec": {
+                "jobLabel": "component",
+                "selector": {
+                    "matchLabels": {
+                        "component": "apiserver",
+                        "provider": "kubernetes"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "default"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "https",
+                        "interval": "30s",
+                        "scheme": "https",
+                        "tlsConfig": {
+                            "caFile": "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
+                            "serverName": "kubernetes"
+                        },
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token"
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-coredns.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-coredns.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..89afb4528e150a6cd411b1ca8ebb7377e673515d
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-coredns.libsonnet
@@ -0,0 +1,35 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "coredns",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "coredns"
+                },
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "coredns",
+                        "component": "metrics"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "kube-system"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "http-metrics",
+                        "interval": "15s",
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token"
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-controller-manager.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-controller-manager.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..447e8a4b2297538db35e340e72baae7a8debff77
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-controller-manager.libsonnet
@@ -0,0 +1,33 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "kube-controller-manager",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "kube-controller-manager"
+                }
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "endpoints": [
+                    {
+                        "port": "http-metrics",
+                        "interval": "30s"
+                    }
+                ],
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "kube-controller-manager"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "kube-system"
+                    ]
+                }
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-scheduler.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-scheduler.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..eaae0c391b75726d3f861dddce78ccc0b3dbfebc
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-scheduler.libsonnet
@@ -0,0 +1,33 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "kube-scheduler",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "kube-scheduler"
+                }
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "endpoints": [
+                    {
+                        "port": "http-metrics",
+                        "interval": "30s"
+                    }
+                ],
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "kube-scheduler"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "kube-system"
+                    ]
+                }
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-state-metrics.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-state-metrics.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..3d24aec390a3a792f6d94d31a447ccfe87f7cbf8
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-kube-state-metrics.libsonnet
@@ -0,0 +1,48 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "kube-state-metrics",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "kube-state-metrics"
+                }
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "kube-state-metrics"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "monitoring"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "https-main",
+                        "scheme": "https",
+                        "interval": "30s",
+                        "honorLabels": true,
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token",
+                        "tlsConfig": {
+                            "insecureSkipVerify": true
+                        }
+                    },
+                    {
+                        "port": "https-self",
+                        "scheme": "https",
+                        "interval": "30s",
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token",
+                        "tlsConfig": {
+                            "insecureSkipVerify": true
+                        }
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-kubelet.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-kubelet.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..6b7dd28ec2a540428aebc3df4181ad7b8d459a98
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-kubelet.libsonnet
@@ -0,0 +1,49 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "kubelet",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "kubelet"
+                }
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "endpoints": [
+                    {
+                        "port": "https-metrics",
+                        "scheme": "https",
+                        "interval": "30s",
+                        "tlsConfig": {
+                            "insecureSkipVerify": true
+                        },
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token"
+                    },
+                    {
+                        "port": "https-metrics",
+                        "scheme": "https",
+                        "path": "/metrics/cadvisor",
+                        "interval": "30s",
+                        "honorLabels": true,
+                        "tlsConfig": {
+                            "insecureSkipVerify": true
+                        },
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token"
+                    }
+                ],
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "kubelet"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "kube-system"
+                    ]
+                }
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-node-exporter.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-node-exporter.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..d1ff25e794f8eb25bd9ea279893b26c0b025c349
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-node-exporter.libsonnet
@@ -0,0 +1,38 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "node-exporter",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "node-exporter"
+                }
+            },
+            "spec": {
+                "jobLabel": "k8s-app",
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "node-exporter"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "monitoring"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "https",
+                        "scheme": "https",
+                        "interval": "30s",
+                        "bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token",
+                        "tlsConfig": {
+                            "insecureSkipVerify": true
+                        }
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus-operator.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus-operator.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..07613f8c5c27d0708b9a15e9194bcbb06f73f012
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus-operator.libsonnet
@@ -0,0 +1,26 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "prometheus-operator",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "prometheus-operator"
+                }
+            },
+            "spec": {
+                "endpoints": [
+                    {
+                        "port": "http"
+                    }
+                ],
+                "selector": {
+                    "matchLabels": {
+                        "k8s-app": "prometheus-operator"
+                    }
+                }
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus.libsonnet b/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..0f4ef084fcef8a330e8390d01707042c2f032390
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service-monitor-prometheus.libsonnet
@@ -0,0 +1,32 @@
+{
+    new(namespace)::
+        {
+            "apiVersion": "monitoring.coreos.com/v1",
+            "kind": "ServiceMonitor",
+            "metadata": {
+                "name": "prometheus",
+                "namespace": namespace,
+                "labels": {
+                    "k8s-app": "prometheus"
+                }
+            },
+            "spec": {
+                "selector": {
+                    "matchLabels": {
+                        "prometheus": "k8s"
+                    }
+                },
+                "namespaceSelector": {
+                    "matchNames": [
+                        "monitoring"
+                    ]
+                },
+                "endpoints": [
+                    {
+                        "port": "web",
+                        "interval": "30s"
+                    }
+                ]
+            }
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-k8s-service.libsonnet b/jsonnet/prometheus/prometheus-k8s-service.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..96781d695ecc8e98d97e71733bb97a8057ee167b
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s-service.libsonnet
@@ -0,0 +1,13 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local service = k.core.v1.service;
+local servicePort = k.core.v1.service.mixin.spec.portsType;
+
+local prometheusPort = servicePort.newNamed("web", 9090, "web");
+
+
+{
+    new(namespace)::
+        service.new("prometheus-k8s", {app: "prometheus", prometheus: "k8s"}, prometheusPort) +
+          service.mixin.metadata.withNamespace(namespace) +
+          service.mixin.metadata.withLabels({prometheus: "k8s"})
+}
diff --git a/jsonnet/prometheus/prometheus-k8s.libsonnet b/jsonnet/prometheus/prometheus-k8s.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..853f62b1a879ba3f648143aac5f44c8a532bdf1a
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-k8s.libsonnet
@@ -0,0 +1,43 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+
+local container = k.core.v1.pod.mixin.spec.containersType;
+local resourceRequirements = container.mixin.resourcesType;
+local selector = k.apps.v1beta2.deployment.mixin.spec.selectorType;
+
+local resources = resourceRequirements.new() +
+  resourceRequirements.withRequests({memory: "400Mi"});
+
+{
+    new(namespace)::
+        {
+          apiVersion: "monitoring.coreos.com/v1",
+          kind: "Prometheus",
+          metadata: {
+            name: "k8s",
+            namespace: namespace,
+            labels: {
+              prometheus: "k8s",
+            },
+          },
+          spec: {
+            replicas: 2,
+            version: "v2.2.1",
+            serviceAccountName: "prometheus-k8s",
+            serviceMonitorSelector: selector.withMatchExpressions({key: "k8s-app", operator: "Exists"}),
+            ruleSelector: selector.withMatchLabels({
+              role: "alert-rules",
+              prometheus: "k8s",
+            }),
+            resources: resources,
+            alerting: {
+              alertmanagers: [
+                {
+                  namespace: "monitoring",
+                  name: "alertmanager-main",
+                  port: "web",
+                },
+              ],
+            },
+          },
+        }
+}
diff --git a/jsonnet/prometheus/prometheus-namespace-role-binding.libsonnet b/jsonnet/prometheus/prometheus-namespace-role-binding.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..8b255fa0fd54534f908748ca2d0bc5d85937692e
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-namespace-role-binding.libsonnet
@@ -0,0 +1,13 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local roleBinding = k.rbac.v1.roleBinding;
+
+{
+  new(serviceAccountNamespace, namespace, name)::
+    roleBinding.new() +
+      roleBinding.mixin.metadata.withName(name) +
+      roleBinding.mixin.metadata.withNamespace(namespace) +
+      roleBinding.mixin.roleRef.withApiGroup("rbac.authorization.k8s.io") +
+      roleBinding.mixin.roleRef.withName(name) +
+      roleBinding.mixin.roleRef.mixinInstance({kind: "Role"}) +
+      roleBinding.withSubjects([{kind: "ServiceAccount", name: name, namespace: serviceAccountNamespace}])
+}
diff --git a/jsonnet/prometheus/prometheus-namespace-role.libsonnet b/jsonnet/prometheus/prometheus-namespace-role.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..5afdcff48402c4a4b75e10cd8e90a05dfb6c1f28
--- /dev/null
+++ b/jsonnet/prometheus/prometheus-namespace-role.libsonnet
@@ -0,0 +1,21 @@
+local k = import "ksonnet.beta.3/k.libsonnet";
+local role = k.rbac.v1.role;
+local policyRule = role.rulesType;
+
+{
+    new(namespace)::
+        local coreRule = policyRule.new() +
+          policyRule.withApiGroups([""]) +
+          policyRule.withResources([
+              "nodes",
+              "services",
+              "endpoints",
+              "pods",
+          ]) +
+          policyRule.withVerbs(["get", "list", "watch"]);
+
+        role.new() +
+          role.mixin.metadata.withName("prometheus-k8s") +
+          role.mixin.metadata.withNamespace(namespace) +
+          role.withRules(coreRule)
+}
diff --git a/jsonnet/prometheus/prometheus.libsonnet b/jsonnet/prometheus/prometheus.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..edc75c0893d5415c4c25ec7f78be4f1f20ef0a7d
--- /dev/null
+++ b/jsonnet/prometheus/prometheus.libsonnet
@@ -0,0 +1,25 @@
+{
+    clusterRoleBinding:: import "prometheus-k8s-cluster-role-binding.libsonnet",
+    clusterRole:: import "prometheus-k8s-cluster-role.libsonnet",
+    roleBindingConfig:: import "prometheus-k8s-role-binding-config.libsonnet",
+    roleBindingNamespace:: import "prometheus-k8s-role-binding-namespace.libsonnet",
+    roleBindingKubeSystem:: import "prometheus-k8s-role-binding-kube-system.libsonnet",
+    roleBindingDefault:: import "prometheus-k8s-role-binding-default.libsonnet",
+    roleConfig:: import "prometheus-k8s-role-config.libsonnet",
+    roleNamespace:: import "prometheus-k8s-role-namespace.libsonnet",
+    roleKubeSystem:: import "prometheus-k8s-role-kube-system.libsonnet",
+    roleDefault:: import "prometheus-k8s-role-default.libsonnet",
+    serviceAccount:: import "prometheus-k8s-service-account.libsonnet",
+    serviceMonitorAlertmanager:: import "prometheus-k8s-service-monitor-alertmanager.libsonnet",
+    serviceMonitorApiserver:: import "prometheus-k8s-service-monitor-apiserver.libsonnet",
+    serviceMonitorCoreDNS:: import "prometheus-k8s-service-monitor-coredns.libsonnet",
+    serviceMonitorControllerManager:: import "prometheus-k8s-service-monitor-kube-controller-manager.libsonnet",
+    serviceMonitorScheduler:: import "prometheus-k8s-service-monitor-kube-scheduler.libsonnet",
+    serviceMonitorKubeStateMetrics:: import "prometheus-k8s-service-monitor-kube-state-metrics.libsonnet",
+    serviceMonitorKubelet:: import "prometheus-k8s-service-monitor-kubelet.libsonnet",
+    serviceMonitorNodeExporter:: import "prometheus-k8s-service-monitor-node-exporter.libsonnet",
+    serviceMonitorPrometheusOperator:: import "prometheus-k8s-service-monitor-prometheus-operator.libsonnet",
+    serviceMonitorPrometheus:: import "prometheus-k8s-service-monitor-prometheus.libsonnet",
+    service:: import "prometheus-k8s-service.libsonnet",
+    prometheus:: import "prometheus-k8s.libsonnet",
+}