diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..51f61a68527fc7f322404e11ec6f853830c95853
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,10 @@
+# Ignore everything
+*
+
+# Except for these files
+!/check
+!/orderedsql.sh
+!/sql
+!/upgrades
+!/LICENSE
+!/README.rst
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..20f79a297d1c37312a7c4788f244822037ca5390
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,33 @@
+stages:
+    - build
+
+variables:
+    DOCKER_REGISTRY: "reg.office.nic.cz"
+
+workflow:
+    auto_cancel:
+        on_new_commit: interruptible
+
+########################################################################################################################
+# Individual jobs
+docker:
+    stage: build
+    before_script:
+        - docker login --username "$DOCKER_USERNAME" --password "$DOCKER_TOKEN" "$DOCKER_REGISTRY"
+    script:
+        - FRED_DB_TAG="$IMAGE_TAG" docker compose build --no-cache --pull --push fred_db
+        # Only push `latest` when commit tag is the latest tag in the repository
+        - last_git_tag="$(git tag | grep -Ex '[0-9]+.[0-9]+.[0-9]+' | sort -Vr | head -n1)"
+        - if [ "$last_git_tag" = "$CI_COMMIT_TAG" ]; then FRED_DB_TAG="latest" docker compose build --push fred_db; fi
+    tags:
+        - dind
+    variables:
+        COMPOSE_FILE: "docker/devel/compose.yml"
+    needs: []
+    rules:
+        - if: $CI_COMMIT_TAG
+          variables:
+              IMAGE_TAG: "$CI_COMMIT_TAG"
+        - if: $CI_COMMIT_BRANCH == "master"
+          variables:
+              IMAGE_TAG: "master"
diff --git a/docker/devel/.dockerignore b/docker/devel/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..fcc7a24289d7185cbf192a820a0d8acf58ca36ca
--- /dev/null
+++ b/docker/devel/.dockerignore
@@ -0,0 +1,5 @@
+# Ignore everything
+*
+
+# Except for these files
+!/entrypoint-initdb.d
diff --git a/docker/devel/Dockerfile b/docker/devel/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..677506f80c8ea371b6b852ae7bf70ec3b1d77f8b
--- /dev/null
+++ b/docker/devel/Dockerfile
@@ -0,0 +1,5 @@
+FROM postgres:13
+
+COPY --from=config ./entrypoint-initdb.d/ /docker-entrypoint-initdb.d/
+COPY ./ /app
+WORKDIR /app
diff --git a/docker/devel/compose.yml b/docker/devel/compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..afb42adc943373d5903b177f11baa5f3c3e7734a
--- /dev/null
+++ b/docker/devel/compose.yml
@@ -0,0 +1,8 @@
+services:
+  fred_db:
+    image: reg.office.nic.cz/fred/db:${FRED_DB_TAG:-latest}
+    build:
+      context: ../..
+      dockerfile: docker/devel/Dockerfile
+      additional_contexts:
+        config: .
diff --git a/docker/devel/entrypoint-initdb.d/01_db.sh b/docker/devel/entrypoint-initdb.d/01_db.sh
new file mode 100644
index 0000000000000000000000000000000000000000..af42885adde32fc6e2fde2260cc5305d029062c8
--- /dev/null
+++ b/docker/devel/entrypoint-initdb.d/01_db.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+echo $PWD
+dsn="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST/$POSTGRES_DB"
+
+psql -v ON_ERROR_STOP=1 "$dsn" <<-EOSQL
+    CREATE DATABASE ${POSTGRES_FRED_DB:-fred};
+EOSQL
diff --git a/docker/devel/entrypoint-initdb.d/02_user.sh b/docker/devel/entrypoint-initdb.d/02_user.sh
new file mode 100644
index 0000000000000000000000000000000000000000..fd823d9f48c5664f1b465a8e8289d8ddac0c43fe
--- /dev/null
+++ b/docker/devel/entrypoint-initdb.d/02_user.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+echo $PWD
+dsn="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST/$POSTGRES_DB"
+
+psql -v ON_ERROR_STOP=1 "$dsn" <<-EOSQL
+    CREATE USER ${POSTGRES_FRED_USER:-fred} WITH PASSWORD '${POSTGRES_FRED_PASSWORD:-password}';
+    GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_FRED_DB:-fred} TO ${POSTGRES_FRED_USER:-fred};
+EOSQL
diff --git a/docker/devel/entrypoint-initdb.d/03_extensions.sh b/docker/devel/entrypoint-initdb.d/03_extensions.sh
new file mode 100644
index 0000000000000000000000000000000000000000..941b26b4ed5acb5fc90c5b55a495c5a4628db1f9
--- /dev/null
+++ b/docker/devel/entrypoint-initdb.d/03_extensions.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+echo $PWD
+dsn="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST/${POSTGRES_FRED_DB:-fred}"
+
+psql -v ON_ERROR_STOP=1 "$dsn" <<-EOSQL
+    CREATE EXTENSION pgcrypto;
+    CREATE EXTENSION pg_trgm;
+    CREATE EXTENSION unaccent;
+EOSQL
diff --git a/docker/devel/entrypoint-initdb.d/04_schema.sh b/docker/devel/entrypoint-initdb.d/04_schema.sh
new file mode 100644
index 0000000000000000000000000000000000000000..489aca7600e5af90dfae5389c536c6a49115c923
--- /dev/null
+++ b/docker/devel/entrypoint-initdb.d/04_schema.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -e
+echo "$PWD"
+dsn="postgresql://${POSTGRES_FRED_USER:-fred}:${POSTGRES_FRED_PASSWORD:-password}@$POSTGRES_HOST/${POSTGRES_FRED_DB:-fred}"
+
+WITH_LOGGER=${WITH_LOGGER:-1}
+if [[ "$WITH_LOGGER" -eq 1 ]]; then
+    /bin/bash ./orderedsql.sh | psql -v ON_ERROR_STOP=1 "$dsn"
+else
+    /bin/bash ./orderedsql.sh --without-log | psql -v ON_ERROR_STOP=1 "$dsn"
+fi