Skip to content

[Fixes #12939] Add rootless support for geonode, cited on GNIP 101 (#12769) #12966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ C_FORCE_ROOT=1
FORCE_REINIT=false
INVOKE_LOG_STDOUT=true

# Linux user that nginx, django and geoserver will run as
GEONODE_UID=0

# LANGUAGE_CODE=it-it
# LANGUAGES=(('en-us','English'),('it-it','Italiano'))

Expand Down Expand Up @@ -236,7 +239,7 @@ LDAP_GROUP_PROFILE_MEMBER_ATTR=uniqueMember
# CELERY__OPTS="--without-gossip --without-mingle -Ofair -B -E"
# CELERY__BEAT_SCHEDULE="/mnt/volumes/statics/celerybeat-schedule"
# CELERY__LOG_LEVEL="INFO"
# CELERY__LOG_FILE="/var/log/celery.log"
# CELERY__LOG_FILE="/var/log/geonode/celery.log"
# CELERY__WORKER_NAME="worker1@%h"

# PostgreSQL
Expand Down
50 changes: 32 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
FROM geonode/geonode-base:latest-ubuntu-22.04
LABEL GeoNode development team
ARG GEONODE_BASE_IMAGE=geonode/geonode-base:latest-ubuntu-22.04
FROM ${GEONODE_BASE_IMAGE}

ARG GEONODE_VERSION=master

# Some label best practices
# https://www.docker.com/blog/docker-best-practices-using-tags-and-labels-to-manage-docker-image-sprawl/
LABEL org.opencontainers.image.title="GeoNode" \
org.opencontainers.image.version=${GEONODE_VERSION} \
org.opencontainers.image.vendor="GeoNode Development Team"

# copy local geonode src inside container
COPY . /usr/src/geonode/
Expand All @@ -11,33 +19,39 @@ WORKDIR /usr/src/geonode
#RUN touch /var/log/cron.log
#RUN service cron start

COPY wait-for-databases.sh /usr/bin/wait-for-databases
RUN chmod +x /usr/bin/wait-for-databases
RUN chmod +x /usr/src/geonode/tasks.py \
&& chmod +x /usr/src/geonode/entrypoint.sh

COPY celery.sh /usr/bin/celery-commands
RUN chmod +x /usr/bin/celery-commands

COPY celery-cmd /usr/bin/celery-cmd
RUN chmod +x /usr/bin/celery-cmd
RUN chmod +x \
wait-for-databases.sh \
tasks.py \
entrypoint.sh \
celery.sh \
celery-cmd && \
mv wait-for-databases.sh /usr/local/bin/wait-for-databases && \
mv celery.sh /usr/local/bin/celery-commands && \
mv celery-cmd /usr/local/bin/celery-cmd

# # Install "geonode-contribs" apps
# RUN cd /usr/src; git clone https://github.com/GeoNode/geonode-contribs.git -b master
# # Install logstash and centralized dashboard dependencies
# RUN cd /usr/src/geonode-contribs/geonode-logstash; pip install --upgrade -e . \
# cd /usr/src/geonode-contribs/ldap; pip install --upgrade -e .

RUN yes w | pip install --src /usr/src -r requirements.txt &&\
yes w | pip install -e .
RUN yes w | pip install --no-cache --src /usr/src -r requirements.txt &&\
yes w | pip install --no-cache -e .

# Cleanup apt update lists
RUN apt-get autoremove --purge &&\
apt-get clean &&\
# This is needed to reduce the size of the image, but it's better to move this RUN to geonode-base
RUN apt-get autoremove --purge && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Create specific log dir to geonode and statics and grant permissions to root group.
# This is needed to avoid permission issues
RUN mkdir -p /var/log/geonode /mnt/volumes/statics && \
chmod -R g=u /var/log/geonode /mnt/volumes/statics

# Export ports
EXPOSE 8000

# We provide no command or entrypoint as this image can be used to serve the django project or run celery tasks
# ENTRYPOINT /usr/src/geonode/entrypoint.sh
# We provide no command as this image can be used to serve the django project or run celery tasks
ENTRYPOINT [ ./entrypoint.sh ]

4 changes: 2 additions & 2 deletions celery-cmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# A configurable celery command.
# Luca Pasquali <[email protected]>
CELERY_BIN=${CELERY_BIN:-"$(which celery||echo celery)"}
Expand All @@ -11,7 +11,7 @@ CELERY__MAX_TASKS_PER_CHILD=${CELERY__MAX_TASKS_PER_CHILD:-"10"}
CELERY__OPTS=${CELERY__OPTS:-"--without-gossip --without-mingle -Ofair -B -E"}
CELERY__BEAT_SCHEDULE=${CELERY__BEAT_SCHEDULE:-"celery.beat:PersistentScheduler"}
CELERY__LOG_LEVEL=${CELERY__LOG_LEVEL:-"INFO"}
CELERY__LOG_FILE=${CELERY__LOG_FILE:-"/var/log/celery.log"}
CELERY__LOG_FILE=${CELERY__LOG_FILE:-"/var/log/geonode/celery.log"}
CELERY__WORKER_NAME=${CELERY__WORKER_NAME:-"worker1@%h"}
CELERY__WORKER_CONCURRENCY=${CELERY__WORKER_CONCURRENCY:-"4"}

Expand Down
4 changes: 2 additions & 2 deletions celery.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
nohup celery -A geonode.celery_app:app beat -l DEBUG -f /var/log/celery.log &>/dev/null &
nohup celery -A geonode.celery_app:app worker --without-gossip --without-mingle -Ofair -B -E --statedb=worker.state --scheduler=celery.beat:PersistentScheduler --loglevel=INFO --concurrency=2 -n worker1@%h -f /var/log/celery.log &>/dev/null &
nohup celery -A geonode.celery_app:app beat -l DEBUG -f /var/log/geonode/celery.log &>/dev/null &
nohup celery -A geonode.celery_app:app worker --without-gossip --without-mingle -Ofair -B -E --statedb=worker.state --scheduler=celery.beat:PersistentScheduler --loglevel=INFO --concurrency=2 -n worker1@%h -f /var/log/geonode/celery.log &>/dev/null &
nohup celery -A geonode.celery_app:app flower --auto_refresh=True --debug=False --broker=${BROKER_URL} --basic_auth=${ADMIN_USERNAME}:${ADMIN_PASSWORD} --address=0.0.0.0 --port=5555 &>/dev/null &
26 changes: 18 additions & 8 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ version: '3.9'
# Common Django template for GeoNode and Celery services below
x-common-django:
&default-common-django
image: geonode/geonode:local
image: geonode/geonode:dev
build:
context: ./
dockerfile: Dockerfile
args:
GEONODE_BASE_IMAGE: geonode/geonode-base:latest-ubuntu-22.04
GEONODE_VERSION: master
restart: unless-stopped
user: '${GEONODE_UID}'
env_file:
- .env
volumes:
Expand Down Expand Up @@ -52,15 +55,17 @@ services:

# Nginx is serving django static and media files and proxies to django and geonode
geonode:
image: geonode/nginx:1.25.3-latest
image: geonode/nginx:dev
container_name: nginx4${COMPOSE_PROJECT_NAME}
env_file:
- .env
environment:
- RESOLVER=127.0.0.11
user: '${GEONODE_UID}'
ports:
- "${HTTP_PORT}:80"
- "${HTTPS_PORT}:443"
# change container ports to run rootless nginx (80->8080 and 443->8443)
- "${HTTP_PORT}:8080"
- "${HTTPS_PORT}:8443"
volumes:
- nginx-confd:/etc/nginx
- nginx-certificates:/geonode-certificates
Expand All @@ -69,24 +74,28 @@ services:

# Gets and installs letsencrypt certificates
letsencrypt:
image: geonode/letsencrypt:2.6.0-latest
image: geonode/letsencrypt:dev
container_name: letsencrypt4${COMPOSE_PROJECT_NAME}
env_file:
- .env
user: '${GEONODE_UID}'
volumes:
- nginx-certificates:/geonode-certificates
restart: unless-stopped
# deploy:
# replicas: 0

# Geoserver backend
geoserver:
image: geonode/geoserver:2.24.3-latest
image: geonode/geoserver:dev
container_name: geoserver4${COMPOSE_PROJECT_NAME}
healthcheck:
test: "curl -m 10 --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://geoserver:8080/geoserver/ows"
start_period: 60s
interval: 60s
timeout: 10s
retries: 2
user: '${GEONODE_UID}'
env_file:
- .env
ports:
Expand All @@ -105,9 +114,10 @@ services:
condition: service_healthy

data-dir-conf:
image: geonode/geoserver_data:2.24.3-latest
image: geonode/geoserver_data:dev
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will not be removed by the other PR for getting rid of the geoserver_data?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, when no longer needed

container_name: gsconf4${COMPOSE_PROJECT_NAME}
entrypoint: sleep infinity
user: '${GEONODE_UID}'
volumes:
- geoserver-data-dir:/geoserver_data/data
restart: unless-stopped
Expand Down
18 changes: 13 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ x-common-django:
image: geonode/geonode:latest-ubuntu-22.04
build:
context: ./
dockerfile: Dockerfile
args:
GEONODE_BASE_IMAGE: geonode/geonode-base:latest-ubuntu-22.04
GEONODE_VERSION: master
restart: unless-stopped
user: '${GEONODE_UID}'
env_file:
- .env
volumes:
Expand All @@ -34,7 +37,7 @@ services:
retries: 2
environment:
- IS_CELERY=False
entrypoint: ["/usr/src/geonode/entrypoint.sh"]
# entrypoint: ["/usr/src/geonode/entrypoint.sh"]
command: "uwsgi --ini /usr/src/geonode/uwsgi.ini"

# Celery worker that executes celery tasks created by Django.
Expand All @@ -46,7 +49,7 @@ services:
condition: service_healthy
environment:
- IS_CELERY=True
entrypoint: ["/usr/src/geonode/entrypoint.sh"]
# entrypoint: ["/usr/src/geonode/entrypoint.sh"]
command: "celery-cmd"

# memcached service
Expand All @@ -68,11 +71,13 @@ services:
container_name: nginx4${COMPOSE_PROJECT_NAME}
env_file:
- .env
user: '${GEONODE_UID}'
environment:
- RESOLVER=127.0.0.11
ports:
- "${HTTP_PORT}:80"
- "${HTTPS_PORT}:443"
# change container ports to run rootless nginx (80->8080 and 443->8443)
- "${HTTP_PORT}:8080"
- "${HTTPS_PORT}:8443"
volumes:
- nginx-confd:/etc/nginx
- nginx-certificates:/geonode-certificates
Expand All @@ -83,6 +88,7 @@ services:
letsencrypt:
image: geonode/letsencrypt:2.6.0-latest
container_name: letsencrypt4${COMPOSE_PROJECT_NAME}
user: '${GEONODE_UID}'
env_file:
- .env
volumes:
Expand All @@ -99,6 +105,7 @@ services:
interval: 60s
timeout: 10s
retries: 2
user: '${GEONODE_UID}'
env_file:
- .env
ports:
Expand All @@ -120,6 +127,7 @@ services:
image: geonode/geoserver_data:2.24.3-latest
container_name: gsconf4${COMPOSE_PROJECT_NAME}
entrypoint: sleep infinity
user: '${GEONODE_UID}'
volumes:
- geoserver-data-dir:/geoserver_data/data
restart: unless-stopped
Expand Down
55 changes: 45 additions & 10 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,65 @@
# Exit script in case of error
set -e

INVOKE_LOG_STDOUT=${INVOKE_LOG_STDOUT:-FALSE}
# Parse bools
parse_bool () {
case $1 in
[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]|1) echo 'true';;
*) echo 'false';;
esac
}

