mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Update container build to use Alpine Linux and Gunicorn instead of CentOS and Apache. Fixes #3246
This results in a much more slim-line container, requiring fewer resources to run. In addition, the majority of the build is now done using the Docker infrastructure, allowing for quicker rebuilds and better use of layers.
This commit is contained in:
parent
1617d003cd
commit
05e2e3cb39
@ -33,6 +33,7 @@ Features
|
||||
| `Feature #3182 <https://redmine.postgresql.org/issues/3182>`_ - Update Jasmine to v3
|
||||
| `Feature #3184 <https://redmine.postgresql.org/issues/3184>`_ - Add a French translation
|
||||
| `Feature #3195 <https://redmine.postgresql.org/issues/3195>`_ - Pass the service name to external processes
|
||||
| `Feature #3246 <https://redmine.postgresql.org/issues/3246>`_ - Update container build to use Alpine Linux and Gunicorn instead of CentOS/Apache
|
||||
|
||||
| `In addition, various changes were made for PEP8 compliance`
|
||||
|
||||
|
2
pkg/docker/.dockerignore
Normal file
2
pkg/docker/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
pgadmin4/web/**/tests/
|
||||
pgadmin4/web/regression/
|
@ -7,58 +7,63 @@
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
# Get the basics out of the way
|
||||
FROM centos:latest
|
||||
# First of all, build frontend with NodeJS in a separate builder container
|
||||
# Node-6 with ABI v48 is supported by all needed C++ packages
|
||||
FROM node:6 AS node-builder
|
||||
|
||||
LABEL name="pgAdmin 4" \
|
||||
vendor="The pgAdmin Development Team" \
|
||||
license="PostgreSQL"
|
||||
COPY ./pgadmin4/web/ /pgadmin4/web/
|
||||
WORKDIR /pgadmin4/web
|
||||
|
||||
# We only need the web/ directory, and a few other things
|
||||
COPY web /var/www/pgadmin
|
||||
COPY requirements.txt /var/www/pgadmin
|
||||
RUN yarn install --cache-folder ./ycache --verbose && \
|
||||
yarn run bundle && \
|
||||
rm -rf ./ycache ./pgadmin/static/js/generated/.cache
|
||||
|
||||
# Install everything we need. Use easy_install to get pip, to avoid setting up EPEL
|
||||
RUN yum install -y python-setuptools python-devel httpd mod_wsgi mod_ssl gcc
|
||||
RUN easy_install pip
|
||||
RUN pip install j2cli
|
||||
# Build Sphinx documentation in separate container
|
||||
FROM python:3.6-alpine3.7 as docs-builder
|
||||
|
||||
# Now install the Python runtime dependencies
|
||||
RUN pip install -r /var/www/pgadmin/requirements.txt
|
||||
# Install only dependencies absolutely required for documentation building
|
||||
RUN apk add --no-cache make
|
||||
RUN pip install --no-cache-dir \
|
||||
sphinx flask_security flask_paranoid python-dateutil flask_sqlalchemy \
|
||||
flask_gravatar simplejson
|
||||
|
||||
# Create required directories for config
|
||||
COPY ./pgadmin4/ /pgadmin4
|
||||
|
||||
RUN LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 make -C /pgadmin4/docs/en_US -f Makefile.sphinx html
|
||||
|
||||
# Create required directories for running
|
||||
RUN mkdir -p /var/log/pgadmin
|
||||
RUN chown -R apache /var/log/pgadmin
|
||||
RUN mkdir -p /var/lib/pgadmin
|
||||
RUN chown -R apache /var/lib/pgadmin
|
||||
RUN mkdir -p /certs
|
||||
RUN chown -R apache /certs
|
||||
RUN chmod 700 /certs
|
||||
# Then install backend, copy static files and set up entrypoint
|
||||
# Need alpine3.7 to get pg_dump and friends in postgresql-client package
|
||||
FROM python:3.6-alpine3.7
|
||||
|
||||
# Push logs to the container's output streams
|
||||
RUN ln -sf /proc/self/fd/1 /var/log/httpd/access_log && \
|
||||
ln -sf /proc/self/fd/1 /var/log/httpd/ssl_access_log && \
|
||||
ln -sf /proc/self/fd/2 /var/log/httpd/error_log && \
|
||||
ln -sf /proc/self/fd/2 /var/log/httpd/ssl_error_log
|
||||
RUN pip --no-cache-dir install gunicorn
|
||||
RUN apk add --no-cache postgresql-client postgresql-libs
|
||||
|
||||
# Apache config time
|
||||
RUN mkdir -p /templates
|
||||
COPY pgadmin4.conf.j2 /templates/
|
||||
COPY entry.sh /
|
||||
WORKDIR /pgadmin4
|
||||
ENV PYTHONPATH=/pgadmin4
|
||||
|
||||
# Finally, remove packages we only needed for building
|
||||
RUN yum -y remove gcc cpp glibc-devel glibc-headers kernel-headers libgomp libmpc mpfr
|
||||
# Install build-dependencies, build & install C extensions and purge deps in one RUN step
|
||||
# so that deps do not increase the size of resulting image by remaining in layers
|
||||
COPY ./pgadmin4/requirements.txt /pgadmin4
|
||||
RUN set -ex && \
|
||||
apk add --no-cache --virtual build-deps build-base postgresql-dev && \
|
||||
pip install --no-cache-dir -r requirements.txt && \
|
||||
apk del --no-cache build-deps
|
||||
|
||||
# Default config options
|
||||
ENV PGADMIN_DEFAULT_EMAIL container@pgadmin.org
|
||||
ENV PGADMIN_DEFAULT_PASSWORD Conta1ner
|
||||
ENV PGADMIN_ENABLE_TLS False
|
||||
ENV PGADMIN_SERVER_NAME pgadmin4
|
||||
COPY --from=node-builder /pgadmin4/web/pgadmin/static/js/generated/ /pgadmin4/pgadmin/static/js/generated/
|
||||
COPY --from=docs-builder /pgadmin4/docs/en_US/_build/html/ /pgadmin4/docs/
|
||||
|
||||
COPY ./pgadmin4/web /pgadmin4
|
||||
COPY ./run_pgadmin.py /pgadmin4
|
||||
COPY ./config_distro.py /pgadmin4
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Precompile and optimize python code to save time and space on startup
|
||||
RUN python -O -m compileall /pgadmin4
|
||||
|
||||
COPY ./entrypoint.sh /entrypoint.sh
|
||||
|
||||
VOLUME /var/lib/pgadmin
|
||||
EXPOSE 80 443
|
||||
|
||||
# Start the service
|
||||
ENTRYPOINT ["/bin/bash", "/entry.sh"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
@ -4,14 +4,16 @@ Building
|
||||
========
|
||||
|
||||
Whilst you can just use the Dockerfile directly, it requires that various pre-configuration steps are performed, for
|
||||
example, the pgAdmin web code must be copied to ./web and yarn install/yarn run bundle must be executed.
|
||||
requirements.txt is also expected to be in this directory, and the pre-built docs must be in web/docs.
|
||||
example, the pgAdmin web code must be copied to `./web`, Sphinx documentation source must be copied to `./docs`
|
||||
and `requirements.txt` is also expected to be in this directory.
|
||||
|
||||
The recommended (and easy) way to build the container is to do:
|
||||
|
||||
```console
|
||||
cd $PGADMIN_SRC/
|
||||
workon pgadmin-venv
|
||||
make docker
|
||||
```
|
||||
|
||||
This will call the build script $PGADMIN_SRC/pkg/docker/build.sh which will prepare a staging directory containing all
|
||||
the required files, then build the container and push it to your repo.
|
||||
@ -21,57 +23,51 @@ Running
|
||||
|
||||
The container will accept the following variables at startup:
|
||||
|
||||
PGADMIN_DEFAULT_EMAIL
|
||||
---------------------
|
||||
|
||||
Default: container@pgadmin.org)
|
||||
PGADMIN_SETUP_EMAIL
|
||||
-------------------
|
||||
|
||||
This is the email address used when setting up the initial administrator account to login to pgAdmin.
|
||||
|
||||
PGADMIN_DEFAULT_PASSWORD
|
||||
------------------------
|
||||
|
||||
Default: Conta1ner
|
||||
PGADMIN_SETUP_PASSWORD
|
||||
----------------------
|
||||
|
||||
This is the password used when setting up the initial administrator account to login to pgAdmin.
|
||||
|
||||
PGADMIN_ENABLE_TLS
|
||||
------------------
|
||||
|
||||
Default: False
|
||||
Default: unset
|
||||
|
||||
If set to the default, False, the container will listen on port 80 for connections in plain text. If set to True, the
|
||||
container will listen on port 443 for TLS connections.
|
||||
If not set, the container will listen on port 8080 for connections in insecure HTTP protocol.
|
||||
If set to any value, the container will listen on port 8443 for TLS connections.
|
||||
|
||||
When TLS is enabled, a certificate and key must be provided. Typically these should be stored on the host file system
|
||||
and mounted from the container. The expected paths are /certs/server.crt and /certs/server.key
|
||||
When TLS is enabled, a certificate and key must be provided.
|
||||
Typically these should be stored on the host file system and mounted from the container.
|
||||
The expected paths are `/certs/server.crt` and `/certs/server.key`.
|
||||
|
||||
PGADMIN_SERVER_NAME
|
||||
-------------------
|
||||
|
||||
Default: pgadmin4
|
||||
|
||||
This variable allows you to specify the value used for the Apache HTTPD ServerName directive. This is commonly used to
|
||||
ensure the CN of the TLS certificate matches what the server expects.
|
||||
You need to explicitly map these ports with `-p` option to some port at your machine.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Run a simple container over port 80:
|
||||
|
||||
docker run -p 80:80 \
|
||||
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
||||
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
||||
```console
|
||||
docker run -p 80:8080 \
|
||||
-e "PGADMIN_SETUP_EMAIL=user@domain.com" \
|
||||
-e "PGADMIN_SETUP_PASSWORD=SuperSecret" \
|
||||
-d pgadmin4
|
||||
```
|
||||
|
||||
Run a TLS secured container using a shared config/storage directory in /private/var/lib/pgadmin on the host:
|
||||
|
||||
docker run -p 443:443 \
|
||||
```console
|
||||
docker run -p 443:8443 \
|
||||
-v "/private/var/lib/pgadmin:/var/lib/pgadmin" \
|
||||
-v "/path/to/certificate.cert:/certs/server.cert" \
|
||||
-v "/path/to/certificate.key:/certs/server.key" \
|
||||
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
||||
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
||||
-e "PGADMIN_ENABLE_TLS=True" \
|
||||
-e "PGADMIN_SERVER_NAME=pgadmin.domain.com" \
|
||||
-d pgadmin4
|
||||
-e "PGADMIN_SETUP_EMAIL=user@domain.com" \
|
||||
-e "PGADMIN_SETUP_PASSWORD=SuperSecret" \
|
||||
-e "PGADMIN_ENABLE_TLS=1" \
|
||||
-d pgadmin4
|
||||
```
|
||||
|
@ -41,60 +41,22 @@ if [ -d docker-build ]; then
|
||||
rm -rf docker-build
|
||||
fi
|
||||
|
||||
mkdir docker-build
|
||||
|
||||
# Create the output directory if not present
|
||||
if [ ! -d dist ]; then
|
||||
mkdir dist
|
||||
fi
|
||||
mkdir -p docker-build/pgadmin4
|
||||
|
||||
# Build the clean tree
|
||||
for FILE in `git ls-files web`
|
||||
do
|
||||
echo Adding $FILE
|
||||
# We use tar here to preserve the path, as Mac (for example) doesn't support cp --parents
|
||||
tar cf - $FILE | (cd docker-build; tar xf -)
|
||||
done
|
||||
|
||||
pushd web
|
||||
yarn install
|
||||
yarn run bundle
|
||||
|
||||
rm -rf pgadmin/static/js/generated/.cache
|
||||
|
||||
for FILE in `ls -d pgadmin/static/js/generated/*`
|
||||
do
|
||||
echo Adding $FILE
|
||||
tar cf - $FILE | (cd ../docker-build/web; tar xf -)
|
||||
done
|
||||
popd
|
||||
|
||||
# Build the docs
|
||||
if [ -d docs/en_US/_build/html ]; then
|
||||
rm -rf docs/en_US/_build/html
|
||||
fi
|
||||
|
||||
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 make -C docs/en_US -f Makefile.sphinx html
|
||||
|
||||
mkdir docker-build/web/docs
|
||||
cp -R docs/en_US/_build/html/* docker-build/web/docs/
|
||||
|
||||
# Configure pgAdmin
|
||||
echo "HELP_PATH = '../../docs/'" >> docker-build/web/config_distro.py
|
||||
echo "DEFAULT_BINARY_PATHS = {" >> docker-build/web/config_distro.py
|
||||
echo " 'pg': ''," >> docker-build/web/config_distro.py
|
||||
echo " 'ppas': ''," >> docker-build/web/config_distro.py
|
||||
echo " 'gpdb': ''" >> docker-build/web/config_distro.py
|
||||
echo "}" >> docker-build/web/config_distro.py
|
||||
echo Copying source tree...
|
||||
git archive HEAD -- docs web requirements.txt | tar xvf - -C docker-build/pgadmin4
|
||||
|
||||
# Copy the Docker specific assets into place
|
||||
cp pkg/docker/Dockerfile docker-build/
|
||||
cp pkg/docker/entry.sh docker-build/
|
||||
cp pkg/docker/pgadmin4.conf.j2 docker-build/
|
||||
cp requirements.txt docker-build/
|
||||
cp pkg/docker/Dockerfile \
|
||||
pkg/docker/entrypoint.sh \
|
||||
pkg/docker/config_distro.py \
|
||||
pkg/docker/run_pgadmin.py \
|
||||
pkg/docker/.dockerignore \
|
||||
docker-build/
|
||||
|
||||
# Build the container
|
||||
docker build docker-build -t $CONTAINER_NAME \
|
||||
-t $CONTAINER_NAME:latest \
|
||||
-t $CONTAINER_NAME:$APP_RELEASE \
|
||||
-t $CONTAINER_NAME:$APP_LONG_VERSION
|
||||
-t $CONTAINER_NAME:$APP_LONG_VERSION
|
||||
|
4
pkg/docker/config_distro.py
Normal file
4
pkg/docker/config_distro.py
Normal file
@ -0,0 +1,4 @@
|
||||
HELP_PATH = '../../docs'
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
'pg': '/usr/bin'
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
export PGADMIN_SETUP_EMAIL=${PGADMIN_DEFAULT_EMAIL}
|
||||
export PGADMIN_SETUP_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
|
||||
|
||||
if [ ${PGADMIN_ENABLE_TLS} != "True" ]; then
|
||||
if [ -f /etc/httpd/conf.d/ssl.conf ]; then
|
||||
mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.disabled
|
||||
fi
|
||||
else
|
||||
if [ -f /etc/httpd/conf.d/ssl.conf.disabled ]; then
|
||||
mv /etc/httpd/conf.d/ssl.conf.disabled /etc/httpd/conf.d/ssl.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
j2 /templates/pgadmin4.conf.j2 > /etc/httpd/conf.d/pgadmin4.conf
|
||||
|
||||
rm -f /run/httpd/httpd.pid
|
||||
|
||||
/usr/sbin/httpd -D FOREGROUND
|
26
pkg/docker/entrypoint.sh
Executable file
26
pkg/docker/entrypoint.sh
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -f /var/lib/pgadmin/pgadmin4.db ]; then
|
||||
if [ -z "${PGADMIN_DEFAULT_EMAIL}" -o -z "${PGADMIN_DEFAULT_PASSWORD}" ]; then
|
||||
echo 'You need to specify PGADMIN_DEFAULT_EMAIL and PGADMIN_DEFAULT_PASSWORD environment variables'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set the default username and password in a
|
||||
# backwards compatible way
|
||||
export PGADMIN_SETUP_EMAIL=${PGADMIN_DEFAULT_EMAIL}
|
||||
export PGADMIN_SETUP_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
|
||||
|
||||
# Initialize DB before starting Gunicorn
|
||||
# Importing pgadmin4 (from this script) is enough
|
||||
python run_pgadmin.py
|
||||
fi
|
||||
|
||||
# NOTE: currently pgadmin can run only with 1 worker due to sessions implementation
|
||||
# Using --threads to have multi-threaded single-process worker
|
||||
|
||||
if [ ! -z ${PGADMIN_ENABLE_TLS} ]; then
|
||||
exec gunicorn --bind 0.0.0.0:${PGADMIN_LISTEN_PORT:-443} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile - --keyfile /certs/server.key --certfile /certs/server.cert run_pgadmin:app
|
||||
else
|
||||
exec gunicorn --bind 0.0.0.0:${PGADMIN_LISTEN_PORT:-80} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile - run_pgadmin:app
|
||||
fi
|
@ -1,43 +0,0 @@
|
||||
########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
ServerName {{ PGADMIN_SERVER_NAME }}
|
||||
{% if PGADMIN_ENABLE_TLS|default('False') == 'True' %}
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
|
||||
<VirtualHost *:443>
|
||||
SSLEngine on
|
||||
SSLCipherSuite HIGH:!aNULL:!MD5
|
||||
SSLCertificateFile "/certs/server.cert"
|
||||
SSLCertificateKeyFile "/certs/server.key"
|
||||
|
||||
ServerName {{ PGADMIN_SERVER_NAME }}
|
||||
WSGIDaemonProcess pgadmin processes=1 threads=25
|
||||
WSGIScriptAlias / /var/www/pgadmin/pgAdmin4.wsgi
|
||||
|
||||
<Directory /var/www/pgadmin>
|
||||
WSGIProcessGroup pgadmin
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
{% else %}
|
||||
<VirtualHost *:80>
|
||||
WSGIDaemonProcess pgadmin processes=1 threads=25
|
||||
WSGIScriptAlias / /var/www/pgadmin/pgAdmin4.wsgi
|
||||
|
||||
<Directory /var/www/pgadmin>
|
||||
WSGIProcessGroup pgadmin
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
{% endif %}
|
4
pkg/docker/run_pgadmin.py
Normal file
4
pkg/docker/run_pgadmin.py
Normal file
@ -0,0 +1,4 @@
|
||||
import builtins
|
||||
builtins.SERVER_MODE = True
|
||||
|
||||
from pgAdmin4 import app
|
Loading…
Reference in New Issue
Block a user