From d83791c3dd8222948b101f9e7584c30a953b8b03 Mon Sep 17 00:00:00 2001 From: Joris Borgdorff Date: Tue, 10 Dec 2019 14:28:08 +0100 Subject: [PATCH 1/4] Atlas docker build Introduces a Dockerfile and all necessery files to run a production deployment of the Atlas frontend. This makes frontend developments easier to test in a live setting. It also facilitates hosting and keeping track of custom builds. --- .dockerignore | 5 +++++ Dockerfile | 45 ++++++++++++++++++++++++++++++++++++++++++ docker/config-local.js | 15 ++++++++++++++ docker/entrypoint.sh | 13 ++++++++++++ docker/nginx.conf | 29 +++++++++++++++++++++++++++ package.json | 1 + 6 files changed, 108 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker/config-local.js create mode 100755 docker/entrypoint.sh create mode 100644 docker/nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..cb42f32f9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +/node_modules +/.git +/.github +/.idea +/.vscode \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..f297f4891 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# Build the source +FROM node:12 as builder + +WORKDIR /code + +# First install dependencies. This part will be cached as long as +# the package(-lock).json files remain identical. +COPY package*.json /code/ +RUN npm install + +# Load code to be built +COPY ./build /code/build +COPY ./js /code/js + +RUN npm run build:docker + +# Production Nginx image +FROM nginx:1.17-alpine + +# Directory where atlas files will be stored +ENV ATLAS_HOME=/usr/share/nginx/html/atlas +# URL where WebAPI can be queried by the client +ENV WEBAPI_URL=http://localhost:8080/WebAPI/ +# Hostname for nginx configuration +ENV ATLAS_HOSTNAME=localhost + +# Configure webserver +COPY ./docker/nginx.conf /etc/nginx/nginx.conf +COPY ./docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Load code +COPY ./images $ATLAS_HOME/images +COPY ./index.html ./README.md ./LICENSE $ATLAS_HOME/ +COPY --from=builder /code/node_modules $ATLAS_HOME/node_modules +COPY --from=builder /code/js $ATLAS_HOME/js + +# Load Atlas configuration +COPY ./docker/config-local.js $ATLAS_HOME/js/config-local.js + +ENTRYPOINT ["/entrypoint.sh"] + +CMD ["nginx", "-g", "daemon off;"] + +EXPOSE 80 diff --git a/docker/config-local.js b/docker/config-local.js new file mode 100644 index 000000000..3e5731ad4 --- /dev/null +++ b/docker/config-local.js @@ -0,0 +1,15 @@ +define([], function () { + var configLocal = {}; + + // WebAPI + configLocal.api = { + name: 'OHDSI', + url: 'http://localhost:8080/WebAPI/' + }; + + configLocal.cohortComparisonResultsEnabled = false; + configLocal.userAuthenticationEnabled = false; + configLocal.plpResultsEnabled = false; + + return configLocal; +}); diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 000000000..5466b1ad0 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +if [ -n "${WEBAPI_URL}" ]; then + sed -i "s|http://localhost:8080/WebAPI/|$WEBAPI_URL|g" "$ATLAS_HOME/js/config-local.js" +fi + +if [ -n "${ATLAS_HOSTNAME}" ]; then + sed -i "s/server_name \$hostname;/server_name $ATLAS_HOSTNAME;/" /etc/nginx/nginx.conf +fi + +exec "$@" \ No newline at end of file diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 000000000..8a78bbf62 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,29 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + + keepalive_timeout 65; + + gzip on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/package.json b/package.json index fe1b58534..f3a4defe3 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "clean": "rimraf ./js/assets/bundle && rimraf ./js/assets/fonts && rimraf ./js/assets/images", "build": "npm run prep && npm run build:dev", "build:dev": "node build/optimize.js && npm run compress", + "build:docker": "npm run clean && npm run build:dev && npm prune --production", "compress": "terser ./js/assets/bundle/bundle.js -o ./js/assets/bundle/bundle.js -c --source-map" }, "repository": { From 0319b920c1186ed566fa140de91a3546bc1f5dea Mon Sep 17 00:00:00 2001 From: Joris Borgdorff Date: Thu, 30 Jan 2020 09:30:03 +0100 Subject: [PATCH 2/4] Added docker-compose file --- .dockerignore | 3 +- docker/.env | 14 +++++++++ docker/.gitignore | 2 ++ docker/docker-compose.yml | 66 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 docker/.env create mode 100644 docker/.gitignore create mode 100644 docker/docker-compose.yml diff --git a/.dockerignore b/.dockerignore index cb42f32f9..1521394d4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,5 @@ /.git /.github /.idea -/.vscode \ No newline at end of file +/.vscode +/docker/postgresql diff --git a/docker/.env b/docker/.env new file mode 100644 index 000000000..bbb7050db --- /dev/null +++ b/docker/.env @@ -0,0 +1,14 @@ +# Set datasource variables +DATASOURCE_HOST=postgresql:5432 +DATASOURCE_DB=ohdsi +DATASOURCE_USERNAME=ohdsi +DATASOURCE_PASSWORD=secret + +# Configure how this server will be reached from a user's perspective +HOSTNAME=localhost +BASE_URL=http://localhost:8080 +# For local development, set the above variables to localhost and https://localhost:8080 respectively. + +# Set the paths to the Atlas and WebAPI source directories +ATLAS_PATH=.. +WEBAPI_PATH=../../WebAPI diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 000000000..d6de75c54 --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1,2 @@ +drivers/ +postgresql/ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 000000000..1a1972252 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3' + +services: + # Atlas service, running Nginx to serve the Javascript files. + atlas: + build: ${ATLAS_PATH} + image: ohdsi/atlas + environment: + WEBAPI_URL: ${BASE_URL}/WebAPI/ + ATLAS_HOSTNAME: ${HOSTNAME} + labels: + - "traefik.http.routers.atlas.rule=PathPrefix(`/atlas`)" + - "traefik.http.services.atlas.loadbalancer.server.port=80" + + # WebAPI service, running Nginx to serve the Javascript files. + webapi: + build: ${WEBAPI_PATH} + image: ohdsi/webapi + labels: + - "traefik.http.routers.webapi.rule=PathPrefix(`/WebAPI`)" + - "traefik.http.services.webapi.loadbalancer.server.port=8080" + environment: + - JAVA_OPTS=-Xmx4g + - CLASSPATH=":/var/lib/ohdsi/webapi/drivers/*" + - WEBAPI_URL=${BASE_URL} + # Specify Spring settings. Any Spring setting that is set in `pom.xml` or your own + # settings.xml can be replaced with a variable in this list. Replace the periods (.) + # in the variable name with underscores (_) + - env=webapi-postgresql + - datasource_driverClassName=org.postgresql.Driver + - datasource_url=jdbc:postgresql://${DATASOURCE_HOST}/${DATASOURCE_DB} + - datasource_ohdsi_schema=ohdsi + - datasource_username=${DATASOURCE_USERNAME} + - datasource_password=${DATASOURCE_PASSWORD} + - spring_jpa_properties_hibernate_default__schema=ohdsi + - spring_jpa_properties_hibernate_dialect=org.hibernate.dialect.PostgreSQLDialect + - spring_batch_repository_tableprefix=ohdsi.BATCH_ + - flyway_datasource_driverClassName=org.postgresql.Driver + - flyway_datasource_url=jdbc:postgresql://${DATASOURCE_HOST}/${DATASOURCE_DB} + - flyway_schemas=ohdsi + - flyway_placeholders_ohdsiSchema=ohdsi + - flyway_datasource_username=${DATASOURCE_USERNAME} + - flyway_datasource_password=${DATASOURCE_PASSWORD} + - flyway_locations=classpath:db/migration/postgresql + + postgresql: + image: bitnami/postgresql:12.1.0 + volumes: + - ./postgresql/data:/bitnami/postgresql + ports: + - "5432:5432" + environment: + - POSTGRESQL_USERNAME=${DATASOURCE_USERNAME} + - POSTGRESQL_PASSWORD=${DATASOURCE_PASSWORD} + - PGPASSWORD=${DATASOURCE_PASSWORD} + - POSTGRESQL_DATABASE=${DATASOURCE_DB} + + # Host both Atlas and WebAPI from the same port: :8080 + traefik: + image: traefik:2.1 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + command: --api.insecure=true --providers.docker + ports: + - "8080:80" + From 1ad0f6ecf91b8ea3870f0d8e4b27f4518041f5fc Mon Sep 17 00:00:00 2001 From: chgl Date: Sat, 28 Mar 2020 17:06:54 +0100 Subject: [PATCH 3/4] replaced nginx base image with the unprivileged variant this made some changes to folder permissions necessary. --- Dockerfile | 23 +++++++++++++++-------- docker/docker-compose.yml | 2 +- docker/nginx.conf | 3 +-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index f297f4891..28f6e5acb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,8 @@ COPY ./js /code/js RUN npm run build:docker # Production Nginx image -FROM nginx:1.17-alpine +FROM nginxinc/nginx-unprivileged:1.17-alpine +USER root # Directory where atlas files will be stored ENV ATLAS_HOME=/usr/share/nginx/html/atlas @@ -26,20 +27,26 @@ ENV ATLAS_HOSTNAME=localhost # Configure webserver COPY ./docker/nginx.conf /etc/nginx/nginx.conf +# this is required so the sed command run by the enginx user in entrypoint.sh +# has permission to create a temp file in the /etc/nginx dir. +RUN chown -R nginx:nginx /etc/nginx + COPY ./docker/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Load code -COPY ./images $ATLAS_HOME/images -COPY ./index.html ./README.md ./LICENSE $ATLAS_HOME/ -COPY --from=builder /code/node_modules $ATLAS_HOME/node_modules -COPY --from=builder /code/js $ATLAS_HOME/js +WORKDIR $ATLAS_HOME +RUN chown nginx:nginx ${ATLAS_HOME} +COPY ./images ./images +COPY ./index.html ./README.md ./LICENSE ./ +COPY --from=builder /code/node_modules ./node_modules +COPY --from=builder --chown=nginx:nginx /code/js ./js # Load Atlas configuration -COPY ./docker/config-local.js $ATLAS_HOME/js/config-local.js +COPY --chown=nginx:nginx ./docker/config-local.js ./js/config-local.js + +USER nginx ENTRYPOINT ["/entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] - -EXPOSE 80 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 1a1972252..a50f5f288 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,7 +10,7 @@ services: ATLAS_HOSTNAME: ${HOSTNAME} labels: - "traefik.http.routers.atlas.rule=PathPrefix(`/atlas`)" - - "traefik.http.services.atlas.loadbalancer.server.port=80" + - "traefik.http.services.atlas.loadbalancer.server.port=8080" # WebAPI service, running Nginx to serve the Javascript files. webapi: diff --git a/docker/nginx.conf b/docker/nginx.conf index 8a78bbf62..905d9bb76 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -1,8 +1,7 @@ -user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; +pid /tmp/nginx.pid; events { worker_connections 1024; From 0c2f0333576181eb44407137fa8926a9469f3658 Mon Sep 17 00:00:00 2001 From: chgl Date: Sat, 28 Mar 2020 17:07:16 +0100 Subject: [PATCH 4/4] added a trailing slash to the WEBAPI_URL if not already present --- docker/entrypoint.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 5466b1ad0..d5bec11ec 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -3,6 +3,10 @@ set -e if [ -n "${WEBAPI_URL}" ]; then + if [ "${WEBAPI_URL: -1}" != "/" ]; then + WEBAPI_URL="$WEBAPI_URL/" + fi + sed -i "s|http://localhost:8080/WebAPI/|$WEBAPI_URL|g" "$ATLAS_HOME/js/config-local.js" fi