INVOKE_LOG_STDOUT=${INVOKE_LOG_STDOUT:-false}

invoke () {
if [ $INVOKE_LOG_STDOUT = 'true' ] || [ $INVOKE_LOG_STDOUT = 'True' ]
then
if [ $(parse_bool $INVOKE_LOG_STDOUT) = 'true' ]; then
/usr/local/bin/invoke $@
else
/usr/local/bin/invoke $@ > /usr/src/geonode/invoke.log 2>&1
/usr/local/bin/invoke $@ > /var/log/geonode/invoke.log 2>&1
fi
echo "$@ tasks done"
}

# Start cron && memcached services
service cron restart
# Not necessary, because cron jobs coiuld be run by the docker host, or use a Cronjob in Kubernetes
# Shoud be fine if we remove cron from base image.
# service cron restart

echo $"\n\n\n"
echo "-----------------------------------------------------"
echo "STARTING DJANGO ENTRYPOINT $(date)"
echo "-----------------------------------------------------"

# check if user exists in passwd file
# if not, change HOME to /tmp
HAS_USER=$(getent passwd $(id -u) | wc -l)
if [ $HAS_USER -eq 1 ]; then
echo "User $_USER exists in passwd file"

if [ $HOME = "/" ]; then
echo "HOME is /, changing to /tmp"
export HOME=/tmp
fi
else
echo "User does not exist in passwd file, changing HOME to /tmp"
export HOME=/tmp
fi
unset HAS_USER

