# The web app: a single Deployment behind a ClusterIP Service, reached only with
# `kubectl port-forward`. setup.sh fills <ACCOUNT_ID>, <AWS_REGION>, <NAMESPACE>,
# <S3_FILES_FS_ID>, <S3_BUCKET_NAME>, <S3_PREFIX>, <MOUNT_ROLE_ARN>, <AGENT_CLIS> and
# <IMAGE_TAG>.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: agent-app
  labels:
    app: agent-app
    app.kubernetes.io/part-of: coding-agents-for-developers
spec:
  # The app keeps running sessions, and the queue that makes each session's actions run one
  # after another, in memory, so it is meant to run as one pod. Recreate makes a rollout
  # stop the old pod before the new one starts. It does not cover a pod deleted or evicted
  # by hand, or a node that stops answering: the ReplicaSet can start a replacement while the
  # old pod is still shutting down (see the README, and issue #162 for a Lease).
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: agent-app
  template:
    metadata:
      labels:
        app: agent-app
        app.kubernetes.io/part-of: coding-agents-for-developers
      # Like the session pods: EKS Auto Mode must not evict the app to consolidate a node.
      # An eviction drops every open terminal and stops any Delete in flight; on a run of
      # this sample, consolidation evicted the app ("Underutilized") in the middle of one.
      annotations:
        karpenter.sh/do-not-disrupt: "true"
    spec:
      serviceAccountName: agent-app
      containers:
        - name: app
          image: <ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com/coding-agents-for-developers-app:<IMAGE_TAG>
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
          # The app listens once it has picked up running sessions, or at once if the pick-up
          # fails (logged), or after 60 seconds if it is still going (it then finishes in the
          # background, and requests for a session wait for it), so the Service and
          # `rollout status` wait for the port.
          readinessProbe:
            tcpSocket: { port: 8080 }
            periodSeconds: 2
          env:
            - name: AWS_REGION
              value: "<AWS_REGION>"
            - name: NAMESPACE
              value: "<NAMESPACE>"
            - name: S3_FILES_FS_ID
              value: "<S3_FILES_FS_ID>"
            - name: S3_BUCKET_NAME
              value: "<S3_BUCKET_NAME>"
            - name: S3_PREFIX
              value: "<S3_PREFIX>"
            - name: MOUNT_ROLE_ARN
              value: "<MOUNT_ROLE_ARN>"
            # Comma-separated CLI ids, each with a warm pool: claude-code,codex,...
            - name: AGENT_CLIS
              value: "<AGENT_CLIS>"
            # Minutes of no terminal activity before a session's pod is released.
            - name: IDLE_MINUTES
              value: "30"
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            runAsUser: 1000
            readOnlyRootFilesystem: true
            capabilities: { drop: ["ALL"] }
---
apiVersion: v1
kind: Service
metadata:
  name: agent-app
  labels:
    app: agent-app
    app.kubernetes.io/part-of: coding-agents-for-developers
spec:
  type: ClusterIP                 # reached only with kubectl port-forward; no Ingress
  selector:
    app: agent-app
  ports:
    - port: 8080
      targetPort: 8080
