diff options
author | 2023-08-13 20:01:42 +0100 | |
---|---|---|
committer | 2023-08-14 11:44:03 +0100 | |
commit | 661f49409e69f5cfafbef4cd41411a72ebc5418d (patch) | |
tree | 9ddd7f2a2ab09cadc5b716be00628e19d839ad4d /kubernetes/namespaces | |
parent | Allow multiple documents within yaml files (diff) |
Copy all files from kubernetes repo into this one
This commit is a like-for-like copy of the [kubernetes repo](https://github.com/python-discord/kubernetes) check that repo for comit history prioir to this commit.
Co-authored-by: Amrou Bellalouna <[email protected]>
Co-authored-by: Bradley Reynolds <[email protected]>
Co-authored-by: Chris <[email protected]>
Co-authored-by: Chris Lovering <[email protected]>
Co-authored-by: ChrisJL <[email protected]>
Co-authored-by: Den4200 <[email protected]>
Co-authored-by: GDWR <[email protected]>
Co-authored-by: Hassan Abouelela <[email protected]>
Co-authored-by: Hassan Abouelela <[email protected]>
Co-authored-by: jchristgit <[email protected]>
Co-authored-by: Joe Banks <[email protected]>
Co-authored-by: Joe Banks <[email protected]>
Co-authored-by: Joe Banks <[email protected]>
Co-authored-by: Johannes Christ <[email protected]>
Co-authored-by: Kieran Siek <[email protected]>
Co-authored-by: kosayoda <[email protected]>
Co-authored-by: ks129 <[email protected]>
Co-authored-by: Leon Sand├©y <[email protected]>
Co-authored-by: Leon Sand├©y <[email protected]>
Co-authored-by: MarkKoz <[email protected]>
Co-authored-by: Matteo Bertucci <[email protected]>
Co-authored-by: Sebastiaan Zeeff <[email protected]>
Co-authored-by: Sebastiaan Zeeff <[email protected]>
Co-authored-by: vcokltfre <[email protected]>
Diffstat (limited to 'kubernetes/namespaces')
205 files changed, 4677 insertions, 0 deletions
diff --git a/kubernetes/namespaces/cert-manager/cert-manager/README.md b/kubernetes/namespaces/cert-manager/cert-manager/README.md new file mode 100644 index 0000000..a7389e6 --- /dev/null +++ b/kubernetes/namespaces/cert-manager/cert-manager/README.md @@ -0,0 +1,13 @@ +# cert-manager + +X.509 certificate management for Kubernetes. + +> cert-manager builds on top of Kubernetes, introducing certificate authorities and certificates as first-class resource types in the Kubernetes API. This makes it possible to provide to developers 'certificates as a service' in your Kubernetes cluster. + +We install cert-mamnanger through [Helm using this guide](https://cert-manager.io/docs/installation/kubernetes/#installing-with-helm). + +## Directories + +`issuers`: Contains configured issuers, right now only letsencrypt production & staging. + +`certificates`: Contains TLS certificates that should be provisioned and where they should be stored. diff --git a/kubernetes/namespaces/cert-manager/cert-manager/certificates/pythondiscord.com.yaml b/kubernetes/namespaces/cert-manager/cert-manager/certificates/pythondiscord.com.yaml new file mode 100644 index 0000000..94bd7dc --- /dev/null +++ b/kubernetes/namespaces/cert-manager/cert-manager/certificates/pythondiscord.com.yaml @@ -0,0 +1,12 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: pythondiscord-com +spec: + secretName: pythondiscord.com-tls + dnsNames: + - pythondiscord.com + - '*.pythondiscord.com' + issuerRef: + name: letsencrypt + kind: ClusterIssuer diff --git a/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-prod.yaml b/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-prod.yaml new file mode 100644 index 0000000..4321377 --- /dev/null +++ b/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-prod.yaml @@ -0,0 +1,18 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt + namespace: cert-manager +spec: + acme: + email: [email protected] + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-account-key + solvers: + - dns01: + cloudflare: + email: [email protected] + apiTokenSecretRef: + name: cloudflare-credentials + key: cloudflare-api-key diff --git a/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-staging.yaml b/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-staging.yaml new file mode 100644 index 0000000..e9fdfc7 --- /dev/null +++ b/kubernetes/namespaces/cert-manager/cert-manager/issuers/letsencrypt-staging.yaml @@ -0,0 +1,18 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: cert-manager +spec: + acme: + email: [email protected] + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-staging-account-key + solvers: + - dns01: + cloudflare: + email: [email protected] + apiTokenSecretRef: + name: cloudflare-credentials + key: cloudflare-api-key diff --git a/kubernetes/namespaces/cert-manager/cert-manager/values.yaml b/kubernetes/namespaces/cert-manager/cert-manager/values.yaml new file mode 100644 index 0000000..1b4551c --- /dev/null +++ b/kubernetes/namespaces/cert-manager/cert-manager/values.yaml @@ -0,0 +1 @@ +installCRDs: true diff --git a/kubernetes/namespaces/default/bitwarden/README.md b/kubernetes/namespaces/default/bitwarden/README.md new file mode 100644 index 0000000..37f01eb --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/README.md @@ -0,0 +1,14 @@ +# BitWarden + +Our internal password manager, used by the admins to share passwords for our services. Hosted at https://bitwarden.pythondiscord.com + +To deploy this, first set up the secrets (see below) and then run `kubectl apply -f .` in this folder. + +## Secrets +This deployment expects a few secrets to exist in a secret called `bitwarden-secret-env`. + + +| Environment | Description | +|-----------------------|-------------------------------------------| +| ADMIN_TOKEN | 64-character token used for initial login | +| DATABASE_URL | Database string: host://user:pass/db | diff --git a/kubernetes/namespaces/default/bitwarden/configmap.yaml b/kubernetes/namespaces/default/bitwarden/configmap.yaml new file mode 100644 index 0000000..c758f5d --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: bitwarden-config-env +data: + # Domain to access bitwarden by + DOMAIN: "https://bitwarden.pythondiscord.com" + + # Password hint must be sent to an email when this is false. + # When it's true, it'll be shown right on the page. + SHOW_PASSWORD_HINT: "false" + + # Admins only, please! + SIGNUPS_ALLOWED: "false" + + # Used for LiveSync + WEBSOCKET_ENABLED: "true" + + # Max conns to the DB + DATABASE_MAX_CONNS: "2" + + # Force bitwarden to use postgres, rather than it's own volume + I_REALLY_WANT_VOLATILE_STORAGE: "true" diff --git a/kubernetes/namespaces/default/bitwarden/deployment.yaml b/kubernetes/namespaces/default/bitwarden/deployment.yaml new file mode 100644 index 0000000..70a22ce --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/deployment.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bitwarden +spec: + replicas: 1 + selector: + matchLabels: + app: bitwarden + template: + metadata: + labels: + app: bitwarden + spec: + containers: + - name: bitwarden + image: vaultwarden/server:latest + imagePullPolicy: Always + resources: + requests: + cpu: 1m + memory: 50Mi + limits: + cpu: 50m + memory: 100Mi + ports: + - containerPort: 80 + envFrom: + - secretRef: + name: bitwarden-secret-env + - configMapRef: + name: bitwarden-config-env + securityContext: + readOnlyRootFilesystem: true diff --git a/kubernetes/namespaces/default/bitwarden/ingress.yaml b/kubernetes/namespaces/default/bitwarden/ingress.yaml new file mode 100644 index 0000000..d0371f6 --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: bitwarden +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: bitwarden.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bitwarden + port: + number: 80 diff --git a/kubernetes/namespaces/default/bitwarden/secrets.yaml b/kubernetes/namespaces/default/bitwarden/secrets.yaml Binary files differnew file mode 100644 index 0000000..34cfd7a --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/secrets.yaml diff --git a/kubernetes/namespaces/default/bitwarden/service.yaml b/kubernetes/namespaces/default/bitwarden/service.yaml new file mode 100644 index 0000000..3df8cc2 --- /dev/null +++ b/kubernetes/namespaces/default/bitwarden/service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: bitwarden +spec: + ports: + - port: 80 + selector: + app: bitwarden diff --git a/kubernetes/namespaces/default/black-knight/README.md b/kubernetes/namespaces/default/black-knight/README.md new file mode 100644 index 0000000..d1f8d89 --- /dev/null +++ b/kubernetes/namespaces/default/black-knight/README.md @@ -0,0 +1,16 @@ +## Black Knight +Deployment file for @Black-Knight, our courageous and ever present anti-raid bot. + +## Secrets +This deployment expects a number of secrets/environment variables to exist in a secret called `black-knight-env`. + +| Environment | Description | +|-----------------------|-------------------------------------------------------------------| +| BOT_TOKEN | The Discord bot token for Black Knight to connect to Discord with | +| DATABASE_URL | A full PostgreSQL connection string to the postgres db | +| BOT_SENTRY_DSN | The DSN to connect send sentry reports to | + +Black knight also requires a redis password, which is pulled from the `redis-credentials` secret. +``` +REDIS_PASSWORD - The password to redis +``` diff --git a/kubernetes/namespaces/default/black-knight/deployment.yaml b/kubernetes/namespaces/default/black-knight/deployment.yaml new file mode 100644 index 0000000..c61429a --- /dev/null +++ b/kubernetes/namespaces/default/black-knight/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: black-knight +spec: + replicas: 1 + selector: + matchLabels: + app: black-knight + template: + metadata: + labels: + app: black-knight + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: black-knight + image: ghcr.io/python-discord/black-knight:latest + imagePullPolicy: Always + resources: + requests: + cpu: 500m + memory: 300Mi + limits: + cpu: 750m + memory: 500Mi + envFrom: + - secretRef: + name: black-knight-env + - secretRef: + name: redis-credentials + securityContext: + readOnlyRootFilesystem: true + imagePullSecrets: + - name: ghcr-pull-secret diff --git a/kubernetes/namespaces/default/black-knight/secrets.yaml b/kubernetes/namespaces/default/black-knight/secrets.yaml Binary files differnew file mode 100644 index 0000000..40909c9 --- /dev/null +++ b/kubernetes/namespaces/default/black-knight/secrets.yaml diff --git a/kubernetes/namespaces/default/blackbox/README.md b/kubernetes/namespaces/default/blackbox/README.md new file mode 100644 index 0000000..f53ef87 --- /dev/null +++ b/kubernetes/namespaces/default/blackbox/README.md @@ -0,0 +1,18 @@ +# Blackbox +These manifests provision a CronJob for blackbox, our database backup tool. + +You can find the repository for blackbox at [lemonsaurus/blackbox](https://github.com/lemonsaurus/blackbox). + +## Secrets +blackbox requires the following secrets in a secret titled `blackbox-env`: + +| Variable | Description | +|--------------------------------|------------------------| +| **POSTGRES_USER** | Postgres username | +| **POSTGRES_PASSWORD** | Postgres password | +| **REDIS_PASSWORD** | Redis password | +| **MONGO_INITDB_ROOT_USERNAME** | MongoDB username | +| **MONGO_INITDB_ROOT_PASSWORD** | MongoDB password | +| **AWS_ACCESS_KEY_ID** | Access key for S3 | +| **AWS_SECRET_ACCESS_KEY** | Secret key for S3 | +| **DEVOPS_WEBHOOK** | Webhook for #dev-ops | diff --git a/kubernetes/namespaces/default/blackbox/blackbox-configmap.yaml b/kubernetes/namespaces/default/blackbox/blackbox-configmap.yaml new file mode 100644 index 0000000..6922b1f --- /dev/null +++ b/kubernetes/namespaces/default/blackbox/blackbox-configmap.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: blackbox-config +data: + blackbox.yaml: | + databases: + mongodb: + main_mongodb: + connection_string: mongodb://{{ MONGO_INITDB_ROOT_USERNAME }}:{{ MONGO_INITDB_ROOT_PASSWORD }}@mongodb.default.svc.cluster.local:27017 + postgres: + main_postgres: + username: {{ POSTGRES_USER }} + password: {{ POSTGRES_PASSWORD }} + host: postgres.default.svc.cluster.local + port: "5432" + redis: + main_redis: + password: {{ REDIS_PASSWORD }} + host: redis.default.svc.cluster.local + port: "6379" + + storage: + s3: + frankfurt_s3: + bucket: blackbox + endpoint: eu-central-1.linodeobjects.com + aws_access_key_id: {{ AWS_ACCESS_KEY_ID }} + aws_secret_access_key: {{ AWS_SECRET_ACCESS_KEY }} + newark_s3: + bucket: blackbox + endpoint: us-east-1.linodeobjects.com + aws_access_key_id: {{ AWS_ACCESS_KEY_ID }} + aws_secret_access_key: {{ AWS_SECRET_ACCESS_KEY }} + singapore_s3: + bucket: blackbox + endpoint: ap-south-1.linodeobjects.com + aws_access_key_id: {{ AWS_ACCESS_KEY_ID }} + aws_secret_access_key: {{ AWS_SECRET_ACCESS_KEY }} + + + notifiers: + discord: + dev_ops: + webhook: {{ DEVOPS_WEBHOOK }} + + retention_days: 7 diff --git a/kubernetes/namespaces/default/blackbox/cronjob.yaml b/kubernetes/namespaces/default/blackbox/cronjob.yaml new file mode 100644 index 0000000..405bfbe --- /dev/null +++ b/kubernetes/namespaces/default/blackbox/cronjob.yaml @@ -0,0 +1,39 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: blackbox +spec: + schedule: "0 15 * * *" + jobTemplate: + spec: + template: + spec: + containers: + - name: blackbox + image: lemonsaurus/blackbox:main + imagePullPolicy: Always + envFrom: + - secretRef: + name: blackbox-env + env: + - name: BLACKBOX_CONFIG_PATH + value: "/blackbox/config_file/blackbox.yaml" + volumeMounts: + - mountPath: /blackbox/config_file + name: blackbox-config + - mountPath: /tmp + name: blackbox-tmp + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: blackbox-config + configMap: + name: blackbox-config + - name: blackbox-tmp + emptyDir: {} + restartPolicy: OnFailure + nodeSelector: + # NOTE: This should be updated to match the highest spec + # instance that is being used by the cluster. + beta.kubernetes.io/instance-type: g6-standard-4 + backoffLimit: 3 diff --git a/kubernetes/namespaces/default/blackbox/secrets.yaml b/kubernetes/namespaces/default/blackbox/secrets.yaml Binary files differnew file mode 100644 index 0000000..3659e59 --- /dev/null +++ b/kubernetes/namespaces/default/blackbox/secrets.yaml diff --git a/kubernetes/namespaces/default/bot/README.md b/kubernetes/namespaces/default/bot/README.md new file mode 100644 index 0000000..6a992b5 --- /dev/null +++ b/kubernetes/namespaces/default/bot/README.md @@ -0,0 +1,18 @@ +## Bot + +Deployment file for @Python, our valiant community bot and workhorse. + +## Secrets +This deployment expects a number of secrets and environment variables to exist in a secret called `bot-env`. + +| Environment | Description | +|-------------------|-------------------------------------------------------------| +| API_KEYS_GITHUB | An API key for Github's API. | +| API_KEYS_SITE_API | The token to access our site's API. | +| BOT_SENTRY_DSN | The sentry DSN to send sentry events to. | +| BOT_TOKEN | The Discord bot token to run the bot on. | +| BOT_TRACE_LOGGERS | Comma separated list of loggers to enable trace logging for | +| DEBUG | Debug mode true/false | +| METABASE_PASSWORD | Password for Metabase | +| METABASE_USERNAME | Username for Metabase | +| URLS_PASTE_URL | The URL to the paste site | diff --git a/kubernetes/namespaces/default/bot/deployment.yaml b/kubernetes/namespaces/default/bot/deployment.yaml new file mode 100644 index 0000000..e05b2ec --- /dev/null +++ b/kubernetes/namespaces/default/bot/deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bot +spec: + replicas: 1 + selector: + matchLabels: + app: bot + template: + metadata: + labels: + app: bot + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: bot + image: ghcr.io/python-discord/bot:latest + imagePullPolicy: Always + resources: + requests: + cpu: 750m + memory: 600Mi + limits: + cpu: 1000m + memory: 1400Mi + envFrom: + - secretRef: + name: bot-env + - secretRef: + name: redis-credentials + volumeMounts: + - mountPath: /bot/logs + name: logs-vol + - mountPath: /.cache/python-tldextract + name: tldextract-cache + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: logs-vol + emptyDir: {} + - name: tldextract-cache + emptyDir: {} diff --git a/kubernetes/namespaces/default/bot/secrets.yaml b/kubernetes/namespaces/default/bot/secrets.yaml Binary files differnew file mode 100644 index 0000000..c48842e --- /dev/null +++ b/kubernetes/namespaces/default/bot/secrets.yaml diff --git a/kubernetes/namespaces/default/code-jam-management/README.md b/kubernetes/namespaces/default/code-jam-management/README.md new file mode 100644 index 0000000..b377130 --- /dev/null +++ b/kubernetes/namespaces/default/code-jam-management/README.md @@ -0,0 +1,11 @@ +# Code Jam Management + +This contains the deployment for the internal [code jam management](https://github.com/python-discord/code-jam-management) service. + +### Required Secret +In a secret named `code-jam-management-env`: + +| Environment | Description | +|--------------|------------------------------------------------------------------------| +| API_TOKEN | A random string to use as the auth token for making requests to CJMS | +| DATABASE_URL | `postgres://<user>:<password>@<host>:<port>/<name>` | diff --git a/kubernetes/namespaces/default/code-jam-management/deployment.yaml b/kubernetes/namespaces/default/code-jam-management/deployment.yaml new file mode 100644 index 0000000..86d8328 --- /dev/null +++ b/kubernetes/namespaces/default/code-jam-management/deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: code-jam-management +spec: + replicas: 1 + selector: + matchLabels: + app: code-jam-management + template: + metadata: + labels: + app: code-jam-management + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: codejam-management + image: ghcr.io/python-discord/code-jam-management:latest + imagePullPolicy: Always + volumeMounts: + - mountPath: /tmp + name: code-jam-mgmt-tmp + - mountPath: /.cache + name: code-jam-mgmt-venv + ports: + - containerPort: 8000 + envFrom: + - secretRef: + name: code-jam-management-env + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: code-jam-mgmt-tmp + emptyDir: + medium: Memory + - name: code-jam-mgmt-venv + emptyDir: {} diff --git a/kubernetes/namespaces/default/code-jam-management/secrets.yaml b/kubernetes/namespaces/default/code-jam-management/secrets.yaml Binary files differnew file mode 100644 index 0000000..6400778 --- /dev/null +++ b/kubernetes/namespaces/default/code-jam-management/secrets.yaml diff --git a/kubernetes/namespaces/default/code-jam-management/service.yaml b/kubernetes/namespaces/default/code-jam-management/service.yaml new file mode 100644 index 0000000..2083adb --- /dev/null +++ b/kubernetes/namespaces/default/code-jam-management/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: code-jam-management +spec: + selector: + app: code-jam-management + ports: + - protocol: TCP + port: 8000 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/forms/backend/README.md b/kubernetes/namespaces/default/forms/backend/README.md new file mode 100644 index 0000000..06fed13 --- /dev/null +++ b/kubernetes/namespaces/default/forms/backend/README.md @@ -0,0 +1,20 @@ +# Forms Backend + +Forms backend is our surveyance system for putting out forms in our community. + +This directory contains the necessary routing manifests, the deployment is located in the [python-discord/forms-backend](https://github.com/python-discord/forms-backend) repository. + +This deployment expects a number of secrets and environment variables to exist in a secret called `forms-backend-env`. + +| Environment | Description | +|----------------------|-----------------------------------------------------------------| +| DATABASE_URL | A MongoDB database url | +| DISCORD_BOT_TOKEN | The bot token to connect to Discord's API with | +| DOCS_PASSWORD | The password required to access the auto-generated API docs | +| HCAPTCHA_API_SECRET | The API key to HCAPTCHA's API | +| OAUTH2_CLIENT_ID | The Discord app OAuth2 client id | +| OAUTH2_CLIENT_SECRET | The Discord app OAuth2 client secret | +| PRODUCTION | Whether the app is in production true/false | +| SECRET_KEY | The key to sign all JWTs with | +| SNEKBOX_URL | The URL to the senkbox service to use for code form submissions | +| FORMS_BACKEND_DSN | The sentry DSN to send sentry events to | diff --git a/kubernetes/namespaces/default/forms/backend/ingress.yaml b/kubernetes/namespaces/default/forms/backend/ingress.yaml new file mode 100644 index 0000000..1967ab4 --- /dev/null +++ b/kubernetes/namespaces/default/forms/backend/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: forms-backend +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: forms-api.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: forms-backend + port: + number: 80 diff --git a/kubernetes/namespaces/default/forms/backend/secrets.yaml b/kubernetes/namespaces/default/forms/backend/secrets.yaml Binary files differnew file mode 100644 index 0000000..8977e99 --- /dev/null +++ b/kubernetes/namespaces/default/forms/backend/secrets.yaml diff --git a/kubernetes/namespaces/default/forms/backend/service.yaml b/kubernetes/namespaces/default/forms/backend/service.yaml new file mode 100644 index 0000000..6e11796 --- /dev/null +++ b/kubernetes/namespaces/default/forms/backend/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: forms-backend +spec: + selector: + app: forms-backend + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/ghost/README.md b/kubernetes/namespaces/default/ghost/README.md new file mode 100644 index 0000000..fee4f8f --- /dev/null +++ b/kubernetes/namespaces/default/ghost/README.md @@ -0,0 +1,7 @@ +# Ghost + +This folder contains the deployment manifests for Ghost, the CMS we use for https://blog.pythondiscord.com/. + +There should be no additional configuration required, there is a setup process on the domain when Ghost first boots, you can reach it by going to https://blog.pythondiscord.com/ghost/ immediately after starting the deployment. + +To deploy this application run `kubectl apply -f ghost` from the root directory of this repository. This will create a deployment, service ingress and persistent volume. diff --git a/kubernetes/namespaces/default/ghost/deployment.yaml b/kubernetes/namespaces/default/ghost/deployment.yaml new file mode 100644 index 0000000..3810e9d --- /dev/null +++ b/kubernetes/namespaces/default/ghost/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ghost +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: ghost + template: + metadata: + labels: + app: ghost + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: ghost + image: ghost:5.38-alpine + imagePullPolicy: Always + ports: + - containerPort: 2368 + env: + - name: url + value: https://blog.pythondiscord.com + - name: database__client + value: sqlite3 + - name: database__connection__filename + value: /var/lib/ghost/content/data/ghost.db + volumeMounts: + - mountPath: /var/lib/ghost/content + name: ghost-data + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: ghost-data + persistentVolumeClaim: + claimName: ghost-storage diff --git a/kubernetes/namespaces/default/ghost/ingress.yaml b/kubernetes/namespaces/default/ghost/ingress.yaml new file mode 100644 index 0000000..30f0589 --- /dev/null +++ b/kubernetes/namespaces/default/ghost/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: ghost +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: blog.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: ghost + port: + number: 2368 diff --git a/kubernetes/namespaces/default/ghost/service.yaml b/kubernetes/namespaces/default/ghost/service.yaml new file mode 100644 index 0000000..b030ecb --- /dev/null +++ b/kubernetes/namespaces/default/ghost/service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: ghost +spec: + ports: + - port: 2368 + selector: + app: ghost diff --git a/kubernetes/namespaces/default/ghost/volume.yaml b/kubernetes/namespaces/default/ghost/volume.yaml new file mode 100644 index 0000000..24c7929 --- /dev/null +++ b/kubernetes/namespaces/default/ghost/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: ghost-storage + labels: + app: ghost +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kubernetes/namespaces/default/grafana/README.md b/kubernetes/namespaces/default/grafana/README.md new file mode 100644 index 0000000..03a9682 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/README.md @@ -0,0 +1,11 @@ +# Grafana + +This folder contains the manifests for deploying our Grafana instance, the service we use to query our data. + +This deployment expects a number of secrets and environment variables to exist in a secret called `grafana-secret-env`. + +| Environment | Description | +|------------------------------|-----------------------------------------------------| +| GF_AUTH_GITHUB_CLIENT_ID | The client ID of the Github app to use for auth | +| GF_AUTH_GITHUB_CLIENT_SECRET | The client secret of the Github app to use for auth | +| GF_SECURITY_ADMIN_PASSWORD | The admin password the the grafana admin console | diff --git a/kubernetes/namespaces/default/grafana/configmap.yaml b/kubernetes/namespaces/default/grafana/configmap.yaml new file mode 100644 index 0000000..87eeba9 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/configmap.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-default +data: + # Root settings + GF_INSTANCE_NAME: "pythondiscord" + GF_SERVER_DOMAIN: "grafana.pythondiscord.com" + GF_SERVER_ROOT_URL: "https://grafana.pythondiscord.com" + GF_SECURITY_COOKIE_SECURE: "true" + + # GitHub Auth + GF_AUTH_GITHUB_ENABLED: "true" + GF_AUTH_GITHUB_SCOPES: "user:email,read:org" + # IDs can be retrieved via `gh api orgs/python-discord/teams`. + GF_AUTH_GITHUB_TEAM_IDS: "2638565,3854739,3114246" + GF_AUTH_GITHUB_AUTH_URL: "https://github.com/login/oauth/authorize" + GF_AUTH_GITHUB_TOKEN_URL: "https://github.com/login/oauth/access_token" + GF_AUTH_GITHUB_API_URL: "https://api.github.com/user" + GF_AUTH_ALLOW_SIGN_UP: "true" + + # Image renderer + GF_RENDERING_SERVER_URL: "http://grafana-image-renderer.default.svc.cluster.local:8081/render" + GF_RENDERING_CALLBACK_URL: "http://grafana.default.svc.cluster.local:3000/" + GF_RENDERING_CONCURRENT_RENDER_REQUEST_LIMIT: "3" + + # Image storage + GF_EXTERNAL_IMAGE_STORAGE_PROVIDED: "local" + + # Metrics + GF_METRICS_ENABLED: "false" + + # User sign up + GF_USERS_AUTO_ASSIGN_ORG: "true" + GF_USERS_AUTO_ASSIGN_ORG_ID: "2" + + # Feature toggles + GF_FEATURE_TOGGLES_ENABLE: "" diff --git a/kubernetes/namespaces/default/grafana/deployment-grafana.yaml b/kubernetes/namespaces/default/grafana/deployment-grafana.yaml new file mode 100644 index 0000000..3acef14 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/deployment-grafana.yaml @@ -0,0 +1,47 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + containers: + - name: grafana + image: grafana/grafana:9.1.7 + imagePullPolicy: Always + ports: + - containerPort: 3000 + resources: + requests: + cpu: 200m + memory: 100Mi + limits: + cpu: 300m + memory: 250Mi + envFrom: + - configMapRef: + name: grafana-default + - secretRef: + name: grafana-secret-env + volumeMounts: + - mountPath: /var/lib/grafana + name: grafana-volume + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: grafana-volume + persistentVolumeClaim: + claimName: grafana-storage + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/grafana/deployment-image-renderer.yaml b/kubernetes/namespaces/default/grafana/deployment-image-renderer.yaml new file mode 100644 index 0000000..ea3e297 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/deployment-image-renderer.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana-image-renderer +spec: + replicas: 0 + selector: + matchLabels: + app: grafana-image-renderer + template: + metadata: + labels: + app: grafana-image-renderer + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: grafana-image-renderer + image: grafana/grafana-image-renderer:latest + resources: + requests: + cpu: 500m + memory: 300Mi + limits: + cpu: 1000m + memory: 500Mi + imagePullPolicy: Always + ports: + - containerPort: 8081 + securityContext: + readOnlyRootFilesystem: true diff --git a/kubernetes/namespaces/default/grafana/ingress.yaml b/kubernetes/namespaces/default/grafana/ingress.yaml new file mode 100644 index 0000000..60138af --- /dev/null +++ b/kubernetes/namespaces/default/grafana/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: grafana +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: grafana.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: grafana + port: + number: 3000 diff --git a/kubernetes/namespaces/default/grafana/secrets.yaml b/kubernetes/namespaces/default/grafana/secrets.yaml Binary files differnew file mode 100644 index 0000000..bb492d1 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/secrets.yaml diff --git a/kubernetes/namespaces/default/grafana/services.yaml b/kubernetes/namespaces/default/grafana/services.yaml new file mode 100644 index 0000000..e5430a2 --- /dev/null +++ b/kubernetes/namespaces/default/grafana/services.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana +spec: + ports: + - port: 3000 + selector: + app: grafana +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana-image-renderer +spec: + ports: + - port: 8081 + selector: + app: grafana-image-renderer diff --git a/kubernetes/namespaces/default/grafana/volume.yaml b/kubernetes/namespaces/default/grafana/volume.yaml new file mode 100644 index 0000000..6283a7c --- /dev/null +++ b/kubernetes/namespaces/default/grafana/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: grafana-storage + labels: + app: grafana +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kubernetes/namespaces/default/graphite/README.md b/kubernetes/namespaces/default/graphite/README.md new file mode 100644 index 0000000..1d14e36 --- /dev/null +++ b/kubernetes/namespaces/default/graphite/README.md @@ -0,0 +1,11 @@ +# Graphite + +These files provision an instance of the [graphite-statsd](https://hub.docker.com/r/graphiteapp/graphite-statsd/) image. + +The following ports are exposed by the service: + +**80**: NGINX +**8125**: StatsD Ingest +**8126**: StatsD Admin + +There is a 10Gi persistent volume mounted at `/opt/graphite/storage` which holds our statistic data. diff --git a/kubernetes/namespaces/default/graphite/deployment.yaml b/kubernetes/namespaces/default/graphite/deployment.yaml new file mode 100644 index 0000000..17c66f8 --- /dev/null +++ b/kubernetes/namespaces/default/graphite/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: graphite +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: graphite + template: + metadata: + labels: + app: graphite + spec: + containers: + - name: graphite + image: graphiteapp/graphite-statsd:latest + imagePullPolicy: Always + resources: + requests: + cpu: 200m + memory: 500Mi + limits: + cpu: 1000m + memory: 750Mi + ports: + - containerPort: 80 + - containerPort: 8125 + - containerPort: 8126 + volumeMounts: + - mountPath: /opt/graphite/storage + name: graphite-volume + volumes: + - name: graphite-volume + persistentVolumeClaim: + claimName: graphite-storage diff --git a/kubernetes/namespaces/default/graphite/service.yaml b/kubernetes/namespaces/default/graphite/service.yaml new file mode 100644 index 0000000..599dcdb --- /dev/null +++ b/kubernetes/namespaces/default/graphite/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: graphite +spec: + ports: + - port: 80 + name: nginx + - port: 8125 + name: statsd + protocol: UDP + - port: 8126 + name: statsd-admin + selector: + app: graphite diff --git a/kubernetes/namespaces/default/graphite/volume.yaml b/kubernetes/namespaces/default/graphite/volume.yaml new file mode 100644 index 0000000..ebb830a --- /dev/null +++ b/kubernetes/namespaces/default/graphite/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: graphite-storage + labels: + app: graphite +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 30Gi diff --git a/kubernetes/namespaces/default/h-asgi/README.md b/kubernetes/namespaces/default/h-asgi/README.md new file mode 100644 index 0000000..fba6b15 --- /dev/null +++ b/kubernetes/namespaces/default/h-asgi/README.md @@ -0,0 +1,3 @@ +## h + +A pure ASGI service that returns h. diff --git a/kubernetes/namespaces/default/h-asgi/deployment.yaml b/kubernetes/namespaces/default/h-asgi/deployment.yaml new file mode 100644 index 0000000..d195201 --- /dev/null +++ b/kubernetes/namespaces/default/h-asgi/deployment.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: h-asgi +spec: + replicas: 1 + selector: + matchLabels: + app: h-asgi + template: + metadata: + labels: + app: h-asgi + spec: + containers: + - name: h-asgi + image: ghcr.io/vcokltfre/h:latest + imagePullPolicy: Always + resources: + requests: + cpu: 30m + memory: 25Mi + limits: + cpu: 30m + memory: 25Mi + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/h-asgi/ingress.yaml b/kubernetes/namespaces/default/h-asgi/ingress.yaml new file mode 100644 index 0000000..b6bfd31 --- /dev/null +++ b/kubernetes/namespaces/default/h-asgi/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://letterh.xyz" + name: h-asgi +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: h.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: h-asgi + port: + number: 80 diff --git a/kubernetes/namespaces/default/h-asgi/service.yaml b/kubernetes/namespaces/default/h-asgi/service.yaml new file mode 100644 index 0000000..53ac73b --- /dev/null +++ b/kubernetes/namespaces/default/h-asgi/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: h-asgi +spec: + selector: + app: h-asgi + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/hastebin/README.md b/kubernetes/namespaces/default/hastebin/README.md new file mode 100644 index 0000000..9491ed4 --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/README.md @@ -0,0 +1,11 @@ +# Hastebin +These manifests provision an instance of the hastebin service used on https://paste-old.pythondiscord.com + +## How to deploy this service +- Check the defaults in `defaults-configmap.yaml` match what you want. + +This deployment expects an environment variable to exist in a secret called `hastebin-redis-password`. + +| Environment | Description | +|------------------|-------------------------------------------------------| +| STORAGE_PASSWORD | The password to the redis instance to store pastes to | diff --git a/kubernetes/namespaces/default/hastebin/defaults-configmap.yaml b/kubernetes/namespaces/default/hastebin/defaults-configmap.yaml new file mode 100644 index 0000000..b05812b --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/defaults-configmap.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: hastebin-defaults +data: + # Set storage method + STORAGE_TYPE: "redis" + + # Set storage host + STORAGE_HOST: "redis.default.svc.cluster.local" + + # Set port of storage host + STORAGE_PORT: "6379" + + # Expiration of documents in seconds + STORAGE_EXPIRE_SECONDS: "2629746" # 1 month + + # Select the Redis DB to use + STORAGE_DB: "2" + + # Maximum length in characters of documents + MAX_LENGTH: "100000" + + # Logging configuration + LOGGING_LEVEL: "verbose" + LOGGING_TYPE: "Console" + LOGGING_COLORIZE: "true" + + # Host address and port + HOST: "0.0.0.0" + PORT: "7777" + + # Length of keys + KEY_LENGTH: "10" + + # Max length of static asset caching + STATIC_MAX_AGE: "86400" + + # Compress assets + RECOMPRESS_STATIC_ASSETS: "true" + + # Kegenerator + KEYGENERATOR_TYPE: "phonetic" + + # Ratelimits + RATELIMITS_NORMAL_TOTAL_REQUESTS: "500" + RATELIMITS_NORMAL_EVERY_MILLISECONDS: "60000" + + # Default documents + DOCUMENTS: "about=./about.md" diff --git a/kubernetes/namespaces/default/hastebin/deployment.yaml b/kubernetes/namespaces/default/hastebin/deployment.yaml new file mode 100644 index 0000000..7f88e05 --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hastebin +spec: + replicas: 1 + selector: + matchLabels: + app: hastebin + template: + metadata: + labels: + app: hastebin + spec: + containers: + - name: hastebin + # Same image as https://github.com/seejohnrun/haste-server/blob/master/Dockerfile + image: node:14.8.0-stretch + command: [ "bash", "/init/init.sh" ] + imagePullPolicy: Always + resources: + requests: + cpu: 5m + memory: 70Mi + limits: + cpu: 100m + memory: 100Mi + ports: + - containerPort: 7777 + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - name: hastebin-init-volume + mountPath: /init + - name: hastebin-code-volume + mountPath: /haste-server + - name: hastebin-npm-cache + mountPath: /home/node/ + envFrom: + - secretRef: + name: hastebin-redis-password + - configMapRef: + name: hastebin-defaults + volumes: + - name: hastebin-init-volume + configMap: + name: hastebin-init + - name: hastebin-code-volume + emptyDir: {} + - name: hastebin-npm-cache + emptyDir: {} + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/hastebin/ingress.yaml b/kubernetes/namespaces/default/hastebin/ingress.yaml new file mode 100644 index 0000000..26437ec --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: hastebin +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: paste-old.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: hastebin + port: + number: 80 diff --git a/kubernetes/namespaces/default/hastebin/init-configmap.yaml b/kubernetes/namespaces/default/hastebin/init-configmap.yaml new file mode 100644 index 0000000..906060f --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/init-configmap.yaml @@ -0,0 +1,49 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: hastebin-init +data: + monkeypatch_extensions.sh: | + #!/bin/bash + + ORIGINAL="file += '\.' + _this.lookupExtensionByType(ret\.language);" + PATCHED="\/\/file += '\.' + _this.lookupExtensionByType(ret\.language);" + FILENAME="static/application.js" + + touch changed + sed -i "s/$ORIGINAL/$PATCHED/w changed" "$FILENAME" + init.sh: | + #!/bin/bash + + # Clone the repo + git clone https://github.com/toptal/haste-server.git + cd haste-server + + # Monkey patch - don't add extensions to the URLs. + # + # This is a pretty messy monkey patch, and it may break if the hastebin + # JS code changes significantly. It makes the URL display as "file" + # instead of "file.py" when you save a file, which makes it possible + # to share the URL without triggering Discord's suspicious URL filter. + cp /init/monkeypatch_extensions.sh ./monkeypatch_extensions.sh + chmod +x monkeypatch_extensions.sh + ./monkeypatch_extensions.sh + + # Check if monkeypatch succeeded. Otherwise, fail hard. + if [ -s changed ]; then + echo "Monkey patch executed: Hastebin will no longer add extensions to URLs." + else + echo "Monkey patch for not adding extension could not be performed. Maybe the hastebin code has changed?" + exit 69 + fi + + # Install and start + npm install + + set -e + + # Generate the config file from the environment + node docker-entrypoint.js > config.js + + # Start Hastebin + npm start diff --git a/kubernetes/namespaces/default/hastebin/secrets.yaml b/kubernetes/namespaces/default/hastebin/secrets.yaml Binary files differnew file mode 100644 index 0000000..9cec074 --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/secrets.yaml diff --git a/kubernetes/namespaces/default/hastebin/service.yaml b/kubernetes/namespaces/default/hastebin/service.yaml new file mode 100644 index 0000000..d34bf5c --- /dev/null +++ b/kubernetes/namespaces/default/hastebin/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: hastebin +spec: + selector: + app: hastebin + ports: + - protocol: TCP + port: 80 + targetPort: 7777 diff --git a/kubernetes/namespaces/default/king-arthur/README.md b/kubernetes/namespaces/default/king-arthur/README.md new file mode 100644 index 0000000..704d45b --- /dev/null +++ b/kubernetes/namespaces/default/king-arthur/README.md @@ -0,0 +1,12 @@ +# King Arthur + +Deployment file for @King Arthur, our DevOps helper bot. + +## Secrets +This deployment expects a number of secrets and environment variables to exist in a secret called `king-arthur-env`. + +| Environment | Description | +| ---------------------------- | ------------------------------------------------------------------------- | +| KING_ARTHUR_TOKEN | The token to authorize with Discord | +| KING_ARTHUR_NOTION_API_TOKEN | The API token to the notion API | +| KING_ARTHUR_CLOUDFLARE_TOKEN | A token for the Cloudflare API used for the Cloudflare commands in Arthur | diff --git a/kubernetes/namespaces/default/king-arthur/deployment.yaml b/kubernetes/namespaces/default/king-arthur/deployment.yaml new file mode 100644 index 0000000..cbc3874 --- /dev/null +++ b/kubernetes/namespaces/default/king-arthur/deployment.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: king-arthur +spec: + replicas: 1 + selector: + matchLabels: + app: king-arthur + template: + metadata: + labels: + app: king-arthur + spec: + serviceAccountName: king-arthur + containers: + - name: king-arthur + image: ghcr.io/python-discord/king-arthur:latest + imagePullPolicy: Always + resources: + requests: + cpu: 400m + memory: 100Mi + limits: + cpu: 500m + memory: 200Mi + envFrom: + - secretRef: + name: king-arthur-env + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/king-arthur/secrets.yaml b/kubernetes/namespaces/default/king-arthur/secrets.yaml Binary files differnew file mode 100644 index 0000000..a410013 --- /dev/null +++ b/kubernetes/namespaces/default/king-arthur/secrets.yaml diff --git a/kubernetes/namespaces/default/king-arthur/service-account.yaml b/kubernetes/namespaces/default/king-arthur/service-account.yaml new file mode 100644 index 0000000..a63a88e --- /dev/null +++ b/kubernetes/namespaces/default/king-arthur/service-account.yaml @@ -0,0 +1,27 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: king-arthur +rules: +- apiGroups: ["", "extensions", "apps", "batch", "rbac.authorization.k8s.io", "cert-manager.io"] + resources: ["*"] + verbs: ["*"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: king-arthur +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: king-arthur +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: king-arthur +subjects: + - kind: ServiceAccount + name: king-arthur + namespace: default diff --git a/kubernetes/namespaces/default/metabase/README.md b/kubernetes/namespaces/default/metabase/README.md new file mode 100644 index 0000000..b246d54 --- /dev/null +++ b/kubernetes/namespaces/default/metabase/README.md @@ -0,0 +1,14 @@ +# Metabase +These manifests provision an instance of Metabase, our database analysis tool. + +## Secrets +A single secret of name `metabase-env` is used with the following values: + +| Environment | Description | +|--------------|-------------------------------------------| +| MB_DB_DBNAME | Database name for internal metabase usage | +| MB_DB_HOST | Address of PostgreSQL database | +| MB_DB_TYPE | Always postgres | +| MB_DB_PASS | Database user password | +| MB_DB_PORT | Always 5432 | +| MB_DB_USER | User for metabase internal | diff --git a/kubernetes/namespaces/default/metabase/deployment.yaml b/kubernetes/namespaces/default/metabase/deployment.yaml new file mode 100644 index 0000000..7a58851 --- /dev/null +++ b/kubernetes/namespaces/default/metabase/deployment.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: metabase +spec: + replicas: 1 + selector: + matchLabels: + app: metabase + template: + metadata: + labels: + app: metabase + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: metabase + image: metabase/metabase:latest + imagePullPolicy: Always + ports: + - containerPort: 3000 + envFrom: + - secretRef: + name: metabase-env + volumeMounts: + - mountPath: /plugins + name: mb-plugins-volume + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: mb-plugins-volume + emptyDir: {} diff --git a/kubernetes/namespaces/default/metabase/ingress.yaml b/kubernetes/namespaces/default/metabase/ingress.yaml new file mode 100644 index 0000000..16b66d5 --- /dev/null +++ b/kubernetes/namespaces/default/metabase/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: metabase +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: metabase.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: metabase + port: + number: 80 diff --git a/kubernetes/namespaces/default/metabase/secrets.yaml b/kubernetes/namespaces/default/metabase/secrets.yaml Binary files differnew file mode 100644 index 0000000..2cb73c5 --- /dev/null +++ b/kubernetes/namespaces/default/metabase/secrets.yaml diff --git a/kubernetes/namespaces/default/metabase/service.yaml b/kubernetes/namespaces/default/metabase/service.yaml new file mode 100644 index 0000000..36118a0 --- /dev/null +++ b/kubernetes/namespaces/default/metabase/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: metabase +spec: + selector: + app: metabase + ports: + - protocol: TCP + port: 80 + targetPort: 3000 diff --git a/kubernetes/namespaces/default/metricity/README.md b/kubernetes/namespaces/default/metricity/README.md new file mode 100644 index 0000000..30c8b95 --- /dev/null +++ b/kubernetes/namespaces/default/metricity/README.md @@ -0,0 +1,13 @@ +# Metricity + +This folder contains the secrets for the metricity service. + +The actual metricity deployment manifest can be found inside the metricity repository at [python-discord/metricity](https://github.com/python-discord/metricity). + +## Secrets +A single secret of name `metricity-env` is used with the following values: + +| Environment | Description | +|--------------|------------------------------------| +| BOT_TOKEN | The Discord bot token to run under | +| DATABASE_URI | Database URI to save the states to | diff --git a/kubernetes/namespaces/default/metricity/secrets.yaml b/kubernetes/namespaces/default/metricity/secrets.yaml Binary files differnew file mode 100644 index 0000000..f97dc51 --- /dev/null +++ b/kubernetes/namespaces/default/metricity/secrets.yaml diff --git a/kubernetes/namespaces/default/modmail/README.md b/kubernetes/namespaces/default/modmail/README.md new file mode 100644 index 0000000..92ac16b --- /dev/null +++ b/kubernetes/namespaces/default/modmail/README.md @@ -0,0 +1,19 @@ +# Modmail + +This folder contains the manifests for our Modmail service. + +## Secrets + +The services require one shared secret called `modmail` containing the following: + +| Key | Value | Description | +| ------------------------| ---------------------------------|--------------------------------------------------------------| +| `CONNECTION_URI` | MongoDB connection URI | Used for storing data | +| `DATABASE_TYPE` | `mongodb` | The type of database to use, only supports mongodb right now | +| `DATA_COLLECTION` | `False` | Disable bot metadata collection by modmail devs | +| `DISABLE_AUTOUPDATES` | `yes` | Auto-updates breaks in production | +| `GUILD_ID` | Snowflake of Discord guild | Guild to respond to commands in | +| `LOG_URL` | URL of the web portal | Used for generating links on the bot | +| `OWNERS` | Comma separated list of user IDs | Used for granting high permissions on the bot | +| `REGISTRY_PLUGINS_ONLY` | `false` | Allows the usage of plugins outside of the official registry | +| `TOKEN` | Discord Token | Used to connect to Discord | diff --git a/kubernetes/namespaces/default/modmail/bot/README.md b/kubernetes/namespaces/default/modmail/bot/README.md new file mode 100644 index 0000000..ac29ac2 --- /dev/null +++ b/kubernetes/namespaces/default/modmail/bot/README.md @@ -0,0 +1,7 @@ +# Modmail bot +These manifests will provision the resources for an instance of our Modmail bot. + +To deploy this bot simply run: +``` +kubectl apply -f deployment.yaml +``` diff --git a/kubernetes/namespaces/default/modmail/bot/deployment.yaml b/kubernetes/namespaces/default/modmail/bot/deployment.yaml new file mode 100644 index 0000000..e640fdc --- /dev/null +++ b/kubernetes/namespaces/default/modmail/bot/deployment.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: modmail-bot +spec: + replicas: 1 + selector: + matchLabels: + app: modmail-bot + template: + metadata: + labels: + app: modmail-bot + spec: + containers: + - name: modmail-bot + image: ghcr.io/python-discord/modmail:latest + resources: + requests: + cpu: 75m + memory: 500Mi + limits: + cpu: 125m + memory: 750Mi + imagePullPolicy: "Always" + volumeMounts: + - mountPath: /modmailbot/plugins + name: plugins-vol + - mountPath: /modmailbot/temp + name: temp-vol + env: + - name: TMPDIR + value: /modmailbot/temp + envFrom: + - secretRef: + name: modmail + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: plugins-vol + emptyDir: {} + - name: temp-vol + emptyDir: + medium: Memory + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/modmail/secrets.yaml b/kubernetes/namespaces/default/modmail/secrets.yaml Binary files differnew file mode 100644 index 0000000..f2d5d5d --- /dev/null +++ b/kubernetes/namespaces/default/modmail/secrets.yaml diff --git a/kubernetes/namespaces/default/modmail/web/README.md b/kubernetes/namespaces/default/modmail/web/README.md new file mode 100644 index 0000000..7b7e19e --- /dev/null +++ b/kubernetes/namespaces/default/modmail/web/README.md @@ -0,0 +1,2 @@ +# Modmail web +These manifests provision an instance of the web logviewer for our Modmail system. diff --git a/kubernetes/namespaces/default/modmail/web/deployment.yaml b/kubernetes/namespaces/default/modmail/web/deployment.yaml new file mode 100644 index 0000000..1070e22 --- /dev/null +++ b/kubernetes/namespaces/default/modmail/web/deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: modmail-web +spec: + replicas: 1 + selector: + matchLabels: + app: modmail-web + template: + metadata: + labels: + app: modmail-web + spec: + containers: + - name: modmail-web + image: ghcr.io/python-discord/logviewer:latest + imagePullPolicy: Always + resources: + requests: + cpu: 50m + memory: 100Mi + limits: + cpu: 100m + memory: 150Mi + ports: + - containerPort: 8000 + envFrom: + - secretRef: + name: modmail + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/modmail/web/ingress.yaml b/kubernetes/namespaces/default/modmail/web/ingress.yaml new file mode 100644 index 0000000..a5990cf --- /dev/null +++ b/kubernetes/namespaces/default/modmail/web/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: modmail-web +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: modmail.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: modmail-web + port: + number: 80 diff --git a/kubernetes/namespaces/default/modmail/web/service.yaml b/kubernetes/namespaces/default/modmail/web/service.yaml new file mode 100644 index 0000000..384e638 --- /dev/null +++ b/kubernetes/namespaces/default/modmail/web/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: modmail-web +spec: + selector: + app: modmail-web + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/mongodb/README.md b/kubernetes/namespaces/default/mongodb/README.md new file mode 100644 index 0000000..05f3f1d --- /dev/null +++ b/kubernetes/namespaces/default/mongodb/README.md @@ -0,0 +1,22 @@ +# Python Discord MongoDB +This folder contains the configuration for Python Discord's MongoDB instance. + +## Volume +A 10Gi volume is provisioned on the Linode Block Storage (Retain) storage class. + +## Secrets +| Key | Value | Description | +| ---------------------------- | -------------------------- | ------------------------------- | +| `MONGO_INITDB_ROOT_USERNAME` | `pythondiscord` | Username of root user | +| `MONGO_INITDB_ROOT_PASSWORD` | Root password for database | Password for the root user | + + +## Deployment +The deployment will pull the `mongo:latest` image from DockerHub. + +It will mount the created volume at `/data/db`. + +It will expose port `27017` to connect to MongoDB. + +## Service +A service called `mongodb` will be created to give the deployment a cluster local DNS record of `mongodb.default.svc.cluster.local`. diff --git a/kubernetes/namespaces/default/mongodb/deployment.yaml b/kubernetes/namespaces/default/mongodb/deployment.yaml new file mode 100644 index 0000000..592c342 --- /dev/null +++ b/kubernetes/namespaces/default/mongodb/deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: mongodb + template: + metadata: + labels: + app: mongodb + spec: + containers: + - name: mongodb + image: mongo:4.4 + imagePullPolicy: Always + ports: + - containerPort: 27017 + resources: + requests: + cpu: 100m + memory: 300Mi + limits: + cpu: 200m + memory: 400Mi + volumeMounts: + - mountPath: /data/db + name: mongodb-volume + - mountPath: /tmp + name: mongo-temp + envFrom: + - secretRef: + name: mongo-credentials + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: mongodb-volume + persistentVolumeClaim: + claimName: mongodb-storage + - name: mongo-temp + emptyDir: + medium: Memory diff --git a/kubernetes/namespaces/default/mongodb/secrets.yaml b/kubernetes/namespaces/default/mongodb/secrets.yaml Binary files differnew file mode 100644 index 0000000..2ca5e82 --- /dev/null +++ b/kubernetes/namespaces/default/mongodb/secrets.yaml diff --git a/kubernetes/namespaces/default/mongodb/service.yaml b/kubernetes/namespaces/default/mongodb/service.yaml new file mode 100644 index 0000000..ed14298 --- /dev/null +++ b/kubernetes/namespaces/default/mongodb/service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: mongodb +spec: + ports: + - port: 27017 + selector: + app: mongodb diff --git a/kubernetes/namespaces/default/mongodb/volume.yaml b/kubernetes/namespaces/default/mongodb/volume.yaml new file mode 100644 index 0000000..094e212 --- /dev/null +++ b/kubernetes/namespaces/default/mongodb/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: mongodb-storage + labels: + app: mongodb +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kubernetes/namespaces/default/olli/README.md b/kubernetes/namespaces/default/olli/README.md new file mode 100644 index 0000000..ff748d5 --- /dev/null +++ b/kubernetes/namespaces/default/olli/README.md @@ -0,0 +1,13 @@ +# Olli + +This folder contains the deployment information for [Olli](https://github.com/python-discord/olli), our Loki-Discord relay. + +The deployment manifest is located within the repository. + +The rest of the configuration can be applied through `kubectl apply -f .` in this directory. + +A secret called `olli-env` with the following a key `WEBHOOK_URL` with the configured Discord webhook. + +| Key | Description | +| --------------| -------------------------- | +| `WEBHOOK_URL` | The Discord webhook to use | diff --git a/kubernetes/namespaces/default/olli/config.yaml b/kubernetes/namespaces/default/olli/config.yaml new file mode 100644 index 0000000..356aba8 --- /dev/null +++ b/kubernetes/namespaces/default/olli/config.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: olli-config +data: + olli.toml: | + [olli] + interval_minutes = 30 + + [loki] + api_url = "http://loki.loki.svc.cluster.local:3100/" + jobs = [ + "default/bot", + "default/site", + "default/sir-lancebot", + "default/metricity", + "default/snekbox", + "default/quackstack", + "default/thread-bot", + "default/black-knight" + ] + + [[olli.tokens]] + token = "ERROR" + color = "#ff5f5f" + + [[olli.tokens]] + token = "CRITICAL" + color = "#ff5f5f" + + [[olli.tokens]] + token = "WARN" + color = "#ffe24d" + case_sensitive = true diff --git a/kubernetes/namespaces/default/olli/secrets.yaml b/kubernetes/namespaces/default/olli/secrets.yaml Binary files differnew file mode 100644 index 0000000..75cdf23 --- /dev/null +++ b/kubernetes/namespaces/default/olli/secrets.yaml diff --git a/kubernetes/namespaces/default/patsy/README.md b/kubernetes/namespaces/default/patsy/README.md new file mode 100644 index 0000000..78e386a --- /dev/null +++ b/kubernetes/namespaces/default/patsy/README.md @@ -0,0 +1,17 @@ +# Patsy + +Patsy is the premiere project for data collection in the python-discord toolchain. It uses word-class technology in a system architected by our in-house engineers to facilitate the automatic transfer, collection, and categorization of user data to develop user-centric solutions to real world problems. It is a marvel of engineering designed to push the limits of what we thought possible. + +The deployment for the [Patsy API](https://git.pydis.com/patsy), there is no ingress as Patsy is designed to only be accessible from within the cluster. + +This API is given help channel messages by the bot and stores them in postgres for after-the-fact processing. +The hope with this project is that we can inspect what topics get asked about often in help channels, along with which ones go un-answered the most. + +## Secret + +It requires a `patsy-env` secret with the following + +| Key | Description | +| -------------- | ------------------------------------------------------------ | +| `DATABASE_URL` | An asyncpg connection string to the postgres database | +| `STATE_SECRET` | A long random string, used to lock down endpoints with auth. | diff --git a/kubernetes/namespaces/default/patsy/deployment.yaml b/kubernetes/namespaces/default/patsy/deployment.yaml new file mode 100644 index 0000000..79fa243 --- /dev/null +++ b/kubernetes/namespaces/default/patsy/deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: patsy +spec: + replicas: 0 + selector: + matchLabels: + app: patsy + template: + metadata: + labels: + app: patsy + spec: + containers: + - name: patsy + image: ghcr.io/python-discord/patsy:latest + imagePullPolicy: Always + ports: + - containerPort: 80 + name: http + envFrom: + - secretRef: + name: patsy-env + startupProbe: + httpGet: + path: /ping + port: http + httpHeaders: + - name: Host + value: patsy.pythondiscord.com + failureThreshold: 3 + periodSeconds: 1 + initialDelaySeconds: 10 + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/patsy/secrets.yaml b/kubernetes/namespaces/default/patsy/secrets.yaml Binary files differnew file mode 100644 index 0000000..8d5c4f3 --- /dev/null +++ b/kubernetes/namespaces/default/patsy/secrets.yaml diff --git a/kubernetes/namespaces/default/patsy/service.yaml b/kubernetes/namespaces/default/patsy/service.yaml new file mode 100644 index 0000000..1844ff3 --- /dev/null +++ b/kubernetes/namespaces/default/patsy/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: patsy +spec: + selector: + app: patsy + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/kubernetes/namespaces/default/pinnwand/README.md b/kubernetes/namespaces/default/pinnwand/README.md new file mode 100644 index 0000000..945b357 --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/README.md @@ -0,0 +1,8 @@ +# pinnwand +These manifests provision an instance of the pinnwand service used on https://paste.pythondiscord.com. + +A init-service is used to download the Python Discord banner logo and save it to a volume, as pinnwand expects it to be present within the image. + +## Secrets & config +This deployment expects an env var named `PINNWAND_DATABASE_URI` to exist in a secret called `pinnwand-postgres-connection`. +All other configuration can be found in `defaults-configmap.yaml`. diff --git a/kubernetes/namespaces/default/pinnwand/defaults-configmap.yaml b/kubernetes/namespaces/default/pinnwand/defaults-configmap.yaml new file mode 100644 index 0000000..96fa074 --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/defaults-configmap.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: pinnwand-config +data: + config.toml: | + # Maximum size in bytes of pastes + paste_size = 524288 + + default_selected_lexer = "python" + # List of lexers to pin to the top of the dropdown list + preferred_lexers = ["python", "autodetect", "pytb", "pycon", "text", "markdown", "restructuredtext", "sql"] + + page_list = ["about", "removal"] + footer = 'View <a href="//github.com/supakeen/pinnwand" target="_BLANK">source code</a>, <a href="/removal">removal</a> information, or read the <a href="/about">about</a> page.' + + paste_help = '''<p>Welcome to Python Discord's pastebin, powered by <a href="//github.com/supakeen/pinnwand" target="_BLANK">pinnwand</a>. It allows you to share code with others. If you write code in the text area below and press the paste button you will be given a link you can share with others so they can view your code as well.</p><p>People with the link can view your pasted code, only you can remove your paste and it expires automatically. Note that anyone could guess the URI to your paste so don't rely on it being private.</p>''' + expiries.30days = 2592000 + expiries.7days = 604800 + expiries.1day = 86400 + + ratelimit.read.capacity = 100 + ratelimit.read.consume = 1 + ratelimit.read.refill = 2 + + ratelimit.create.capacity = 10 # Default is 2 + ratelimit.create.consume = 1 # Default is 2 + ratelimit.create.refill = 10 # Default is 1 + + ratelimit.delete.capacity = 2 + ratelimit.delete.consume = 2 + ratelimit.delete.refill = 1 + + report_email = "[email protected]" diff --git a/kubernetes/namespaces/default/pinnwand/deployment.yaml b/kubernetes/namespaces/default/pinnwand/deployment.yaml new file mode 100644 index 0000000..2a6525a --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pinnwand +spec: + replicas: 1 + selector: + matchLabels: + app: pinnwand + template: + metadata: + labels: + app: pinnwand + spec: + initContainers: + - name: init-service + image: busybox:latest + command: ["wget", "https://raw.githubusercontent.com/python-discord/branding/main/logos/badge/badge_512x172.png", "-O", "/tmp/logo.png"] + volumeMounts: + - name: pinnwand-logo + mountPath: /tmp/ + containers: + - name: pinnwand + image: ghcr.io/supakeen/pinnwand:v1.5.0-psql + command: ["venv/bin/python3", "-m", "pinnwand", "-vvvvvvvv", "--configuration-path", "/config/config.toml", "http"] + imagePullPolicy: Always + resources: + requests: + cpu: 5m + memory: 70Mi + limits: + cpu: 100m + memory: 100Mi + ports: + - containerPort: 8000 + envFrom: + - secretRef: + name: pinnwand-postgres-connection + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - name: pinnwand-config + mountPath: /config/ + - name: pinnwand-logo + mountPath: /usr/app/pinnwand/static/logo.png + subPath: logo.png + volumes: + - name: pinnwand-logo + emptyDir: {} + - name: pinnwand-config + configMap: + name: pinnwand-config + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/pinnwand/ingress.yaml b/kubernetes/namespaces/default/pinnwand/ingress.yaml new file mode 100644 index 0000000..17dcb83 --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: pinnwand +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: paste.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: pinnwand + port: + number: 80 diff --git a/kubernetes/namespaces/default/pinnwand/secrets.yaml b/kubernetes/namespaces/default/pinnwand/secrets.yaml Binary files differnew file mode 100644 index 0000000..7fb586b --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/secrets.yaml diff --git a/kubernetes/namespaces/default/pinnwand/service.yaml b/kubernetes/namespaces/default/pinnwand/service.yaml new file mode 100644 index 0000000..be6bc4f --- /dev/null +++ b/kubernetes/namespaces/default/pinnwand/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: pinnwand +spec: + selector: + app: pinnwand + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/pixels-modsite/README.md b/kubernetes/namespaces/default/pixels-modsite/README.md new file mode 100644 index 0000000..ee95650 --- /dev/null +++ b/kubernetes/namespaces/default/pixels-modsite/README.md @@ -0,0 +1,13 @@ +# Pixels + +The deployment for the [Pixels modsite project](https://git.pydis.com/pixels-modsite), hosted at https://pixels-modsite.pythondiscord.com. + +This mod site will give Discord mods easy access to moderation actions for the pixels event. + +## Secret + +It requires a `pixels-modsite-env` secret with the following entries: + +| Environment | Description | +|-------------------|-----------------------------------------------------------------| +| DISCORD_BOT_TOKEN | The Discord bot token to use to check roles of users logging in | diff --git a/kubernetes/namespaces/default/pixels-modsite/deployment.yaml b/kubernetes/namespaces/default/pixels-modsite/deployment.yaml new file mode 100644 index 0000000..2b9d632 --- /dev/null +++ b/kubernetes/namespaces/default/pixels-modsite/deployment.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pixels-modsite +spec: + replicas: 1 + selector: + matchLabels: + app: pixels-modsite + template: + metadata: + labels: + app: pixels-modsite + spec: + containers: + - name: pixels-modsite + image: ghcr.io/python-discord/pixels-modsite:latest + imagePullPolicy: Always + ports: + - containerPort: 3000 + envFrom: + - secretRef: + name: pixels-modsite-env + securityContext: + readOnlyRootFilesystem: true + imagePullSecrets: + - name: ghcr-pull-secret + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/pixels-modsite/ingress.yaml b/kubernetes/namespaces/default/pixels-modsite/ingress.yaml new file mode 100644 index 0000000..80c8dbe --- /dev/null +++ b/kubernetes/namespaces/default/pixels-modsite/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: pixels-modsite +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: pixels-modsite.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: pixels-modsite + port: + number: 80 diff --git a/kubernetes/namespaces/default/pixels-modsite/secrets.yaml b/kubernetes/namespaces/default/pixels-modsite/secrets.yaml Binary files differnew file mode 100644 index 0000000..0f4d361 --- /dev/null +++ b/kubernetes/namespaces/default/pixels-modsite/secrets.yaml diff --git a/kubernetes/namespaces/default/pixels-modsite/service.yaml b/kubernetes/namespaces/default/pixels-modsite/service.yaml new file mode 100644 index 0000000..8118f09 --- /dev/null +++ b/kubernetes/namespaces/default/pixels-modsite/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: pixels-modsite +spec: + selector: + app: pixels-modsite + ports: + - protocol: TCP + port: 80 + targetPort: 3000 diff --git a/kubernetes/namespaces/default/pixels/README.md b/kubernetes/namespaces/default/pixels/README.md new file mode 100644 index 0000000..10e4a5d --- /dev/null +++ b/kubernetes/namespaces/default/pixels/README.md @@ -0,0 +1,25 @@ +# Pixels + +The deployment for the [Pixels project](https://git.pydis.com/pixels-v2), hosted at https://pixels.pythondiscord.com. + +## Secret + +It requires a `pixels-env` secret with the following entries: + +| Environment | Description | +|---------------|---------------------------------------------------------------------------------------------------------| +| AUTH_URL | A Discord OAuth2 URL with scopes: identify & guilds.members.read | +| BASE_URL | Where the root endpoint can be found | +| CLIENT_ID | Discord Oauth2 client ID | +| CLIENT_SECRET | Discord Oauth2 client secret | +| DATABASE_URL | Postgres database URL. | +| FORCE_LOGIN | Whether to requires authorization for all endpoints beside the login page, and limits access to helpers | +| GUILD_ID | The guild to check for user roles in | +| HELPERS_ROLE | Helpers role ID | +| JWT_SECRET | 32 byte (64 digit hex string) secret for encoding tokens. Any value can be used. | +| LOG_LEVEL | What level to log at | +| MOD_ROLE | Moderator role ID | +| PRODUCTION | Whether the app is in production | +| REDIS_URL | Redis storage URL | +| SENTRY_DSN | The Sentry DSN to send sentry events to | +| WEBHOOK_URL | The webhook to periodically post the canvas state to | diff --git a/kubernetes/namespaces/default/pixels/deployment.yaml b/kubernetes/namespaces/default/pixels/deployment.yaml new file mode 100644 index 0000000..7775216 --- /dev/null +++ b/kubernetes/namespaces/default/pixels/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pixels +spec: + replicas: 1 + selector: + matchLabels: + app: pixels + template: + metadata: + labels: + app: pixels + spec: + containers: + - name: pixels + image: ghcr.io/python-discord/pixels:latest + imagePullPolicy: Always + ports: + - containerPort: 8000 + envFrom: + - secretRef: + name: pixels-env + startupProbe: + httpGet: + path: /health + port: 8000 + httpHeaders: + - name: Host + value: pixels.pythondiscord.com + failureThreshold: 15 + periodSeconds: 2 + timeoutSeconds: 5 + initialDelaySeconds: 10 + securityContext: + readOnlyRootFilesystem: true + imagePullSecrets: + - name: ghcr-pull-secret + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/pixels/ingress.yaml b/kubernetes/namespaces/default/pixels/ingress.yaml new file mode 100644 index 0000000..bfc0ada --- /dev/null +++ b/kubernetes/namespaces/default/pixels/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: pixels +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: pixels.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: pixels + port: + number: 80 diff --git a/kubernetes/namespaces/default/pixels/secrets.yaml b/kubernetes/namespaces/default/pixels/secrets.yaml Binary files differnew file mode 100644 index 0000000..b3c77cd --- /dev/null +++ b/kubernetes/namespaces/default/pixels/secrets.yaml diff --git a/kubernetes/namespaces/default/pixels/service.yaml b/kubernetes/namespaces/default/pixels/service.yaml new file mode 100644 index 0000000..41860a1 --- /dev/null +++ b/kubernetes/namespaces/default/pixels/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: pixels +spec: + selector: + app: pixels + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/policy-bot/README.md b/kubernetes/namespaces/default/policy-bot/README.md new file mode 100644 index 0000000..ed44a63 --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/README.md @@ -0,0 +1,24 @@ +# Policy Bot +Policy Bot is our instance of [palantir/policy-bot](https://github.com/palantir/policy-bot) for managing review policy across our GitHub repositories. + +Actual review policy is stored inside our GitHub repositories in the `.github/review-policy.yml` file, so the configuration here is purely for interacting with GitHub and some lower level things. + +## GitHub Configuration + +Follow the instructions in the [repository](https://github.com/palantir/policy-bot#deployment) to provision a GitHub application. Our manifests are configured to run the policy bot at https://policy-bot.pythondiscord.com/. + +## Secrets + +This app requires a `policy-bot-defaults` secret with the following entries: + +| Environment | Description | +|--------------------------------------------------|-----------------------------------------------------------------------| +| GITHUB_APP_PRIVATE_KEY | Contents of the PEM certificate downloadable from the GitHub App page | +| GITHUB_APP_WEBHOOK_SECRET | Webhook secret from GitHub App Page | +| GITHUB_OAUTH_CLIENT_SECRET | OAuth 2 client secret from Github App page | +| POLICYBOT_OPTIONS_DO_NOT_LOAD_COMMIT_PUSHED_DATE | Set to True to not use deprecated commit_pushed_date from Github API | +| POLICYBOT_SESSIONS_KEY | Random characters for signing user sessions | + +Run `kubectl apply -f .` inside this directory to apply the the configuration. + +Access the running application over [policy-bot.pythondiscord.com]([https://policy-bot.pythondiscord.com/])! diff --git a/kubernetes/namespaces/default/policy-bot/configmap.yaml b/kubernetes/namespaces/default/policy-bot/configmap.yaml new file mode 100644 index 0000000..6183948 --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/configmap.yaml @@ -0,0 +1,49 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: policy-bot-defaults +data: + policy-bot.yml: | + # Options for the http server + server: + # The listen address and port + address: "0.0.0.0" + port: 8080 + # The public URL, used for URL generation when the server is behind a proxy + public_url: https://policy-bot.pythondiscord.com/ + + # Options for logging output + logging: + # If true, logs are printed in human-readable form. We recommend using + # "false" to output JSON-formatted logs in production + text: false + # Set a minimum logging level threshold + # Choose from: debug, info, warn, error + level: debug + + # Options for connecting to GitHub + github: + # The URL of the GitHub homepage. Can also be set by the GITHUB_WEB_URL + # environment variable. + web_url: "https://github.com" + # The base URL for v3 (REST) API requests. Can also be set by the + # GITHUB_V3_API_URL environment variable. + v3_api_url: "https://api.github.com" + # The base URL for v4 (GraphQL) API requests. Can also be set by the + # GITHUB_V4_API_URL environment variable. + v4_api_url: "https://api.github.com/graphql" + app: + # The integration ID of the GitHub app. Can also be set by the + # GITHUB_APP_INTEGRATION_ID environment variable. + integration_id: 91554 + oauth: + # The client ID of the OAuth app associated with the GitHub app. Can also + # be set by the GITHUB_OAUTH_CLIENT_ID environment variable. + client_id: "Iv1.5be42b7c960b1ab2" + + # Options for application behavior + options: + # The path within repositories to find the policy.yml file + policy_path: .github/review-policy.yml + # The context prefix for status checks created by the bot + status_check_context: "Review requirements" diff --git a/kubernetes/namespaces/default/policy-bot/deployment.yaml b/kubernetes/namespaces/default/policy-bot/deployment.yaml new file mode 100644 index 0000000..1b3f96b --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: policy-bot +spec: + replicas: 1 + selector: + matchLabels: + app: policy-bot + template: + metadata: + labels: + app: policy-bot + spec: + containers: + - name: policy-bot + image: palantirtechnologies/policy-bot:latest + imagePullPolicy: Always + resources: + requests: + cpu: 50m + memory: 50Mi + limits: + cpu: 100m + memory: 100Mi + ports: + - containerPort: 8080 + volumeMounts: + - mountPath: /secrets + name: policy-bot-config + securityContext: + readOnlyRootFilesystem: true + envFrom: + - secretRef: + name: policy-bot-secrets + volumes: + - name: policy-bot-config + configMap: + name: policy-bot-defaults + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/policy-bot/ingress.yaml b/kubernetes/namespaces/default/policy-bot/ingress.yaml new file mode 100644 index 0000000..088dd01 --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: policy-bot +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: policy-bot.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: policy-bot + port: + number: 80 diff --git a/kubernetes/namespaces/default/policy-bot/secrets.yaml b/kubernetes/namespaces/default/policy-bot/secrets.yaml Binary files differnew file mode 100644 index 0000000..9d91e70 --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/secrets.yaml diff --git a/kubernetes/namespaces/default/policy-bot/service.yaml b/kubernetes/namespaces/default/policy-bot/service.yaml new file mode 100644 index 0000000..da0fb64 --- /dev/null +++ b/kubernetes/namespaces/default/policy-bot/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: policy-bot +spec: + selector: + app: policy-bot + ports: + - protocol: TCP + port: 80 + targetPort: 8080 diff --git a/kubernetes/namespaces/default/postgresql/README.md b/kubernetes/namespaces/default/postgresql/README.md new file mode 100644 index 0000000..07eed4f --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/README.md @@ -0,0 +1,16 @@ +# Postgres +This folder contains the manifests for Postgres, our primary database. + +You can alter the configuration file inside the `configmap.yaml` file which will be injected into the database container upon boot. Certain parameters (marked in the file) will require a server restart whereas others can be reloaded by using `SELECT pg_reload_conf();` inside Postgres. + +Note that there may be up to a minute before your changes to the ConfigMap are reflected inside the container, if things do not change after that you will have to restart the server for the configuration to apply. + +## Secrets + +postgres requires a `postgres-env` secret with the following entries: + +| Environment | Description | +|-------------------|-----------------------------------| +| PGDATA | The path to the pg_data directory | +| POSTGRES_PASSWORD | The default password to use | +| POSTGRES_USER | The default user to use | diff --git a/kubernetes/namespaces/default/postgresql/configmap.yaml b/kubernetes/namespaces/default/postgresql/configmap.yaml new file mode 100644 index 0000000..a2c9a4e --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/configmap.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-config +data: + postgresql.conf: | + # From pgtune + max_connections = 110 + shared_buffers = 1536MB + effective_cache_size = 4608MB + maintenance_work_mem = 384MB + checkpoint_completion_target = 0.9 + wal_buffers = 16MB + default_statistics_target = 100 + random_page_cost = 1.1 + effective_io_concurrency = 200 + work_mem = 3574kB + min_wal_size = 1GB + max_wal_size = 4GB + max_worker_processes = 4 + max_parallel_workers_per_gather = 2 + max_parallel_workers = 4 + max_parallel_maintenance_workers = 2 + + # Custom conf + listen_addresses = '*' + password_encryption = md5 + shared_preload_libraries = 'pg_stat_statements' # (change requires restart) diff --git a/kubernetes/namespaces/default/postgresql/deployment.yaml b/kubernetes/namespaces/default/postgresql/deployment.yaml new file mode 100644 index 0000000..cfe6101 --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: ghcr.io/chrislovering/psql_extended:15 + imagePullPolicy: "Always" + ports: + - name: postgres + containerPort: 5432 + envFrom: + - secretRef: + name: postgres-env + args: ["-c", "config_file=/etc/postgresql/postgresql.conf"] + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + subPath: pgdata + - name: postgres-config + mountPath: /etc/postgresql + - name: dshm + mountPath: /dev/shm + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: postgres-storage + - name: postgres-config + configMap: + name: postgres-config + - name: dshm + emptyDir: + medium: Memory + sizeLimit: 2Gi diff --git a/kubernetes/namespaces/default/postgresql/secrets.yaml b/kubernetes/namespaces/default/postgresql/secrets.yaml Binary files differnew file mode 100644 index 0000000..902f7d5 --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/secrets.yaml diff --git a/kubernetes/namespaces/default/postgresql/service.yaml b/kubernetes/namespaces/default/postgresql/service.yaml new file mode 100644 index 0000000..f69deae --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: postgres + name: postgres +spec: + ports: + - port: 5432 + selector: + app: postgres diff --git a/kubernetes/namespaces/default/postgresql/volume.yaml b/kubernetes/namespaces/default/postgresql/volume.yaml new file mode 100644 index 0000000..53108ce --- /dev/null +++ b/kubernetes/namespaces/default/postgresql/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: postgres-storage + labels: + app: postgres +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 25Gi diff --git a/kubernetes/namespaces/default/prestashop/README.md b/kubernetes/namespaces/default/prestashop/README.md new file mode 100644 index 0000000..183f87c --- /dev/null +++ b/kubernetes/namespaces/default/prestashop/README.md @@ -0,0 +1,12 @@ +# Prestashop + +This folder contains the ingress and values.yaml file for the deployment of Prestashop, used for our merch store. It additionally deploys MariaDB, used for data storage. + +## Deployment + +``` +$ helm repo add bitnami https://charts.bitnami.com/bitnami +$ helm install prestashop bitnami/prestashop -f prestashop/values.yaml --set prestashopPassword=<admin passsword>,mariadb.auth.rootPassword=<database password>,smtpPassword=<password from mailgun> +``` + +The Helm chart can be located [here](https://github.com/bitnami/charts/tree/master/bitnami/prestashop), including all available parameters. diff --git a/kubernetes/namespaces/default/prestashop/ingress.yaml b/kubernetes/namespaces/default/prestashop/ingress.yaml new file mode 100644 index 0000000..c4abc58 --- /dev/null +++ b/kubernetes/namespaces/default/prestashop/ingress.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Service +metadata: + name: prestashop-svc +spec: + selector: + app.kubernetes.io/instance: prestashop + app.kubernetes.io/name: prestashop + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: merch +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: merch.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prestashop-svc + port: + number: 80 diff --git a/kubernetes/namespaces/default/prestashop/values.yaml b/kubernetes/namespaces/default/prestashop/values.yaml new file mode 100644 index 0000000..865393a --- /dev/null +++ b/kubernetes/namespaces/default/prestashop/values.yaml @@ -0,0 +1,49 @@ +prestashopHost: merch.pythondiscord.com + +prestashopUsername: [email protected] +prestashopPassword: +prestashopEmail: [email protected] +prestashopFirstName: Joe +prestashopLastName: Banks + +allowEmptyPassword: false + +smtpHost: smtp.mailgun.org +smtpPort: 587 +smtpUser: [email protected] +smtpProtocol: tls + +podAnnotations: + prometheus.io/scrape: "false" + +mariadb: + primary: + persistence: + enabled: true + storageClass: linode-block-storage-retain + size: 10Gi + +containerPorts: + http: 8080 + https: 8443 + +updateStrategy: + type: Recreate + +service: + type: ClusterIP + +ingress: + enabled: false + +persistence: + enabled: true + storageClass: "linode-block-storage-retain" + + size: 10Gi + +metrics: + enabled: false + + podAnnotations: + prometheus.io/scrape: "false" diff --git a/kubernetes/namespaces/default/public-stats/README.md b/kubernetes/namespaces/default/public-stats/README.md new file mode 100644 index 0000000..2654eaa --- /dev/null +++ b/kubernetes/namespaces/default/public-stats/README.md @@ -0,0 +1,7 @@ +# Public Stats + +Python Discord Public Stats is the public stats portal for viewing server statistics at https://stats.pythondiscord.com/ + +The deployment manifest is located in the [python-discord/public-stats](https://github.com/python-discord/public-stats/blob/master/deployment.yaml) repo. + +To apply the service and ingress run `kubectl apply -f .` in this folder. diff --git a/kubernetes/namespaces/default/public-stats/ingress.yaml b/kubernetes/namespaces/default/public-stats/ingress.yaml new file mode 100644 index 0000000..c620eb2 --- /dev/null +++ b/kubernetes/namespaces/default/public-stats/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: public-stats +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: stats.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: public-stats + port: + number: 8000 diff --git a/kubernetes/namespaces/default/public-stats/service.yaml b/kubernetes/namespaces/default/public-stats/service.yaml new file mode 100644 index 0000000..d52055f --- /dev/null +++ b/kubernetes/namespaces/default/public-stats/service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: public-stats +spec: + ports: + - port: 8000 + selector: + app: public-stats diff --git a/kubernetes/namespaces/default/quackstack/README.md b/kubernetes/namespaces/default/quackstack/README.md new file mode 100644 index 0000000..c8b8a92 --- /dev/null +++ b/kubernetes/namespaces/default/quackstack/README.md @@ -0,0 +1,7 @@ +# QuackStack + +The deployment for the [QuackStack](https://github.com/python-discord/quackstack) project, hosted at https://quackstack.pythondiscord.com. + +This project doesn't need any configuration right now. + +To deploy this application run `kubectl apply -f .` from this directory. This will create a deployment, service and ingress. diff --git a/kubernetes/namespaces/default/quackstack/deployment.yaml b/kubernetes/namespaces/default/quackstack/deployment.yaml new file mode 100644 index 0000000..15747c2 --- /dev/null +++ b/kubernetes/namespaces/default/quackstack/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: quackstack +spec: + replicas: 1 + selector: + matchLabels: + app: quackstack + template: + metadata: + labels: + app: quackstack + spec: + containers: + - name: quackstack + image: ghcr.io/python-discord/quackstack:main + imagePullPolicy: Always + ports: + - containerPort: 80 diff --git a/kubernetes/namespaces/default/quackstack/ingress.yaml b/kubernetes/namespaces/default/quackstack/ingress.yaml new file mode 100644 index 0000000..624e153 --- /dev/null +++ b/kubernetes/namespaces/default/quackstack/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: quackstack +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: quackstack.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: quackstack + port: + number: 80 diff --git a/kubernetes/namespaces/default/quackstack/service.yaml b/kubernetes/namespaces/default/quackstack/service.yaml new file mode 100644 index 0000000..86926c5 --- /dev/null +++ b/kubernetes/namespaces/default/quackstack/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: quackstack +spec: + selector: + app: quackstack + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/kubernetes/namespaces/default/redirects/README.md b/kubernetes/namespaces/default/redirects/README.md new file mode 100644 index 0000000..cbaf102 --- /dev/null +++ b/kubernetes/namespaces/default/redirects/README.md @@ -0,0 +1,8 @@ +# Redirects +Some of our point to an external service, for example https://git.pythondiscord.com/ points towards our GitHub organisation. + +This folder contains all the redirects for our subdomains. + +They consist of an Ingress to handle the redirection through rewrite annotations. + +To deploy these routes simply run `kubectl apply -f .` in this folder. diff --git a/kubernetes/namespaces/default/redirects/github.yaml b/kubernetes/namespaces/default/redirects/github.yaml new file mode 100644 index 0000000..130b0dd --- /dev/null +++ b/kubernetes/namespaces/default/redirects/github.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/rewrite-target: "https://github.com/python-discord/$1" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: github-redirect +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: git.pythondiscord.com + http: + paths: + - path: /(.*) + pathType: Prefix + backend: + service: + name: site + port: + number: 80 diff --git a/kubernetes/namespaces/default/redirects/paypal.yaml b/kubernetes/namespaces/default/redirects/paypal.yaml new file mode 100644 index 0000000..d84afa1 --- /dev/null +++ b/kubernetes/namespaces/default/redirects/paypal.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/rewrite-target: "https://www.paypal.com/paypalme/pythondiscord" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: paypal-redirect +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: paypal.pythondiscord.com + http: + paths: + - path: /(.*) + pathType: Prefix + backend: + service: + name: site + port: + number: 80 diff --git a/kubernetes/namespaces/default/redirects/sentry.yaml b/kubernetes/namespaces/default/redirects/sentry.yaml new file mode 100644 index 0000000..c4ad8e6 --- /dev/null +++ b/kubernetes/namespaces/default/redirects/sentry.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/rewrite-target: "https://sentry.io/organizations/python-discord/issues/" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: sentry-redirect +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: sentry.pythondiscord.com + http: + paths: + - path: /(.*) + pathType: Prefix + backend: + service: + name: site + port: + number: 80 diff --git a/kubernetes/namespaces/default/redis/README.md b/kubernetes/namespaces/default/redis/README.md new file mode 100644 index 0000000..d496758 --- /dev/null +++ b/kubernetes/namespaces/default/redis/README.md @@ -0,0 +1,34 @@ +# Python Discord Redis +This folder contains the configuration for Python Discord's Redis instance. + +## ConfigMap +**We'll need to create a ConfigMap for this service, which will hold the `redis.conf` configuration.** + +Do the following: +1. Make a copy of `redis.conf.template` called `redis.conf` +2. Edit your `redis.conf` to replace `<INSERT PASSWORD>` with the password you'd like your redis instance to use. +3. Use `kubectl create configmap redis-conf --from-file=redis.conf` to create the ConfigMap +4. Delete the `redis.conf`. **We don't wanna commit that password anywhere!** + +## Volume +A 10Gi volume is provisioned on the Linode Block Storage (Retain) storage class. + +## Deployment +The deployment will pull the `redis:latest` image from DockerHub. + +It will mount the created volume at `/data`. + +It will expose port `6379` to connect to Redis. + +## Service +A service called `redis` will be created to give the deployment a cluster local DNS record of `redis.default.svc.cluster.local`. + +## Secrets + +Redis requires a `redis-credentials` secret with the following entries: + +| Environment | Description | +|----------------|---------------------------------------| +| REDIS_HOST | The host redis is running on | +| REDIS_PASSWORD | The password to connect to redis with | +| REDIS_PORT | The port redis is listening on | diff --git a/kubernetes/namespaces/default/redis/configmap.yaml b/kubernetes/namespaces/default/redis/configmap.yaml new file mode 100644 index 0000000..2a2f23e --- /dev/null +++ b/kubernetes/namespaces/default/redis/configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: redis-conf + namespace: default +data: + redis.conf: | + # Store all commands used and replay on server startup + appendonly yes + + # Set working directory + dir /data + + # Set a memory maximum + maxmemory 1gb diff --git a/kubernetes/namespaces/default/redis/deployment.yaml b/kubernetes/namespaces/default/redis/deployment.yaml new file mode 100644 index 0000000..ef5d68c --- /dev/null +++ b/kubernetes/namespaces/default/redis/deployment.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - name: redis + image: redis:latest + command: + - redis-server + args: + - /config/redis.conf + - --requirepass + - $(REDIS_PASSWORD) + imagePullPolicy: Always + resources: + requests: + cpu: 50m + memory: 100Mi + limits: + cpu: 100m + memory: 150Mi + ports: + - containerPort: 6379 + envFrom: + - secretRef: + name: redis-credentials + volumeMounts: + - name: redis-data-volume + mountPath: /data # Must match the dir in the redis.conf + - name: redis-config-volume + mountPath: /config + securityContext: + readOnlyRootFilesystem: true + + volumes: + - name: redis-data-volume + persistentVolumeClaim: + claimName: redis-storage + - name: redis-config-volume + configMap: + name: redis-conf + + securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/redis/redis.conf.template b/kubernetes/namespaces/default/redis/redis.conf.template new file mode 100644 index 0000000..6d8eeac --- /dev/null +++ b/kubernetes/namespaces/default/redis/redis.conf.template @@ -0,0 +1,11 @@ +# Store all commands used and replay on server startup +appendonly yes + +# Set password +requirepass <INSERT PASSWORD> + +# Set working directory +dir /data + +# Set a memory maximum +maxmemory 1gb diff --git a/kubernetes/namespaces/default/redis/secrets.yaml b/kubernetes/namespaces/default/redis/secrets.yaml Binary files differnew file mode 100644 index 0000000..29e4c15 --- /dev/null +++ b/kubernetes/namespaces/default/redis/secrets.yaml diff --git a/kubernetes/namespaces/default/redis/service.yaml b/kubernetes/namespaces/default/redis/service.yaml new file mode 100644 index 0000000..0be72e8 --- /dev/null +++ b/kubernetes/namespaces/default/redis/service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis +spec: + ports: + - port: 6379 # Redis default port + selector: + app: redis diff --git a/kubernetes/namespaces/default/redis/volume.yaml b/kubernetes/namespaces/default/redis/volume.yaml new file mode 100644 index 0000000..6522ea6 --- /dev/null +++ b/kubernetes/namespaces/default/redis/volume.yaml @@ -0,0 +1,13 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: redis-storage + labels: + app: redis +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kubernetes/namespaces/default/sir-lancebot/README.md b/kubernetes/namespaces/default/sir-lancebot/README.md new file mode 100644 index 0000000..293a955 --- /dev/null +++ b/kubernetes/namespaces/default/sir-lancebot/README.md @@ -0,0 +1,29 @@ +## Sir Lancebot +``` +Oh brave Sir Lancebot! + +Whereat he turned and stood with folded arms and numerous antennae, +"Why frown upon a friend? Few live that have too many." +A weary-waiting optical array, now calibrated to a sad wrath. +Hereafter, thus t'was with him that we hath forged our path. +``` + +## Secrets +This deployment expects a number of secrets and environment variables to exist in a secret called `sir-lancebot-env` shown below. The bot also relies on redis credentials being available in a secret named `redis-credentials` + + +| Environment | Description | +|---------------------------|------------------------------------------| +| BOT_SENTRY_DSN | The DSN for the Sentry project. | +| CLIENT_DEBUG | Should the bot start in DEBUG mode? | +| CLIENT_TOKEN | The bot token to run the bot on. | +| LATEX_API_URL | The URl tha the latex API is served from | +| TOKENS_GIPHY | API key for Giphy. | +| TOKENS_GITHUB | GitHub access token, for Hacktoberstats. | +| TOKENS_IGDB_CLIENT_ID | Client ID IGDB - used to find games. | +| TOKENS_IGDB_CLIENT_SECRET | Client secret IGDB - used to find games. | +| TOKENS_NASA | API key for NASA. | +| TOKENS_TMDB | Token for TMBD. Used for scarymovie.py. | +| TOKENS_UNSPLASH | Token for unsplash. | +| TOKENS_YOUTUBE | API key for YouTube. | +| WOLFRAM_KEY | API key for Wolfram Alpha. | diff --git a/kubernetes/namespaces/default/sir-lancebot/deployment.yaml b/kubernetes/namespaces/default/sir-lancebot/deployment.yaml new file mode 100644 index 0000000..826af5b --- /dev/null +++ b/kubernetes/namespaces/default/sir-lancebot/deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sir-lancebot +spec: + replicas: 1 + selector: + matchLabels: + app: sir-lancebot + template: + metadata: + labels: + app: sir-lancebot + spec: + containers: + - name: sir-lancebot + image: ghcr.io/python-discord/sir-lancebot:latest + imagePullPolicy: Always + resources: + requests: + cpu: 400m + memory: 100Mi + limits: + cpu: 500m + memory: 200Mi + envFrom: + - secretRef: + name: sir-lancebot-env + - secretRef: + name: redis-credentials + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - name: lancebot-data-vol + mountPath: /bot/bot/exts/fun/_latex_cache + - name: lancebot-logs-vol + mountPath: /bot/bot/log + - name: lancebot-tmp-vol + mountPath: /tmp + volumes: + - name: lancebot-data-vol + emptyDir: {} + - name: lancebot-logs-vol + emptyDir: {} + - name: lancebot-tmp-vol + emptyDir: + medium: Memory + securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/sir-lancebot/secrets.yaml b/kubernetes/namespaces/default/sir-lancebot/secrets.yaml Binary files differnew file mode 100644 index 0000000..a54c729 --- /dev/null +++ b/kubernetes/namespaces/default/sir-lancebot/secrets.yaml diff --git a/kubernetes/namespaces/default/sir-robin/README.md b/kubernetes/namespaces/default/sir-robin/README.md new file mode 100644 index 0000000..652cb53 --- /dev/null +++ b/kubernetes/namespaces/default/sir-robin/README.md @@ -0,0 +1,17 @@ +## Sir-Robin +Deployment file for @Sir-Robin, the not-quite-so-bot as Sir Lancebot, is our humble events bot. +He is tasked with dealing with all the things that the event team can throw at it! + +## Secrets +This deployment expects a number of secrets/environment variables to exist in a secret called `sir-robin-env`. The bot also relies on redis credentials being available in a secret named `redis-credentials` + +| Environment | Description | +|---------------------------|-----------------------------------------------| +| AOC_LEADERBOARDS | A list of all AOC leaderboards to use | +| AOC_STAFF_LEADERBOARD_ID | The staff AOC leaderboard. | +| AOC_YEAR | The current year to use for AOC | +| BOT_DEBUG | Whether debug is enabled (true/false) | +| BOT_TOKEN | The bot token to run the bot on. | +| CODE_JAM_API_KEY | The API key to the code jam management system | +| SITE_API_TOKEN | The token to access the site API. | +| SITE_URL | The base URL for our website. | diff --git a/kubernetes/namespaces/default/sir-robin/deployment.yaml b/kubernetes/namespaces/default/sir-robin/deployment.yaml new file mode 100644 index 0000000..dc2a839 --- /dev/null +++ b/kubernetes/namespaces/default/sir-robin/deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sir-robin +spec: + replicas: 1 + selector: + matchLabels: + app: sir-robin + template: + metadata: + labels: + app: sir-robin + spec: + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: sir-robin + image: ghcr.io/python-discord/sir-robin:latest + imagePullPolicy: Always + resources: + requests: + cpu: 500m + memory: 300Mi + limits: + cpu: 750m + memory: 500Mi + envFrom: + - secretRef: + name: sir-robin-env + - secretRef: + name: redis-credentials + securityContext: + readOnlyRootFilesystem: true diff --git a/kubernetes/namespaces/default/sir-robin/secrets.yaml b/kubernetes/namespaces/default/sir-robin/secrets.yaml Binary files differnew file mode 100644 index 0000000..d40e958 --- /dev/null +++ b/kubernetes/namespaces/default/sir-robin/secrets.yaml diff --git a/kubernetes/namespaces/default/site/README.md b/kubernetes/namespaces/default/site/README.md new file mode 100644 index 0000000..3eff711 --- /dev/null +++ b/kubernetes/namespaces/default/site/README.md @@ -0,0 +1,25 @@ +# Python Discord Site +This folder contains the manifests for Python Discord site. + +## Serving static files + +Usually, a web server like `nginx` should be deployed and configured to serve static files needed by Django. Then we'd put an `Ingress` +rule to route traffic to the `STATIC_URL` to that webserver. +Check the [official docs](https://docs.djangoproject.com/en/4.2/howto/static-files/deployment/) for more info. + +In this setup, we do it differently thanks to [WhiteNoise](https://whitenoise.readthedocs.io/en/stable/base.html#), which sets up +a middleware that handles the caching, compression and serving of the static files for us. + +## Secrets + +The deployment expects the following secrets to be available in `site-env`: + +| Environment | Description | +|-----------------------|------------------------------------------------------------| +| DATABASE_URL | The URL for the Postgresql database. | +| GITHUB_APP_ID | The ID of a GitHub Application (related to the above key). | +| GITHUB_APP_KEY | A PEM key for a GitHub Application. | +| GITHUB_TOKEN | An API key to the Github API | +| METRICITY_DB_URL | The URL for the Metricity database. | +| SECRET_KEY | Secret key for Django. | +| SITE_DSN | The Sentry Data Source Name. | diff --git a/kubernetes/namespaces/default/site/deployment.yaml b/kubernetes/namespaces/default/site/deployment.yaml new file mode 100644 index 0000000..2f88af8 --- /dev/null +++ b/kubernetes/namespaces/default/site/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: site +spec: + replicas: 2 + selector: + matchLabels: + app: site + template: + metadata: + labels: + app: site + spec: + containers: + - name: site + image: ghcr.io/python-discord/site:latest + imagePullPolicy: Always + ports: + - containerPort: 8000 + livenessProbe: + httpGet: + path: / + port: 8000 + httpHeaders: + - name: Host + value: pythondiscord.com + failureThreshold: 2 + periodSeconds: 30 + timeoutSeconds: 5 + initialDelaySeconds: 10 + startupProbe: + httpGet: + path: / + port: 8000 + httpHeaders: + - name: Host + value: pythondiscord.com + failureThreshold: 15 + periodSeconds: 2 + timeoutSeconds: 5 + initialDelaySeconds: 10 + resources: + limits: + cpu: 500m + memory: 1000Mi + requests: + cpu: 250m + memory: 400Mi + env: + # Needs to match with the variable name being read in django-prometheus + # https://github.com/korfuri/django-prometheus/blob/434a3ba36bdada45c9633451f5f6cfd145814ccf/django_prometheus/exports.py#L119 + - name: prometheus_multiproc_dir + value: /tmp + envFrom: + - secretRef: + name: site-env + volumeMounts: + # Used for `gunicorn` worker heartbeats as well as the Prometheus + # client library's multiprocessing mode. + - name: django-tmp + mountPath: /tmp + securityContext: + readOnlyRootFilesystem: true + volumes: + - name: django-tmp + emptyDir: + medium: Memory + securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/default/site/ingress.yaml b/kubernetes/namespaces/default/site/ingress.yaml new file mode 100644 index 0000000..9f12daf --- /dev/null +++ b/kubernetes/namespaces/default/site/ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + nginx.ingress.kubernetes.io/server-snippet: | + location ~* /metrics { + deny all; + return 403; + } + name: site +spec: + tls: + - hosts: + - "*.pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: www.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: site + port: + number: 80 diff --git a/kubernetes/namespaces/default/site/redirect.yaml b/kubernetes/namespaces/default/site/redirect.yaml new file mode 100644 index 0000000..33cf7d2 --- /dev/null +++ b/kubernetes/namespaces/default/site/redirect.yaml @@ -0,0 +1,28 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/server-snippet: | + location ~* / { + return 308 https://www.pythondiscord.com$request_uri; + } + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: www-redirect +spec: + tls: + - hosts: + - "pythondiscord.com" + secretName: pythondiscord.com-tls + rules: + - host: pythondiscord.com + http: + paths: + - path: /(.*) + pathType: Prefix + backend: + service: + name: site + port: + number: 80 diff --git a/kubernetes/namespaces/default/site/secrets.yaml b/kubernetes/namespaces/default/site/secrets.yaml Binary files differnew file mode 100644 index 0000000..1e42248 --- /dev/null +++ b/kubernetes/namespaces/default/site/secrets.yaml diff --git a/kubernetes/namespaces/default/site/service.yaml b/kubernetes/namespaces/default/site/service.yaml new file mode 100644 index 0000000..4f06394 --- /dev/null +++ b/kubernetes/namespaces/default/site/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: site + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8000" +spec: + selector: + app: site + ports: + - protocol: TCP + port: 80 + targetPort: 8000 diff --git a/kubernetes/namespaces/default/snekbox-forms/README.md b/kubernetes/namespaces/default/snekbox-forms/README.md new file mode 100644 index 0000000..4514032 --- /dev/null +++ b/kubernetes/namespaces/default/snekbox-forms/README.md @@ -0,0 +1,5 @@ +# Snekbox-forms + +This folder contains manifests for a Snekbox service specific to the forms project. This instance has no 3rd party libs installed, unlike regular snekbox, so submissions via forms can only use the stdlib. + +The deployment manifest for this service is based on in manifest found inside the snekbox repository at [python-discord/snekbox](https://github.com/python-discord/snekbox), modified only by removing the volume mount, and 3rd party dep installation script. diff --git a/kubernetes/namespaces/default/snekbox-forms/deployment.yaml b/kubernetes/namespaces/default/snekbox-forms/deployment.yaml new file mode 100644 index 0000000..2464249 --- /dev/null +++ b/kubernetes/namespaces/default/snekbox-forms/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: snekbox-forms +spec: + replicas: 1 + selector: + matchLabels: + app: snekbox-forms + template: + metadata: + labels: + app: snekbox-forms + spec: + initContainers: + - name: init-service + image: busybox:latest + command: ["/bin/sh", "-c"] + args: + - > + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/random.png -O /tmp/cj-inputs/random.png; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled1_order.txt -O /tmp/cj-inputs/shuffled1_order.txt; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled1.png -O /tmp/cj-inputs/shuffled1.png; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled4_order.txt -O /tmp/cj-inputs/shuffled4_order.txt; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled4.png -O /tmp/cj-inputs/shuffled4.png; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled8_order.txt -O /tmp/cj-inputs/shuffled8_order.txt; + wget https://files.pydis.wtf/33649562-5739-4f23-9219-28fc236b86bc/shuffled8.png -O /tmp/cj-inputs/shuffled8.png; + wget https://raw.githubusercontent.com/python-discord/snekbox/main/config/snekbox.cfg -O /tmp/config/snekbox.cfg; + echo -e 'mount {\n src:"/snekbox/cj-inputs"\n dst:"/cj-inputs"\n is_bind: true\n rw: false}' >> /tmp/config/snekbox.cfg; + volumeMounts: + - name: snekbox-cj-inputs + mountPath: /tmp/cj-inputs/ + - name: snekbox-forms-config + mountPath: /tmp/config/ + containers: + - name: snekbox-forms + image: ghcr.io/python-discord/snekbox:latest + imagePullPolicy: Always + ports: + - containerPort: 8060 + securityContext: + privileged: true + volumeMounts: + - name: snekbox-forms-user-base-volume + mountPath: /snekbox/user_base + - name: snekbox-cj-inputs + mountPath: /snekbox/cj-inputs + - name: snekbox-forms-config + mountPath: /snekbox/config/snekbox.cfg + subPath: snekbox.cfg + lifecycle: + postStart: + exec: + command: + - "/bin/sh" + - "-c" + - >- + PYTHONUSERBASE=/snekbox/user_base + pip install --user --upgrade + pip + pillow==10.0.0 + opencv-python-headless==4.8.0.74 + volumes: + - name: snekbox-forms-user-base-volume + emptyDir: {} + - name: snekbox-cj-inputs + emptyDir: {} + - name: snekbox-forms-config + emptyDir: {} diff --git a/kubernetes/namespaces/default/snekbox-forms/service.yaml b/kubernetes/namespaces/default/snekbox-forms/service.yaml new file mode 100644 index 0000000..99937eb --- /dev/null +++ b/kubernetes/namespaces/default/snekbox-forms/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: snekbox-forms +spec: + selector: + app: snekbox-forms + ports: + - protocol: TCP + port: 80 + targetPort: 8060 diff --git a/kubernetes/namespaces/default/snekbox/README.md b/kubernetes/namespaces/default/snekbox/README.md new file mode 100644 index 0000000..bd7446b --- /dev/null +++ b/kubernetes/namespaces/default/snekbox/README.md @@ -0,0 +1,5 @@ +# Snekbox + +This folder contains manifests for Snekbox service. + +The actual snekbox deployment manifest can be found inside the snekbox repository at [python-discord/snekbox](https://github.com/python-discord/snekbox). diff --git a/kubernetes/namespaces/default/snekbox/service.yaml b/kubernetes/namespaces/default/snekbox/service.yaml new file mode 100644 index 0000000..9ae20b0 --- /dev/null +++ b/kubernetes/namespaces/default/snekbox/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: snekbox +spec: + selector: + app: snekbox + ports: + - protocol: TCP + port: 80 + targetPort: 8060 diff --git a/kubernetes/namespaces/kube-system/nginx/README.md b/kubernetes/namespaces/kube-system/nginx/README.md new file mode 100644 index 0000000..f940702 --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/README.md @@ -0,0 +1,7 @@ +# NGINX + +NGINX ingress is our ingress controller for all PyDis web properties. + +This directory contains resources for the Helm chart we use to deploy. + +Documentation for deploying nginx-ingress with Helm is located [here](https://kubernetes.github.io/ingress-nginx/deploy/#using-helm), the chart is located [here](https://github.com/kubernetes/ingress-nginx/tree/main/charts/ingress-nginx). diff --git a/kubernetes/namespaces/kube-system/nginx/internal-svc.yaml b/kubernetes/namespaces/kube-system/nginx/internal-svc.yaml new file mode 100644 index 0000000..636404a --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/internal-svc.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: ingress-nginx-internal + namespace: kube-system +spec: + selector: + app.kubernetes.io/instance: ingress-nginx + ports: + - protocol: TCP + port: 80 + name: http + targetPort: 80 + - protocol: TCP + port: 443 + name: https + targetPort: 443 diff --git a/kubernetes/namespaces/kube-system/nginx/mtls/Makefile b/kubernetes/namespaces/kube-system/nginx/mtls/Makefile new file mode 100644 index 0000000..3ee6b5f --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/mtls/Makefile @@ -0,0 +1,10 @@ +certs: + cat *.pem > ca.crt + +secret: + kubectl create secret -n kube-system generic mtls-client-crt-bundle --from-file=ca.crt=ca.crt + +all: certs secret + +delete: + kubectl delete secret -n kube-system mtls-client-crt-bundle diff --git a/kubernetes/namespaces/kube-system/nginx/mtls/ca.crt b/kubernetes/namespaces/kube-system/nginx/mtls/ca.crt new file mode 100644 index 0000000..f1567c5 --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/mtls/ca.crt @@ -0,0 +1,55 @@ +-----BEGIN CERTIFICATE----- +MIIGCjCCA/KgAwIBAgIIV5G6lVbCLmEwDQYJKoZIhvcNAQENBQAwgZAxCzAJBgNV +BAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMRQwEgYDVQQLEwtPcmln +aW4gUHVsbDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv +cm5pYTEjMCEGA1UEAxMab3JpZ2luLXB1bGwuY2xvdWRmbGFyZS5uZXQwHhcNMTkx +MDEwMTg0NTAwWhcNMjkxMTAxMTcwMDAwWjCBkDELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkRmxhcmUsIEluYy4xFDASBgNVBAsTC09yaWdpbiBQdWxsMRYwFAYD +VQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMSMwIQYDVQQD +ExpvcmlnaW4tcHVsbC5jbG91ZGZsYXJlLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAN2y2zojYfl0bKfhp0AJBFeV+jQqbCw3sHmvEPwLmqDLqynI +42tZXR5y914ZB9ZrwbL/K5O46exd/LujJnV2b3dzcx5rtiQzso0xzljqbnbQT20e +ihx/WrF4OkZKydZzsdaJsWAPuplDH5P7J82q3re88jQdgE5hqjqFZ3clCG7lxoBw +hLaazm3NJJlUfzdk97ouRvnFGAuXd5cQVx8jYOOeU60sWqmMe4QHdOvpqB91bJoY +QSKVFjUgHeTpN8tNpKJfb9LIn3pun3bC9NKNHtRKMNX3Kl/sAPq7q/AlndvA2Kw3 +Dkum2mHQUGdzVHqcOgea9BGjLK2h7SuX93zTWL02u799dr6Xkrad/WShHchfjjRn +aL35niJUDr02YJtPgxWObsrfOU63B8juLUphW/4BOjjJyAG5l9j1//aUGEi/sEe5 +lqVv0P78QrxoxR+MMXiJwQab5FB8TG/ac6mRHgF9CmkX90uaRh+OC07XjTdfSKGR +PpM9hB2ZhLol/nf8qmoLdoD5HvODZuKu2+muKeVHXgw2/A6wM7OwrinxZiyBk5Hh +CvaADH7PZpU6z/zv5NU5HSvXiKtCzFuDu4/Zfi34RfHXeCUfHAb4KfNRXJwMsxUa ++4ZpSAX2G6RnGU5meuXpU5/V+DQJp/e69XyyY6RXDoMywaEFlIlXBqjRRA2pAgMB +AAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1Ud +DgQWBBRDWUsraYuA4REzalfNVzjann3F6zAfBgNVHSMEGDAWgBRDWUsraYuA4REz +alfNVzjann3F6zANBgkqhkiG9w0BAQ0FAAOCAgEAkQ+T9nqcSlAuW/90DeYmQOW1 +QhqOor5psBEGvxbNGV2hdLJY8h6QUq48BCevcMChg/L1CkznBNI40i3/6heDn3IS +zVEwXKf34pPFCACWVMZxbQjkNRTiH8iRur9EsaNQ5oXCPJkhwg2+IFyoPAAYURoX +VcI9SCDUa45clmYHJ/XYwV1icGVI8/9b2JUqklnOTa5tugwIUi5sTfipNcJXHhgz +6BKYDl0/UP0lLKbsUETXeTGDiDpxZYIgbcFrRDDkHC6BSvdWVEiH5b9mH2BON60z +0O0j8EEKTwi9jnafVtZQXP/D8yoVowdFDjXcKkOPF/1gIh9qrFR6GdoPVgB3SkLc +5ulBqZaCHm563jsvWb/kXJnlFxW+1bsO9BDD6DweBcGdNurgmH625wBXksSdD7y/ +fakk8DagjbjKShYlPEFOAqEcliwjF45eabL0t27MJV61O/jHzHL3dknXeE4BDa2j +bA+JbyJeUMtU7KMsxvx82RmhqBEJJDBCJ3scVptvhDMRrtqDBW5JShxoAOcpFQGm +iYWicn46nPDjgTU0bX1ZPpTpryXbvciVL5RkVBuyX2ntcOLDPlZWgxZCBp96x07F +AnOzKgZk4RzZPNAxCXERVxajn/FLcOhglVAKo5H0ac+AitlQ0ip55D2/mf8o72tM +fVQ6VpyjEXdiIXWUq/o= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjQCCQDLTrV5jIanizANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJV +SzEXMBUGA1UECgwOUHl0aG9uIERpc2NvcmQxGjAYBgNVBAMMEXB5dGhvbmRpc2Nv +cmQuY29tMSQwIgYJKoZIhvcNAQkBFhV0bHNAcHl0aG9uZGlzY29yZC5jb20wHhcN +MjEwMzA2MjMwMzQ0WhcNMjIwMzA2MjMwMzQ0WjBoMQswCQYDVQQGEwJVSzEXMBUG +A1UECgwOUHl0aG9uIERpc2NvcmQxGjAYBgNVBAMMEXB5dGhvbmRpc2NvcmQuY29t +MSQwIgYJKoZIhvcNAQkBFhV0bHNAcHl0aG9uZGlzY29yZC5jb20wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpRDoQqJPxGV38DsR4x3QKMV2P7lQiT6VK +fTBK9PIeExBgCTHsJN0s68eXAF9tIgInXbmwbF3ysIs+j8nXTO/OThGJ4jE6J6RA +MC31zfzHcF/0Qc4VNaQEK1x/gX7dT0SpgNIJ5eTvz8h++spMjYonEMJ3L4Mu5R8h +QDnLeD2/c7NfEtY9sv4AMTS3cn8I4q2HuwSEKTOGVs5LwAjruAtv4KvKG3W02PvX +Ja3hEisIHaHB2K7aAK2m4gKDrczeQaQWOtlPjlWmvTEnU/chI3PUXazvUJqeS449 +kw9JGoFjPwVSyY2sxYuFL9TAMNxVj+bJ/VX5GU6qCo1wW8R3ItltAgMBAAEwDQYJ +KoZIhvcNAQELBQADggEBAAaxy5Mbi0fuQFvmQ5ViR2Y6yySeUIDdYMPN/92rzubJ +w1yUS/liJ0L01RS/3VvAuchE+3uIK5ybaR2zwgnmWjIIyllC2cyOwNrzCbSTEZpH +3blSwmPr01fwIXFwANfK+Qz5NdG0LrrU6RloIajqkDXwgDXfMCfJwl6JnRORGUHk +QOGtP4mWA1KqHMtPRQKSv/7TK2s+Sbg/e1T+0iE/VbhzJZonF0/VDQk2huyD7Z7I +VJ62bzsI0V59pGmZYAen9g9EfmZXn2m3QTd+tQytzmnUKyuwfmXt4mnvxkral+ES +eB4Nzv4EDPjThS8LLp7xEL5PBS+FAF5EdZPK23FtexQ= +-----END CERTIFICATE----- diff --git a/kubernetes/namespaces/kube-system/nginx/mtls/cloudflare-cert.pem b/kubernetes/namespaces/kube-system/nginx/mtls/cloudflare-cert.pem new file mode 100644 index 0000000..965f0bf --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/mtls/cloudflare-cert.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGCjCCA/KgAwIBAgIIV5G6lVbCLmEwDQYJKoZIhvcNAQENBQAwgZAxCzAJBgNV +BAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMRQwEgYDVQQLEwtPcmln +aW4gUHVsbDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv +cm5pYTEjMCEGA1UEAxMab3JpZ2luLXB1bGwuY2xvdWRmbGFyZS5uZXQwHhcNMTkx +MDEwMTg0NTAwWhcNMjkxMTAxMTcwMDAwWjCBkDELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkRmxhcmUsIEluYy4xFDASBgNVBAsTC09yaWdpbiBQdWxsMRYwFAYD +VQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMSMwIQYDVQQD +ExpvcmlnaW4tcHVsbC5jbG91ZGZsYXJlLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAN2y2zojYfl0bKfhp0AJBFeV+jQqbCw3sHmvEPwLmqDLqynI +42tZXR5y914ZB9ZrwbL/K5O46exd/LujJnV2b3dzcx5rtiQzso0xzljqbnbQT20e +ihx/WrF4OkZKydZzsdaJsWAPuplDH5P7J82q3re88jQdgE5hqjqFZ3clCG7lxoBw +hLaazm3NJJlUfzdk97ouRvnFGAuXd5cQVx8jYOOeU60sWqmMe4QHdOvpqB91bJoY +QSKVFjUgHeTpN8tNpKJfb9LIn3pun3bC9NKNHtRKMNX3Kl/sAPq7q/AlndvA2Kw3 +Dkum2mHQUGdzVHqcOgea9BGjLK2h7SuX93zTWL02u799dr6Xkrad/WShHchfjjRn +aL35niJUDr02YJtPgxWObsrfOU63B8juLUphW/4BOjjJyAG5l9j1//aUGEi/sEe5 +lqVv0P78QrxoxR+MMXiJwQab5FB8TG/ac6mRHgF9CmkX90uaRh+OC07XjTdfSKGR +PpM9hB2ZhLol/nf8qmoLdoD5HvODZuKu2+muKeVHXgw2/A6wM7OwrinxZiyBk5Hh +CvaADH7PZpU6z/zv5NU5HSvXiKtCzFuDu4/Zfi34RfHXeCUfHAb4KfNRXJwMsxUa ++4ZpSAX2G6RnGU5meuXpU5/V+DQJp/e69XyyY6RXDoMywaEFlIlXBqjRRA2pAgMB +AAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1Ud +DgQWBBRDWUsraYuA4REzalfNVzjann3F6zAfBgNVHSMEGDAWgBRDWUsraYuA4REz +alfNVzjann3F6zANBgkqhkiG9w0BAQ0FAAOCAgEAkQ+T9nqcSlAuW/90DeYmQOW1 +QhqOor5psBEGvxbNGV2hdLJY8h6QUq48BCevcMChg/L1CkznBNI40i3/6heDn3IS +zVEwXKf34pPFCACWVMZxbQjkNRTiH8iRur9EsaNQ5oXCPJkhwg2+IFyoPAAYURoX +VcI9SCDUa45clmYHJ/XYwV1icGVI8/9b2JUqklnOTa5tugwIUi5sTfipNcJXHhgz +6BKYDl0/UP0lLKbsUETXeTGDiDpxZYIgbcFrRDDkHC6BSvdWVEiH5b9mH2BON60z +0O0j8EEKTwi9jnafVtZQXP/D8yoVowdFDjXcKkOPF/1gIh9qrFR6GdoPVgB3SkLc +5ulBqZaCHm563jsvWb/kXJnlFxW+1bsO9BDD6DweBcGdNurgmH625wBXksSdD7y/ +fakk8DagjbjKShYlPEFOAqEcliwjF45eabL0t27MJV61O/jHzHL3dknXeE4BDa2j +bA+JbyJeUMtU7KMsxvx82RmhqBEJJDBCJ3scVptvhDMRrtqDBW5JShxoAOcpFQGm +iYWicn46nPDjgTU0bX1ZPpTpryXbvciVL5RkVBuyX2ntcOLDPlZWgxZCBp96x07F +AnOzKgZk4RzZPNAxCXERVxajn/FLcOhglVAKo5H0ac+AitlQ0ip55D2/mf8o72tM +fVQ6VpyjEXdiIXWUq/o= +-----END CERTIFICATE----- diff --git a/kubernetes/namespaces/kube-system/nginx/mtls/pydis-cert.pem b/kubernetes/namespaces/kube-system/nginx/mtls/pydis-cert.pem new file mode 100644 index 0000000..d1dba63 --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/mtls/pydis-cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTDCCAjQCCQDLTrV5jIanizANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJV +SzEXMBUGA1UECgwOUHl0aG9uIERpc2NvcmQxGjAYBgNVBAMMEXB5dGhvbmRpc2Nv +cmQuY29tMSQwIgYJKoZIhvcNAQkBFhV0bHNAcHl0aG9uZGlzY29yZC5jb20wHhcN +MjEwMzA2MjMwMzQ0WhcNMjIwMzA2MjMwMzQ0WjBoMQswCQYDVQQGEwJVSzEXMBUG +A1UECgwOUHl0aG9uIERpc2NvcmQxGjAYBgNVBAMMEXB5dGhvbmRpc2NvcmQuY29t +MSQwIgYJKoZIhvcNAQkBFhV0bHNAcHl0aG9uZGlzY29yZC5jb20wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpRDoQqJPxGV38DsR4x3QKMV2P7lQiT6VK +fTBK9PIeExBgCTHsJN0s68eXAF9tIgInXbmwbF3ysIs+j8nXTO/OThGJ4jE6J6RA +MC31zfzHcF/0Qc4VNaQEK1x/gX7dT0SpgNIJ5eTvz8h++spMjYonEMJ3L4Mu5R8h +QDnLeD2/c7NfEtY9sv4AMTS3cn8I4q2HuwSEKTOGVs5LwAjruAtv4KvKG3W02PvX +Ja3hEisIHaHB2K7aAK2m4gKDrczeQaQWOtlPjlWmvTEnU/chI3PUXazvUJqeS449 +kw9JGoFjPwVSyY2sxYuFL9TAMNxVj+bJ/VX5GU6qCo1wW8R3ItltAgMBAAEwDQYJ +KoZIhvcNAQELBQADggEBAAaxy5Mbi0fuQFvmQ5ViR2Y6yySeUIDdYMPN/92rzubJ +w1yUS/liJ0L01RS/3VvAuchE+3uIK5ybaR2zwgnmWjIIyllC2cyOwNrzCbSTEZpH +3blSwmPr01fwIXFwANfK+Qz5NdG0LrrU6RloIajqkDXwgDXfMCfJwl6JnRORGUHk +QOGtP4mWA1KqHMtPRQKSv/7TK2s+Sbg/e1T+0iE/VbhzJZonF0/VDQk2huyD7Z7I +VJ62bzsI0V59pGmZYAen9g9EfmZXn2m3QTd+tQytzmnUKyuwfmXt4mnvxkral+ES +eB4Nzv4EDPjThS8LLp7xEL5PBS+FAF5EdZPK23FtexQ= +-----END CERTIFICATE----- diff --git a/kubernetes/namespaces/kube-system/nginx/values.yaml b/kubernetes/namespaces/kube-system/nginx/values.yaml new file mode 100644 index 0000000..858f041 --- /dev/null +++ b/kubernetes/namespaces/kube-system/nginx/values.yaml @@ -0,0 +1,34 @@ +controller: + # Will add custom headers before sending response traffic to the client according to: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#add-headers + addHeaders: + x-powered-by: Joe Banks + + config: + enable-real-ip: true + forwarded-for-header: cf-connecting-ip + generate-request-id: true + + extraArgs: + default-ssl-certificate: "default/pythondiscord.com-tls" + + # This section refers to the creation of the IngressClass resource + # IngressClass resources are supported since k8s >= 1.18 + ingressClassResource: + enabled: true + default: true + + kind: DaemonSet + + service: + annotations: + service.beta.kubernetes.io/linode-loadbalancer-throttle: 0 + service.beta.kubernetes.io/linode-loadbalancer-default-proxy-protocol: none + + metrics: + port: 10254 + enabled: true + + service: + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "10254" diff --git a/kubernetes/namespaces/monitoring/alerts/Makefile b/kubernetes/namespaces/monitoring/alerts/Makefile new file mode 100644 index 0000000..c599ee6 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/Makefile @@ -0,0 +1,11 @@ +.PHONY: alerts alertmanager + +all: alerts alertmanager + +# Upload the alerting rules to the Kubernetes cluster +alerts: + kubectl create configmap -n monitoring prometheus-alert-rules --from-file=alerts.d/ -o yaml --dry-run=client | kubectl apply -f - + +# Upload the alertmanager configuration to the Kubernetes cluster +alertmanager: + kubectl create configmap -n monitoring alertmanager-config --from-file=alertmanager.yaml=alertmanager.yaml -o yaml --dry-run=client | kubectl apply -f - diff --git a/kubernetes/namespaces/monitoring/alerts/README.md b/kubernetes/namespaces/monitoring/alerts/README.md new file mode 100644 index 0000000..75f70ac --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/README.md @@ -0,0 +1,5 @@ +# Alerts + +This directory contains alerting rules and routing configuration for production. + +To build and upload this configuration, see the annotated `Makefile` in this directory. diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager.yaml new file mode 100644 index 0000000..bef166a --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager.yaml @@ -0,0 +1,24 @@ +route: + group_by: ['alertname', 'cluster', 'service'] + + group_wait: 15s + + group_interval: 1m + + receiver: devops-team + +receivers: +- name: devops-team + slack_configs: + - api_url_file: "/opt/pydis/alertmanager/webhooks/DEVOPS_HOOK" + send_resolved: true + title: '{{ if eq .Status "firing" }}[FIRING]{{ else }}[RESOLVED]{{ end }}' + text: | + {{ if eq .Status "firing" }}{{ range .Alerts }} + **{{ .Annotations.summary }}:** + {{ .Annotations.description }} [(Link)]({{.GeneratorURL}}) + + {{ end }}{{ else }}Alert has resolved.{{ end }} + fields: + - title: Alert + value: "{{ .GroupLabels.alertname }}" diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/deployment.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/deployment.yaml new file mode 100644 index 0000000..4f1c322 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/deployment.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: alertmanager + namespace: monitoring +spec: + replicas: 3 + selector: + matchLabels: + app: alertmanager + template: + metadata: + labels: + app: alertmanager + spec: + serviceAccountName: prometheus + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - alertmanager + namespaces: + - monitoring + topologyKey: kubernetes.io/hostname + weight: 100 + initContainers: + - image: debian:bullseye-slim + imagePullPolicy: Always + name: alertmanager-peering-setup + command: [ + '/opt/pydis/alertmanager/init.d/find-pods.sh' + ] + volumeMounts: + - name: alertmanager-init + mountPath: /opt/pydis/alertmanager/init.d + - name: alertmanager-tmp + mountPath: /tmp + securityContext: + runAsUser: 0 + containers: + - image: prom/alertmanager:latest + imagePullPolicy: Always + name: alertmanager + command: + - /bin/sh + - -c + - | + exec /bin/alertmanager \ + --config.file=/opt/pydis/alertmanager/config.d/alertmanager.yaml \ + --web.external-url=https://alertmanager.pythondiscord.com \ + --storage.path=/data/alertmanager \ + $(cat /tmp/peers) + ports: + - name: am + containerPort: 9093 + - name: am-peering + containerPort: 9094 + volumeMounts: + - name: alertmanager-config + mountPath: /opt/pydis/alertmanager/config.d + - name: alertmanager-webhooks + mountPath: /opt/pydis/alertmanager/webhooks + - name: alertmanager-tmp-data + mountPath: /data + - name: alertmanager-tmp + mountPath: /tmp + securityContext: + readOnlyRootFilesystem: true + restartPolicy: Always + volumes: + - name: alertmanager-config + configMap: + name: alertmanager-config + - name: alertmanager-webhooks + secret: + secretName: alert-manager-hook + - name: alertmanager-tmp-data + emptyDir: {} + - name: alertmanager-tmp + emptyDir: {} + - name: alertmanager-init + configMap: + name: alertmanager-init + defaultMode: 0777 + securityContext: + fsGroup: 1000 + runAsUser: 1000 diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/ingress.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/ingress.yaml new file mode 100644 index 0000000..fc99e52 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: alertmanager + namespace: monitoring +spec: + tls: + - hosts: + - "*.pythondiscord.com" + rules: + - host: alertmanager.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: alertmanager + port: + number: 9093 diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/initscript.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/initscript.yaml new file mode 100644 index 0000000..f1f36e2 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/initscript.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: alertmanager-init + namespace: monitoring +data: + find-pods.sh: | + #!/bin/sh + + # Install curl and jq for JSON parsing + apt update && apt install -y curl jq + + # Find the template hash + echo Finding template hash... + TEMPLATE_HASH=$(echo $HOSTNAME | cut -d- -f2) + + # Query kubernetes API for all matching pods + echo Querying Kubernetes API for pods... + PODS=$(curl \ + -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ + https://kubernetes.default/api/v1/namespaces/monitoring/pods\?labelSelector=pod-template-hash=$TEMPLATE_HASH\&pretty=false -sk -o /tmp/peers.json) + + echo Finding Alertmanager IPs... + AM_IPS=$(jq '.items[].status.podIP' /tmp/peers.json -r) + + echo Generating CLI flags for Alertmanager... + PEER_ARGS=$(echo $AM_IPS | sed 's/ /\n/g' | awk '{ print "--cluster.peer="$1":9094" }') + + echo Writing CLI flags to /tmp/peers... + echo $PEER_ARGS > /tmp/peers diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/sd-service.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/sd-service.yaml new file mode 100644 index 0000000..8ec901a --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/sd-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: alertmanager-sd + namespace: monitoring +spec: + selector: + app: alertmanager + clusterIP: None + ports: + - port: 9093 + targetPort: 9093 + name: am + - port: 9094 + targetPort: 9094 + name: am-peering diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/secrets.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/secrets.yaml Binary files differnew file mode 100644 index 0000000..7cc1d95 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/secrets.yaml diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/service-account.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/service-account.yaml new file mode 100644 index 0000000..3f26311 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/service-account.yaml @@ -0,0 +1,28 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: alertmanager +rules: +- apiGroups: [""] + resources: ["pods", "endpoints"] + verbs: ["get", "list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: alertmanager + namespace: monitoring +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: alertmanager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: alertmanager +subjects: + - kind: ServiceAccount + name: alertmanager + namespace: monitoring diff --git a/kubernetes/namespaces/monitoring/alerts/alertmanager/service.yaml b/kubernetes/namespaces/monitoring/alerts/alertmanager/service.yaml new file mode 100644 index 0000000..145b1e2 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alertmanager/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: alertmanager + namespace: monitoring + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9093" +spec: + selector: + app: alertmanager + ports: + - port: 9093 + targetPort: 9093 diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/alertmanager.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/alertmanager.yaml new file mode 100644 index 0000000..b3fcad9 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/alertmanager.yaml @@ -0,0 +1,21 @@ +groups: +- name: alertmanager + rules: + + - alert: AlertManagerClusterFailedPeers + expr: alertmanager_cluster_failed_peers > 0 + for: 1m + labels: + severity: warning + annotations: + summary: "An Alertmanager node is reporting failed peers" + description: "AM {{ $labels.instance }} is reporting that {{ $value }} of it's peers is invalid." + + - alert: AlertManagerHealthScore + expr: alertmanager_cluster_health_score > 0 + for: 1m + labels: + severity: warning + annotations: + summary: "An AlertManagerNode is reporting an unhealthy cluster" + description: "AM {{ $labels.instance }} is reporting that the cluster has a health score of {{ $value }} (where 0 is healthy.)" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/certificates.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/certificates.yaml new file mode 100644 index 0000000..10eb3dd --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/certificates.yaml @@ -0,0 +1,13 @@ +groups: +- name: certificates + interval: 1d + rules: + + - alert: CertificateExpiringSoon + expr: (certmanager_certificate_expiration_timestamp_seconds - time()) / 60 / 60 / 24 < 7 + for: 0m + labels: + severity: warning + annotations: + summary: "Certificate is expiring in < 7 days" + description: "The certificate named {{ $labels.name }} is due for expiry in {{ $value | humanize }} days." diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/coredns.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/coredns.yaml new file mode 100644 index 0000000..9daa660 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/coredns.yaml @@ -0,0 +1,20 @@ +groups: +- name: coredns + rules: + + - alert: CoreDNSPanics + expr: increase(coredns_panics_total[1m]) > 0 + for: 0m + labels: + severity: page + annotations: + summary: "CoreDNS is experiencing panic" + description: "Number of CoreDNS panics encountered: {{ $value }}" + + - alert: CoreDNSCacheMisses + expr: rate(coredns_cache_misses_total{}[10m]) / rate(coredns_cache_misses_total{}[10m] offset 10m) > 5.00 + labels: + severity: page + annotations: + summary: "High CoreDNS cache misses in last 10 minutes" + description: "This can sometimes be an indication of networking troubles, currently {{ $value | humanizePercentage }} over last 10 minutes." diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/cpu.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/cpu.yaml new file mode 100644 index 0000000..5e8868e --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/cpu.yaml @@ -0,0 +1,21 @@ +groups: +- name: cpu + rules: + + - alert: HighCPUThrottling + expr: rate(container_cpu_cfs_throttled_seconds_total{pod=~".+", container_name!="POD", image!=""}[5m]) > 1 + for: 5m + labels: + severity: page + annotations: + summary: "Container {{ $labels.container_name }} in {{ $labels.pod }} high throttling " + description: "{{ $labels.container_name }} inside {{ $labels.pod }} is at {{ $value }}" + + - alert: HighNodeCPU + expr: 100 - (avg by (kubernetes_node) (irate(node_cpu_seconds_total{job="node-exporter",mode="idle"}[5m])) * 100) > 80 + for: 5m + labels: + severity: page + annotations: + summary: "Node {{ $labels.kubernetes_node }} has CPU over 80% for last 5 minute" + description: "CPU on {{ $labels.kubernetes_node }} is averaging {{ $value }}" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/jobs.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/jobs.yaml new file mode 100644 index 0000000..723d267 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/jobs.yaml @@ -0,0 +1,20 @@ +groups: +- name: jobs + rules: + - alert: KubernetesCronjobSuspended + expr: kube_cronjob_spec_suspend != 0 + for: 0m + labels: + severity: page + annotations: + summary: "Kubernetes CronJob suspended: {{ $labels.cronjob }}" + description: "CronJob {{ $labels.kubernetes_namespace }}/{{ $labels.cronjob }} is suspended" + + - alert: KubernetesJobFailed + expr: kube_job_status_failed > 0 + for: 0m + labels: + severity: page + annotations: + summary: "Kubernetes Job failed: {{ $labels.job_name }}" + description: "Job {{$labels.kubernetes_namespacenamespace}}/{{$labels.job_name}} failed to complete" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/memory.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/memory.yaml new file mode 100644 index 0000000..d53da5e --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/memory.yaml @@ -0,0 +1,12 @@ +groups: +- name: memory + rules: + + - alert: NodeHighMemoryUsage + expr: node_memory_Active_bytes / node_memory_MemTotal_bytes > 0.8 + for: 30s + labels: + severity: page + annotations: + summary: "Node {{ $labels.kubernetes_node }} has RAM usage >80% for 5 minutes" + description: 'RAM usage is currently {{ $value | humanizePercentage }} on {{ $labels.kubernetes_node }}' diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/nginx.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/nginx.yaml new file mode 100644 index 0000000..441f7df --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/nginx.yaml @@ -0,0 +1,30 @@ +groups: +- name: nginx + rules: + + - alert: NGINX4XXRequests + expr: sum by(service) (rate(nginx_ingress_controller_requests{status=~"^4..", status!="404", service!="pixels"}[1m])) / sum by(service) (rate(nginx_ingress_controller_requests[1m])) > 0.5 + for: 1m + labels: + severity: page + annotations: + summary: "High rate of 4XX requests for inbound requests" + description: "Rate of 4XX errors is {{ $value | humanizePercentage }} on service `{{ $labels.service }}`" + + - alert: NGINX5XXRequests + expr: sum(rate(nginx_ingress_controller_requests{status=~"^5.."}[1m])) by (service) / sum(rate(nginx_ingress_controller_requests{}[1m])) by (service) > 0.5 + for: 1m + labels: + severity: page + annotations: + summary: "High rate of 5XX requests for inbound requests" + description: "Rate of 5XX errors is {{ $value | humanizePercentage }} on service `{{ $labels.service }}`" + + - alert: NGINXP99Timing + expr: histogram_quantile(0.99, sum by(host, service, le) (rate(nginx_ingress_controller_request_duration_seconds_bucket{service!~"(grafana|metabase|prestashop-svc)", host!="pydis-api.default.svc.cluster.local"}[5m]))) > 3 and on(service) increase(nginx_ingress_controller_requests[5m]) > 10 + for: 5m + labels: + severity: page + annotations: + summary: "Request timing P99 has been over 3 seconds for 5 minutes" + description: "Requests to service {{ $labels.host }} (to service {{ $labels.service }}) have taken over 3 seconds (P99) to complete." diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/nodes.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/nodes.yaml new file mode 100644 index 0000000..6bfa6d1 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/nodes.yaml @@ -0,0 +1,49 @@ +groups: +- name: nodes + rules: + + - alert: KubernetesNodeDiskPressure + expr: kube_node_status_condition{condition="DiskPressure",status="true"} == 1 + for: 1m + labels: + severity: page + annotations: + summary: Node {{ $labels.kubernetes_node }} is experiencing disk pressure + description: "{{ $labels.kubernetes_node }} does not have adequate space to work with." + + - alert: KubernetesNodeMemoryPressure + expr: kube_node_status_condition{condition="MemoryPressure",status="true"} == 1 + for: 15s + labels: + severity: page + annotations: + summary: Node {{ $labels.kubernetes_node }} is experiencing memory pressure + description: "{{ $labels.kubernetes_node }} does not have adequate RAM to work with." + + - alert: KubernetesNodeNetworkUnavailable + expr: kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1 + for: 15s + labels: + severity: page + annotations: + summary: Node {{ $labels.kubernetes_node }} is experiencing network problems + description: "{{ $labels.kubernetes_node }} is experiencing trouble with inbound and outbound connections" + + + - alert: KubernetesNodePIDPressure + expr: kube_node_status_condition{condition="PIDPressure",status="true"} == 1 + for: 15s + labels: + severity: page + annotations: + summary: Node {{ $labels.kubernetes_node }} is experiencing PID exhaustion + description: "{{ $labels.kubernetes_node }} does not have enough PIDs to work with." + + - alert: KubernetesNodeReady + expr: kube_node_status_condition{condition="Ready",status="true"} == 0 + for: 5m + labels: + severity: page + annotations: + summary: Kubernetes node ({{ $labels.kubernetes_node }} ) is marked as unready + description: "Node {{ $labels.kubernetes_node }} has been unready for a long time" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/pods.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/pods.yaml new file mode 100644 index 0000000..9efdffa --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/pods.yaml @@ -0,0 +1,20 @@ +groups: +- name: pods + rules: + - alert: KubernetesPodNotHealthy + expr: min_over_time(sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"})[3m:1m]) > 0 + for: 3m + labels: + severity: page + annotations: + summary: "Kubernetes Pod not healthy: {{ $labels.namespace }}/{{ $labels.pod }}" + description: "Pod has been in a non-ready state for longer than 3 minutes." + + - alert: KubernetesPodCrashLooping + expr: increase(kube_pod_container_status_restarts_total[5m]) > 3 + for: 1m + labels: + severity: warning + annotations: + summary: "Kubernetes pod crash looping: {{ $labels.kubernetes_namespace }}/{{ $labels.pod }}" + description: "Pod {{ $labels.pod }} is crash looping" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/postgres.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/postgres.yaml new file mode 100644 index 0000000..399a84b --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/postgres.yaml @@ -0,0 +1,29 @@ +groups: +- name: postgres + rules: + - alert: PostgresUp + expr: pg_up == 0 + for: 0m + labels: + severity: page + annotations: + summary: "PostgreSQL is offline" + description: "Postgres Exporter cannot connect to PostgreSQL." + + - alert: PostgresTooManyConnections + expr: (sum(pg_stat_activity_count) by (instance)) / on (instance) pg_settings_max_connections * 100 > 80 + for: 1m + labels: + severity: page + annotations: + summary: PostgreSQL connections near max_connections setting + description: "PostgreSQL instance is near the maximum connection limit, currently {{ $value }} connections" + + - alert: PostgresDeadlockedTable + expr: increase(pg_stat_database_deadlocks{datname!~"template.*|postgres"}[1m]) > 3 + for: 1m + labels: + severity: page + annotations: + summary: Too many deadlocked tables + description: "PostgreSQL has dead-locks, value: {{ $value }}" diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/prometheus.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/prometheus.yaml new file mode 100644 index 0000000..25e555d --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/prometheus.yaml @@ -0,0 +1,13 @@ +groups: +- name: prometheus + rules: + + # Alert for any instance that is unreachable for >5 minutes. + - alert: InstanceDown + expr: up == 0 + for: 5m + labels: + severity: page + annotations: + summary: "Instance {{ $labels.instance }} down" + description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes." diff --git a/kubernetes/namespaces/monitoring/alerts/alerts.d/redis.yaml b/kubernetes/namespaces/monitoring/alerts/alerts.d/redis.yaml new file mode 100644 index 0000000..6b946f6 --- /dev/null +++ b/kubernetes/namespaces/monitoring/alerts/alerts.d/redis.yaml @@ -0,0 +1,20 @@ +groups: +- name: redis + rules: + - alert: RedisDown + expr: redis_up == 0 + for: 1m + labels: + severity: page + annotations: + summary: "Redis is offline" + description: "Redis Exporter cannot connect to Redis." + + - alert: RedisOutOfMemory + expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.9 + for: 0m + labels: + severity: page + annotations: + summary: "Redis is approaching it's memory limit" + description: "Redis is currently using {{ $value | humanizePercentage }} of configured memory." diff --git a/kubernetes/namespaces/monitoring/calico-metrics-svc.yaml b/kubernetes/namespaces/monitoring/calico-metrics-svc.yaml new file mode 100644 index 0000000..5690881 --- /dev/null +++ b/kubernetes/namespaces/monitoring/calico-metrics-svc.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: felix-metrics-svc + namespace: kube-system + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9091" +spec: + selector: + k8s-app: calico-node + ports: + - port: 9091 + targetPort: 9091 diff --git a/kubernetes/namespaces/monitoring/exporters/README.md b/kubernetes/namespaces/monitoring/exporters/README.md new file mode 100644 index 0000000..6ed79f5 --- /dev/null +++ b/kubernetes/namespaces/monitoring/exporters/README.md @@ -0,0 +1,8 @@ +# Exporters +This directory contains prometheus exporters for various services running on our cluster. + +If any secrets are required for each exporter they will be in a secrets.yaml file next to the deployment. + +Below is a list of the exporters: +- [postgres_exporter](https://github.com/wrouesnel/postgres_exporter) +- [redis_exporter](https://github.com/oliver006/redis_exporter) diff --git a/kubernetes/namespaces/monitoring/exporters/postgres/postgres_exporter.yaml b/kubernetes/namespaces/monitoring/exporters/postgres/postgres_exporter.yaml new file mode 100644 index 0000000..5542d74 --- /dev/null +++ b/kubernetes/namespaces/monitoring/exporters/postgres/postgres_exporter.yaml @@ -0,0 +1,65 @@ +# Exporter for taking statistics on our PostgreSQL instance +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres-exporter + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: postgres-exporter + template: + metadata: + labels: + app: postgres-exporter + spec: + containers: + - name: postgres-exporter + image: quay.io/prometheuscommunity/postgres-exporter:latest + imagePullPolicy: Always + resources: + requests: + cpu: 5m + memory: 20Mi + limits: + cpu: 20m + memory: 50Mi + ports: + - containerPort: 9187 + env: + - name: PG_EXPORTER_EXTEND_QUERY_PATH + value: /opt/python-discord/queries/queries.yaml + envFrom: + - secretRef: + name: postgres-exporter-env + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /opt/python-discord/queries + name: queries + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + volumes: + - configMap: + defaultMode: 420 + name: postgres-exporter-queries + name: queries +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres-exporter + namespace: monitoring + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9187" +spec: + selector: + app: postgres-exporter + ports: + - protocol: TCP + port: 9187 + targetPort: 9187 diff --git a/kubernetes/namespaces/monitoring/exporters/postgres/secrets.yaml b/kubernetes/namespaces/monitoring/exporters/postgres/secrets.yaml Binary files differnew file mode 100644 index 0000000..bec9067 --- /dev/null +++ b/kubernetes/namespaces/monitoring/exporters/postgres/secrets.yaml diff --git a/kubernetes/namespaces/monitoring/exporters/redis/redis_exporter.yaml b/kubernetes/namespaces/monitoring/exporters/redis/redis_exporter.yaml new file mode 100644 index 0000000..28a8489 --- /dev/null +++ b/kubernetes/namespaces/monitoring/exporters/redis/redis_exporter.yaml @@ -0,0 +1,54 @@ +# Exporter for taking statistics on our Redis instance +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis-exporter + namespace: monitoring +spec: + replicas: 1 + selector: + matchLabels: + app: redis-exporter + template: + metadata: + labels: + app: redis-exporter + spec: + containers: + - name: redis-exporter + image: oliver006/redis_exporter:latest + imagePullPolicy: Always + resources: + requests: + cpu: 5m + memory: 20Mi + limits: + cpu: 20m + memory: 50Mi + ports: + - containerPort: 9187 + envFrom: + - secretRef: + name: redis-exporter-env + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true +--- +apiVersion: v1 +kind: Service +metadata: + name: redis-exporter + namespace: monitoring + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9121" +spec: + selector: + app: redis-exporter + ports: + - protocol: TCP + port: 9121 + targetPort: 9121 diff --git a/kubernetes/namespaces/monitoring/exporters/redis/secrets.yaml b/kubernetes/namespaces/monitoring/exporters/redis/secrets.yaml Binary files differnew file mode 100644 index 0000000..f6ce9d0 --- /dev/null +++ b/kubernetes/namespaces/monitoring/exporters/redis/secrets.yaml diff --git a/kubernetes/namespaces/monitoring/kube-state-metrics/deployment.yaml b/kubernetes/namespaces/monitoring/kube-state-metrics/deployment.yaml new file mode 100644 index 0000000..5b5c2e7 --- /dev/null +++ b/kubernetes/namespaces/monitoring/kube-state-metrics/deployment.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kube-state-metrics + namespace: monitoring +spec: + selector: + matchLabels: + app: kube-state-metrics + template: + metadata: + labels: + app: kube-state-metrics + spec: + serviceAccountName: kube-state-metrics + containers: + - image: ghcr.io/python-discord/kube-state-metrics:v2.1.0 + imagePullPolicy: Always + args: + - --metric-labels-allowlist=pods=[*] + name: kube-state-metrics + securityContext: + readOnlyRootFilesystem: true + imagePullSecrets: + - name: ghcr-pull-secret + restartPolicy: Always + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true diff --git a/kubernetes/namespaces/monitoring/kube-state-metrics/service-account.yaml b/kubernetes/namespaces/monitoring/kube-state-metrics/service-account.yaml new file mode 100644 index 0000000..17b56cb --- /dev/null +++ b/kubernetes/namespaces/monitoring/kube-state-metrics/service-account.yaml @@ -0,0 +1,136 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: kube-state-metrics + namespace: monitoring +rules: + - apiGroups: + - "" + resources: + - configmaps + - secrets + - nodes + - pods + - services + - resourcequotas + - replicationcontrollers + - limitranges + - persistentvolumeclaims + - persistentvolumes + - namespaces + - endpoints + verbs: + - list + - watch + - apiGroups: + - extensions + resources: + - daemonsets + - deployments + - replicasets + - ingresses + verbs: + - list + - watch + - apiGroups: + - apps + resources: + - statefulsets + - daemonsets + - deployments + - replicasets + verbs: + - list + - watch + - apiGroups: + - batch + resources: + - cronjobs + - jobs + verbs: + - list + - watch + - apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - list + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - list + - watch + - apiGroups: + - certificates.k8s.io + resources: + - certificatesigningrequests + verbs: + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + - volumeattachments + verbs: + - list + - watch + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - list + - watch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - list + - watch +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-state-metrics + namespace: monitoring +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kube-state-metrics + namespace: monitoring +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kube-state-metrics +subjects: + - kind: ServiceAccount + name: kube-state-metrics + namespace: monitoring diff --git a/kubernetes/namespaces/monitoring/kube-state-metrics/service.yaml b/kubernetes/namespaces/monitoring/kube-state-metrics/service.yaml new file mode 100644 index 0000000..7faa2c1 --- /dev/null +++ b/kubernetes/namespaces/monitoring/kube-state-metrics/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: kube-state-metrics + namespace: monitoring + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" +spec: + selector: + app: kube-state-metrics + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 diff --git a/kubernetes/namespaces/monitoring/kubewatch/README.md b/kubernetes/namespaces/monitoring/kubewatch/README.md new file mode 100644 index 0000000..294c666 --- /dev/null +++ b/kubernetes/namespaces/monitoring/kubewatch/README.md @@ -0,0 +1,3 @@ +# Kubewatch + +> **kubewatch** is a Kubernetes watcher that currently publishes notification to available collaboration hubs/notification channels. Run it in your k8s cluster, and you will get event notifications through webhooks. diff --git a/kubernetes/namespaces/monitoring/kubewatch/configmap.yaml b/kubernetes/namespaces/monitoring/kubewatch/configmap.yaml new file mode 100644 index 0000000..902cfbc --- /dev/null +++ b/kubernetes/namespaces/monitoring/kubewatch/configmap.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kubewatch-config + namespace: monitoring +data: + .kubewatch.yaml: | + namespace: "" + handler: + discord: + webhook: "" + ignores: + - pixels-discord-channel + - cert-manager-cainjector-leader-election + - cert-manager-controller + - ingress-controller-leader-nginx + - cluster-autoscaler-status + - ingress-controller-leader + resource: + deployment: true + replicationcontroller: true + replicaset: true + daemonset: true + services: true + pod: true + job: true + node: false + clusterrole: true + serviceaccount: true + persistentvolume: true + namespace: true + secret: true + configmap: true + ingress: true diff --git a/kubernetes/namespaces/monitoring/kubewatch/deployment.yaml b/kubernetes/namespaces/monitoring/kubewatch/deployment.yaml new file mode 100644 index 0000000..a674648 --- /dev/null +++ b/kubernetes/namespaces/monitoring/kubewatch/deployment.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kubewatch + namespace: monitoring +spec: + selector: + matchLabels: + app: kubewatch + template: + metadata: + labels: + app: kubewatch + spec: + serviceAccountName: kubewatch + containers: + - image: ghcr.io/python-discord/kubewatch:latest + imagePullPolicy: Always + name: kubewatch + volumeMounts: + - name: config-volume + mountPath: /root + envFrom: + - secretRef: + name: kubewatch-secrets + securityContext: + readOnlyRootFilesystem: true + restartPolicy: Always + volumes: + - name: config-volume + configMap: + name: kubewatch-config diff --git a/kubernetes/namespaces/monitoring/kubewatch/secrets.yaml b/kubernetes/namespaces/monitoring/kubewatch/secrets.yaml Binary files differnew file mode 100644 index 0000000..7427da2 --- /dev/null +++ b/kubernetes/namespaces/monitoring/kubewatch/secrets.yaml diff --git a/kubernetes/namespaces/monitoring/kubewatch/service-account.yaml b/kubernetes/namespaces/monitoring/kubewatch/service-account.yaml new file mode 100644 index 0000000..f0748ba --- /dev/null +++ b/kubernetes/namespaces/monitoring/kubewatch/service-account.yaml @@ -0,0 +1,30 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: kubewatch + namespace: monitoring +rules: +- apiGroups: ["", "extensions", "apps", "batch", "rbac.authorization.k8s.io", ] + resources: ["*"] + verbs: ["get", "watch", "list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kubewatch + namespace: monitoring +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kubewatch + namespace: monitoring +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubewatch +subjects: + - kind: ServiceAccount + name: kubewatch + namespace: monitoring diff --git a/kubernetes/namespaces/monitoring/node_exporter/daemonset.yaml b/kubernetes/namespaces/monitoring/node_exporter/daemonset.yaml new file mode 100644 index 0000000..075b1b7 --- /dev/null +++ b/kubernetes/namespaces/monitoring/node_exporter/daemonset.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: node-exporter + namespace: monitoring +spec: + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + selector: + matchLabels: + name: node-exporter + phase: prod + template: + metadata: + labels: + name: node-exporter + phase: prod + annotations: + seccomp.security.alpha.kubernetes.io/pod: 'docker/default' + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + - matchExpressions: + - key: beta.kubernetes.io/os + operator: In + values: + - linux + securityContext: + runAsNonRoot: true + runAsUser: 65534 + hostPID: true + containers: + - name: node-exporter + image: quay.io/prometheus/node-exporter:v1.2.0 + args: + - --path.procfs=/host/proc + - --path.sysfs=/host/sys + - --path.rootfs=/host/root + - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker|var/lib/containerd|var/lib/containers/.+)($|/) + - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$ + ports: + - name: metrics + containerPort: 9100 + securityContext: + readOnlyRootFilesystem: true + resources: + requests: + cpu: 10m + memory: 24Mi + limits: + cpu: 200m + memory: 100Mi + volumeMounts: + - name: proc + mountPath: /host/proc + readOnly: true + - name: sys + mountPath: /host/sys + readOnly: true + - name: root + mountPath: /host/root + readOnly: true + tolerations: + - effect: NoSchedule + operator: Exists + volumes: + - name: proc + hostPath: + path: /proc + - name: sys + hostPath: + path: /sys + - name: root + hostPath: + path: / diff --git a/kubernetes/namespaces/monitoring/node_exporter/service.yaml b/kubernetes/namespaces/monitoring/node_exporter/service.yaml new file mode 100644 index 0000000..b6be8d5 --- /dev/null +++ b/kubernetes/namespaces/monitoring/node_exporter/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: node-exporter + namespace: monitoring + annotations: + prometheus.io/scrape: 'true' +spec: + type: ClusterIP + clusterIP: None + selector: + name: node-exporter + phase: prod + ports: + - name: metrics + protocol: TCP + port: 80 + targetPort: 9100 diff --git a/kubernetes/namespaces/monitoring/prometheus/deployment.yaml b/kubernetes/namespaces/monitoring/prometheus/deployment.yaml new file mode 100644 index 0000000..5a806ff --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/deployment.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: monitoring +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + serviceAccountName: prometheus + containers: + - image: prom/prometheus:latest + imagePullPolicy: Always + args: [ + "--storage.tsdb.path", "/opt/prometheus/data", + "--config.file", "/etc/prometheus/prometheus.yaml", + "--web.external-url", "https://prometheus.pythondiscord.com", + "--web.enable-lifecycle", + "--web.enable-admin-api", + "--web.page-title", "Python Discord Prometheus", + "--storage.tsdb.retention.size", "28GB", + "--storage.tsdb.retention.time", "100d" + ] + name: prometheus + ports: + - name: prometheus + containerPort: 9090 + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - name: prometheus-data + mountPath: /opt/prometheus/data + - name: prometheus-config + mountPath: /etc/prometheus + - name: prometheus-alerts + mountPath: /opt/pydis/prometheus/alerts.d + restartPolicy: Always + securityContext: + fsGroup: 2000 + runAsUser: 1000 + runAsNonRoot: true + volumes: + - name: prometheus-data + persistentVolumeClaim: + claimName: prometheus-storage + - name: prometheus-config + configMap: + name: prometheus-config + - name: prometheus-alerts + configMap: + name: prometheus-alert-rules diff --git a/kubernetes/namespaces/monitoring/prometheus/ingress.yaml b/kubernetes/namespaces/monitoring/prometheus/ingress.yaml new file mode 100644 index 0000000..69e240a --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "kube-system/mtls-client-crt-bundle" + nginx.ingress.kubernetes.io/auth-tls-error-page: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + name: prometheus + namespace: monitoring +spec: + tls: + - hosts: + - "*.pythondiscord.com" + rules: + - host: prometheus.pythondiscord.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus + port: + number: 9090 diff --git a/kubernetes/namespaces/monitoring/prometheus/prometheus-config.yaml b/kubernetes/namespaces/monitoring/prometheus/prometheus-config.yaml new file mode 100644 index 0000000..7ad047c --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/prometheus-config.yaml @@ -0,0 +1,267 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + namespace: monitoring +data: + prometheus.yaml: |- + # Global config + global: + scrape_interval: 15s + + rule_files: + - /opt/pydis/prometheus/alerts.d/*.yaml + + alerting: + alertmanagers: + - scheme: http + dns_sd_configs: + - names: + - alertmanager-sd.monitoring.svc.cluster.local + type: A + port: 9093 + + # Scrape configs for running Prometheus on a Kubernetes cluster. + # This uses separate scrape configs for cluster components (i.e. API server, node) + # and services to allow each to use different authentication configs. + # + # Kubernetes labels will be added as Prometheus labels on metrics via the + # `labelmap` relabeling action. + scrape_configs: + + # Scrape config for API servers. + # + # Kubernetes exposes API servers as endpoints to the default/kubernetes + # service so this uses `endpoints` role and uses relabelling to only keep + # the endpoints associated with the default/kubernetes service using the + # default named port `https`. This works for single API server deployments as + # well as HA API server deployments. + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + # Using endpoints to discover kube-apiserver targets finds the pod IP + # (host IP since apiserver uses host network) which is not used in + # the server certificate. + insecure_skip_verify: true + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + # Keep only the default/kubernetes service endpoints for the https port. This + # will add targets for each API server which Kubernetes adds an endpoint to + # the default/kubernetes service. + relabel_configs: + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: default;kubernetes;https + - replacement: apiserver + action: replace + target_label: job + + # Scrape config for node (i.e. kubelet) /metrics (e.g. 'kubelet_'). Explore + # metrics from a node by scraping kubelet (127.0.0.1:10250/metrics). + - job_name: 'kubelet' + kubernetes_sd_configs: + - role: node + + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + # Kubelet certs don't have any fixed IP SANs + insecure_skip_verify: true + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - replacement: 'monitoring' + target_label: kubernetes_namespace + + metric_relabel_configs: + - source_labels: + - namespace + action: replace + regex: (.+) + target_label: kubernetes_namespace + + # Scrape config for Kubelet cAdvisor. Explore metrics from a node by + # scraping kubelet (127.0.0.1:10250/metrics/cadvisor). + - job_name: 'kubernetes-cadvisor' + kubernetes_sd_configs: + - role: node + + scheme: https + metrics_path: /metrics/cadvisor + tls_config: + # Kubelet certs don't have any fixed IP SANs + insecure_skip_verify: true + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + metric_relabel_configs: + - source_labels: + - namespace + action: replace + target_label: kubernetes_namespace + - source_labels: + - pod + regex: (.*) + replacement: $1 + action: replace + target_label: pod_name + - source_labels: + - container + regex: (.*) + replacement: $1 + action: replace + target_label: container_name + + # Scrap etcd metrics from masters via etcd-scraper-proxy + - job_name: 'etcd' + kubernetes_sd_configs: + - role: pod + scheme: http + relabel_configs: + - source_labels: [__meta_kubernetes_namespace] + action: keep + regex: 'kube-system' + - source_labels: [__meta_kubernetes_pod_label_component] + action: keep + regex: 'etcd-scraper-proxy' + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + + # Scrape config for service endpoints. + # + # The relabeling allows the actual service scrape endpoint to be configured + # via the following annotations: + # + # * `prometheus.io/scrape`: Only scrape services that have a value of `true` + # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need + # to set this to `https` & most likely set the `tls_config` of the scrape config. + # * `prometheus.io/path`: If the metrics path is not `/metrics` override this. + # * `prometheus.io/port`: If the metrics are exposed on a different port to the + # service then set this appropriately. + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: job + - action: replace + source_labels: + - __meta_kubernetes_pod_node_name + target_label: kubernetes_node + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + metric_relabel_configs: + - source_labels: + - namespace + action: replace + regex: (.+) + target_label: kubernetes_namespace + + # Example scrape config for probing services via the Blackbox Exporter. + # + # The relabeling allows the actual service scrape endpoint to be configured + # via the following annotations: + # + # * `prometheus.io/probe`: Only probe services that have a value of `true` + - job_name: 'kubernetes-services' + + metrics_path: /probe + params: + module: [http_2xx] + + kubernetes_sd_configs: + - role: service + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe] + action: keep + regex: true + - source_labels: [__address__] + target_label: __param_target + - target_label: __address__ + replacement: blackbox + - source_labels: [__param_target] + target_label: instance + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_service_name] + target_label: job + metric_relabel_configs: + - source_labels: + - namespace + action: replace + regex: (.+) + target_label: kubernetes_namespace + + # Example scrape config for pods + # + # The relabeling allows the actual pod scrape endpoint to be configured via the + # following annotations: + # + # * `prometheus.io/scrape`: Only scrape pods that have a value of `true` + # * `prometheus.io/path`: If the metrics path is not `/metrics` override this. + # * `prometheus.io/port`: Scrape the pod on the indicated port instead of the + # pod's declared ports (default is a port-free target if none are declared). + - job_name: 'kubernetes-pods' + + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: kubernetes_pod_name + metric_relabel_configs: + - source_labels: + - namespace + action: replace + regex: (.+) + target_label: kubernetes_namespace diff --git a/kubernetes/namespaces/monitoring/prometheus/service-account.yaml b/kubernetes/namespaces/monitoring/prometheus/service-account.yaml new file mode 100644 index 0000000..00cf0c2 --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/service-account.yaml @@ -0,0 +1,32 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: prometheus +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- nonResourceURLs: + - "/metrics" + verbs: + - get +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: monitoring +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus +subjects: + - kind: ServiceAccount + name: prometheus + namespace: monitoring diff --git a/kubernetes/namespaces/monitoring/prometheus/service.yaml b/kubernetes/namespaces/monitoring/prometheus/service.yaml new file mode 100644 index 0000000..5ec3a21 --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: monitoring +spec: + selector: + app: prometheus + ports: + - port: 9090 + targetPort: 9090 diff --git a/kubernetes/namespaces/monitoring/prometheus/volume.yaml b/kubernetes/namespaces/monitoring/prometheus/volume.yaml new file mode 100644 index 0000000..4468a20 --- /dev/null +++ b/kubernetes/namespaces/monitoring/prometheus/volume.yaml @@ -0,0 +1,14 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: prometheus-storage + namespace: monitoring + labels: + app: prometheus +spec: + storageClassName: linode-block-storage-retain + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 30Gi |