diff --git a/ChangeLog.md b/ChangeLog.md index 79da3b398..b8a77fd27 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,6 +14,7 @@ This project's release branch is `master`. This log is written from the perspect * Use `--keep NIX_PATH` for all pure shells so references to `` continues to work. * Backport ACMEv2 support in obelisk server to regain LetsEncrypt account creation. * Enable https in `ob run` +* Add Docker support, for building minimal and customizable images ## v0.2.0.0 - 2019-8-17 diff --git a/README.md b/README.md index c0d3d54d1..8af6fe8ce 100644 --- a/README.md +++ b/README.md @@ -345,3 +345,61 @@ This should copy over and install the application on your device (if you see a ##### Build a release version After having configured signing for your app, you may proceed to build a release version of the app. This is no different to how you build the non-release version, so consult the section [Android](#android) further above for exact instructions on building and deploying to your device. + + +## Docker + +### Variables + +Setting the following environment variables will be helpful for keeping build and run parameters consistent: + +```bash +export NAME=app +export VERSION=$(git rev-parse HEAD) +export CONFIGDIR=/path/to/obelisk/config +``` + +### Building + +#### Default + +To build a Docker image using a default configuration, run: +``` +docker load < $(nix-build -A dockerImage --no-out-link --argstr name $NAME --argstr version $VERSION) +``` + +#### Custom + +To build with a custom configuration, Obelisk's default configuration can be imported and overriden in a `release.nix` file added to your top-level directory: + +```nix +{ }: +let + project = import ./. {}; + obelisk = import ./.obelisk/impl { + system = builtins.currentSystem; + }; + mkBaseDockerImageConfig = { version }: obelisk.dockerImageConfig { + name = "app"; + exe = project.linuxExe; + version = version; + }; +in { + customDockerImage = args@{ version ? "latest" }: + obelisk.nixpkgs.dockerTools.buildImage (mkBaseDockerImageConfig args // { + config.expose = 3000; # overriding default port 8000 + }); +} +``` + +The custom image can then be built with: `nix-build release.nix -A customDockerImage --no-out-link --argstr version $VERSION` + +### Running + +Using the default configuration, the image can then be run with: + +```bash +docker run -p 127.0.0.1:8000:8000/tcp --volume "$CONFIGDIR:/var/run/backend/config" "${NAME}:${VERSION}" +``` + +And the application should be accessible at `http://localhost:8000`. \ No newline at end of file diff --git a/default.nix b/default.nix index 115b5edff..ce85db460 100644 --- a/default.nix +++ b/default.nix @@ -224,6 +224,35 @@ in rec { }; }; + dockerImageConfig = args@{exe, name, version, extraContents ? [], extraPaths ? []}: + let + appDirSetupScript = nixpkgs.runCommand "appDirSetupScript.sh" {} '' + mkdir -p $out/var/lib/backend + ln -sft $out/var/lib/backend '${exe}'/* + ${nixpkgs.findutils}/bin/find $out/var/lib/backend + ''; + in { + name = name; + tag = version; + contents = [ nixpkgs.iana-etc nixpkgs.cacert appDirSetupScript ] ++ extraContents; + keepContentsDirlinks = true; + config = { + Env = [ + ("PATH=" + builtins.concatStringsSep(":")(extraPaths ++ [ + "/var/lib/backend" # put the obelisk project on the path. + "/bin" # put contents on path + ] ++ map (pkg: "${pkg}/bin") pkgs.stdenv.initialPath # put common tools in path so docker exec is useful + )) + ]; + Expose = 8000; + Entrypoint = ["/var/lib/backend/backend"]; + WorkingDir = "/var/lib/backend"; + User = "99:99"; + }; + }; + + dockerImage = args: nixpkgs.dockerTools.buildImage (dockerImageConfig args); + serverExe = backend: frontend: assets: optimizationLevel: version: pkgs.runCommand "serverExe" {} '' mkdir $out @@ -349,6 +378,8 @@ in rec { exe = serverOn system dummyVersion; server = args@{ hostName, adminEmail, routeHost, enableHttps, version }: server (args // { exe = linuxExe version; }); + dockerImage = args@{ name, version }: + dockerImage (args // { exe = linuxExe version; }); obelisk = import (base + "/.obelisk/impl") {}; }; haskellPackageSets = {