From e033cc74216a385de0323b6462504cb8b6d8e227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Choutri?= Date: Thu, 30 Dec 2021 15:55:24 +0100 Subject: [PATCH] Docker setup (#54) * Added Dockerfile and updated README.md accordingly The Dockerfile is a minimal setup to construct a layered docker image, which automatically launches into the nix-shell when executed interactively. The README.md now contains basic instructions about how to build and run the image, although it does not yet specify how to e.g. sync the database files to be persistent or other niceties. --- .dockerignore | 2 ++ .github/workflows/ci.yml | 13 +++++++++---- Dockerfile | 21 +++++++++++++++++++++ Makefile | 32 +++++++++++++++++++++++--------- README.md | 31 +++++++++++++++++++++++++++++++ database.env | 3 +++ default.nix | 6 ++++++ docker-compose.yml | 25 +++++++++++++++++++++++++ environment.docker.sh | 9 +++++++++ environment.sh | 2 +- nix/pin.nix | 2 +- nix/pkgs.nix | 3 +-- scripts/start-tmux.sh | 14 ++++++++++++++ shell.nix | 7 +++++++ 14 files changed, 153 insertions(+), 17 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 database.env create mode 100644 docker-compose.yml create mode 100755 environment.docker.sh create mode 100755 scripts/start-tmux.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..dff38d74 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ + +assets/node_modules \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 029823ab..ab6487fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,17 +9,22 @@ jobs: tests: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v2.3.1 - - name: Local cache - uses: actions/cache@v2 + + - name: Cache install Nix packages + uses: rikhuijzer/cache-install@v1.0.8 with: - path: /nix/store - key: "${{ runner.os }}-nix-cache" + key: nix-${{ hashFiles('default.nix') }} - uses: cachix/install-nix-action@v12 with: nix_path: nixpkgs=channel:nixos-unstable + - uses: cachix/cachix-action@v10 + with: + name: flora-pm + - run: nix-build nix/ci.nix - run: nix-shell --run "echo OK" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..2ea164e6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:1 +FROM nixos/nix + +RUN nix-channel --update +RUN nix-env -iA nixpkgs.gnumake + +# generate a working directory +WORKDIR /flora-server + +# copy the files relevant to build core dependencies +COPY default.nix flora.cabal shell.nix environment.sh environment.docker.sh Makefile scripts/start-tmux.sh ./ +COPY nix/ ./nix/ + +# let nix build the dependencies. This uses nix-shell to cache the setup phase. +RUN nix-shell + +# copy asset-relevant dependency files +COPY assets/package.json assets/yarn.lock assets/ +RUN nix-shell --run "make assets-deps" + +CMD [ "/bin/sh", "-c", "sleep 1d"] diff --git a/Makefile b/Makefile index 46511579..a0bd9f0a 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,6 @@ assets-watch: ## Continuously rebuild the web assets assets-clean: ## Remove JS artifacts @cd assets/ && rm -R node_modules -db-init: ## Initialize the dev database - @initdb -D _database - -db-start: ## Start the dev database - @postgres -D _database - db-create: ## Create the database @createdb -h $(FLORA_DB_HOST) -p $(FLORA_DB_PORT) -U $(FLORA_DB_USER) $(FLORA_DB_DATABASE) @@ -35,7 +29,9 @@ db-setup: db-create ## Setup the dev database @migrate init "$(FLORA_PG_CONNSTRING)" @migrate migrate "$(FLORA_PG_CONNSTRING)" migrations -db-reset: db-drop db-setup ## Reset the dev database +db-reset: db-drop db-setup db-provision ## Reset the dev database (uses Cabal) + +db-provision: ## Load the development data in the database @cabal run -- flora-cli provision-fixtures repl: ## Start a REPL @@ -60,15 +56,33 @@ style: ## Run the code formatters (stylish-haskell, cabal-fmt, nixfmt) @cabal-fmt -i flora.cabal @nixfmt *.nix nix/*.nix +nix-build: ## Build the backend with Nix + @nix-build + +nix-start: ## Start the server build with Nix. Does not source the environment. + ./result/bin/flora-server + nix-shell: ## Enter the Nix shell @nix-shell +nix-provision: ## + ./result/bin/flora-cli provision-fixtures + nix-clean: ## Clean the Nix build artifacts @nix-store --delete --ignore-liveness result @rm result -nix-build: ## Build the backend with Nix - @nix-build +nix-tmux: nix-build ## Start a tmux session with the nix build system + @./scripts/start-tmux.sh + +docker-build: ## Build the docker image + @docker-compose build + +docker-start: ## Start the container cluster + @docker-compose up -d + +docker-enter: ## Enter the docker environment + docker-compose exec flora-server "nix-shell" tags: @ghc-tags -c diff --git a/README.md b/README.md index ad496849..ce834ac5 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,14 @@ For ease of development, a `shell.nix` file is provided. It brings with it syste To jump into the development environment, use `make nix-shell`. It is impure by default, so your editor and development tools will still be accessible. +## Installing using Docker instead + +If you are using an environment that is not friendly to nix, like MacOS, you may want to use Docker instead. + +To build the image, run `docker build -t flora-server .`. The build will take a while to download and set up dependencies the first time it is run, but subsequent builds should be significantly faster. + +The image is set up to run the nix-shell on boot, so once the build is complete simply run `docker run -it -p 8083:8083 --rm flora-server`. Then you should be able to build the server itself by `nix-build`, or use any of the `make` commands as described below. + ### Flora server Configuration is handled through environment variables. They are all prefixed by `FLORA_` to avoid conflict, and the @@ -55,6 +63,29 @@ $ make db-setup # Implies db-create you can also use `db-create` and `db-drop` to create and delete the database in the PostgreSQL instance. +### Docker Workflow + +A docker-based workflow is provided: + +```bash +# It's gonna take around 13 minutes the first time you build, +# run "make docker-start" the next times. +$ docker-compose up -d --build +$ make docker-enter +# You'll be in the docker container +(docker)$ source environment.docker.sh +(docker)$ make nix-tmux +# You'll be in a tmux session, everything should be launched +# Visit localhost:8084 from your web browser to see if it all works. + +# To provision the development database, type: +$ make docker-enter +(docker)$ source environment.docker.sh +(docker)$ make db-drop +(docker)$ db-setup # password is 'postgres' by default +(docker)$ make nix-provision +# And you should be good! +``` --- You can explore the Makefile rules by typing `make` in your shell. diff --git a/database.env b/database.env new file mode 100644 index 00000000..38a6d2f6 --- /dev/null +++ b/database.env @@ -0,0 +1,3 @@ +POSTGRES_USER="postgres" +POSTGRES_PASSWORD="postgres" +POSTGRES_DB="flora_dev" \ No newline at end of file diff --git a/default.nix b/default.nix index e5840bff..8b55eec7 100644 --- a/default.nix +++ b/default.nix @@ -13,5 +13,11 @@ let in pkgs.haskell.lib.overrideCabal cabal2nix (drv: { inherit src; + doBenchmark = false; + doCheck = true; # Run the flora tests + doHaddock = false; + doHoogle = false; + enableExecutableProfiling = false; + enableLibraryProfiling = false; isExecutable = true; }) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..b0a7dd1a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: "3" +services: + flora-server: + build: . + container_name: flora-server + ports: + - "8084:8084" + volumes: + - database-data:/flora-server/pgdata/ + - .:/flora-server:Z + links: + - database + + database: + image: "postgres" + container_name: database + expose: + - "5432" + env_file: + - database.env + volumes: + - database-data:/flora-server/pgdata/ + +volumes: + database-data: diff --git a/environment.docker.sh b/environment.docker.sh new file mode 100755 index 00000000..e256c55a --- /dev/null +++ b/environment.docker.sh @@ -0,0 +1,9 @@ +source environment.sh + +export FLORA_DB_HOST="database" + +export FLORA_PG_URI="postgresql://${FLORA_DB_USER}:${FLORA_DB_PASSWORD}@${FLORA_DB_HOST}:${FLORA_DB_PORT}/${FLORA_DB_DATABASE}" +export FLORA_PG_CONNSTRING="host=${FLORA_DB_HOST} dbname=${FLORA_DB_DATABASE} user=${FLORA_DB_USER} password=${FLORA_DB_PASSWORD}" + + +export FLORA_HTTP_PORT=8084 diff --git a/environment.sh b/environment.sh index 9cca68ed..f2ba703e 100755 --- a/environment.sh +++ b/environment.sh @@ -13,7 +13,7 @@ export FLORA_PG_URI="postgresql://${FLORA_DB_USER}:${FLORA_DB_PASSWORD}@${FLORA_ export FLORA_PG_CONNSTRING="host=${FLORA_DB_HOST} dbname=${FLORA_DB_DATABASE} user=${FLORA_DB_USER} password=${FLORA_DB_PASSWORD}" export FLORA_HTTP_PORT=8083 -export FLORA_ENVIRONMENT="local" +export FLORA_ENVIRONMENT="development" export FLORA_DOMAIN="localhost" diff --git a/nix/pin.nix b/nix/pin.nix index decc2e55..2b5aef6a 100644 --- a/nix/pin.nix +++ b/nix/pin.nix @@ -1,4 +1,4 @@ import (builtins.fetchTarball { url = - "https://github.com/NixOS/nixpkgs/archive/2c2a09678ce2ce4125591ac4fe2f7dfaec7a609c.tar.gz"; + "https://github.com/NixOS/nixpkgs/archive/589ce6d8899f9800cb90d85618cf46026a8d784d.tar.gz"; }) diff --git a/nix/pkgs.nix b/nix/pkgs.nix index 0dd60514..75639204 100644 --- a/nix/pkgs.nix +++ b/nix/pkgs.nix @@ -38,11 +38,10 @@ import ./pin.nix { prometheus-client = hpNew.callHackage "prometheus-client" "1.1.0" { }; - PyF = hpOld.callHackage "PyF" "0.10.1.0" { }; + PyF = hpOld.callHackage "PyF" "0.10.2.0" { }; data-sketches = hpOld.callHackage "data-sketches" "0.3.1.0" { }; pcre2 = hpOld.callHackage "pcre2" "2.0.3" { }; optics-core = hpOld.callHackage "optics-core" "0.4" { }; - # PyF = hpOld.callHackage "PyF" "0.10.2.0" { }; lucid = hpOld.callHackage "lucid" "2.11.0" { }; servant-lucid = hpNew.callCabal2nix "servant-lucid" (fetchTarball { url = diff --git a/scripts/start-tmux.sh b/scripts/start-tmux.sh new file mode 100755 index 00000000..94229f41 --- /dev/null +++ b/scripts/start-tmux.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +tmux kill-session -t 'flora' || true +tmux new-session -d -s 'flora' +tmux rename-window 'flora' +sleep 1 +tmux send-keys -t "flora" 'make nix-start' 'C-m' +tmux select-window -t flora:0 +sleep 1 +tmux split-window -h 'make assets-watch' +tmux send-keys -t "flora" 'C-b' +tmux attach-session -t flora diff --git a/shell.nix b/shell.nix index 36d4ef2c..140fba42 100644 --- a/shell.nix +++ b/shell.nix @@ -17,6 +17,10 @@ pkgs.haskellPackages.shellFor { pkgs.concurrently pkgs.esbuild pkgs.nodePackages.postcss-cli + pkgs.iputils + pkgs.tmux + pkgs.bash + pkgs.nixfmt ]; exactDeps = true; NIX_PATH = "nixpkgs=${pkgs.path}:."; @@ -24,5 +28,8 @@ pkgs.haskellPackages.shellFor { source environment.sh export LOCALE_ARCHIVE="/nix/store/m53mq2077pfxhqf37gdbj7fkkdc1c8hc-glibc-locales-2.27/lib/locale/locale-archive" export LC_ALL=C.UTF-8 + printf "To start the server: \'make nix-build && make nix-start\'\n" + printf "To start the assets pipeline: \'make assets-watch\'\n" + printf "Happy hacking!\n" ''; }