Skip to content

web: Add optional auto-scaling to the deployment

Antoine R. Dumont requested to merge web-add-autoscaling into production

This adds the auto-scaling part required in the reference task.

make swh-helm-diff
make swh-helm-diff
./helm-diff.sh swh
[swh] Comparing changes between branches production and web-add-autoscaling...
Switched to branch 'production'
Your branch is up to date with 'origin/production'.
[swh] Generate config in production branch for swh/values/default.yaml...
[swh] Generate config in production branch for swh/values/minikube.yaml...
[swh] Generate config in production branch for swh/values/production-cassandra.yaml...
[swh] Generate config in production branch for swh/values/production.yaml...
[swh] Generate config in production branch for swh/values/staging-cassandra.yaml...
[swh] Generate config in production branch for swh/values/staging.yaml...
Switched to branch 'web-add-autoscaling'
[swh] Generate config in web-add-autoscaling branch for swh/values/default.yaml...
[swh] Generate config in web-add-autoscaling branch for swh/values/minikube.yaml...
[swh] Generate config in web-add-autoscaling branch for swh/values/production-cassandra.yaml...
[swh] Generate config in web-add-autoscaling branch for swh/values/production.yaml...
[swh] Generate config in web-add-autoscaling branch for swh/values/staging-cassandra.yaml...
[swh] Generate config in web-add-autoscaling branch for swh/values/staging.yaml...


------------- diff for swh/values/default.yaml -------------

No differences


------------- diff for swh/values/minikube.yaml -------------

--- /tmp/swh-chart.swh.9h65qILO/minikube.yaml.before    2023-10-05 15:57:38.620596181 +0200
+++ /tmp/swh-chart.swh.9h65qILO/minikube.yaml.after     2023-10-05 15:57:39.804597623 +0200
@@ -160,20 +160,102 @@
     if [ -e "${DB_VERSION}" ]; then
       echo "Unable to find the code version"
       exit 1
     fi

     if [ "$DB_VERSION" -ne "$CODE_VERSION" ]; then
       echo "code and DB versions are different. Blocking the deployment"
       exit 1
     fi
 ---
+# Source: swh/templates/web/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  namespace: swh
+  name: web-configuration-template
+data:
+  config.yml.template: |
+    storage:
+      cls: remote
+      url: http://fake-storage.i.s.s.n:8002
+    search:
+      cls: remote
+      url: http://fake-search.i.s.s.n:5005
+    scheduler:
+      cls: remote
+      url: http://fake-scheduler.i.s.s.n:5008
+    vault:
+      cls: remote
+      url: http://fake-vault.i.s.s.n:5006
+    counters_backend: swh-counters
+    counters:
+      cls: remote
+      url: http://fake-counters.i.s.s.n:5006
+
+    secret_key: ${DJANGO_SECRET_KEY}
+    production_db:
+
+      host: db1.i.s.s.n
+      port: 5432
+      name: swh-web
+      user: swh-web
+      password: ${POSTGRESQL_PASSWORD}
+    throttling:
+      cache_uri: fake-memcached:11211
+      scopes:
+        swh_api:
+          exempted_networks:
+          - 10.100.100.0/24
+          - 127.0.0.0/8
+          - 192.168.100.0/24
+          - 192.168.102.0/24
+          limiter_rate:
+            default: 120/h
+        swh_api_origin_search:
+          limiter_rate:
+            default: 120/h
+    add_forge_now:
+      email_address: add-forge-now@webapp.s.s.n
+    allowed_hosts:
+    - webapp.internal.minikube
+    content_display_max_size: 5242880
+    debug: false
+    deposit:
+      private_api_password: ${DEPOSIT_PASSWORD}
+      private_api_url: https://deposit-rp.i.s.s.n/1/private/
+      private_api_user: ${DEPOSIT_USERNAME}
+    give:
+      public_key: ${GIVE_PUBLIC_KEY}
+      token: ${GIVE_PRIVATE_TOKEN}
+    history_counters_url: http://counters0.i.s.s.n:5011/counters_history/history.json
+    instance_name: webapp.internal.minikube
+    keycloak:
+      realm_name: SwhMinikube
+      server_url: https://auth.s.o/auth/
+    matomo: {}
+    search_config:
+      metadata_backend: swh-indexer-storage
+    swh_extra_django_apps:
+    - swh.web.add_forge_now
+    - swh.web.archive_coverage
+    - swh.web.badges
+    - swh.web.banners
+    - swh.web.deposit
+    - swh.web.inbound_email
+    - swh.web.jslicenses
+    - swh.web.mailmap
+    - swh.web.metrics
+    - swh.web.save_code_now
+    - swh.web.save_origin_webhooks
+    - swh.web.vault
+---
 # Source: swh/charts/keda/templates/crds/crd-clustertriggerauthentications.yaml
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.12.0
   labels:
     app.kubernetes.io/name: keda-operator
     helm.sh/chart: keda-2.11.0
     app.kubernetes.io/component: operator
