feat: Cache | implement npm cache

This commit is contained in:
2025-11-23 00:20:55 +05:00
parent c4a94772d9
commit 945be1fa0a
5 changed files with 382 additions and 20 deletions

View File

@@ -1,17 +1,39 @@
import { Construct } from "constructs"; import { Construct } from "constructs";
import { TerraformStack } from "cdktf"; import { TerraformStack } from "cdktf";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider"; import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
import { NixCache } from "./nix"; import { NixCache } from "./nix";
import { NpmCache } from "./npm";
export class CacheInfrastructure extends TerraformStack { export class CacheInfrastructure extends TerraformStack {
constructor(scope: Construct, id: string) { constructor(scope: Construct, id: string) {
super(scope, id); super(scope, id);
const kubernetes = new KubernetesProvider(this, "kubernetes", { const provider = new KubernetesProvider(this, "kubernetes", {
configPath: "~/.kube/config", configPath: "~/.kube/config",
}); });
const namespace = "package-cache";
new NamespaceV1(this, "package-cache-namespace", {
metadata: {
name: namespace,
},
});
// Add cache-related infrastructure components here // Add cache-related infrastructure components here
new NixCache(this, "nix-cache", kubernetes); new NixCache(this, "nix-cache", {
provider,
namespace,
name: "nix-cache",
host: "nix.dogar.dev",
});
new NpmCache(this, "npm-cache", {
provider,
namespace,
name: "npm-cache",
host: "npm.dogar.dev",
});
} }
} }

View File

