Add GitLab and GitLab Runner.

Change-Id: Iaf9bbf4567db2ee7c5b36c6be767825093a2881d
diff --git a/gitlab-system/gitlab-runner/.gitignore b/gitlab-system/gitlab-runner/.gitignore
new file mode 100644
index 0000000..91cc9ca
--- /dev/null
+++ b/gitlab-system/gitlab-runner/.gitignore
@@ -0,0 +1 @@
+/config.toml
diff --git a/gitlab-system/gitlab-runner/default.nix b/gitlab-system/gitlab-runner/default.nix
new file mode 100644
index 0000000..e98d43f
--- /dev/null
+++ b/gitlab-system/gitlab-runner/default.nix
@@ -0,0 +1,89 @@
+{ system ? builtins.currentSystem }:
+let
+  pkgs = import <nixpkgs> {
+    inherit system;
+    overlays = [
+      (self: super: {
+        docker = super.docker.override {
+          iptables = self.iptables-legacy;
+        };
+      })
+    ];
+  };
+
+in
+let
+  img = spec: {
+    streamed = pkgs.dockerTools.streamLayeredImage spec;
+    layered = pkgs.dockerTools.buildLayeredImage spec;
+    image = pkgs.dockerTools.buildImage spec;
+  };
+
+in
+let
+  init =
+    pkgs.writeShellScriptBin "init" ''
+      set -xeuo pipefail
+
+      if ! [ -e /vol/docker-data/docker.ext4 ]; then
+          ${pkgs.busybox}/bin/dd if=/dev/zero of=/vol/docker-data/docker.ext4 bs=1G count=0 seek=30
+          ${pkgs.e2fsprogs}/bin/mkfs.ext4 /vol/docker-data/docker.ext4
+      fi
+      ${pkgs.e2fsprogs}/bin/e2fsck -y /vol/docker-data/docker.ext4
+      ${pkgs.busybox}/bin/mkdir -p /var/lib/docker
+      ${pkgs.busybox}/bin/mount -o loop,rw /vol/docker-data/docker.ext4 /var/lib/docker
+
+      ${pkgs.docker}/bin/dockerd --storage-driver=overlay2 &
+      sleep 10s
+
+      ${pkgs.docker}/bin/docker kill $(${pkgs.docker}/bin/docker ps -a -q) || :
+      ${pkgs.docker}/bin/docker system prune --volumes --force || :
+
+      exec ${pkgs.gitlab-runner}/bin/gitlab-runner run
+    '';
+
+  src = ./.;
+
+  extraDeps = with pkgs; [
+    # for Docker
+    cacert
+
+    # for GitLab runner
+    docker
+  ];
+
+  maintenanceDeps = with pkgs; [
+    bash
+    busybox
+    coreutils
+    findutils
+    pxattr
+    strace
+  ];
+
+in
+img {
+  name = "docker.benkard.de/mulk/gitlab-runner";
+  #tag = "latest";
+  maxLayers = 125;
+  contents = extraDeps ++ maintenanceDeps;
+  extraCommands =
+    ''
+      #!${pkgs.runtimeShell}
+
+      install -dm755 etc/gitlab-runner
+      install -dm755 vol/docker-data
+      install -dm755 tmp
+
+      cp -a ${src}/* .
+    '';
+  config = {
+    Entrypoint = [ "${init}/bin/init" ];
+    Cmd = [ ];
+    Workdir = "/";
+    Volumes = {
+      "/etc/gitlab-runner" = { };
+      "/vol/docker-data" = { };
+    };
+  };
+}
diff --git a/gitlab-system/gitlab-runner/gitlab-runner.yaml b/gitlab-system/gitlab-runner/gitlab-runner.yaml
new file mode 100644
index 0000000..c562d69
--- /dev/null
+++ b/gitlab-system/gitlab-runner/gitlab-runner.yaml
@@ -0,0 +1,88 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: gitlab-runner
+  namespace: mulk
+  labels:
+    name: gitlab-runner
+    k8s-app: gitlab-runner
+
+spec:
+  replicas: 1
+
+  strategy:
+    rollingUpdate:
+      maxSurge: 1
+      maxUnavailable: 1
+
+  selector:
+    matchLabels:
+      k8s-app: gitlab-runner
+      name: gitlab-runner
+
+  template:
+    metadata:
+      labels:
+        name: gitlab-runner
+        k8s-app: gitlab-runner
+
+    spec:
+      imagePullSecrets:
+        - name: portus-token
+
+      runtimeClassName: kata
+
+      containers:
+        - name: master
+          image: docker.benkard.de/mulk/gitlab-runner:miyj7qdmgdbbqk7zkj3wdq0ld9zxdk2z
+
+          securityContext:
+            # In a Kata container, this only gives the container full
+            # access to the guest VM rather than the host.  (To ensure
+            # this, it is important to set privileged_without_host_devices
+            # = true in the [plugins.cri.containerd.runtimes.kata] section
+            # of containerd's config.toml.)
+            privileged: true
+
+          volumeMounts:
+            # Configuration data.
+            - name: config
+              mountPath: /etc/gitlab-runner
+
+            # State.
+            - name: docker-data
+              mountPath: /vol/docker-data
+            - name: tmp
+              mountPath: /tmp
+
+          resources:
+            limits:
+              memory: 4G
+
+      volumes:
+        - name: config
+          secret:
+            secretName: gitlab-runner-config
+        - name: docker-data
+          persistentVolumeClaim:
+            claimName: gitlab-runner-docker
+        - name: tmp
+          emptyDir: {}
+
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: gitlab-runner-docker
+  namespace: mulk
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi