bazel-cache: deploy, add waw-hdd-yolo-1 ceph pool
diff --git a/app/bazel-cache/prod.jsonnet b/app/bazel-cache/prod.jsonnet
new file mode 100644
index 0000000..9b65e95
--- /dev/null
+++ b/app/bazel-cache/prod.jsonnet
@@ -0,0 +1,108 @@
+# bazel-cache.k0.hswaw.net, a Bazel Cache based on buchgr/bazel-remote.
+# Once https://github.com/bazelbuild/bazel/pull/4889 gets merged, this will
+# likely be replaced with just an Rados GW instance.
+
+local kube = import "../../kube/kube.libsonnet";
+
+{
+    local app = self,
+    local cfg = app.cfg,
+    cfg:: {
+        namespace: "bazel-cache",
+        domain: "k0.hswaw.net",
+        storageClassName: "waw-hdd-yolo-1",
+    },
+
+    metadata(component):: {
+        namespace: cfg.namespace,
+        labels: {
+            "app.kubernetes.io/name": "bazel-cache",
+            "app.kubernetes.io/managed-by": "kubecfg",
+            "app.kubernetes.io/component": component,
+        },
+    },
+
+    namespace: kube.Namespace(cfg.namespace),
+
+    volumeClaim: kube.PersistentVolumeClaim("bazel-cache-storage") {
+        metadata+: app.metadata("bazel-cache-storage"),
+        spec+: {
+            storageClassName: cfg.storageClassName,
+            accessModes: [ "ReadWriteOnce" ],
+            resources: {
+                requests: {
+                    storage: "40Gi",
+                },
+            },
+        },
+    },
+
+
+    deployment: kube.Deployment("bazel-remote") {
+        metadata+: app.metadata("bazel-cache"),
+        spec+: {
+            replicas: 1,
+            template+: {
+                spec+: {
+                    volumes_: {
+                        data: kube.PersistentVolumeClaimVolume(app.volumeClaim),
+                    },
+                    containers_: {
+                        auth: kube.Container("bazel-remote") {
+                            image: "buchgr/bazel-remote-cache",
+                            volumeMounts_: {
+                                data: { mountPath: "/data" },
+                            },
+                            ports_: {
+                                http: {
+                                    containerPort: 8080,
+                                    protocol: "TCP",
+                                },
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    },
+
+    service: kube.Service("bazel-cache") {
+        metadata+: app.metadata("bazel-cache"),
+        target_pod:: app.deployment.spec.template,
+        spec+: {
+            type: "ClusterIP",
+            ports: [
+                { name: "http", port: 8080, targetPort: 8080, protocol: "TCP" },
+            ],
+        }
+    },
+
+    ingress: kube.Ingress("bazel-cache") {
+        metadata+: app.metadata("bazel-cache") {
+            annotations+: {
+                "kubernetes.io/tls-acme": "true",
+                "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
+                "nginx.ingress.kubernetes.io/backend-protocol": "HTTP",
+                "nginx.ingress.kubernetes.io/proxy-body-size": "0",
+            },
+        },
+        spec+: {
+            tls: [
+                {
+                    hosts: ["bazel-cache.%s" % [cfg.domain]],
+                    secretName: "bazel-cache-tls",
+                },
+            ],
+            rules: [
+                {
+                    host: "bazel-cache.%s" % [cfg.domain],
+                    http: {
+                        paths: [
+                            { path: "/", backend: app.service.name_port },
+                        ]
+                    },
+                }
+            ],
+        },
+    },
+}