diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d41ad965..8e3ddd0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -141,5 +141,5 @@ oci_calculator: entrypoint: [""] script: - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json - - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE/calculator:latest + - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/app-config/cara-public-docker-image/Dockerfile --destination $CI_REGISTRY_IMAGE/calculator:latest diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b3a5065f..00000000 --- a/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM python:3.9 - -COPY ./ /opt/cara/src -RUN python -m venv /opt/cara/app -RUN cd /opt/cara/src && /opt/cara/app/bin/pip install -r /opt/cara/src/requirements.txt -EXPOSE 8080 -ENTRYPOINT ["/bin/sh", "-c", "echo 'CARA is running on http://localhost:8080' && echo 'Please see https://gitlab.cern.ch/cara/cara for terms of use.' && /opt/cara/app/bin/python -m cara.apps.calculator --no-debug"] diff --git a/app-config/cara-public-docker-image/Dockerfile b/app-config/cara-public-docker-image/Dockerfile new file mode 100644 index 00000000..d61f49d7 --- /dev/null +++ b/app-config/cara-public-docker-image/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.9 + +# Copy just the requirements.txt initially, allowing Docker effectively to cache the build (good for dev). +COPY ./requirements.txt /tmp/requirements.txt + +RUN python -m venv /opt/cara/app +RUN sed '/\.\[/d' -i /tmp/requirements.txt && /opt/cara/app/bin/pip install -r /tmp/requirements.txt +RUN apt-get update && apt-get install -y nginx + +# Now that we have done the installation of the dependencies, copy the cara source. +COPY ./ /opt/cara/src +COPY ./app-config/cara-public-docker-image/run_cara.sh /opt/cara/start.sh + +# To ensure that we have installed the full requirements, re-run the pip install. +# In the best case this will be a no-op. +RUN cd /opt/cara/src/ && /opt/cara/app/bin/pip install -r /opt/cara/src/requirements.txt +RUN /opt/cara/app/bin/jupyter trust /opt/cara/src/cara/apps/expert/*.ipynb +COPY ./app-config/cara-public-docker-image/nginx.conf /opt/cara/nginx.conf + +EXPOSE 8080 +ENTRYPOINT ["/bin/sh", "-c", "/opt/cara/start.sh"] diff --git a/app-config/cara-public-docker-image/nginx.conf b/app-config/cara-public-docker-image/nginx.conf new file mode 100644 index 00000000..b873a7d2 --- /dev/null +++ b/app-config/cara-public-docker-image/nginx.conf @@ -0,0 +1,57 @@ +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + large_client_header_buffers 4 16k; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400; + + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + server { + listen 8080 default_server; + listen [::]:8080 default_server; + server_name _; + root /opt/cara/src; + + # Load configuration files for the default server block. + include /opt/app-root/etc/nginx.default.d/*.conf; + + large_client_header_buffers 4 16k; + + location /voila-server/ { + proxy_pass http://localhost:8082/voila-server/; + } + rewrite ^/expert-app$ /voila-server/ last; + rewrite ^/(files/static)/(.*)$ /voila-server/voila/$1/$2 last; + + location / { + proxy_pass http://localhost:8081; + } + } +} diff --git a/app-config/cara-public-docker-image/run_cara.sh b/app-config/cara-public-docker-image/run_cara.sh new file mode 100755 index 00000000..43d963b2 --- /dev/null +++ b/app-config/cara-public-docker-image/run_cara.sh @@ -0,0 +1,16 @@ + +echo 'CARA is running on http://localhost:8080' +echo 'Please see https://gitlab.cern.ch/cara/cara for terms of use.' + +# Run a proxy for the apps (listening on 8080). +nginx -c /opt/cara/nginx.conf + +# Run the expert app in the background. +cd /opt/cara/src/cara +/opt/cara/app/bin/python -m voila /opt/cara/src/cara/apps/expert/cara.ipynb \ + --port=8082 --no-browser --base_url=/voila-server/ \ + --Voila.tornado_settings 'allow_origin=*' \ + >> /var/log/expert-app.log 2>&1 & + +# Run the calculator in the foreground. +/opt/cara/app/bin/python -m cara.apps.calculator --port 8081 --no-debug diff --git a/cara/apps/calculator/__main__.py b/cara/apps/calculator/__main__.py index 10298c84..7ec61206 100644 --- a/cara/apps/calculator/__main__.py +++ b/cara/apps/calculator/__main__.py @@ -21,6 +21,11 @@ def configure_parser(parser) -> argparse.ArgumentParser: help="Change the URL path prefix to the calculator app", default="/calculator" ) + parser.add_argument( + "--port", + help="The port to listen on", + default="8080" + ) return parser @@ -33,7 +38,7 @@ def main(): assert theme_dir.exists() assert (theme_dir / 'templates').exists() app = make_app(debug=args.no_debug, calculator_prefix=args.prefix, theme_dir=theme_dir) - app.listen(8080) + app.listen(args.port) IOLoop.instance().start()