@@ -9744,20 +9826,38 @@
     app: prometheus-statsd-exporter
   ports:
     - name: statsd
       port: 9125
       targetPort: 9125
       protocol: UDP
     - name: http
       port: 9102
       targetPort: 9102
 ---
+# Source: swh/templates/web/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: web
+  namespace: swh
+spec:
+  type: ClusterIP
+  selector:
+    app: web
+  ports:
+    - port: 5004
+      targetPort: 5004
+      name: webapp
+    - port: 80
+      targetPort: 80
+      name: webstatic
+---
 # Source: swh/charts/keda/templates/manager/deployment.yaml
 apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: keda-operator
   namespace: default
   annotations:
     {}
   labels:
     app: keda-operator
@@ -10118,20 +10218,276 @@
         volumeMounts:
           - name: config
             mountPath: /etc/prometheus/statsd-mapping.yml
             subPath: config.yml
             readOnly: true
       volumes:
         - name: config
           configMap:
             name: prometheus-statsd-exporter
 ---
+# Source: swh/templates/web/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  namespace: swh
+  name: web
+  labels:
+    app: web
+spec:
+  revisionHistoryLimit: 2
+  selector:
+    matchLabels:
+      app: web
+  strategy:
+    type: RollingUpdate
+    rollingUpdate:
+      maxSurge: 1
+  template:
+    metadata:
+      labels:
+        app: web
+      annotations:
+        checksum/config: 2bc485166c625fe75ceed8935e23f86458bd321c45758e1b8c60499586bc2740
+    spec:
+      affinity:
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+            - matchExpressions:
+              - key: swh/web
+                operator: In
+                values:
+                - "true"
+      priorityClassName: swh-frontend-rpc
+
+      initContainers:
+        - name: prepare-configuration
+          image: debian:bullseye
+          imagePullPolicy: IfNotPresent
+          command:
+            - /bin/bash
+          args:
+            - -c
+            - eval echo "\"$(</etc/swh/configuration-template/config.yml.template)\"" > /etc/swh/config.yml
+          env:
+
+            - name: POSTGRESQL_PASSWORD
+              valueFrom:
+                secretKeyRef:
+                  name: swh-postgresql-web-secret
+                  key: postgres-swh-web-password
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+
+            - name: DJANGO_SECRET_KEY
+              valueFrom:
+                secretKeyRef:
+                  name: webapp-django-secrets
+                  key: webapp-django-secret-key
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+
+
+            - name: DEPOSIT_PASSWORD
+              valueFrom:
+                secretKeyRef:
+                  name: deposit-secrets
+                  key: password
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+            - name: DEPOSIT_USERNAME
+              valueFrom:
+                secretKeyRef:
+                  name: deposit-secrets
+                  key: username
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+
+
+            - name: GIVE_PRIVATE_TOKEN
+              valueFrom:
+                secretKeyRef:
+                  name: web-give-secrets
+                  key: private-token
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+            - name: GIVE_PUBLIC_KEY
+              valueFrom:
+                secretKeyRef:
+                  name: web-give-secrets
+                  key: public-key
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+
+          volumeMounts:
+            - name: configuration
+              mountPath: /etc/swh
+            - name: configuration-template
+              mountPath: /etc/swh/configuration-template
+        - name: prepare-static
+          image: container-registry.softwareheritage.org/swh/infra/swh-apps/web:20231004.3
+          imagePullPolicy: IfNotPresent
+          command:
+            - /bin/bash
+          args:
+            - -c
+            - cp -r $PWD/.local/share/swh/web/static/ /usr/share/swh/web/static/
+          volumeMounts:
+          - name: static
+            mountPath: /usr/share/swh/web/static
+      containers:
+        - name: web
+          resources:
+            requests:
+              memory: 50Mi
+              cpu: 50m
+          image: container-registry.softwareheritage.org/swh/infra/swh-apps/web:20231004.3
+          imagePullPolicy: IfNotPresent
+          ports:
+            - containerPort: 5004
+              name: webapp
+          readinessProbe:
+            httpGet:
+              path: /
+              port: webapp
+              httpHeaders:
+                - name: Host
+                  value:
+            initialDelaySeconds: 5
+            failureThreshold: 30
+            periodSeconds: 10
+            timeoutSeconds: 30
+          livenessProbe:
+            httpGet:
+              path: /
+              port: webapp
+              httpHeaders:
+                - name: Host
+                  value:
+            initialDelaySeconds: 3
+            periodSeconds: 10
+            timeoutSeconds: 30
+          command:
+            - /bin/bash
+          args:
+            - -c
+            - /opt/swh/entrypoint.sh
+          env:
+            - name: STATSD_HOST
+              value: prometheus-statsd-exporter
+            - name: STATSD_PORT
+              value: "9125"
+            - name: LOG_LEVEL
+              value: "INFO"
+            - name: SWH_CONFIG_FILENAME
+              value: /etc/swh/config.yml
+
+            - name: DJANGO_SECRET_KEY
+              valueFrom:
+                secretKeyRef:
+                  name: webapp-django-secrets
+                  key: webapp-django-secret-key
+                  # 'name' secret must exist & include that ^ key
+                  optional: false
+
+          volumeMounts:
+          - name: configuration
+            mountPath: /etc/swh
+            readOnly: true
+        - name: nginx
+          resources:
+            requests:
+              memory: 50Mi
+              cpu: 50m
+          image: nginx:bullseye
+          imagePullPolicy: IfNotPresent
+          ports:
+            - containerPort: 80
+              name: webstatic
+          readinessProbe:
+            httpGet:
+              path: static/robots.txt
+              port: webstatic
+            initialDelaySeconds: 5
+            failureThreshold: 30
+            periodSeconds: 10
+          livenessProbe:
+            httpGet:
+              path: static/robots.txt
+              port: webstatic
+            initialDelaySeconds: 3
+            periodSeconds: 10
+          volumeMounts:
+            - name: static
+              mountPath: /usr/share/nginx/html
+      volumes:
+      - name: configuration
+        emptyDir: {}
+      - name: configuration-template
+        configMap:
+         name: web-configuration-template
+         items:
+         - key: "config.yml.template"
+           path: "config.yml.template"
+      - name: static
+        emptyDir: {}
+---
+# Source: swh/templates/web/autoscaling.yaml
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  namespace: swh
+  name: web
+  labels:
+    app: web
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: web
+  minReplicas: 1
+  maxReplicas: 2
+  metrics:
+  - type: Resource
+    resource:
+      name: cpu
+      target:
+        type: Utilization
+        averageUtilization: 50
+---
+# Source: swh/templates/web/ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  namespace: swh
+  name: swh-web-ingress
+spec:
+  rules:
+  - http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: web
+            port:
+              number: 5004
+      - path: /static
+        pathType: Prefix
+        backend:
+          service:
+            name: web
+            port:
+              number: 80
+    host:
+---
 # Source: swh/charts/keda/templates/metrics-server/apiservice.yaml
 apiVersion: apiregistration.k8s.io/v1
 kind: APIService
 metadata:
   annotations:
   labels:
     app.kubernetes.io/name: v1beta1.external.metrics.k8s.io
     helm.sh/chart: keda-2.11.0
     app.kubernetes.io/component: operator
     app.kubernetes.io/managed-by: Helm


