# Production-grade Deployment template
# Yer tutucuları (<UPPER_CASE>) kendi değerlerinle değiştir.
# Bu template aşağıdaki en iyi pratikleri içerir:
#  - resource requests/limits
#  - readiness/liveness/startup probes
#  - non-root, read-only root FS, dropped capabilities
#  - topology spread (HA için)
#  - PodDisruptionBudget örneği (ayrı dosyada — pdb.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <APP_NAME>
  namespace: <NAMESPACE>
  labels:
    app.kubernetes.io/name: <APP_NAME>
    app.kubernetes.io/component: api
    app.kubernetes.io/part-of: <SYSTEM_NAME>
    app.kubernetes.io/managed-by: argocd
spec:
  replicas: 3
  revisionHistoryLimit: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 0           # zero-downtime için 0
  selector:
    matchLabels:
      app.kubernetes.io/name: <APP_NAME>
  template:
    metadata:
      labels:
        app.kubernetes.io/name: <APP_NAME>
        app.kubernetes.io/component: api
      annotations:
        # Prometheus scrape (eğer kullanıyorsan)
        prometheus.io/scrape: "true"
        prometheus.io/port: "9090"
        prometheus.io/path: "/metrics"
    spec:
      serviceAccountName: <APP_NAME>           # least-privilege sa
      automountServiceAccountToken: false       # gerekmiyorsa kapat
      terminationGracePeriodSeconds: 30
      securityContext:
        runAsNonRoot: true
        runAsUser: 65532
        runAsGroup: 65532
        fsGroup: 65532
        seccompProfile:
          type: RuntimeDefault
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: <APP_NAME>
                topologyKey: kubernetes.io/hostname
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app.kubernetes.io/name: <APP_NAME>
      containers:
        - name: app
          image: <REGISTRY>/<IMAGE>:<TAG>      # SHA-pinned önerilir (sha256:...)
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
            - name: metrics
              containerPort: 9090
              protocol: TCP
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: APP_VERSION
              value: "<VERSION>"               # release-please/Argo Image Updater set eder
          envFrom:
            - configMapRef:
                name: <APP_NAME>-config
            - secretRef:
                name: <APP_NAME>-secrets       # External Secrets Operator ile yönetilir
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              cpu: 1000m                        # CPU limit'i opsiyonel — throttling yapar
              memory: 512Mi                     # OOM önler
          startupProbe:
            httpGet:
              path: /health/live
              port: http
            failureThreshold: 30
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health/live
              port: http
            initialDelaySeconds: 0
            periodSeconds: 10
            failureThreshold: 3
            timeoutSeconds: 5
          readinessProbe:
            httpGet:
              path: /health/ready
              port: http
            initialDelaySeconds: 0
            periodSeconds: 5
            failureThreshold: 3
            timeoutSeconds: 3
          lifecycle:
            preStop:
              exec:
                # Graceful shutdown: load balancer'a "kayıyorum" deyince
                # mevcut isteklerin bitmesini bekle
                command: ["sh", "-c", "sleep 15"]
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: cache
              mountPath: /var/cache/app
      volumes:
        - name: tmp
          emptyDir: {}
        - name: cache
          emptyDir:
            sizeLimit: 100Mi
