Skip to content

Commit 7c7dfd0

Browse files
committed
#510 add Docker Multi Stage build, slim image from 977 to 561MB, run Containers non-root
1 parent 6ea0ef5 commit 7c7dfd0

16 files changed

Lines changed: 153 additions & 120 deletions

.dockerignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# VCS
22
.git
33
.gitignore
4+
.github
45

56
# Local pixi environment (built inside the image via `pixi install`)
67
.pixi
@@ -10,7 +11,12 @@ instance
1011
report.md
1112
docs/_build
1213
GeoHealthCheck/static/lib
13-
GeoHealthCheck/data.db
14+
!GeoHealthCheck/static/lib/jqueryui
15+
!GeoHealthCheck/static/lib/jspark
16+
GeoHealthCheck/static/docs
17+
**/data.db
18+
*.log
19+
**/*.log
1420

1521
# Tooling / caches
1622
.pytest_cache

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,13 @@ instance
5858
tmp/
5959
GeoHealthCheck/static/docs
6060
GeoHealthCheck/static/lib
61+
!GeoHealthCheck/static/lib/jqueryui
62+
!GeoHealthCheck/static/lib/jspark
6163
GeoHealthCheck.wsgi
6264
GeoHealthCheck.conf
6365

6466
# Data
65-
GeoHealthCheck/data.db
67+
data.db
6668
# test report
6769
report.md
6870

Dockerfile

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,67 @@
1-
FROM ghcr.io/prefix-dev/pixi:0.72.0-noble
1+
FROM ghcr.io/prefix-dev/pixi:0.72.2-noble AS build
2+
3+
# ARGS
4+
ARG LANGUAGE="en_US"
5+
ARG ENCODING="UTF-8"
6+
7+
ENV LOCALE_STR="${LANGUAGE}.${ENCODING} ${ENCODING}" \
8+
DEBIAN_FRONTEND=noninteractive
9+
10+
# Install and Configure default locale
11+
# NB GHC has its own language handlling via Babel.
12+
RUN apt update -y \
13+
&& apt install -y locales \
14+
&& echo "${LOCALE_STR}" > /etc/locale.gen \
15+
&& locale-gen \
16+
&& rm -rf /var/lib/apt/lists/*
17+
18+
WORKDIR /app
19+
COPY . .
20+
21+
RUN pixi install -e prod --locked
22+
RUN echo '#!/bin/bash' > /app/pixi-env.sh
23+
RUN pixi shell-hook -e prod -s bash --as-is >> /app/pixi-env.sh
24+
RUN echo 'exec "$@"' >> /app/pixi-env.sh
25+
RUN echo chmod +x /app/pixi-env.sh
26+
RUN pixi run -e prod setup
27+
RUN cp docker/config_site.py instance/
28+
RUN if [ -d docker/plugins ]; then cp -ar docker/plugins/* /app/GeoHealthCheck/plugins/; fi
29+
30+
# Slim down, removing unused files generated within build
31+
RUN rm -rf /app/GeoHealthCheck/docs
32+
RUN find /app/GeoHealthCheck/static/lib -type d -name docs | xargs rm -rf
33+
RUN find /app/GeoHealthCheck/static/lib -type d -name src | xargs rm -rf
34+
35+
FROM ubuntu:24.04 AS production
236

337
# Credits to yjacolin for providing first versions
438
LABEL original_developer="yjacolin <yves.jacolin@camptocamp.com>" \
539
maintainer="Just van den Broecke <justb4@gmail.com>"
640

41+
# Copy the compiled locale files from the builder
42+
COPY --from=build /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive
43+
COPY --from=build /etc/locale.gen /etc/locale.gen
44+
COPY --from=build /etc/default/locale /etc/default/locale
45+
746
# These are default values,
847
# Override when running container via docker(-compose)
948

10-
# ARGS
11-
ARG TZ="Etc/UTC"
12-
ARG LANG="en_US.UTF-8"
13-
ARG ADD_DEB_PACKAGES=""
14-
1549
# General ENV settings
16-
ENV LC_ALL="en_US.UTF-8" \
17-
LANG="en_US.UTF-8" \
18-
LANGUAGE="en_US.UTF-8" \
19-
\
20-
\
21-
DEB_PACKAGES="ca-certificates locales postgresql-client" \
22-
DEB_BUILD_DEPS="curl adduser" \
50+
ENV LANG='en_US.UTF-8' \
51+
LANGUAGE='en_US:en' \
52+
LC_ALL='en_US.UTF-8' \
53+
TZ='Etc/UTC' \
54+
DEB_PACKAGES="ca-certificates postgresql-client" \
55+
DEB_BUILD_DEPS="adduser" \
2356
ADMIN_NAME=admin \
2457
ADMIN_PWD=admin \
2558
ADMIN_EMAIL=admin.istrator@mydomain.com \
26-
SQLALCHEMY_DATABASE_URI='sqlite:////GeoHealthCheck/DB/data.db' \
59+
SQLALCHEMY_DATABASE_URI='sqlite:////app/instance/DB/data.db' \
2760
SQLALCHEMY_ENGINE_OPTION_PRE_PING=False \
2861
SECRET_KEY='d544ccc37dc3ad214c09b1b7faaa64c60351d5c8bb48b342' \
29-
GHC_HOME=/GeoHealthCheck \
62+
GHC_HOME=/app \
63+
GHC_USER=ghc \
64+
GHC_USER_HOME=/home/ghc \
3065
GHC_PROBE_HTTP_TIMEOUT_SECS=30 \
3166
GHC_MINIMAL_RUN_FREQUENCY_MINS=10 \
3267
GHC_RETENTION_DAYS=30 \
@@ -55,57 +90,39 @@ ENV LC_ALL="en_US.UTF-8" \
5590
GHC_GEOIP_LATFIELD='lat' \
5691
GHC_GEOIP_LONFIELD='lon' \
5792
GHC_METADATA_CACHE_SECS=900 \
58-
\
59-
# WSGI server settings, assumed is gunicorn \
60-
HOST=0.0.0.0 \
61-
PORT=80 \
62-
WSGI_WORKERS=4 \
63-
WSGI_WORKER_TIMEOUT=6000 \
64-
WSGI_WORKER_CLASS='gevent' \
65-
\
93+
HOST=0.0.0.0 \
94+
PORT=80 \
95+
WSGI_WORKERS=4 \
96+
WSGI_WORKER_TIMEOUT=6000 \
97+
WSGI_WORKER_CLASS='gevent' \
98+
GHC_USER_PLUGINS=''
99+
66100
# GHC Core Plugins modules and/or classes, seldom needed to set: \
67101
# if not specified here or in Container environment \
68102
# all GHC built-in Plugins will be active. \
69103
#ENV GHC_PLUGINS 'GeoHealthCheck.plugins.probe.owsgetcaps,\
70104
# GeoHealthCheck.plugins.probe.wms, ...., ...\
71105
# GeoHealthCheck.plugins.check.checks' \
72-
\
73-
# GHC User Plugins, best be overridden via Container environment \
74-
GHC_USER_PLUGINS=''
75-
76-
# Add standard files and Add/override Plugins
77-
# Alternative Entrypoints to run GHC jobs
78-
# Override default Entrypoint with these on Containers
79-
COPY docker/scripts/*.sh docker/config_site.py docker/plugins /
80106

81-
# Add Source Code
82-
COPY . ${GHC_HOME}
83-
84-
WORKDIR ${GHC_HOME}
107+
# GHC User Plugins, best be overridden via Container environment \
85108

86109
# Install operating system dependencies
87110
RUN \
88-
apt-get update \
89-
&& apt-get --no-install-recommends install -y ${DEB_PACKAGES} ${DEB_BUILD_DEPS} ${ADD_DEB_PACKAGES} \
90-
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \
111+
apt update \
112+
&& apt --no-install-recommends install -y ${DEB_PACKAGES} ${DEB_BUILD_DEPS} \
91113
&& echo "For ${TZ} date=$(date)" && echo "Locale=$(locale)" \
92-
&& adduser --disabled-password --shell /bin/bash --home ${GHC_HOME} --gecos "User" ghc \
93-
&& chmod +x /*.sh \
94-
&& pixi install --locked -e prod \
95-
&& pixi run -e prod setup \
96-
&& cp /config_site.py ${GHC_HOME}/instance/config_site.py \
97-
&& if [ -d /plugins ]; then cp -ar /plugins/* ${GHC_HOME}/GeoHealthCheck/plugins/; fi && rm -rf /plugins \
98-
&& apt-get remove --purge -y ${DEB_BUILD_DEPS} \
99-
&& apt-get clean \
114+
&& adduser --disabled-password --shell /bin/bash --gecos "User" ${GHC_USER} \
115+
&& apt remove --purge -y ${DEB_BUILD_DEPS} \
116+
&& apt clean \
100117
&& apt autoremove -y \
101118
&& rm -rf /var/lib/apt/lists/*
102119

103-
# For later: run as user 'ghc'
104-
# USER ghc
120+
WORKDIR /app
121+
COPY --from=build --chown=${GHC_USER}:${GHC_USER} /app /app
105122

106-
# For SQLite
107-
VOLUME ["/GeoHealthCheck/DB/"]
123+
# For later: run as user 'ghc'
124+
USER ${GHC_USER}
108125

109126
EXPOSE ${PORT}
110127

111-
ENTRYPOINT /run-web.sh
128+
ENTRYPOINT [ "/app/docker/scripts/run-web.sh" ]

docker/README.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ GHC Docker images are hosted at [Docker Hub](https://hub.docker.com/r/geopython/
55
In the best case an install/run of GHC is a matter of minutes!
66

77
If you are reading this from Docker Hub, local links will not work.
8-
In that case use the [Docker Readme at GHC GitHub](https://github.com/geopython/GeoHealthCheck/blob/master/docker/README.md).
8+
In that case use the [Docker Readme at GHC GitHub](https://github.com/geopython/geohealthcheck/blob/master/docker/README.md).
99

1010
Since GHC release 0.4.0 GHC can run completely with two Docker containers from the same
1111
GHC Docker image:
@@ -15,14 +15,13 @@ GHC Docker image:
1515

1616
## Requirements
1717

18-
Docker installed and Docker daemon running.
19-
[Docker Compose](https://docs.docker.com/compose/install) is separate install.
18+
Docker with Docker Compose installed and Docker daemon running.
2019

2120
For installing Docker on Ubuntu there
2221
is a [bash helper script](install-docker-ubuntu.sh).
2322

24-
NB: The ``docker`` commands below may need to be prepended with
25-
``sudo``, dependent on your login rights.
23+
NB: The `docker` commands below may need to be prepended with
24+
`sudo`, dependent on your rights to run `docker` commands.
2625

2726
## Build
2827

@@ -43,7 +42,7 @@ For example [run.sh](run.sh) which launches GHC using the robust `gunicorn` WSGI
4342
## Run
4443

4544
```
46-
docker run -d --name ghc_web --rm -p 8083:80 -v ghc_sqlitedb:/GeoHealthCheck/DB geopython/geohealthcheck:latest
45+
docker run -d --name ghc_web --rm -p 8083:80 -v ghc_sqlitedb:/app/instance/DB geopython/geohealthcheck:latest
4746
```
4847

4948
go to http://localhost:8083 (port 80 in GHC Container is mapped to 8083 on host).
@@ -56,7 +55,7 @@ This mode can be disabled by passing `GHC_RUNNER_IN_WEBAPP` to as an ENV
5655
var to the Docker container:
5756

5857
```
59-
docker run --name ghc_web --rm -e GHC_RUNNER_IN_WEBAPP=False -p 8083:80 -v ghc_sqlitedb:/GeoHealthCheck/DB geopython/geohealthcheck:latest
58+
docker run --name ghc_web --rm -e GHC_RUNNER_IN_WEBAPP=False -p 8083:80 -v ghc_sqlitedb:/app/instance/DB geopython/geohealthcheck:latest
6059
6160
```
6261

@@ -66,7 +65,13 @@ You can then run `GHC Runner` as a separate container by overriding
6665
the default `ENTRYPOINT` with `/run-runner.sh`:
6766

6867
```
69-
docker run -d --name ghc_runner --rm --entrypoint "/run-runner.sh" -v ghc_sqlitedb:/GeoHealthCheck/DB geopython/geohealthcheck:latest
68+
docker run -d --name ghc_runner --rm --entrypoint "/app/docker/scripts/run-runner.sh" -v ghc_sqlitedb:/app/instance/DB geopython/geohealthcheck:latest
69+
```
70+
71+
You can also run the GHC standard tests by overriding the default `ENTRYPOINT` with `/run-tests.sh`:
72+
73+
```
74+
docker run --name ghc_tests --rm --entrypoint "docker/scripts/run-tests.sh" -v ghc_sqlitedb:/app/instance/DB -e GHC_LOG_LEVEL=10 geopython/geohealthcheck:latest
7075
```
7176

7277
But the most optimal way to run GHC with scheduled jobs and optionally Postgres as backend DB,
@@ -177,7 +182,7 @@ Here we use `.env` files.
177182
- /run-runner.sh
178183
179184
volumes:
180-
- ghc_sqlitedb:/GeoHealthCheck/DB
185+
- ghc_sqlitedb:/app/instance/DB
181186
182187
```
183188

@@ -206,7 +211,7 @@ version:
206211
- /run-runner.sh
207212
208213
postgis_ghc:
209-
image: mdillon/postgis:9.6-alpine
214+
image: mdillon/postgis:14-3.5-alpine
210215
211216
container_name: postgis_ghc
212217
@@ -223,7 +228,8 @@ Here [ghc-postgis.env](compose/ghc-postgis.env) adds extra Postgres-related conf
223228
## Other tasks
224229

225230
You can always `bash` into the GHC Container to run maintenance tasks.
226-
The GHC installation is at `/GeoHealthCheck` within the Docker Container.
231+
The GHC installation is at `/app` within the Docker Container. The container runs under
232+
user `ghc`. The home dir is `/home/ghc`.
227233

228234
```
229235
@@ -232,7 +238,7 @@ docker exec -it docker_geohealthcheck_1 bash
232238
233239
# setup Python venv
234240
source /venv/bin/activate .
235-
cd /GeoHealthCheck/
241+
cd /app/
236242
237243
# next can use Invoke commands e.g. DB upgrade
238244
invoke upgrade

docker/compose/docker-compose.postgis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ services:
3131
# - configure in ghc.env
3232
# - mount these as docker volume on host
3333
# See https://docs.docker.com/compose/compose-file/#volumes
34-
# - ./../GeoHealthCheck/plugins:/plugins:ro
34+
# - ./../app/plugins:/plugins:ro
3535

3636
ghc_runner:
3737
image: geopython/geohealthcheck:latest
@@ -51,15 +51,15 @@ services:
5151
- postgis_ghc
5252

5353
entrypoint:
54-
- /run-runner.sh
54+
- /app/docker/scripts/run-runner.sh
5555

5656
# volumes:
5757
# Optional Plugins, using Path on the host, relative to this Compose file
5858
# To activate 2 steps:
5959
# - configure in ghc.env
6060
# - mount these as docker volume on host
6161
# See https://docs.docker.com/compose/compose-file/#volumes
62-
# - ./../GeoHealthCheck/plugins:/plugins:ro
62+
# - ./../app/plugins:/plugins:ro
6363

6464
postgis_ghc:
6565
image: postgis/postgis:14-3.5-alpine

docker/compose/docker-compose.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ services:
2020
- ghc.env
2121

2222
volumes:
23-
- ghc_sqlitedb:/GeoHealthCheck/DB
23+
- ghc_sqlitedb:/app/instance/DB
2424
# Optional Plugins, using Path on the host, relative to this Compose file
2525
# To activate: 2 steps for runner and GHC webapp:
2626
# - configure in ghc.env
2727
# - mount these as docker volume on host
2828
# See https://docs.docker.com/compose/compose-file/#volumes
29-
# - ./../GeoHealthCheck/plugins:/plugins:ro
29+
# - ./../app/plugins:/plugins:ro
3030

3131
ghc_runner:
3232
image: geopython/geohealthcheck:latest
@@ -39,16 +39,16 @@ services:
3939
- ghc.env
4040

4141
entrypoint:
42-
- /run-runner.sh
42+
- /app/docker/scripts/run-runner.sh
4343

4444
volumes:
45-
- ghc_sqlitedb:/GeoHealthCheck/DB
45+
- ghc_sqlitedb:/app/instance/DB
4646
# Optional Plugins, using Path on the host, relative to this Compose file
4747
# To activate 2 steps:
4848
# - configure in ghc.env
4949
# - mount these as docker volume on host
5050
# See https://docs.docker.com/compose/compose-file/#volumes
51-
# - ./../GeoHealthCheck/plugins:/plugins:ro
51+
# - ./../app/plugins:/plugins:ro
5252

5353
# docker-compose v2+ needs separate volumes section
5454
volumes:

docker/compose/ghc.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
SQLALCHEMY_DATABASE_URI=sqlite:////GeoHealthCheck/DB/data.db
1+
SQLALCHEMY_DATABASE_URI=sqlite:////app/instance/DB/data.db
22

33
# Core variables settings, change at will.
44
GHC_RUNNER_IN_WEBAPP=False

0 commit comments

Comments
 (0)