diff --git a/cache-infrastructure/index.ts b/cache-infrastructure/index.ts index 2c7992c..4bd7603 100644 --- a/cache-infrastructure/index.ts +++ b/cache-infrastructure/index.ts @@ -4,6 +4,7 @@ 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"; +import { PipCache } from "./pip"; export class CacheInfrastructure extends TerraformStack { constructor(scope: Construct, id: string) { @@ -35,5 +36,12 @@ export class CacheInfrastructure extends TerraformStack { name: "npm-cache", host: "npm.dogar.dev", }); + + new PipCache(this, "pip-cache", { + provider, + namespace, + name: "pip-cache", + host: "pip.dogar.dev", + }); } } diff --git a/cache-infrastructure/pip/index.ts b/cache-infrastructure/pip/index.ts new file mode 100644 index 0000000..0191048 --- /dev/null +++ b/cache-infrastructure/pip/index.ts @@ -0,0 +1,168 @@ +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 { + LonghornPvc, + OnePasswordSecret, + PublicIngressRoute, +} from "../../utils"; + +type PipCacheOptions = { + provider: KubernetesProvider; + namespace: string; + name: string; + host: string; +}; + +export class PipCache extends Construct { + constructor(scope: Construct, id: string, opts: PipCacheOptions) { + super(scope, id); + + const { provider, namespace, name, host } = opts; + + new OnePasswordSecret(this, "devpi-secret", { + provider, + namespace, + name: "devpi", + itemPath: "vaults/Lab/items/devpi", + }); + + const pvc = new LonghornPvc(this, "pvc", { + provider, + namespace, + name, + size: "128Gi", + accessModes: ["ReadWriteMany"], + }); + + 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: "ScheduleAnyway", + labelSelector: [ + { + matchLabels: { + app: name, + }, + }, + ], + }, + ], + affinity: { + podAntiAffinity: { + requiredDuringSchedulingIgnoredDuringExecution: [ + { + topologyKey: "kubernetes.io/hostname", + labelSelector: [ + { + matchExpressions: [ + { + key: "app", + operator: "In", + values: [name], + }, + ], + }, + ], + }, + ], + }, + }, + volume: [ + { + name: "data", + persistentVolumeClaim: { + claimName: pvc.name, + }, + }, + ], + container: [ + { + name, + image: "jonasal/devpi-server:latest", + env: [ + { + name: "DEVPI_PASSWORD", + valueFrom: { + secretKeyRef: { + name: "devpi", + key: "password", + }, + }, + }, + ], + port: [ + { + name, + containerPort: 3141, + }, + ], + volumeMount: [ + { + name: "data", + mountPath: "/devpi", + }, + ], + }, + ], + }, + }, + }, + }); + + new ServiceV1(this, "service", { + provider, + metadata: { + name, + namespace, + }, + spec: { + selector: { + app: name, + }, + port: [ + { + port: 3141, + targetPort: name, + }, + ], + type: "ClusterIP", + }, + }); + + new PublicIngressRoute(this, "ingress", { + provider, + namespace, + name, + host, + serviceName: name, + servicePort: 3141, + }); + } +} diff --git a/cache-infrastructure/pip/manifest.yaml b/cache-infrastructure/pip/manifest.yaml deleted file mode 100644 index 32d407e..0000000 --- a/cache-infrastructure/pip/manifest.yaml +++ /dev/null @@ -1,128 +0,0 @@ ---- -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