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.pull/9/head
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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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" \
|
||||
-e "PGADMIN_SETUP_EMAIL=user@domain.com" \
|
||||
-e "PGADMIN_SETUP_PASSWORD=SuperSecret" \
|
||||
-e "PGADMIN_ENABLE_TLS=1" \
|
||||
-d pgadmin4
|
||||
```
|
||||
|
|
|
|||
|
|
@ -41,57 +41,19 @@ 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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 %}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import builtins
|
||||
builtins.SERVER_MODE = True
|
||||
|
||||
from pgAdmin4 import app
|
||||
Loading…
Reference in New Issue