------------- diff for swh/values/production-cassandra.yaml -------------

--- /tmp/swh-chart.swh.9h65qILO/production-cassandra.yaml.before        2023-10-05 15:57:38.808596410 +0200
+++ /tmp/swh-chart.swh.9h65qILO/production-cassandra.yaml.after 2023-10-05 15:57:39.956597808 +0200
@@ -12645,21 +12645,20 @@
 # Source: swh/templates/web/deployment.yaml
 apiVersion: apps/v1
 kind: Deployment
 metadata:
   namespace: swh-cassandra
   name: web
   labels:
     app: web
 spec:
   revisionHistoryLimit: 2
-  replicas: 2
   selector:
     matchLabels:
       app: web
   strategy:
     type: RollingUpdate
     rollingUpdate:
       maxSurge: 1
   template:
     metadata:
       labels:
@@ -12842,20 +12841,43 @@
         emptyDir: {}
       - name: configuration-template
         configMap:
          name: web-configuration-template
          items:
          - key: "config.yml.template"
            path: "config.yml.template"
       - name: static
         emptyDir: {}
 ---
+# Source: swh/templates/web/autoscaling.yaml
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  namespace: swh-cassandra
+  name: web
+  labels:
+    app: web
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: web
+  minReplicas: 2
+  maxReplicas: 4
+  metrics:
+  - type: Resource
+    resource:
+      name: cpu
+      target:
+        type: Utilization
+        averageUtilization: 50
+---
 # Source: swh/templates/graphql/ingress.yaml
 apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   namespace: swh-cassandra
   name: graphql-ingress
   annotations:
     nginx.ingress.kubernetes.io/rewrite-target: /
 spec:
   rules:


