diff options
-rw-r--r-- | flake.nix | 15 | ||||
-rw-r--r-- | readme.md | 65 |
2 files changed, 79 insertions, 1 deletions
@@ -31,6 +31,9 @@ | |||
31 | develPackagesAndScripts = [ | 31 | develPackagesAndScripts = [ |
32 | postgresql_13 # PostgreSQL server with the standard admin tools. | 32 | postgresql_13 # PostgreSQL server with the standard admin tools. |
33 | python.pkgs.ipython # Interactive Python REPL for experimenting. | 33 | python.pkgs.ipython # Interactive Python REPL for experimenting. |
34 | heroku # CLI for the Heroku hosting platform. | ||
35 | skopeo # Docker container upload utility. | ||
36 | pwgen # Simple random token generator. | ||
34 | 37 | ||
35 | # More pleasant alternative to psql, with colours and auto-completion. | 38 | # More pleasant alternative to psql, with colours and auto-completion. |
36 | # Custom configuration to suppress irrelevant warnings and messages. | 39 | # Custom configuration to suppress irrelevant warnings and messages. |
@@ -92,7 +95,7 @@ | |||
92 | 95 | ||
93 | in { | 96 | in { |
94 | 97 | ||
95 | packages = { | 98 | packages = rec { |
96 | # Minimal production server. | 99 | # Minimal production server. |
97 | # This includes only application files tracked by git. | 100 | # This includes only application files tracked by git. |
98 | # Using `gunicorn` on top of `uvicorn` is recommended for bigger loads. | 101 | # Using `gunicorn` on top of `uvicorn` is recommended for bigger loads. |
@@ -100,6 +103,16 @@ | |||
100 | cd ${./.} | 103 | cd ${./.} |
101 | ${pythonWithDependencies}/bin/uvicorn --app-dir app app:main "$@" | 104 | ${pythonWithDependencies}/bin/uvicorn --app-dir app app:main "$@" |
102 | ''; | 105 | ''; |
106 | |||
107 | # Minimal docker image. | ||
108 | # The Heroku hosting service assigns the `$PORT` dynamically. | ||
109 | docker = dockerTools.streamLayeredImage { | ||
110 | maxLayers = 2; | ||
111 | name = "app-docker"; | ||
112 | config.EntryPoint = writeShellScript "run.sh" '' | ||
113 | ${server} --host 0.0.0.0 --port $PORT | ||
114 | ''; | ||
115 | }; | ||
103 | }; | 116 | }; |
104 | 117 | ||
105 | devShell = mkShell rec { | 118 | devShell = mkShell rec { |
@@ -349,6 +349,8 @@ course, asking students to deploy their application on the Internet could be a | |||
349 | motivational factor. It would also facilitate evaluating and grading projects, | 349 | motivational factor. It would also facilitate evaluating and grading projects, |
350 | avoiding deployment and testing hassles to the teaching staff. | 350 | avoiding deployment and testing hassles to the teaching staff. |
351 | 351 | ||
352 | #### Standard daemon | ||
353 | |||
352 | The Nix Flake provides a Nix package which can be used to run the web | 354 | The Nix Flake provides a Nix package which can be used to run the web |
353 | application in a production context as a [daemon], managed by a standard [init] | 355 | application in a production context as a [daemon], managed by a standard [init] |
354 | system. | 356 | system. |
@@ -356,6 +358,69 @@ system. | |||
356 | [daemon]: https://en.wikipedia.org/wiki/Daemon_(computing) | 358 | [daemon]: https://en.wikipedia.org/wiki/Daemon_(computing) |
357 | [init]: https://en.wikipedia.org/wiki/Init | 359 | [init]: https://en.wikipedia.org/wiki/Init |
358 | 360 | ||
361 | #### Docker container | ||
362 | |||
363 | A [Docker] container can also be derived from this package to be deployed on | ||
364 | popular cloud hosting services. | ||
365 | |||
366 | [Docker]: https://www.docker.com/resources/what-container | ||
367 | |||
368 | ##### Example of container deployment | ||
369 | |||
370 | An example of deployment procedure using the free tier provided by the [Heroku] | ||
371 | hosting service is given below. This makes use of the [skopeo] tool to upload | ||
372 | the Docker container to the service. | ||
373 | |||
374 | [Heroku]: https://www.heroku.com/ | ||
375 | [skopeo]: https://github.com/containers/skopeo | ||
376 | |||
377 | ```sh | ||
378 | # Log in to an Heroku account. | ||
379 | heroku login | ||
380 | |||
381 | # Create a new project with a random name, hosted somewhere in Europe. | ||
382 | heroku create --region eu | ||
383 | |||
384 | # Set a local environment variable with the assigned name of the project so | ||
385 | # that the next commands operate on it. | ||
386 | set --export HEROKU_APP 'name of the created app' | ||
387 | |||
388 | # Set a randomly-generated signed cookie secret key for our application. | ||
389 | heroku config:set COOKIE_SECRET_KEY=$(pwgen --secure 128 1) | ||
390 | |||
391 | # Attach a PostgreSQL database to the newly created app. | ||
392 | # This sets a connection URL in "DATABASE_URL" in the server's environment, | ||
393 | # containing the confidential database username and password. | ||
394 | heroku addons:create heroku-postgresql:hobby-dev --version=13 | ||
395 | |||
396 | # Create the tables in the database. | ||
397 | heroku psql < ./sql/tables.sql | ||
398 | |||
399 | # Prepare a Docker container. | ||
400 | # This creates a Docker archive streaming script as `./result`. | ||
401 | nix build .#docker | ||
402 | |||
403 | # Log in to the Heroku container registry to upload our container. | ||
404 | skopeo login --username _ --password $(heroku auth:token) registry.heroku.com | ||
405 | |||
406 | # Upload the Docker image to Heroku (uploading about ~200MB). | ||
407 | ./result \ | ||
408 | | gzip --fast \ | ||
409 | | skopeo --insecure-policy copy \ | ||
410 | docker-archive:/dev/stdin \ | ||
411 | docker://registry.heroku.com/$HEROKU_APP/web | ||
412 | |||
413 | # Deploy and launch the uploaded container. | ||
414 | heroku container:release web | ||
415 | |||
416 | # If all went well, the app should now be deployed and accessible on | ||
417 | # https://$HEROKU_APP.herokuapp.com | ||
418 | heroku open | ||
419 | |||
420 | # If not, logs can be remotely inspected for debugging. | ||
421 | heroku logs --tail | ||
422 | ``` | ||
423 | |||
359 | 424 | ||
360 | ## Copyright and licensing | 425 | ## Copyright and licensing |
361 | 426 | ||