alasio 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/cli/src/cluster/host.js +47 -0
  2. package/dist/cli/src/cluster/host.js.map +1 -0
  3. package/dist/cli/src/commands/init.js +10 -6
  4. package/dist/cli/src/commands/init.js.map +1 -1
  5. package/dist/cli/src/commands/status.js +11 -4
  6. package/dist/cli/src/commands/status.js.map +1 -1
  7. package/dist/cli/src/commands/uninstall.js +4 -2
  8. package/dist/cli/src/commands/uninstall.js.map +1 -1
  9. package/dist/cli/src/commands/up.js +5 -3
  10. package/dist/cli/src/commands/up.js.map +1 -1
  11. package/dist/cli/src/kube/api.js +6 -0
  12. package/dist/cli/src/kube/api.js.map +1 -1
  13. package/dist/cli/src/kube/apply.js +78 -13
  14. package/dist/cli/src/kube/apply.js.map +1 -1
  15. package/dist/cli/src/kube/rollout.js +31 -3
  16. package/dist/cli/src/kube/rollout.js.map +1 -1
  17. package/dist/cli/src/main.js +2 -1
  18. package/dist/cli/src/main.js.map +1 -1
  19. package/dist/cli/src/manifests/alasio.js +43 -16
  20. package/dist/cli/src/manifests/alasio.js.map +1 -1
  21. package/dist/cli/src/manifests/config.js +106 -2
  22. package/dist/cli/src/manifests/config.js.map +1 -1
  23. package/dist/cli/src/manifests/index.js +6 -1
  24. package/dist/cli/src/manifests/index.js.map +1 -1
  25. package/dist/cli/src/manifests/juicefs-csi.js +303 -0
  26. package/dist/cli/src/manifests/juicefs-csi.js.map +1 -0
  27. package/dist/cli/src/manifests/neon.js +97 -14
  28. package/dist/cli/src/manifests/neon.js.map +1 -1
  29. package/dist/cli/src/manifests/network-policies.js +37 -0
  30. package/dist/cli/src/manifests/network-policies.js.map +1 -1
  31. package/dist/cli/src/manifests/object-store.js +2 -1
  32. package/dist/cli/src/manifests/object-store.js.map +1 -1
  33. package/dist/cli/src/manifests/valkey.js +95 -0
  34. package/dist/cli/src/manifests/valkey.js.map +1 -0
  35. package/dist/cli/src/manifests/workspace-storage.js +134 -0
  36. package/dist/cli/src/manifests/workspace-storage.js.map +1 -0
  37. package/dist/cli/src/release.js +5 -5
  38. package/dist/src/kube/config.js +6 -1
  39. package/dist/src/kube/config.js.map +1 -1
  40. package/package.json +1 -1
@@ -4,9 +4,13 @@ import { lakeObjects } from "./lake.js";
4
4
  import { neonObjects } from "./neon.js";
5
5
  import { networkPolicyObjects } from "./network-policies.js";
6
6
  import { objectStoreObjects } from "./object-store.js";
7
+ import { workspaceStorageObjects } from "./workspace-storage.js";
7
8
  export { decodeInstallConfig, InstallConfig, InstallConfigError } from "./config.js";
8
9
  export { NAMESPACE } from "./common.js";