invoke update

# Preserving the original behavior.
if [ ! -e $HOME/.bashrc ]; then
echo "No $HOME/.bashrc found, using skeleton"
cp /etc/skel/.bashrc $HOME/.bashrc
fi

source $HOME/.bashrc
source $HOME/.override_env

# Load the environment variables, if exists
if [ -e $HOME/.override_env ]; then
source $HOME/.override_env
fi

echo DOCKER_API_VERSION=$DOCKER_API_VERSION
echo POSTGRES_USER=$POSTGRES_USER
Expand All @@ -44,15 +80,14 @@ echo MONITORING_DATA_TTL=$MONITORING_DATA_TTL

cmd="$@"

if [ ${IS_CELERY} = "true" ] || [ ${IS_CELERY} = "True" ]
then
if [ $(parse_bool $IS_CELERY) = 'true' ]; then
echo "Executing Celery server $cmd for Production"
else

else
invoke migrations
invoke prepare

if [ ${FORCE_REINIT} = "true" ] || [ ${FORCE_REINIT} = "True" ] || [ ! -e "/mnt/volumes/statics/geonode_init.lock" ]; then
if [ $(parse_bool $FORCE_REINIT) = 'true' ] || [ ! -e "/mnt/volumes/statics/geonode_init.lock" ]; then
invoke fixtures
invoke monitoringfixture
invoke initialized
Expand Down
2 changes: 1 addition & 1 deletion uwsgi.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[uwsgi]
# uwsgi-socket = 0.0.0.0:8000
http-socket = 0.0.0.0:8000
logto = /var/log/geonode.log
logto = /var/log/geonode/geonode.log
# pidfile = /tmp/geonode.pid

chdir = /usr/src/geonode/
Expand Down
Loading