@@ -8,14 +8,23 @@ import { ServiceV1 } from "@cdktf/provider-kubernetes/lib/service-v1";
import { PublicIngressRoute, LonghornPvc } from "../../utils"; import { PublicIngressRoute, LonghornPvc } from "../../utils";
type NixCacheOptions = {
provider: KubernetesProvider;
name: string;
namespace: string;
host: string;
};
export class NixCache extends Construct { export class NixCache extends Construct {
constructor(scope: Construct, id: string, provider: KubernetesProvider) { constructor(scope: Construct, id: string, options: NixCacheOptions) {
super(scope, id); super(scope, id);
const { provider, name, namespace, host } = options;
const pvc = new LonghornPvc(this, "pvc", { const pvc = new LonghornPvc(this, "pvc", {
provider, provider,
name: "nix-cache", name,
namespace: "homelab", namespace,
accessModes: ["ReadWriteMany"], accessModes: ["ReadWriteMany"],
size: "64Gi", size: "64Gi",
}); });
@@ -25,11 +34,11 @@ export class NixCache extends Construct {
"utf-8", "utf-8",
); );
const configMap = new ConfigMapV1(this, "config-map", { new ConfigMapV1(this, "config", {
provider, provider,
metadata: { metadata: {
name: "nix-cache", name,
namespace: "homelab", namespace,
}, },
data: { data: {
"nix-cache.conf": nginxConfig, "nix-cache.conf": nginxConfig,
@@ -39,12 +48,12 @@ export class NixCache extends Construct {
new ServiceV1(this, "service", { new ServiceV1(this, "service", {
provider, provider,
metadata: { metadata: {
name: "nix-cache", name,
namespace: "homelab", namespace,
}, },
spec: { spec: {
selector: { selector: {
app: "nix-cache", app: name,
}, },
port: [ port: [
{ {
@@ -60,20 +69,20 @@ export class NixCache extends Construct {
new DeploymentV1(this, "deployment", { new DeploymentV1(this, "deployment", {
provider, provider,
metadata: { metadata: {
name: "nix-cache", name,
namespace: "homelab", namespace,
}, },
spec: { spec: {
replicas: "3", replicas: "3",
selector: { selector: {
matchLabels: { matchLabels: {
app: "nix-cache", app: name,
}, },
}, },
template: { template: {
metadata: { metadata: {
labels: { labels: {
app: "nix-cache", app: name,
}, },
}, },
spec: { spec: {
@@ -104,7 +113,7 @@ export class NixCache extends Construct {
{ {
name: "nginx-config", name: "nginx-config",
configMap: { configMap: {
name: configMap.metadata.name, name,
items: [ items: [
{ {
key: "nix-cache.conf", key: "nix-cache.conf",
@@ -121,10 +130,10 @@ export class NixCache extends Construct {
new PublicIngressRoute(this, "ingress-route", { new PublicIngressRoute(this, "ingress-route", {
provider, provider,
name: "nix-cache", name,
namespace: "homelab", namespace,
host: "nix.dogar.dev", host,
serviceName: "nix-cache", serviceName: name,
servicePort: 80, servicePort: 80,
}); });
} }

View File

@@ -0,0 +1,19 @@
storage: /verdaccio/storage
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
"@*/*":
access: $all
publish: never
proxy: npmjs
"**":
access: $all
publish: never
proxy: npmjs
log:
- {type: stdout, format: pretty, level: http}

View File

@@ -0,0 +1,184 @@
import * as fs from "fs";
import * as path from "path";
import { Construct } from "constructs";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { DeploymentV1 } from "@cdktf/provider-kubernetes/lib/deployment-v1";
import { ServiceV1 } from "@cdktf/provider-kubernetes/lib/service-v1";
import { ConfigMapV1 } from "@cdktf/provider-kubernetes/lib/config-map-v1";
import { LonghornPvc, PublicIngressRoute } from "../../utils";
type NpmCacheOptions = {
provider: KubernetesProvider;
namespace: string;
host: string;
name: string;
};
export class NpmCache extends Construct {
constructor(scope: Construct, id: string, opts: NpmCacheOptions) {
super(scope, id);
const { provider, namespace, name, host } = opts;
new ConfigMapV1(this, "config", {
provider,
metadata: {
name,
namespace,
},
data: {
"config.yaml": fs.readFileSync(
path.join(__dirname, "config.yaml"),
"utf8",
),
},
});
const pvc = new LonghornPvc(this, "pvc", {
provider,
namespace,
name,
size: "128Gi",
accessModes: ["ReadWriteMany"],
});
new ServiceV1(this, "service", {
provider,
metadata: {
name,
namespace,
},
spec: {
selector: {
app: name,
},
port: [
{
port: 4873,
targetPort: name,
},
],
type: "ClusterIP",
},
});
new DeploymentV1(this, "deployment", {
provider,
metadata: {
name,
namespace,
},
spec: {
replicas: "3",
selector: {
matchLabels: {
app: name,
},
},
template: {
metadata: {
labels: {
app: name,
},
},
spec: {
nodeSelector: {
nodepool: "worker",
},
topologySpreadConstraint: [
{
maxSkew: 1,
topologyKey: "kubernetes.io/hostname",
whenUnsatisfiable: "DoNotSchedule",
labelSelector: [
{
matchLabels: {
app: name,
},
},
],
},
],
affinity: {
podAntiAffinity: {
requiredDuringSchedulingIgnoredDuringExecution: [
{
topologyKey: "kubernetes.io/hostname",
labelSelector: [
{
matchExpressions: [
{
key: "app",
operator: "In",
values: [name],
},
],
},
],
},
],
},
},
volume: [
{
name: "storage",
persistentVolumeClaim: {
claimName: pvc.name,
},
},
{
name: "config",
configMap: {
name,
},
},
],
container: [
{
name,
image: "verdaccio/verdaccio:latest",
env: [
{
name: "VERDACCIO_APP_CONFIG",
value: "/verdaccio/conf/custom.yaml",
},
{
name: "VERDACCIO_PORT",
value: "4873",
},
],
port: [
{
name,
containerPort: 4873,
},
],
volumeMount: [
{
name: "storage",
mountPath: "/verdaccio/storage",
},
{
name: "config",
mountPath: "/verdaccio/conf/config.yaml",
subPath: "config.yaml",
},
],
},
],
},
},
},
});
new PublicIngressRoute(this, "ingress", {
provider,
namespace,
name,
host,
serviceName: name,
servicePort: 4873,
});
}
}

View File

@@ -0,0 +1,128 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: devpi
namespace: homelab
spec:
storageClassName: longhorn
accessModes:
- ReadWriteMany
resources:
requests:
storage: 128Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: devpi
namespace: homelab
spec:
replicas: 3
selector:
matchLabels:
app: devpi
template:
metadata:
labels:
app: devpi
spec:
nodeSelector:
nodepool: worker
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: devpi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- devpi
topologyKey: "kubernetes.io/hostname"
containers:
- name: devpi
image: jonasal/devpi-server:latest
env:
- name: DEVPI_PASSWORD
valueFrom:
secretKeyRef:
name: devpi-secret
key: password
ports:
- containerPort: 3141
volumeMounts:
- name: data
mountPath: /devpi
volumes:
- name: data
persistentVolumeClaim:
claimName: devpi
---
apiVersion: v1
kind: Service
metadata:
name: devpi
namespace: homelab
spec:
selector:
app: devpi
ports:
- port: 3141
targetPort: 3141
protocol: TCP
type: ClusterIP
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: devpi
namespace: homelab
spec:
ipAllowList:
sourceRange:
- "127.0.0.1/32"
- "10.43.0.0/16"
rateLimit:
average: 10
burst: 50
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: devpi
namespace: homelab
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
cert-manager.io/cluster-issuer: "cloudflare-issuer"
cert-manager.io/acme-challenge-type: "dns01"
cert-manager.io/private-key-size: "4096"
# Traefik Middleware
traefik.io/router.middlewares: "devpi@kubernetescrd"
spec:
ingressClassName: traefik
tls:
- hosts:
- pip.dogar.dev
secretName: devpi-tls
rules:
- host: pip.dogar.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: devpi
port:
number: 3141