apiVersion: apps/v1 kind: Deployment metadata: name: impuestos-api namespace: impuestos labels: { app: impuestos, component: api } spec: replicas: 2 selector: matchLabels: { app: impuestos, component: api } template: metadata: labels: { app: impuestos, component: api } spec: # 30s: the process drains in-flight requests for up to 25s before it exits. terminationGracePeriodSeconds: 30 initContainers: # Every replica runs this. Concurrent runs are safe: the migration holds a Postgres # advisory lock on one pinned connection, so the second pod waits for the first. - name: migrate image: ghcr.io/example/impuestos-api:latest command: ['node', 'dist/db/migrate.cli.js'] envFrom: - configMapRef: { name: impuestos-config } - secretRef: { name: impuestos-secrets } resources: requests: { cpu: 50m, memory: 128Mi } limits: { memory: 256Mi } containers: - name: api image: ghcr.io/example/impuestos-api:latest ports: - name: http containerPort: 4000 env: - name: ROLE value: 'server' # The dedicated worker Deployment does the jobs. An API replica that also # polled would multiply the pollers by the replica count. - name: JOBS_INLINE value: 'false' envFrom: - configMapRef: { name: impuestos-config } - secretRef: { name: impuestos-secrets } # Liveness answers as long as the process is alive; readiness also checks the # database and the storage driver, and goes false the moment a drain begins. livenessProbe: httpGet: { path: /healthz, port: http } initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: { path: /readyz, port: http } initialDelaySeconds: 2 periodSeconds: 5 failureThreshold: 2 resources: requests: { cpu: 100m, memory: 256Mi } limits: { memory: 512Mi } volumeMounts: - name: tmp mountPath: /tmp securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: { drop: ['ALL'] } volumes: # The root filesystem is read only, so the one place anything may be written is an # empty directory that dies with the pod. Nothing durable belongs here: uploads go # through the storage driver to S3. - name: tmp emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: impuestos-api namespace: impuestos spec: type: ClusterIP selector: { app: impuestos, component: api } ports: - name: http port: 4000 targetPort: http