diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index da91a690ae1a9a5e46dc5198faf800683e95178d..9444f87ce4a2740a833e4a2d596d07a761157bb8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,158 +1,144 @@
-variables:
-  DOCKER_TLS_CERTDIR: "" # HACK: see https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
-  DOCKER_IMAGE: "docker:20.10.12"
-
-stages:
-  - build
-  - deploy
-
-#==[ Backend build ]============================================================
-
-# TODO: cache docker layers
-# TODO: build ts
-be-build-job:
-  image: $DOCKER_IMAGE
-  stage: build
-  tags:
-    - commul
-  services:
-    - docker:dind
-  variables:
-    IMAGE_NAME: $CI_REGISTRY_IMAGE/backend
-  before_script:
-    - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN https://$CI_REGISTRY
-  script:
-    - >
-      docker build
-      --rm --no-cache
-      --target production
-      --tag=$IMAGE_NAME:${CI_COMMIT_SHA}
-      --tag=$IMAGE_NAME:${CI_COMMIT_REF_NAME}
-      --tag=$IMAGE_NAME:${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
-      backend
-    - docker image push --all-tags $IMAGE_NAME
-  only:
-    - tags
-    - development
-
-#==[ Backend deployment ]=======================================================
-
-.be-deploy-job:
-  image: alpine:latest
-  # image: $DOCKER_IMAGE
-  stage: deploy
-  needs:
-    - job: be-build-job
-      artifacts: false # TODO: maybe we can get the build image as an artifact?
-  tags:
-    - commul
-  # services:
-  #   - docker:dind
-  variables:
-    KUBECTL_VERSION: v1.8.10
-    IMAGE_NAME: $CI_REGISTRY_IMAGE/backend
-  before_script:
-    - "#==[ install kubectl ]=================="
-    - wget https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl
-    # NOTE: version is too ald and don't have sha256 available
-    #- wget https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl.sha256
-    # - echo "$(<kubectl.sha256)  kubectl" | sha256sum --check
-    - mv kubectl /usr/bin/ && chmod +x /usr/bin/kubectl
-    - "#==[ configure kubectl ]================"
-    - kubectl config set-cluster "k8sproduction" --server="$KUBE_URL" --certificate-authority="$KUBE_CA_PEM_FILE"
-    - kubectl config set-credentials "gitlab-deploy" --token=$K8S_PRODUCTION_TOKEN
-    - kubectl config set-context "$CI_PROJECT_ID" --cluster="k8sproduction" --user="gitlab-deploy" --namespace="$K8S_NAMESPACE"
-    - kubectl config use-context "$CI_PROJECT_ID"
-  script:
-    - kubectl set image deployment/$K8S_DEPLOYMENT oetzi=${IMAGE_NAME}:${CI_COMMIT_SHA}
-
-be-prd-deploy-job:
-  extends: .be-deploy-job
-  environment:
-    name: production/backend
-    deployment_tier: production
-    url: https://kommul.eurac.edu/oetzi
-  variables:
-    K8S_NAMESPACE: kommul
-    K8S_DEPLOYMENT: oetzi-webserver-deployment
-  only:
-    - tags
-
-be-stg-deploy-job:
-  extends: .be-deploy-job
-  environment:
-    name: staging/backend
-    deployment_tier: staging
-    url: https://kommul-dev.eurac.edu/oetzi
-  variables:
-    K8S_NAMESPACE: kommul-dev
-    K8S_DEPLOYMENT: oetzi-webserver-deployment
-  only:
-    - development
-
-#==[ Frontend build ]===========================================================
-
-fe-build-job:
-  image: node:16-alpine
-  stage: build
-  tags:
-    - commul
-  cache:
-    - key:
-        files:
-          - frontend/package-lock.json
-      paths:
-        - frontend/node_modules
-  script:
-    - cd frontend
-    - npm install
-    - npm run build
-  artifacts:
-    paths:
-      - frontend/dist/
-    # TODO: set expiration in docker registry too
-    expire_in: 1 week
-  only:
-    - tags
-    - development
-
-#==[ Frontend deployment ]======================================================
-
-.fe-deploy-job:
-  image: alpine:latest
-  stage: deploy
-  needs:
-    - job: fe-build-job
-      artifacts: true
-  tags:
-    - commul
-  before_script:
-    - ./ci/install-butler-on-alpine.sh
-  script:
-    - >
-      butler push 
-      frontend/dist
-      eurac/$GAME_NAME:html5
-      --userversion ${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
-
-fe-prd-deploy-job:
-  extends: .fe-deploy-job
-  environment:
-    name: production/frontend
-    deployment_tier: production
-    url: https://eurac.itch.io/oetzi
-  variables:
-    GAME_NAME: oetzi
-  only:
-    - tags
-
-fe-stg-deploy-job:
-  extends: .fe-deploy-job
-  environment:
-    name: staging/frontend
-    deployment_tier: staging
-    url: https://eurac.itch.io/oetzi-staging
-  variables:
-    GAME_NAME: oetzi-staging
-  only:
-    - development
+variables:
+  DOCKER_TLS_CERTDIR: "" # HACK: see https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
+  DOCKER_IMAGE: "docker:20.10.12"
+
+stages:
+  - build
+  - deploy
+
+#==[ Backend build ]============================================================
+
+# TODO: cache docker layers
+# TODO: build ts
+be-build-job:
+  image: $DOCKER_IMAGE
+  stage: build
+  tags:
+    - commul
+  services:
+    - docker:dind
+  variables:
+    IMAGE_NAME: $CI_REGISTRY_IMAGE/backend
+  before_script:
+    - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN https://$CI_REGISTRY
+  script:
+    - >
+      docker build
+      --rm --no-cache
+      --target production
+      --tag=$IMAGE_NAME:${CI_COMMIT_SHA}
+      --tag=$IMAGE_NAME:${CI_COMMIT_REF_NAME}
+      --tag=$IMAGE_NAME:${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
+      backend
+    - docker image push --all-tags $IMAGE_NAME
+  only:
+    - tags
+    - development
+
+#==[ Backend deployment ]=======================================================
+
+.be-deploy-job:
+  image: alpine:latest
+  stage: deploy
+  needs:
+    - job: be-build-job
+      artifacts: false
+  tags:
+    - commul
+  variables:
+    IMAGE_NAME: $CI_REGISTRY_IMAGE/backend
+  before_script:
+    - ./ci/install-kubectl-on-alpine.sh
+  script:
+    - kubectl set image deployment/${K8S_DEPLOYMENT} oetzi=${IMAGE_NAME}:${CI_COMMIT_SHA} --namespace=${K8S_NAMESPACE}
+
+be-prd-deploy-job:
+  extends: .be-deploy-job
+  environment:
+    name: production/backend
+    deployment_tier: production
+    url: https://kommul.eurac.edu/oetzi
+  variables:
+    K8S_NAMESPACE: kommul
+    K8S_DEPLOYMENT: oetzi-webserver-deployment
+  only:
+    - tags
+
+be-stg-deploy-job:
+  extends: .be-deploy-job
+  environment:
+    name: staging/backend
+    deployment_tier: staging
+    url: https://kommul-dev.eurac.edu/oetzi
+  variables:
+    K8S_NAMESPACE: kommul-dev
+    K8S_DEPLOYMENT: oetzi-webserver-deployment
+  only:
+    - development
+
+#==[ Frontend build ]===========================================================
+
+fe-build-job:
+  image: node:16-alpine
+  stage: build
+  tags:
+    - commul
+  cache:
+    - key:
+        files:
+          - frontend/package-lock.json
+      paths:
+        - frontend/node_modules
+  script:
+    - cd frontend
+    - npm install
+    - npm run build
+  artifacts:
+    paths:
+      - frontend/dist/
+    # TODO: set expiration in docker registry too
+    expire_in: 1 week
+  only:
+    - tags
+    - development
+
+#==[ Frontend deployment ]======================================================
+
+.fe-deploy-job:
+  image: alpine:latest
+  stage: deploy
+  needs:
+    - job: fe-build-job
+      artifacts: true
+  tags:
+    - commul
+  before_script:
+    - ./ci/install-butler-on-alpine.sh
+  script:
+    - >
+      butler push
+      frontend/dist
+      eurac/$GAME_NAME:html5
+      --userversion ${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
+
+fe-prd-deploy-job:
+  extends: .fe-deploy-job
+  environment:
+    name: production/frontend
+    deployment_tier: production
+    url: https://eurac.itch.io/oetzi
+  variables:
+    GAME_NAME: oetzi
+  only:
+    - tags
+
+fe-stg-deploy-job:
+  extends: .fe-deploy-job
+  environment:
+    name: staging/frontend
+    deployment_tier: staging
+    url: https://eurac.itch.io/oetzi-staging
+  variables:
+    GAME_NAME: oetzi-staging
+  only:
+    - development
diff --git a/ci/install-kubectl-on-alpine.sh b/ci/install-kubectl-on-alpine.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4260ff35a86a881ef010123cd83c6f5e0ee883ab
--- /dev/null
+++ b/ci/install-kubectl-on-alpine.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env sh
+
+set -e # exit of first error
+#set -o xtrace # trace commands
+
+echo "Installing kubectl..."
+
+KUBECTL_VERSION=v1.8.10
+KUBECTL_URL=https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl
+
+wget $KUBECTL_URL
+# NOTE: version is too ald and doesn't have sha256 available
+# wget https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl.sha256
+# echo "$(<kubectl.sha256)  kubectl" | sha256sum --check
+mv kubectl /usr/bin/
+chmod +x /usr/bin/kubectl
+
+echo "Configuring kubectl..."
+
+K8S_USER=gitlab-deploy
+K8S_CLUSTER=k8sproduction
+
+kubectl config \
+  set-cluster "$K8S_CLUSTER" \
+  --server="$KUBE_URL" \
+  --certificate-authority="$KUBE_CA_PEM_FILE"
+
+kubectl config \
+  set-credentials "$K8S_USER" \
+  --token="$K8S_PRODUCTION_TOKEN"
+
+kubectl config \
+  set-context "$CI_PROJECT_ID" \
+  --cluster="$K8S_CLUSTER" \
+  --user="$K8S_USER"
+
+kubectl config \
+  use-context "$CI_PROJECT_ID"