9
- /** The objects of the installation `config` describes: agent-sandbox's, alasio's, Neon's, the object store's, the lake's, and the NetworkPolicies. */
10
+ /**
11
+ * The objects of the installation `config` describes: agent-sandbox's, alasio's, Neon's,
12
+ * the object store's, the lake's, workspace storage's, and the NetworkPolicies.
13
+ */
10
14
  export function manifests(config) {
11
15
  return [
12
16
  ...agentSandboxObjects(config),
@@ -14,6 +18,7 @@ export function manifests(config) {
14
18
  ...neonObjects(config),
15
19
  ...objectStoreObjects(config),
16
20
  ...lakeObjects(config),
21
+ ...workspaceStorageObjects(config),
17
22
  ...networkPolicyObjects(config),
18
23
  ];
19
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/manifests/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,kBAAkB,EAA0B,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,sJAAsJ;AACtJ,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,OAAO;QACL,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC9B,GAAG,aAAa,CAAC,MAAM,CAAC;QACxB,GAAG,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,kBAAkB,CAAC,MAAM,CAAC;QAC7B,GAAG,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,oBAAoB,CAAC,MAAM,CAAC;KAChC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/manifests/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,kBAAkB,EAA0B,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,OAAO;QACL,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC9B,GAAG,aAAa,CAAC,MAAM,CAAC;QACxB,GAAG,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,kBAAkB,CAAC,MAAM,CAAC;QAC7B,GAAG,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,uBAAuB,CAAC,MAAM,CAAC;QAClC,GAAG,oBAAoB,CAAC,MAAM,CAAC;KAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,303 @@
1
+ import { imageReference } from "../images.js";
2
+ import { VOLUME_DRIVER_LABEL } from "../kube/apply.js";
3
+ import { goJson } from "./common.js";
4
+ /** The driver's name, which StorageClasses name as their provisioner. */
5
+ export const CSI_DRIVER = "csi.juicefs.com";
6
+ const VERSION = "v0.33.0";
7
+ const CONTROLLER = "juicefs-csi-controller";
8
+ const NODE = "juicefs-csi-node";
9
+ const CONFIG = "juicefs-csi-driver-config";
10
+ const CONTROLLER_ACCOUNT = "juicefs-csi-controller-sa";
11
+ const NODE_ACCOUNT = "juicefs-csi-node-sa";
12
+ /** The PriorityClass of mount pods. */
13
+ const MOUNT_PRIORITY_CLASS = "alasio-juicefs-mount";
14
+ /** The labels of the node service's mount pods. */
15
+ export const MOUNT_POD_LABELS = { "app.kubernetes.io/name": "juicefs-mount" };
16
+ /** The labels that select the controller's and the node service's pods, upstream's but for its version. */
17
+ export const CONTROLLER_POD_LABELS = { app: CONTROLLER, "app.kubernetes.io/name": "juicefs-csi-driver", "app.kubernetes.io/instance": "juicefs-csi-driver" };
18
+ export const NODE_POD_LABELS = { app: NODE, "app.kubernetes.io/name": "juicefs-csi-driver", "app.kubernetes.io/instance": "juicefs-csi-driver" };
19
+ /** The selector of the controller's, the node service's and the mount pods' pods, by their name labels. */
20
+ export const JUICEFS_PODS_SELECTOR = `app.kubernetes.io/name in (${MOUNT_POD_LABELS["app.kubernetes.io/name"]}, ${CONTROLLER_POD_LABELS["app.kubernetes.io/name"]})`;
21
+ /** Where each of those pods serves its Prometheus metrics (administration/monitoring.md). */
22
+ export const JUICEFS_METRICS_PORT = 9567;
23
+ /** The label of what the driver needs to delete its volumes' data, which alasio keeps while they remain. */
24
+ export const VOLUME_DRIVER = { [VOLUME_DRIVER_LABEL]: CSI_DRIVER };
25
+ /** The labels of the driver's objects: upstream's, at its version, managed by alasio, and needed by its volumes. */
26
+ const LABELS = {
27
+ "app.kubernetes.io/name": "juicefs-csi-driver",
28
+ "app.kubernetes.io/instance": "juicefs-csi-driver",
29
+ "app.kubernetes.io/version": VERSION,
30
+ "app.kubernetes.io/managed-by": "alasio",
31
+ ...VOLUME_DRIVER,
32
+ };
33
+ /** Where the controller and node service keep mount points and the client's configuration, on the node. */
34
+ const MOUNT_PATH = "/var/lib/juicefs/volume";
35
+ const CONFIG_PATH = "/var/lib/juicefs/config";
36
+ /** The controller's socket, which its sidecars reach it by. */
37
+ const CONTROLLER_SOCKET_DIR = "/var/lib/csi/sockets/pluginproxy/";
38
+ /**
39
+ * The driver's configuration, its ConfigMap's config.yaml: one patch, for the mount pods
40
+ * of workspace storage's class. Mount options here take precedence over a volume's, and
41
+ * reach mount pods made after a change.
42
+ */
43
+ export function driverConfig({ workspaceStorage }) {
44
+ const { csi, storageClassName, cacheSizeMiB, backupInterval } = workspaceStorage;
45
+ return {
46
+ enableNodeSelector: false,
47
+ mountPodPatch: [{
48
+ pvcSelector: { matchStorageClassName: storageClassName },
49
+ ceMountImage: imageReference(csi.mountImage),
50
+ resources: csi.mountPod.resources,
51
+ mountOptions: [
52
+ // The read cache, bounded, and keeping a fifth of the node's disk free.
53
+ `cache-size=${cacheSizeMiB}`,
54
+ "free-space-ratio=0.2",
55
+ `backup-meta=${backupInterval}`,
56
+ ],
57
+ // Ready once the mount answers as FUSE's. A mount pod mounts its volume's directory
58
+ // alone (as `subdir`), so that is the mount's root, and nothing is under it by the
59
+ // volume's path; unmounted, the root is the node's own directory.
60
+ readinessProbe: { exec: { command: ["sh", "-c", 'test "$(stat --file-system --format=%T ${MOUNT_POINT})" = fuseblk'] }, initialDelaySeconds: 5, periodSeconds: 10, failureThreshold: 3 },
61
+ }],
62
+ };
63
+ }
64
+ /** What the controller and node service are told alike: where they are, where mount pods keep their mounts, and the pods' priority. */
65
+ function pluginEnv({ workspaceStorage }) {
66
+ return [
67
+ { name: "NODE_NAME", valueFrom: { fieldRef: { fieldPath: "spec.nodeName" } } },
68
+ { name: "JUICEFS_MOUNT_NAMESPACE", valueFrom: { fieldRef: { fieldPath: "metadata.namespace" } } },
69
+ { name: "POD_NAME", valueFrom: { fieldRef: { fieldPath: "metadata.name" } } },
70
+ { name: "JUICEFS_MOUNT_PATH", value: MOUNT_PATH },
71
+ { name: "JUICEFS_CONFIG_PATH", value: CONFIG_PATH },
72
+ { name: "JUICEFS_MOUNT_PRIORITY_NAME", value: MOUNT_PRIORITY_CLASS },
73
+ { name: "JUICEFS_MOUNT_PREEMPTION_POLICY", value: "Never" },
74
+ ...(workspaceStorage.csi.shareMountPod ? [{ name: "FS_SHARE_MOUNT", value: "true" }] : []),
75
+ ];
76
+ }
77
+ /** The plugin's liveness, which its liveness-probe sidecar answers on the plugin's healthz port. */
78
+ const PLUGIN_PROBE = { httpGet: { path: "/healthz", port: "healthz" }, initialDelaySeconds: 10, periodSeconds: 10, timeoutSeconds: 3, failureThreshold: 5 };
79
+ /** The liveness-probe sidecar, for the plugin's socket in `socketVolume`. */
80
+ function livenessProbe({ workspaceStorage }, socketVolume) {
81
+ return {
82
+ name: "liveness-probe",
83
+ image: imageReference(workspaceStorage.csi.livenessProbeImage),
84
+ args: ["--csi-address=/csi/csi.sock", "--health-port=9909"],
85
+ resources: { requests: { cpu: "5m", memory: "16Mi" }, limits: { memory: "64Mi" } },
86
+ volumeMounts: [{ name: socketVolume, mountPath: "/csi" }],
87
+ };
88
+ }
89
+ /** A rule granting `verbs` on `resources` of `apiGroups`. */
90
+ function rule(apiGroups, resources, verbs) {
91
+ return { apiGroups, resources, verbs };
92
+ }
93
+ /** Who the controller and node service are, and what they may do, as upstream grants it. */
94
+ function identities({ workspaceStorage }) {
95
+ const { namespace } = workspaceStorage.csi;
96
+ const account = (name) => ({ apiVersion: "v1", kind: "ServiceAccount", metadata: { name, namespace, labels: LABELS } });
97
+ const role = (name, rules) => ({
98
+ apiVersion: "rbac.authorization.k8s.io/v1",
99
+ kind: "ClusterRole",
100
+ metadata: { name, labels: LABELS },
101
+ rules,
102
+ });
103
+ const binding = (name, roleName, accountName) => ({
104
+ apiVersion: "rbac.authorization.k8s.io/v1",
105
+ kind: "ClusterRoleBinding",
106
+ metadata: { name, labels: LABELS },
107
+ subjects: [{ kind: "ServiceAccount", name: accountName, namespace }],
108
+ roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "ClusterRole", name: roleName },
109
+ });
110
+ const provisioner = "juicefs-external-provisioner-role";
111
+ const nodeService = "juicefs-csi-external-node-service-role";
112
+ return [
113
+ account(CONTROLLER_ACCOUNT),
114
+ account(NODE_ACCOUNT),
115
+ role(provisioner, [
116
+ rule([""], ["persistentvolumes"], ["get", "list", "watch", "create", "delete", "patch"]),
117
+ rule([""], ["persistentvolumeclaims", "persistentvolumeclaims/status"], ["get", "list", "watch", "update", "patch"]),
118
+ rule(["storage.k8s.io"], ["storageclasses"], ["get", "list", "watch"]),
119
+ rule([""], ["events"], ["list", "watch", "create", "update", "patch"]),
120
+ rule(["storage.k8s.io"], ["csinodes"], ["get", "list", "watch"]),
121
+ rule([""], ["nodes"], ["get", "list", "watch"]),
122
+ rule([""], ["secrets"], ["get", "list", "watch", "create", "update", "patch", "delete"]),
123
+ rule([""], ["pods", "pods/log"], ["get", "list", "watch", "create", "update", "patch", "delete"]),
124
+ rule(["batch"], ["jobs"], ["get", "create", "update", "patch", "delete", "list", "watch"]),
125
+ rule([""], ["endpoints"], ["get", "list", "watch", "create", "update", "patch"]),
126
+ rule(["apps"], ["daemonsets"], ["get", "list"]),
127
+ rule(["coordination.k8s.io"], ["leases"], ["get", "watch", "list", "delete", "update", "create"]),
128
+ rule([""], ["configmaps"], ["get", "watch", "list", "delete", "update", "create"]),
129
+ ]),
130
+ role(nodeService, [
131
+ rule([""], ["pods"], ["get", "list", "create", "update", "delete", "patch", "watch"]),
132
+ rule([""], ["pods/log"], ["get"]),
133
+ rule([""], ["secrets"], ["get", "create", "update", "delete", "patch"]),
134
+ rule(["batch"], ["jobs"], ["get", "create", "update", "delete", "patch"]),
135
+ rule([""], ["nodes"], ["get", "list"]),
136
+ rule([""], ["nodes/proxy"], ["*"]),
137
+ rule([""], ["persistentvolumes", "persistentvolumeclaims"], ["get", "list"]),
138
+ rule([""], ["pods/exec"], ["create"]),
139
+ rule([""], ["events"], ["create", "get"]),
140
+ rule(["storage.k8s.io"], ["storageclasses"], ["get", "watch"]),
141
+ rule([""], ["configmaps"], ["get", "update"]),
142
+ ]),
143
+ binding("juicefs-csi-provisioner-binding", provisioner, CONTROLLER_ACCOUNT),
144
+ binding("juicefs-csi-node-service-binding", nodeService, NODE_ACCOUNT),
145
+ ];
146
+ }
147
+ /** The controller: the plugin, provisioning, and the resizer, which grows a volume's quota as its claim grows. */
148
+ function controller(config) {
149
+ const { csi } = config.workspaceStorage;
150
+ return {
151
+ apiVersion: "apps/v1",
152
+ kind: "StatefulSet",
153
+ metadata: { name: CONTROLLER, namespace: csi.namespace, labels: { ...LABELS, "app.kubernetes.io/component": "controller" } },
154
+ spec: {
155
+ serviceName: CONTROLLER,
156
+ replicas: 1,
157
+ selector: { matchLabels: CONTROLLER_POD_LABELS },
158
+ template: {
159
+ metadata: { labels: { ...LABELS, ...CONTROLLER_POD_LABELS } },
160
+ spec: {
161
+ serviceAccountName: CONTROLLER_ACCOUNT,
162
+ priorityClassName: "system-cluster-critical",
163
+ tolerations: [{ key: "CriticalAddonsOnly", operator: "Exists" }],
164
+ containers: [
165
+ {
166
+ name: "juicefs-plugin",
167
+ image: imageReference(csi.image),
168
+ args: ["--endpoint=$(CSI_ENDPOINT)", "--logtostderr", "--nodeid=$(NODE_NAME)", "--leader-election", "--provisioner=true", "--config=/etc/config/config.yaml"],
169
+ env: [{ name: "CSI_ENDPOINT", value: `unix://${CONTROLLER_SOCKET_DIR}csi.sock` }, ...pluginEnv(config)],
170
+ ports: [{ name: "healthz", containerPort: 9909, protocol: "TCP" }],
171
+ livenessProbe: PLUGIN_PROBE,
172
+ // It mounts the file system itself, to make and remove volumes' directories.
173
+ securityContext: { privileged: true, capabilities: { add: ["SYS_ADMIN"] } },
174
+ resources: csi.controller.resources,
175
+ volumeMounts: [
176
+ { name: "socket-dir", mountPath: CONTROLLER_SOCKET_DIR },
177
+ { name: "jfs-dir", mountPath: "/jfs", mountPropagation: "Bidirectional" },
178
+ { name: "jfs-root-dir", mountPath: "/root/.juicefs", mountPropagation: "Bidirectional" },
179
+ { name: "juicefs-config", mountPath: "/etc/config" },
180
+ ],
181
+ },
182
+ {
183
+ name: "csi-resizer",
184
+ image: imageReference(csi.resizerImage),
185
+ args: ["--csi-address=$(ADDRESS)", "--timeout=20s", "--leader-election", "--v=2"],
186
+ env: [{ name: "ADDRESS", value: `${CONTROLLER_SOCKET_DIR}csi.sock` }],
187
+ resources: { requests: { cpu: "5m", memory: "24Mi" }, limits: { memory: "128Mi" } },
188
+ volumeMounts: [{ name: "socket-dir", mountPath: CONTROLLER_SOCKET_DIR }],
189
+ },
190
+ livenessProbe(config, "socket-dir"),
191
+ ],
192
+ volumes: [
193
+ { name: "socket-dir", emptyDir: {} },
194
+ { name: "jfs-dir", hostPath: { path: MOUNT_PATH, type: "DirectoryOrCreate" } },
195
+ { name: "jfs-root-dir", hostPath: { path: CONFIG_PATH, type: "DirectoryOrCreate" } },
196
+ { name: "juicefs-config", configMap: { name: CONFIG } },
197
+ ],
198
+ },
199
+ },
200
+ },
201
+ };
202
+ }
203
+ /** The node service: the plugin, which makes mount pods and binds their mounts into pods, and the registrar, which names it to kubelet. */
204
+ function nodeService(config) {
205
+ const { csi } = config.workspaceStorage;
206
+ const pluginDir = `/var/lib/kubelet/csi-plugins/${CSI_DRIVER}/`;
207
+ return {
208
+ apiVersion: "apps/v1",
209
+ kind: "DaemonSet",
210
+ metadata: { name: NODE, namespace: csi.namespace, labels: { ...LABELS, "app.kubernetes.io/component": "node" } },
211
+ spec: {
212
+ selector: { matchLabels: NODE_POD_LABELS },
213
+ template: {
214
+ metadata: { labels: { ...LABELS, ...NODE_POD_LABELS } },
215
+ spec: {
216
+ serviceAccountName: NODE_ACCOUNT,
217
+ priorityClassName: "system-node-critical",
218
+ dnsPolicy: "ClusterFirstWithHostNet",
219
+ tolerations: [{ key: "CriticalAddonsOnly", operator: "Exists" }],
220
+ containers: [
221
+ {
222
+ name: "juicefs-plugin",
223
+ image: imageReference(csi.image),
224
+ args: ["--endpoint=$(CSI_ENDPOINT)", "--logtostderr", "--nodeid=$(NODE_NAME)", "--enable-manager=true", "--config=/etc/config/config.yaml"],
225
+ env: [
226
+ { name: "CSI_ENDPOINT", value: "unix:/csi/csi.sock" },
227
+ { name: "HOST_IP", valueFrom: { fieldRef: { fieldPath: "status.hostIP" } } },
228
+ { name: "KUBELET_PORT", value: "10250" },
229
+ ...pluginEnv(config),
230
+ ],
231
+ ports: [{ name: "healthz", containerPort: 9909, protocol: "TCP" }],
232
+ livenessProbe: PLUGIN_PROBE,
233
+ securityContext: { privileged: true },
234
+ resources: csi.node.resources,
235
+ volumeMounts: [
236
+ { name: "kubelet-dir", mountPath: "/var/lib/kubelet", mountPropagation: "Bidirectional" },
237
+ { name: "plugin-dir", mountPath: "/csi" },
238
+ { name: "device-dir", mountPath: "/dev" },
239
+ { name: "jfs-dir", mountPath: "/jfs", mountPropagation: "Bidirectional" },
240
+ { name: "jfs-root-dir", mountPath: "/root/.juicefs", mountPropagation: "Bidirectional" },
241
+ { name: "juicefs-config", mountPath: "/etc/config" },
242
+ // Where it keeps each mount's FUSE descriptor, by which a mount pod that
243
+ // crashes comes back under the same mount (guide/configurations.md
244
+ // "Automatic mount point recovery").
245
+ { name: "jfs-fuse-fd", mountPath: "/tmp" },
246
+ ],
247
+ },
248
+ {
249
+ name: "node-driver-registrar",
250
+ image: imageReference(csi.registrarImage),
251
+ args: ["--csi-address=$(ADDRESS)", "--kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)", "--v=5"],
252
+ env: [{ name: "ADDRESS", value: "/csi/csi.sock" }, { name: "DRIVER_REG_SOCK_PATH", value: `${pluginDir}csi.sock` }],
253
+ resources: { requests: { cpu: "5m", memory: "16Mi" }, limits: { memory: "64Mi" } },
254
+ volumeMounts: [{ name: "plugin-dir", mountPath: "/csi" }, { name: "registration-dir", mountPath: "/registration" }],
255
+ },
256
+ livenessProbe(config, "plugin-dir"),
257
+ ],
258
+ volumes: [
259
+ { name: "kubelet-dir", hostPath: { path: "/var/lib/kubelet", type: "Directory" } },
260
+ { name: "plugin-dir", hostPath: { path: pluginDir, type: "DirectoryOrCreate" } },
261
+ { name: "registration-dir", hostPath: { path: "/var/lib/kubelet/plugins_registry/", type: "Directory" } },
262
+ { name: "device-dir", hostPath: { path: "/dev", type: "Directory" } },
263
+ { name: "jfs-dir", hostPath: { path: MOUNT_PATH, type: "DirectoryOrCreate" } },
264
+ { name: "jfs-root-dir", hostPath: { path: CONFIG_PATH, type: "DirectoryOrCreate" } },
265
+ { name: "juicefs-config", configMap: { name: CONFIG } },
266
+ { name: "jfs-fuse-fd", hostPath: { path: "/var/run/juicefs-csi", type: "DirectoryOrCreate" } },
267
+ ],
268
+ },
269
+ },
270
+ },
271
+ };
272
+ }
273
+ /** The driver's objects, unless the cluster already has the driver: the CSIDriver and the mount pods' PriorityClass among them, which are the cluster's. */
274
+ export function juicefsCsiObjects(config) {
275
+ const { csi } = config.workspaceStorage;
276
+ if (!csi.enabled)
277
+ return [];
278
+ const csiDriver = {
279
+ apiVersion: "storage.k8s.io/v1",
280
+ kind: "CSIDriver",
281
+ metadata: { name: CSI_DRIVER, labels: LABELS },
282
+ spec: { attachRequired: false, podInfoOnMount: true },
283
+ };
284
+ const priorityClass = {
285
+ apiVersion: "scheduling.k8s.io/v1",
286
+ kind: "PriorityClass",
287
+ metadata: { name: MOUNT_PRIORITY_CLASS, labels: LABELS },
288
+ // As high as a pod's may be, so mount pods outlast the workspaces they serve, and
289
+ // never preempting, so a new one evicts nothing.
290
+ value: 1_000_000_000,
291
+ preemptionPolicy: "Never",
292
+ globalDefault: false,
293
+ description: "JuiceFS's mount pods, which serve alasio's workspaces",
294
+ };
295
+ const configMap = {
296
+ apiVersion: "v1",
297
+ kind: "ConfigMap",
298
+ metadata: { name: CONFIG, namespace: csi.namespace, labels: LABELS },
299
+ data: { "config.yaml": goJson(driverConfig(config), " ") },
300
+ };
301
+ return [csiDriver, priorityClass, ...identities(config), configMap, controller(config), nodeService(config)];
302
+ }
303
+ //# sourceMappingURL=juicefs-csi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juicefs-csi.js","sourceRoot":"","sources":["../../../../src/manifests/juicefs-csi.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { imageReference } from "../images.js";
2
2
  import { claimSpec, componentName, databaseSecret, given, goJson, helperResources, imagePullSecrets, NAMESPACE, neonName, otelEnv, RELEASE, restrictedContainer, s3Endpoint, script, selectorLabels, sha256, stackLabels, stackPodSpec, waitFor, waitForObjectStore, } from "./common.js";
3
+ import { JUICEFS_METRICS_PORT, JUICEFS_PODS_SELECTOR, VOLUME_DRIVER } from "./juicefs-csi.js";
4
+ import { VALKEY, VALKEY_PORT } from "./valkey.js";
5
+ import { VALKEY_ADDRESS, workspacesBucketUrl } from "./workspace-storage.js";
3
6
  /** A Service of the stack's: its name and component, selecting the component's pods, on `ports`. */
4
7
  function service(name, component, ports) {
5
8
  return {
@@ -14,13 +17,13 @@ function secretVariable(secret, key) {
14
17
  return { name: key, valueFrom: { secretKeyRef: { name: secret, key } } };
15
18
  }
16
19
  /**
17
- * The stack's secrets, made once and kept, and each service's rendered from them, by
18
- * neon/control/kube-setup.ts: a Job, which applying alasio runs to completion before
20
+ * The stack's secrets, made once and kept, and each service's rendered from them, workspace
21
+ * storage's among them when it is on, by neon/control/kube-setup.ts: a Job, which applying alasio runs to completion before
19
22
  * anything else of alasio starts (../kube/apply.ts).
20
23
  */
21
24
  function setup(config) {
22
25
  const name = neonName("setup");
23
- const { objectStore } = config;
26
+ const { objectStore, workspaceStorage } = config;
24
27
  const metadata = { name, namespace: NAMESPACE, labels: stackLabels("neon-setup") };
25
28
  const serviceAccount = { apiVersion: "v1", kind: "ServiceAccount", metadata };
26
29
  const role = {
@@ -66,6 +69,16 @@ function setup(config) {
66
69
  { name: "S3_REGION", value: objectStore.external.region },
67
70
  { name: "S3_BUCKET_NEON", value: objectStore.buckets.neon },
68
71
  { name: "S3_BUCKET_LAKE", value: objectStore.buckets.lake },
72
+ ...(workspaceStorage.enabled
73
+ ? [
74
+ { name: "WORKSPACES_NAME", value: workspaceStorage.name },
75
+ { name: "WORKSPACES_BUCKET", value: objectStore.buckets.workspaces },
76
+ { name: "WORKSPACES_BUCKET_URL", value: workspacesBucketUrl(config) },
77
+ { name: "WORKSPACES_TRASH_DAYS", value: String(workspaceStorage.trashDays) },
78
+ { name: "VALKEY_ADDRESS", value: VALKEY_ADDRESS },
79
+ { name: "WORKSPACES_SECRET_LABELS", value: JSON.stringify(VOLUME_DRIVER) },
80
+ ]
81
+ : []),
69
82
  ...(objectStore.bundled.enabled ? [] : [
70
83
  { name: "S3_EXTERNAL", value: "1" },
71
84
  { name: "S3_ACCESS_KEY", valueFrom: { secretKeyRef: { name: objectStore.external.existingSecret, key: "accessKey" } } },
@@ -486,10 +499,13 @@ function compute(config) {
486
499
  }
487
500
  /**
488
501
  * A logical dump of alasio's database, restorable into any Postgres whatever becomes of
489
- * the stack, to the object store's backups bucket, of which the last `keep` are kept.
502
+ * the stack, to the object store's backups bucket, and beside it, with workspace storage,
503
+ * the newest dump JuiceFS has made of its file system's metadata, which it makes in the
504
+ * workspaces bucket's `<name>/meta/`; of each, the last `keep` are kept.
490
505
  */
491
506
  function backup(config) {
492
507
  const component = "neon-backup";
508
+ const { objectStore, workspaceStorage } = config;
493
509
  const dump = {
494
510
  name: "dump",
495
511
  image: imageReference(config.neon.computeImage),
@@ -514,13 +530,26 @@ function backup(config) {
514
530
  command: [
515
531
  "/bin/sh",
516
532
  "-c",
517
- script("set -eu", 's3() { aws s3 --endpoint-url "$S3_ENDPOINT" "$@"; }', "stamp=$(date -u +%Y%m%dT%H%M%SZ)", 's3 cp /backup/alasio.dump "s3://$BUCKET/alasio-$stamp.dump"', "s3 ls \"s3://$BUCKET/\" | awk '{print $4}' | grep '^alasio-.*\\.dump$' | sort -r | tail -n +$((KEEP + 1)) \\", ' | while read -r old; do s3 rm "s3://$BUCKET/$old"; done'),
533
+ script("set -eu", 's3() { aws s3 --endpoint-url "$S3_ENDPOINT" "$@"; }',
534
+ // Deletes all but the newest KEEP of the backups whose names match $1, which sort by when they were made.
535
+ "prune() { s3 ls \"s3://$BUCKET/\" | awk '{print $4}' | grep \"$1\" | sort -r | tail -n +$((KEEP + 1)) \\", ' | while read -r old; do s3 rm "s3://$BUCKET/$old"; done; }', "stamp=$(date -u +%Y%m%dT%H%M%SZ)", 's3 cp /backup/alasio.dump "s3://$BUCKET/alasio-$stamp.dump"', "prune '^alasio-.*\\.dump$'", ...(workspaceStorage.enabled
536
+ ? [
537
+ 'meta="s3://$WORKSPACES_BUCKET/$WORKSPACES_NAME/meta/"',
538
+ "dump=$(s3 ls \"$meta\" | awk '{print $4}' | grep '^dump-.*\\.json\\.gz$' | sort -r | head -n 1)",
539
+ // None until a workspace's volume has been mounted for a while.
540
+ 'if [ -n "$dump" ]; then s3 cp "$meta$dump" "s3://$BUCKET/$WORKSPACES_NAME-$dump"; else echo "JuiceFS has dumped no metadata of $WORKSPACES_NAME yet"; fi',
541
+ 'prune "^$WORKSPACES_NAME-dump-.*\\.json\\.gz$"',
542
+ ]
543
+ : [])),
518
544
  ],
519
545
  env: [
520
546
  { name: "S3_ENDPOINT", value: s3Endpoint(config) },
521
- { name: "BUCKET", value: config.objectStore.buckets.backups },
547
+ { name: "BUCKET", value: objectStore.buckets.backups },
522
548
  { name: "KEEP", value: String(config.neon.backup.keep) },
523
- { name: "AWS_DEFAULT_REGION", value: config.objectStore.external.region },
549
+ ...(workspaceStorage.enabled
550
+ ? [{ name: "WORKSPACES_BUCKET", value: objectStore.buckets.workspaces }, { name: "WORKSPACES_NAME", value: workspaceStorage.name }]
551
+ : []),
552
+ { name: "AWS_DEFAULT_REGION", value: objectStore.external.region },
524
553
  { name: "HOME", value: "/tmp" },
525
554
  ],
526
555
  envFrom: [{ secretRef: { name: neonName("s3-admin") } }],
@@ -558,14 +587,16 @@ function backup(config) {
558
587
  }
559
588
  /**
560
589
  * The stack's telemetry: every Neon service's, SeaweedFS's and the lake's Prometheus
561
- * metrics, scraped and sent on as OTLP where alasio's telemetry goes, when it goes
562
- * anywhere. Its pod carries its configuration's checksum, so it is replaced when that
563
- * changes.
590
+ * metrics, and with workspace storage JuiceFS's and Valkey's, scraped and sent on as OTLP
591
+ * where alasio's telemetry goes, when it goes anywhere. JuiceFS's are its driver's and
592
+ * mount pods', found among the pods of the driver's namespace, which the collector may
593
+ * list; Valkey's are read with its password. Its pod carries its configuration's
594
+ * checksum, so it is replaced when that changes.
564
595
  */
565
596
  function collector(config, endpoint) {
566
597
  const name = neonName("collector");
567
598
  const component = "neon-collector";
568
- const { telemetry } = config;
599
+ const { telemetry, workspaceStorage } = config;
569
600
  const safekeeper = neonName("safekeeper");
570
601
  const targets = {
571
602
  pageserver: [`${neonName("pageserver")}:9898`],
@@ -576,19 +607,51 @@ function collector(config, endpoint) {
576
607
  ...(config.objectStore.bundled.enabled ? { seaweedfs: [`${componentName("seaweedfs")}:9327`] } : {}),
577
608
  ...(config.lake.enabled ? { lake: [`${componentName("lake")}:9464`] } : {}),
578
609
  };
610
+ // Each running pod at its address, on the metrics port, named by its pod. The
611
+ // collector reads `$` as the start of a variable, and `$$` as a `$`.
612
+ const juicefs = {
613
+ job_name: "juicefs",
614
+ scrape_interval: "30s",
615
+ kubernetes_sd_configs: [{
616
+ role: "pod",
617
+ namespaces: { names: [workspaceStorage.csi.namespace] },
618
+ selectors: [{ role: "pod", label: JUICEFS_PODS_SELECTOR }],
619
+ }],
620
+ relabel_configs: [
621
+ { source_labels: ["__meta_kubernetes_pod_phase"], regex: "Running", action: "keep" },
622
+ { source_labels: ["__meta_kubernetes_pod_ip"], target_label: "__address__", replacement: `$$1:${JUICEFS_METRICS_PORT}` },
623
+ { source_labels: ["__meta_kubernetes_pod_name"], target_label: "pod" },
624
+ ],
625
+ };
579
626
  const collectorConfig = {
580
627
  receivers: {
581
628
  prometheus: {
582
629
  config: {
583
- scrape_configs: Object.keys(targets).sort().map((job) => ({ job_name: job, scrape_interval: "30s", static_configs: [{ targets: targets[job] }] })),
630
+ scrape_configs: [
631
+ ...Object.keys(targets).sort().map((job) => ({ job_name: job, scrape_interval: "30s", static_configs: [{ targets: targets[job] }] })),
632
+ ...(workspaceStorage.enabled ? [juicefs] : []),
633
+ ],
584
634
  },
585
635
  },
636
+ ...(workspaceStorage.enabled
637
+ ? {
638
+ redis: {
639
+ endpoint: `${VALKEY}:${VALKEY_PORT}`,
640
+ password: "${env:VALKEY_PASSWORD}",
641
+ collection_interval: "30s",
642
+ // How near it is to refusing writes: used memory against this.
643
+ metrics: { "redis.maxmemory": { enabled: true } },
644
+ },
645
+ }
646
+ : {}),
586
647
  },
587
648
  processors: { resource: { attributes: [{ key: "service.namespace", value: "alasio-neon", action: "upsert" }] }, batch: {} },
588
649
  exporters: { otlphttp: { endpoint, ...(telemetry.headersSecret ? { headers: "${file:/etc/otelcol/headers/headers.yaml}" } : {}) } },
589
650
  service: {
590
651
  telemetry: { metrics: { level: "none" } },
591
- pipelines: { metrics: { receivers: ["prometheus"], processors: ["resource", "batch"], exporters: ["otlphttp"] } },
652
+ pipelines: {
653
+ metrics: { receivers: ["prometheus", ...(workspaceStorage.enabled ? ["redis"] : [])], processors: ["resource", "batch"], exporters: ["otlphttp"] },
654
+ },
592
655
  },
593
656
  };
594
657
  const configMap = {
@@ -607,12 +670,14 @@ function collector(config, endpoint) {
607
670
  template: {
608
671
  metadata: { labels: stackLabels(component), annotations: { "checksum/config": sha256(goJson(collectorConfig)) } },
609
672
  spec: {
673
+ ...(workspaceStorage.enabled ? { serviceAccountName: name } : {}),
610
674
  ...stackPodSpec(config),
611
675
  containers: [{
612
676
  name: "collector",
613
677
  image: imageReference(config.neon.collector.image),
614
678
  imagePullPolicy: "IfNotPresent",
615
679
  args: ["--config=/etc/otelcol/config.yaml"],
680
+ ...(workspaceStorage.enabled ? { env: [{ name: "VALKEY_PASSWORD", valueFrom: { secretKeyRef: { name: VALKEY, key: "password" } } }] } : {}),
616
681
  securityContext: { ...restrictedContainer(), readOnlyRootFilesystem: true },
617
682
  resources: config.neon.collector.resources,
618
683
  volumeMounts: [
@@ -632,7 +697,25 @@ function collector(config, endpoint) {
632
697
  },
633
698
  },
634
699
  };
635
- return [configMap, deployment];
700
+ if (!workspaceStorage.enabled)
701
+ return [configMap, deployment];
702
+ // Who the collector is, and that it may find JuiceFS's pods in the driver's namespace.
703
+ const serviceAccount = { apiVersion: "v1", kind: "ServiceAccount", metadata: { name, namespace: NAMESPACE, labels: stackLabels(component) } };
704
+ const metadata = { name, namespace: workspaceStorage.csi.namespace, labels: stackLabels(component) };
705
+ const role = {
706
+ apiVersion: "rbac.authorization.k8s.io/v1",
707
+ kind: "Role",
708
+ metadata,
709
+ rules: [{ apiGroups: [""], resources: ["pods"], verbs: ["get", "list", "watch"] }],
710
+ };
711
+ const binding = {
712
+ apiVersion: "rbac.authorization.k8s.io/v1",
713
+ kind: "RoleBinding",
714
+ metadata,
715
+ subjects: [{ kind: "ServiceAccount", name, namespace: NAMESPACE }],
716
+ roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name },
717
+ };
718
+ return [serviceAccount, role, binding, configMap, deployment];
636
719
  }
637
720
  /** Neon's objects, when it runs. */
638
721
  export function neonObjects(config) {