------------- diff for swh/values/production.yaml -------------

No differences


------------- diff for swh/values/staging-cassandra.yaml -------------

--- /tmp/swh-chart.swh.9h65qILO/staging-cassandra.yaml.before   2023-10-05 15:57:39.276596979 +0200
+++ /tmp/swh-chart.swh.9h65qILO/staging-cassandra.yaml.after    2023-10-05 15:57:40.436598393 +0200
@@ -19450,21 +19450,20 @@
 # Source: swh/templates/web/deployment.yaml
 apiVersion: apps/v1
 kind: Deployment
 metadata:
   namespace: swh-cassandra
   name: web
   labels:
     app: web
 spec:
   revisionHistoryLimit: 2
-  replicas: 2
   selector:
     matchLabels:
       app: web
   strategy:
     type: RollingUpdate
     rollingUpdate:
       maxSurge: 1
   template:
     metadata:
       labels:
@@ -19670,20 +19669,43 @@
   minReplicas: 2
   maxReplicas: 10
   metrics:
   - type: Resource
     resource:
       name: cpu
       target:
         type: Utilization
         averageUtilization: 150
 ---
+# Source: swh/templates/web/autoscaling.yaml
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  namespace: swh-cassandra
+  name: web
+  labels:
+    app: web
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: web
+  minReplicas: 2
+  maxReplicas: 3
+  metrics:
+  - type: Resource
+    resource:
+      name: cpu
+      target:
+        type: Utilization
+        averageUtilization: 50
+---
 # Source: swh/templates/graphql/ingress.yaml
 apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   namespace: swh-cassandra
   name: graphql-ingress
   annotations:
     nginx.ingress.kubernetes.io/rewrite-target: /
 spec:
   rules:


------------- diff for swh/values/staging.yaml -------------

No differences

Refs. swh/infra/sysadm-environment#4812 (closed)

Merge request reports