Skip to content

Commit fb17c1d

Browse files
authored
Add Docker Compose profiles for dev and prod server setups (#198)
Since we are moving towards always running against Postgres, just using `lnt runserver` without any Postgres server will eventually stop being supported. To avoid creating a barrier for running local instances, I want to make it easier to run a "real" server locally backed by Postgres. To do that, the easiest way is to simplify the Docker Compose setup so that a full service can be brought up for local development in a single command. This is achieved using profiles: - Default (no profile): starts db + webserver, built from source, bound to localhost:8000. Suitable for local development: docker compose -f docker/compose.yaml --env-file docker/dev.env up - prod profile: adds Nginx reverse proxy on port 80. The production deployment uses docker/compose.prod.yaml as an override to pull the pre-built LNT image from ghcr.io and bind volumes to the host filesystem, like it used to.
1 parent 7d6146e commit fb17c1d

9 files changed

Lines changed: 90 additions & 98 deletions

File tree

deployment/compose.env.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ LNT_DB_PASSWORD=${__db_password__}
22
LNT_AUTH_TOKEN=${__auth_token__}
33
LNT_IMAGE=${__lnt_image__}
44
LNT_NGINX_CONFIG=${__lnt_nginx_config__}
5-
LNT_EXTERNAL_PORT=${__lnt_external_port__}
5+
LNT_NGINX_EXTERNAL_PORT=${__lnt_nginx_external_port__}

deployment/compose.prod.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#
2+
# This file contains overrides for production deployments of LNT:
3+
# - Bind volumes inside the Docker container to the EC2 host filesystem
4+
# (e.g. /var/lib/lnt -> /var/lib/lnt) for ease of access.
5+
# - Pull a pre-built image of the LNT webserver instead of building from source.
6+
# This allows controling the version of LNT used from Terraform.
7+
#
8+
9+
services:
10+
webserver:
11+
build: !reset
12+
image: ghcr.io/llvm/llvm-lnt:${LNT_IMAGE:-latest}
13+
14+
volumes:
15+
instance:
16+
driver: local
17+
driver_opts:
18+
o: bind
19+
type: none
20+
device: /var/lib/lnt
21+
22+
database:
23+
driver: local
24+
driver_opts:
25+
o: bind
26+
type: none
27+
device: /var/lib/postgresql

deployment/ec2-volume-mapping.yaml

Lines changed: 0 additions & 20 deletions
This file was deleted.

deployment/main.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ data "cloudinit_config" "startup_scripts" {
8181
content = file("${path.module}/../docker/compose.yaml")
8282
},
8383
{
84-
path = "/etc/lnt/ec2-volume-mapping.yaml"
84+
path = "/etc/lnt/compose.prod.yaml"
8585
permissions = "0400" # read-only for owner
86-
content = file("${path.module}/ec2-volume-mapping.yaml")
86+
content = file("${path.module}/compose.prod.yaml")
8787
},
8888
{
8989
path = "/etc/lnt/compose.env"
@@ -93,7 +93,7 @@ data "cloudinit_config" "startup_scripts" {
9393
__auth_token__ = local.lnt_auth_token,
9494
__lnt_image__ = local.lnt_image,
9595
__lnt_nginx_config__ = "/etc/lnt/nginx.conf",
96-
__lnt_external_port__ = local.lnt_external_port,
96+
__lnt_nginx_external_port__ = local.lnt_external_port,
9797
})
9898
},
9999
{

deployment/on-ec2-boot.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fi
3232

3333
echo "Starting LNT service with Docker compose"
3434
docker compose --file /etc/lnt/compose.yaml \
35-
--file /etc/lnt/ec2-volume-mapping.yaml \
35+
--file /etc/lnt/compose.prod.yaml \
36+
--profile nginx \
3637
--env-file /etc/lnt/compose.env \
3738
up

docker/compose.yaml

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
# This file composes a full service running LNT. A LNT service is comprised
2-
# of a container running a Postgres database, a container running a Nginx
3-
# reverse proxy and a container running a LNT webserver using gunicorn.
1+
# This file composes a full service running LNT. A LNT service is comprised of:
2+
# - A container running a Postgres database
3+
# - A LNT webserver using gunicorn connected to that database
4+
# - Optionally, a Nginx reverse proxy in front of the webserver
5+
#
6+
# The webserver is built from source and binds to localhost:8000, which is useful
7+
# for local development.
8+
#
9+
# When desired, the 'nginx' profile can be used, which adds the Nginx reverse proxy.
410
#
511
# In order to compose the full service, some secrets are required. They are taken
612
# as environment variables, which means they can be stored in a file and included
@@ -13,33 +19,26 @@
1319
# The authentication token used to require authentication to
1420
# perform destructive actions.
1521
#
16-
# Additionally, the following aspects of the container can be customized:
17-
#
18-
# LNT_IMAGE
19-
# The version of the llvm-lnt webserver image used for the service.
20-
# Defaults to 'latest'.
22+
# Additionally, the following aspects can be customized:
2123
#
2224
# LNT_NGINX_CONFIG
23-
# The path to the configuration file to use for Nginx. By default, the nginx
24-
# configuration in this source tree is used, however this must be specified
25-
# whenever running from a host where the source tree is not available, or
26-
# when a fundamentally different configuration is desired.
25+
# The path to the configuration file to use for Nginx. By default, './nginx.conf'
26+
# is used, however this must be specified whenever running from a host where the
27+
# source tree is not available, or when a fundamentally different configuration
28+
# is desired.
2729
#
28-
# LNT_EXTERNAL_PORT
29-
# The externally-visible port that will be exposed by the service to interact
30-
# with the webserver. This defaults to '8000', which is consistent with what
31-
# LNT uses by default for local servers and development.
30+
# LNT_NGINX_EXTERNAL_PORT
31+
# The externally-visible port that will be exposed by the Nginx reverse proxy.
32+
# This defaults to '80', which is the convention for HTTP servers.
3233

3334
name: llvm-lnt
3435

3536
services:
3637
webserver:
3738
container_name: webserver
38-
image: ghcr.io/llvm/llvm-lnt:${LNT_IMAGE:-latest}
39-
# Useful for local debugging
40-
# build:
41-
# context: ../
42-
# dockerfile: docker/lnt.dockerfile
39+
build:
40+
context: ../
41+
dockerfile: docker/lnt.dockerfile
4342
environment:
4443
- DB_USER=lntuser
4544
- DB_HOST=dbserver
@@ -56,9 +55,7 @@ services:
5655
condition: on-failure
5756
volumes:
5857
- instance:/var/lib/lnt
59-
# Only expose this port to the internal Docker network, but not to
60-
# the outside world.
61-
expose:
58+
ports:
6259
- "8000"
6360
networks:
6461
- lnt_network
@@ -78,17 +75,16 @@ services:
7875
- lnt_network
7976

8077
nginx:
78+
profiles: [nginx]
8179
container_name: nginx_reverse_proxy
8280
image: docker.io/nginx:latest
8381
restart: unless-stopped
8482
volumes:
8583
- ${LNT_NGINX_CONFIG:-./nginx.conf}:/etc/nginx/conf.d/default.conf:ro
8684
depends_on:
8785
- webserver
88-
# The Nginx server listens to port 80 inside the container, but exposes
89-
# the specified port to the outside world.
9086
ports:
91-
- "${LNT_EXTERNAL_PORT:-8000}:80"
87+
- "${LNT_NGINX_EXTERNAL_PORT:-80}:80"
9288
networks:
9389
- lnt_network
9490
logging:

docker/dev.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
LNT_DB_PASSWORD=dev-password
2+
LNT_AUTH_TOKEN=dev-token

docker/lnt.dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# This Dockerfile defines an image that contains a production LNT server.
1+
# This Dockerfile defines an image that contains a minimal LNT server.
22
# It requires additional information passed as environment variables:
33
#
44
# DB_USER

docs/running_server.rst

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,51 @@
33
Running a LNT Server
44
====================
55

6-
Running a LNT server locally is easy and can be sufficient for basic tasks. To do
7-
so:
6+
We provide a Docker Compose service that brings up a LNT web server attached
7+
to a Postgres database. To start the server, run::
88

9-
#. Install ``lnt`` as explained in the :ref:`installation section <installation>`.
10-
11-
#. Create a LNT installation::
12-
13-
lnt create path/to/installation
14-
15-
This will create the LNT configuration file and the default database at the
16-
specified path.
17-
18-
#. You can then run the server on that installation::
9+
docker compose -f docker/compose.yaml --env-file docker/dev.env up
1910

20-
lnt runserver path/to/installation
11+
Once the server is running, you are ready to submit data to it. See the section
12+
on :ref:`importing data <importing_data>` for details.
2113

22-
Note that running the server in this way is not recommended for production, since
23-
this server is single-threaded and uses a SQLite database.
14+
The ``dev.env`` file provides default secrets suitable for local use. For your
15+
own deployment, create an env file with your own values for ``LNT_DB_PASSWORD``
16+
and ``LNT_AUTH_TOKEN``. Refer to the Docker Compose file for all available
17+
environment variables.
2418

25-
#. You are now ready to submit data to the server. See the section on :ref:`importing data <importing_data>`
26-
for details.
19+
Adding an Nginx Reverse Proxy
20+
-----------------------------
2721

28-
#. While the above is enough for most use cases, you can also customize your installation.
29-
To do so, edit the generated ``lnt.cfg``, for example to:
22+
To add an Nginx reverse proxy in front of the webserver (as done for the
23+
lnt.llvm.org deployment), use the ``nginx`` profile::
3024

31-
a. Update the databases list.
32-
b. Update the public URL the server is visible at.
33-
c. Update the ``nt_emailer`` configuration.
25+
docker compose -f docker/compose.yaml --profile nginx --env-file <env-file> up
3426

27+
This starts the Nginx service on port 80 (configurable via
28+
``LNT_NGINX_EXTERNAL_PORT``) in addition to the database and webserver.
3529

36-
Server Architecture
37-
-------------------
30+
Running without Docker
31+
----------------------
3832

39-
The LNT web app is currently implemented as a Flask WSGI web app, with Jinja2
40-
for the templating engine. The hope is to eventually move to a more AJAXy web
41-
interface. The database layer uses SQLAlchemy for its ORM, and is typically
42-
backed by SQLite or Postgres.
33+
Running a ``lnt`` server outside Docker is possible too:
4334

44-
Running a Production Server on Docker
45-
-------------------------------------
35+
#. Install ``lnt`` as explained in the :ref:`installation section <installation>`.
4636

47-
We provide a Docker Compose service that can be used to easily bring up a fully working
48-
production server within minutes. The service can be built and run with::
37+
#. Create a LNT installation::
4938

50-
docker compose --file docker/compose.yaml --env-file <env-file> up
39+
lnt create path/to/installation
5140

52-
``<env-file>`` should be the path to a file containing environment variables
53-
required by the containers. Please refer to the Docker Compose file for details.
54-
This service runs a Nginx server that acts as a reverse proxy for the LNT web
55-
server, which is itself attached to a Postgres database. For production use, we
56-
recommend using this service and tweaking the desired aspects in your custom setup
57-
(for example redirecting ports or changing volume binds).
41+
#. You can then run the server on that installation::
5842

59-
Rebuilding the LNT Webserver Docker Image
60-
-----------------------------------------
43+
lnt runserver path/to/installation
6144

62-
By default, the Docker compose setup will use a published version of the LNT
63-
Docker image from ghcr.io. To use a locally-built Docker image instead, use::
45+
Note that running the server in this way is not recommended for production, since
46+
it runs a single-threaded Flask server instead of running behind ``gunicorn``.
6447

65-
docker build --file docker/lnt.dockerfile .
48+
Server Architecture
49+
-------------------
6650

67-
and then replace the Docker image in the Docker compose file.
51+
The LNT web app is implemented as a Flask WSGI web app, with Jinja2 for the
52+
templating engine. The database layer uses SQLAlchemy for its ORM, backed by
53+
Postgres.

0 commit comments

Comments
 (0)