Kubernetes manifests examples

apiVersion: apps/v1
kind: Deployment
metadata:
  # deployment name
  name: my_app
  namespace: default
spec:
  selector:
    matchLabels:
      # label for the deployment used by Service to connect
      app: my_app
  template:
    metadata:
      labels:
        app: my_app
    spec:
      containers:
          # container name in pod
        - name: php
          # docker image used for this container
          image: my-php-fpm
          # always get the docker image from registry
          imagePullPolicy: Always
          ports:
            # port to communicate
            - containerPort: 9000
          # load environment variables from config map
          envFrom:
            - configMapRef:
                name: my_app
            # load encoded secret from Secrets manifest
            - secretRef:
                name: my_app_secrets
          # set resources
          resources:
            requests:
              memory: "64Mi"
              cpu: "10m"
            limits:
              memory: "512Mi"
              cpu: "100m"
          # (optional)
          lifecycle:
            # used to trigger actions after container starts
            postStart:
              exec:
                command:
                  - "/bin/bash"
                  - "-c"
                  - 'curl -s -X GET --max-time 3000 http://${SERVICE_NAME}.notifications.svc.cluster.local/start/${HOSTNAME}/php >&1; exit 0'
            # used to trigger actions before container stops
            preStop:
              exec:
                command:
                  - "/bin/bash"
                  - "-c"
                  - 'curl -s -X GET --max-time 3000 http://${SERVICE_NAME}.notifications.svc.cluster.local/stop/${HOSTNAME}/php >&1; exit 0'
          # mount volumes for this container
          volumeMounts:
            # thumbnails volume
            - mountPath: /app/web/thumbs
              name: thumbnails
            # files uploads volume
            - mountPath: /uploads
              name: uploads
        # similar to above explanations
        - name: nginx
          image: my-nginx
          imagePullPolicy: Always
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: my_app
          resources:
            requests:
              memory: "32Mi"
              cpu: "10m"
            limits:
              memory: "256Mi"
              cpu: "100m"
          lifecycle:
            postStart:
              exec:
                command:
                  - "/bin/bash"
                  - "-c"
                  - 'curl -s -X GET --max-time 3000 http://${SERVICE_NAME}.notifications.svc.cluster.local/start/${HOSTNAME}/php >&1; exit 0'
            preStop:
              exec:
                command:
                  - "/bin/bash"
                  - "-c"
                  - 'curl -s -X GET --max-time 3000 http://${SERVICE_NAME}.notifications.svc.cluster.local/stop/${HOSTNAME}/php >&1; exit 0'
          volumeMounts:
            - mountPath: /app/web/thumbs
              name: thumbnails
      # all init containers will run before the main containers
      initContainers:
        - name: update-database
          image: my-app-nginx
          envFrom:
            - configMapRef:
                name: my-app-config
          command:
            - "bin/console"
            - "setup:install"
      # set volumes per deployment that will be used by containers using volumeMounts
      volumes:
        # define thumbnails directory as empty volume every time
        - name: thumbnails
          emptyDir: {}
        # load uploads directory from PersistentVolumeClaim
        - name: uploads
          persistentVolumeClaim:
            claimName: my-app-uploads
apiVersion: v1
kind: Service
metadata:
  name: my-app-node-port
  namespace: default
spec:
  type: NodePort
  selector:
    app: my_app
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-cluster-ip
  namespace: defualt
spec:
  type: ClusterIP
  selector:
    app: my_app
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-load-balancer
  namespace: default
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: database-host
  namespace: dedfault
spec:
  type: ExternalName
  externalName: "__RDS_HOST__"
# Documentation: https://kubernetes.io/docs/concepts/services-networking/ingress/
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    controller.scope.enabled: "true"
    controller.scope.namespace: "default"
spec:
  # (optional) if you want to listen to 443 port
  tls:
    - hosts:
        - www.example.com
      # secret defined for SSL certificate
      secretName: example.com-tls
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app
                port:
                  number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
  namespace: default
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
  namespace: default
spec:
  rules:
    - host: "foo.bar.com"
      http:
        paths:
          - pathType: Prefix
            path: "/bar"
            backend:
              service:
                name: service1
                port:
                  number: 80
    - host: "*.foo.com"
      http:
        paths:
          - pathType: Prefix
            path: "/foo"
            backend:
              service:
                name: service2
                port:
                  number: 80
apiVersion: v1
kind: ConfigMap
metadata:
  # config map name, will be used by deployments, cronjobs, etc
  name: my-app-config
  namespace: default
data:
  APP_ENV: prod

  MYSQL_HOST: "127.0.0.1"
  MYSQL_USER: mysql_username_here

  UPLOAD_DIRECTORY: /data/uploads
apiVersion: v1
kind: Secret
metadata:
  name: my-app-secrets
  namespace: default
data:
  my_db_password: a2lzcGhw # base64 encoded
  redis_password: a2lzcGhw # base64 encoded

# you can create secrets with the following command
#
# kubectl create secret general secret-name --from-literal=MYSQL_PASSWORD=mypass123 --from-literal=APP_SECRET=qawsed1234 -o yaml --dry-run
#
apiVersion: v1
kind: PersistentVolume
metadata:
  name: uploaded-files
  # PVs don't have a namespace
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: /mnt/nfs/uploaded_files
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-app-uploads
  namespace: default
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Gi
# if you define PVC for AWS EFS, just set the storage to 1Gi, no matter how big the EFS is
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: my-cron-job
  namespace: default
  labels:
    app: my-cron-job
spec:
  # run every minute
  schedule: "* * * * *"
  # do not allow concurrent jobs
  concurrencyPolicy: Forbid
  # delete successful pods
  successfulJobsHistoryLimit: 0
  # keep last 2 failed pods for debug
  failedJobsHistoryLimit: 2
  startingDeadlineSeconds: 120
  suspend: false
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: my-cron-job
        spec:
          restartPolicy: Never
          nodeSelector:
            type: cron
          containers:
            # name of the container in pod
            - name: app-cron
              # docker image to load for this container
              image: my-php-container:tag_name
              # always download image from registry
              imagePullPolicy: Always
              # define necessary resources for this container
              resources:
                requests:
                  cpu: "1"
                  memory: "256Mi"
                limits:
                  cpu: "1"
                  memory: "1Gi"
              # load all variables defined in config map
              envFrom:
                - configMapRef:
                    name: my-app-config
              env:
                # set inline variable for container
                - name: CONTAINER_PURPOSE
                  value: cron
                # register a secret (password) to env vars from secrets manifests
                - name: MYSQL_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: my-app-secrets
                      # reference to variable name in secrets manifest
                      key: my_db_password
              command:
                - vendor/bin/codecept
              args:
                - run
                - "--dry-run"
              volumeMounts:
                - name: project-data
                  mountPath: /stored_data
          volumes:
            # using aws EFS
            - name: project-data
              nfs:
                server: 1a2b3c4d.efs.eu-central-1.amazonaws.com
                path: /
            # using PVC
            - name: uploads
              persistentVolumeClaim:
                claimName: uploaded-files
apiVersion: batch/v1
kind: Job
metadata:
  name: thumbs-cleanup
  namespace: default
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: php
          image: my-custom-container
          imagePullPolicy: Always
          command:
            - vendor/bin/console
            - cleanup:thumbs
          envFrom:
            - configMapRef:
                name: my-config
          env:
            - name: CONTAINER_PURPOSE
              value: job
            - name: MY_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-password
                  key: password