app/factorio: implement kube
diff --git a/app/factorio/kube/factorio.libsonnet b/app/factorio/kube/factorio.libsonnet
new file mode 100644
index 0000000..b90419a
--- /dev/null
+++ b/app/factorio/kube/factorio.libsonnet
@@ -0,0 +1,97 @@
+# Factorio on Kubernetes.
+
+local kube = import "../../../kube/kube.libsonnet";
+
+{
+    local factorio = self,
+    local cfg = factorio.cfg,
+
+    cfg:: {
+        namespace: error "namespace must be set",
+        appName: "factorio",
+        storageClassName: "waw-hdd-redundant-1",
+        prefix: "", # if set, should be 'foo-'
+
+        rconPort: 2137,
+        rconPassword: "farts",
+
+        tag: "latest",
+        image: "registry.k0.hswaw.net/app/factorio:" + cfg.tag,
+        resources: {
+            requests: {
+                cpu: "500m",
+                memory: "500Mi",
+            },
+            limits: {
+                cpu: "1",
+                memory: "1Gi",
+            },
+        },
+    },
+
+
+    makeName(suffix):: cfg.prefix + suffix,
+
+    metadata:: {
+        namespace: cfg.namespace,
+        labels: {
+            "app.kubernetes.io/name": cfg.appName,
+            "app.kubernetes.io/managed-by": "kubecfg",
+            "app.kubernetes.io/component": "factorio",
+        },
+    },
+
+    volumeClaim: kube.PersistentVolumeClaim(factorio.makeName("factorio")) {
+        metadata+: factorio.metadata,
+        spec+: {
+            storageClassName: cfg.storageClassName,
+            accessModes: [ "ReadWriteOnce" ],
+            resources: {
+                requests: {
+                    storage: "5Gi",
+                },
+            },
+        },
+    },
+    deployment: kube.Deployment(factorio.makeName("factorio")) {
+        metadata+: factorio.metadata,
+        spec+: {
+            replicas: 1,
+            template+: {
+                spec+: {
+                    volumes_: {
+                        data: kube.PersistentVolumeClaimVolume(factorio.volumeClaim),
+                    },
+                    containers_: {
+                        factorio: kube.Container(factorio.makeName("factorio")) {
+                            image: cfg.image,
+                            args: [
+                                "/entrypoint.sh",
+                                "--rcon-port", std.toString(cfg.rconPort),
+                                "--rcon-password", cfg.rconPassword,
+                            ],
+                            ports_: {
+                                client: { containerPort: 34197 },
+                                rcon: { containerPort: cfg.rconPort },
+                            },
+                            volumeMounts_: {
+                                data: { mountPath: "/data" },
+                            },
+                            resources: cfg.resources,
+                        },
+                    },
+                },
+            },
+        },
+    },
+    svc: kube.Service(factorio.makeName("factorio")) {
+        metadata+: factorio.metadata,
+        target_pod:: factorio.deployment.spec.template,
+        spec+: {
+            ports: [
+                { name: "client", port: 34197, targetPort: 34197, protocol: "UDP" },
+            ],
+            type: "LoadBalancer",
+        },
+    },
+}
diff --git a/app/factorio/kube/prod.jsonnet b/app/factorio/kube/prod.jsonnet
new file mode 100644
index 0000000..9604033
--- /dev/null
+++ b/app/factorio/kube/prod.jsonnet
@@ -0,0 +1,22 @@
+local factorio = import "factorio.libsonnet";
+local kube = import "../../../kube/kube.libsonnet";
+
+
+// Available versions:
+//  - 0.16.51-1
+//  - 0.17.41-1
+
+{
+    local prod = self,
+
+    namespace: kube.Namespace("factorio"),
+    instance(name, tag):: factorio {
+        cfg+: {
+            namespace: "factorio",
+            prefix: name + "-",
+            tag: tag,
+        }
+    },
+
+    q3k: prod.instance("q3k", "0.17.41-1"),
+}