Compare commits

..

4 Commits

8 changed files with 419 additions and 22 deletions

View File

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

View File

@@ -1,7 +1,10 @@
providers:
kubernetesCRD:
allowCrossNamespace: true
ingress:
ingressClass:
enabled: true
isDefaultClass: false
isDefaultClass: true
name: traefik
deployment:
replicas: 3

View File

@@ -9,6 +9,7 @@ import {
IpAllowListMiddlewareTCP,
} from "./traefik";
import { ValkeyCluster } from "./valkey";
import { InternalIngressRoute } from "../utils";
export class NetworkSecurity extends TerraformStack {
constructor(scope: Construct, id: string) {
@@ -79,5 +80,23 @@ export class NetworkSecurity extends TerraformStack {
name: "tcp-ip-allow-list",
sourceRanges: ["192.168.18.0/24", "10.42.0.0/16"],
});
new InternalIngressRoute(this, "longhorn-ui", {
provider: kubernetes,
namespace: "longhorn-system",
name: "longhorn-ui",
host: "longhorn.dogar.dev",
serviceName: "longhorn-frontend",
servicePort: 80,
});
new InternalIngressRoute(this, "grafana-ui", {
provider: kubernetes,
namespace: "monitoring",
name: "grafana-ui",
host: "grafana.dogar.dev",
serviceName: "prometheus-operator-grafana",
servicePort: 80,
});
}
}

View File

@@ -60,9 +60,22 @@ export class ValkeyCluster extends Construct {
},
},
},
{
name: "SHAHAB_PASSWORD",
valueFrom: {
secretKeyRef: { name: "valkey", key: "password" },
},
},
],
command: ["/bin/sh", "-c"],
args: ['exec valkey-server --requirepass "$PASSWORD"'],
args: [
`
valkey-server --requirepass "$PASSWORD" &
sleep 2
valkey-cli -a "$PASSWORD" ACL SETUSER shahab on ">$SHAHAB_PASSWORD" allcommands allkeys
wait
`,
],
readinessProbe: {
tcpSocket: [
{