diff --git a/k8s/base/configmaps/application-config.yaml b/k8s/base/configmaps/application-config.yaml new file mode 100644 index 0000000..15765e3 --- /dev/null +++ b/k8s/base/configmaps/application-config.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: application-config + namespace: urlshortener + labels: + app: urlshortener +data: + # Spring Boot Actuator configuration + management.endpoints.web.exposure.include: "health,info,metrics,prometheus" + management.endpoint.health.probes.enabled: "true" + management.health.livenessState.enabled: "true" + management.health.readinessState.enabled: "true" + + # Logging configuration + logging.level.root: "INFO" + logging.level.me.lenajenichen: "DEBUG" + logging.pattern.console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" + + # Application common settings + spring.application.name: "urlshortener" + + # Server configuration + server.error.include-message: "always" + server.error.include-binding-errors: "always" + server.error.include-stacktrace: "on_param" + server.error.include-exception: "false" + diff --git a/k8s/base/configmaps/database-config.yaml b/k8s/base/configmaps/database-config.yaml new file mode 100644 index 0000000..a9e09fd --- /dev/null +++ b/k8s/base/configmaps/database-config.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: database-config + namespace: urlshortener + labels: + app: urlshortener +data: + # PostgreSQL connection settings + # These will be used by services that need database access + # Note: Password should be set via secret: urlshortener-secrets (database-password key) + spring.r2dbc.url: "r2dbc:postgresql://postgres:5432/urlshortener" + spring.r2dbc.username: "urlshortener" + # Password is loaded from secret: urlshortener-secrets.database-password + + # Connection pool settings + spring.r2dbc.pool.initial-size: "5" + spring.r2dbc.pool.max-size: "20" + spring.r2dbc.pool.max-idle-time: "30m" + + # Database migration (if using Flyway or Liquibase) + spring.flyway.enabled: "true" + spring.flyway.baseline-on-migrate: "true" + diff --git a/k8s/base/configmaps/service-config.yaml b/k8s/base/configmaps/service-config.yaml new file mode 100644 index 0000000..146acc4 --- /dev/null +++ b/k8s/base/configmaps/service-config.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: service-config + namespace: urlshortener + labels: + app: urlshortener +data: + # Service discovery - internal service URLs + shortener.service.url: "http://shortener-service:8083" + auth.service.url: "http://auth-service:8080" + analytics.service.url: "http://analytics-service:8080" + redirect.service.url: "http://redirect-service:8080" + + # External service URLs (if needed) + shortener.service.external.url: "https://api.urlshortener.example.com/api/shortener" + redirect.service.external.url: "https://short.urlshortener.example.com" + diff --git a/k8s/base/deployments/analytics-service-deployment.yaml b/k8s/base/deployments/analytics-service-deployment.yaml new file mode 100644 index 0000000..2984ca9 --- /dev/null +++ b/k8s/base/deployments/analytics-service-deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: analytics-service + namespace: urlshortener + labels: + app: analytics-service + component: backend +spec: + replicas: 2 + selector: + matchLabels: + app: analytics-service + template: + metadata: + labels: + app: analytics-service + component: backend + spec: + containers: + - name: analytics-service + image: analytics-service:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + env: + - name: SERVER_PORT + value: "8080" + - name: SPRING_APPLICATION_NAME + value: analytics-service + - name: SPRING_R2DBC_PASSWORD + valueFrom: + secretKeyRef: + name: urlshortener-secrets + key: database-password + envFrom: + - configMapRef: + name: application-config + - configMapRef: + name: database-config + - configMapRef: + name: service-config + - secretRef: + name: urlshortener-secrets + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + startupProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 30 + restartPolicy: Always + diff --git a/k8s/base/deployments/auth-service-deployment.yaml b/k8s/base/deployments/auth-service-deployment.yaml new file mode 100644 index 0000000..b639b5d --- /dev/null +++ b/k8s/base/deployments/auth-service-deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: auth-service + namespace: urlshortener + labels: + app: auth-service + component: backend +spec: + replicas: 2 + selector: + matchLabels: + app: auth-service + template: + metadata: + labels: + app: auth-service + component: backend + spec: + containers: + - name: auth-service + image: auth-service:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + env: + - name: SERVER_PORT + value: "8080" + - name: SPRING_APPLICATION_NAME + value: auth-service + - name: SPRING_R2DBC_PASSWORD + valueFrom: + secretKeyRef: + name: urlshortener-secrets + key: database-password + envFrom: + - configMapRef: + name: application-config + - configMapRef: + name: database-config + - configMapRef: + name: service-config + - secretRef: + name: urlshortener-secrets + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + startupProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 30 + restartPolicy: Always + diff --git a/k8s/base/deployments/redirect-service-deployment.yaml b/k8s/base/deployments/redirect-service-deployment.yaml new file mode 100644 index 0000000..59b31a3 --- /dev/null +++ b/k8s/base/deployments/redirect-service-deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redirect-service + namespace: urlshortener + labels: + app: redirect-service + component: backend +spec: + replicas: 3 + selector: + matchLabels: + app: redirect-service + template: + metadata: + labels: + app: redirect-service + component: backend + spec: + containers: + - name: redirect-service + image: redirect-service:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + env: + - name: SERVER_PORT + value: "8080" + - name: SPRING_APPLICATION_NAME + value: redirect-service + - name: SPRING_R2DBC_PASSWORD + valueFrom: + secretKeyRef: + name: urlshortener-secrets + key: database-password + envFrom: + - configMapRef: + name: application-config + - configMapRef: + name: database-config + - configMapRef: + name: service-config + - secretRef: + name: urlshortener-secrets + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + startupProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 30 + restartPolicy: Always + diff --git a/k8s/base/deployments/shortener-service-deployment.yaml b/k8s/base/deployments/shortener-service-deployment.yaml new file mode 100644 index 0000000..f63c69d --- /dev/null +++ b/k8s/base/deployments/shortener-service-deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: shortener-service + namespace: urlshortener + labels: + app: shortener-service + component: backend +spec: + replicas: 2 + selector: + matchLabels: + app: shortener-service + template: + metadata: + labels: + app: shortener-service + component: backend + spec: + containers: + - name: shortener-service + image: shortener-service:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8083 + name: http + protocol: TCP + env: + - name: SERVER_PORT + value: "8083" + - name: SPRING_APPLICATION_NAME + value: shortener-service + - name: SPRING_R2DBC_PASSWORD + valueFrom: + secretKeyRef: + name: urlshortener-secrets + key: database-password + envFrom: + - configMapRef: + name: application-config + - configMapRef: + name: database-config + - configMapRef: + name: service-config + - secretRef: + name: urlshortener-secrets + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8083 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8083 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + startupProbe: + httpGet: + path: /actuator/health + port: 8083 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 30 + restartPolicy: Always + diff --git a/k8s/base/ingress/ingress.yaml b/k8s/base/ingress/ingress.yaml index e69de29..e760332 100644 --- a/k8s/base/ingress/ingress.yaml +++ b/k8s/base/ingress/ingress.yaml @@ -0,0 +1,54 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: urlshortener-ingress + namespace: urlshortener + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/ssl-redirect: "true" + cert-manager.io/cluster-issuer: "letsencrypt-prod" +spec: + ingressClassName: nginx + tls: + - hosts: + - api.urlshortener.example.com + - short.urlshortener.example.com + secretName: urlshortener-tls + rules: + # API routes for shortener and auth services + - host: api.urlshortener.example.com + http: + paths: + - path: /api/shortener + pathType: Prefix + backend: + service: + name: shortener-service + port: + number: 8083 + - path: /api/auth + pathType: Prefix + backend: + service: + name: auth-service + port: + number: 8080 + - path: /api/analytics + pathType: Prefix + backend: + service: + name: analytics-service + port: + number: 8080 + # Redirect service - handles short URL redirects + - host: short.urlshortener.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: redirect-service + port: + number: 8080 + diff --git a/k8s/base/namespace.yaml b/k8s/base/namespace.yaml index e69de29..eaf8a07 100644 --- a/k8s/base/namespace.yaml +++ b/k8s/base/namespace.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: urlshortener + labels: + name: urlshortener + environment: production + diff --git a/k8s/base/secrets/secrets-template.yaml b/k8s/base/secrets/secrets-template.yaml new file mode 100644 index 0000000..91b6b6e --- /dev/null +++ b/k8s/base/secrets/secrets-template.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Secret +metadata: + name: urlshortener-secrets + namespace: urlshortener + labels: + app: urlshortener +type: Opaque +stringData: + # Database credentials + # IMPORTANT: Replace these with actual values or use a secret management system + database-password: "CHANGE_ME" + + # JWT secrets for authentication + jwt.secret: "CHANGE_ME_JWT_SECRET_KEY_MIN_32_CHARS" + jwt.expiration: "86400000" # 24 hours in milliseconds + + # API keys (if needed for external services) + # external-api-key: "CHANGE_ME" + + # Encryption keys + # encryption.key: "CHANGE_ME_ENCRYPTION_KEY" + +--- +# Instructions for creating secrets: +# +# Option 1: Using kubectl create secret +# kubectl create secret generic urlshortener-secrets \ +# --from-literal=database-password='your-password' \ +# --from-literal=jwt.secret='your-jwt-secret' \ +# --namespace=urlshortener +# +# Option 2: Using sealed-secrets or external-secrets operator +# Option 3: Using a secret management system (HashiCorp Vault, AWS Secrets Manager, etc.) +# +# Option 4: Base64 encode and use the data field instead of stringData: +# echo -n 'your-password' | base64 + diff --git a/k8s/base/services/analytics-service-service.yaml b/k8s/base/services/analytics-service-service.yaml new file mode 100644 index 0000000..958a94b --- /dev/null +++ b/k8s/base/services/analytics-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: analytics-service + namespace: urlshortener + labels: + app: analytics-service + component: backend +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: analytics-service + sessionAffinity: None + diff --git a/k8s/base/services/auth-service-service.yaml b/k8s/base/services/auth-service-service.yaml new file mode 100644 index 0000000..84c57cd --- /dev/null +++ b/k8s/base/services/auth-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: auth-service + namespace: urlshortener + labels: + app: auth-service + component: backend +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: auth-service + sessionAffinity: None + diff --git a/k8s/base/services/redirect-service-service.yaml b/k8s/base/services/redirect-service-service.yaml new file mode 100644 index 0000000..7f25c5a --- /dev/null +++ b/k8s/base/services/redirect-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: redirect-service + namespace: urlshortener + labels: + app: redirect-service + component: backend +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: redirect-service + sessionAffinity: None + diff --git a/k8s/base/services/shortener-service-service.yaml b/k8s/base/services/shortener-service-service.yaml new file mode 100644 index 0000000..6e9fc46 --- /dev/null +++ b/k8s/base/services/shortener-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: shortener-service + namespace: urlshortener + labels: + app: shortener-service + component: backend +spec: + type: ClusterIP + ports: + - port: 8083 + targetPort: 8083 + protocol: TCP + name: http + selector: + app: shortener-service + sessionAffinity: None +