Skip to content
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

Deperecate use of process.env, add healthcheck #186

Merged
merged 10 commits into from
Dec 16, 2024
Merged
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
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.git
.idea
build

**/*.env*
6 changes: 1 addition & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
# PCDS config
REACT_APP_BC_BASE_MAP_TILES_URL=https://services.pacificclimate.org/tiles/bc-albers-lite/{z}/{x}/{y}.png

Nospamas marked this conversation as resolved.
Show resolved Hide resolved
# YNWT config
REACT_APP_YNWT_BASE_MAP_TILES_URL=https://services.pacificclimate.org/tiles/yukon-albers-lite/{z}/{x}/{y}.png
PUBLIC_URL=%REPLACE_PUBLIC_URL%
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PUBLIC_URL=http://localhost:3000
2 changes: 1 addition & 1 deletion .env.production
Original file line number Diff line number Diff line change
@@ -1 +1 @@
PUBLIC_URL=http://localhost:3333/
PUBLIC_URL=%REPLACE_PUBLIC_URL%
4 changes: 4 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ jobs:
run: |
git fetch --prune --unshallow
echo "REACT_APP_APP_VERSION=$(git describe --tags --abbrev=0) ($(git rev-parse --abbrev-ref HEAD):$(git log -1 --format=%h))" >> $GITHUB_ENV
- name: Build npm package
run: |
npm ci
npm run build
- name: Publish to Registry
uses: docker/build-push-action@v1
with:
Expand Down
11 changes: 6 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# These variables are set to make it convenient to run the docker image locally.
tag = $(shell git rev-parse --abbrev-ref HEAD)
port = 30502
port = 30503
public_url = http://localhost:${port}

image:
@SDP_TAG=$(tag) SDP_PORT=$(port) SDP_PUBLIC_URL=$(public_url) docker compose -f docker/docker-compose.yaml build --build-arg REACT_APP_APP_VERSION='$(shell ./generate-commitish.sh)'
@npm run build
@SDP_TAG=$(tag) SDP_PORT=$(port) docker compose -f docker/docker-compose.yaml build --build-arg REACT_APP_APP_VERSION='$(shell ./generate-commitish.sh)'

up:
@SDP_TAG=$(tag) SDP_PORT=$(port) SDP_PUBLIC_URL=$(public_url) docker compose -f docker/docker-compose.yaml up -d --force-recreate
@echo "Station Data Portal running at $(public_url)"
@SDP_TAG=$(tag) SDP_PORT=$(port) docker compose -f docker/docker-compose.yaml up --force-recreate
@echo "Station Data Portal running on $(port)"
@docker logs -f station-data-portal-frontend

down:
@SDP_TAG=$(tag) SDP_PORT=$(port) SDP_PUBLIC_URL=$(public_url) docker compose -f docker/docker-compose.yaml down
@SDP_TAG=$(tag) SDP_PORT=$(port) docker compose -f docker/docker-compose.yaml down
19 changes: 19 additions & 0 deletions craco.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,29 @@ const { CracoAliasPlugin } = require("react-app-alias");
const options = {}; // default is empty for most cases

module.exports = {
eslint: null,
plugins: [
{
plugin: CracoAliasPlugin,
options: {},
},
],
// Works around a warning that plotly.js doesn't have a source map
// As warnings are treated as errors in the build, this is necessary
// node_modules are generally external code so it is hard to fix the warning
// and we can safely ignore sourcemap errors.
webpack: {
configure: {
ignoreWarnings: [
function ignoreSourcemapsloaderWarnings(warning) {
return (
warning.module &&
warning.module.resource.includes("node_modules") &&
warning.details &&
warning.details.includes("source-map-loader")
);
},
],
},
},
Nospamas marked this conversation as resolved.
Show resolved Hide resolved
};
43 changes: 12 additions & 31 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,20 @@
# This Dockerfile adapted from https://mherman.org/blog/dockerizing-a-react-app/
# and Client Explorer Dockerfile.

# This Dockerfile can (and should) be used to pass through automatically generated
# version information to the build which is triggered when the image is run.
# To do this, issue the following build command:
#
# docker build --build-arg REACT_APP_APP_VERSION="$(./generate-commitish.sh)" -t <tag> .

# At this moment, Node.js 10.16 LTS is recommended for most users.
#
# In future, as we scale up, we may want to use an Alpine base image, which would reduce
# the size of the image by about an order of magnitude and reduce the attack surface of
# the image as well.
FROM node:22-bookworm-slim

Nospamas marked this conversation as resolved.
Show resolved Hide resolved
FROM node:16
RUN apt-get -y update && \
apt-get install --no-install-recommends \
-y curl rpl && \
rm -rf /var/lib/apt/lists/*

ADD . /app
WORKDIR /app
RUN chown node /app

ENV PATH /app/node_modules/.bin:$PATH
COPY --chown=node:node package.json /app/package.json

# Currently, we have to force install. For details, see ./docs/installation.md
RUN npm install --quiet --force
RUN npm install -g serve
COPY --chown=node:node . /app

EXPOSE 8080

# Move the build arg REACT_APP_APP_VERSION into an
# environment variable of the same name, for consumption
# by the npm build process in ./entrypoint.sh
ARG REACT_APP_APP_VERSION
ENV REACT_APP_APP_VERSION $REACT_APP_APP_VERSION
COPY --chown=node build /app
COPY --chown=node docker/entrypoint.sh /app/docker/entrypoint.sh
WORKDIR /app

USER node
ENTRYPOINT docker/entrypoint.sh
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl", "-f", "http://localhost:8080/healthcheck.js" ]

ENTRYPOINT ["docker/entrypoint.sh"]
25 changes: 0 additions & 25 deletions docker/bc-config.yaml

This file was deleted.

3 changes: 0 additions & 3 deletions docker/bc.env

This file was deleted.

25 changes: 25 additions & 0 deletions docker/config.bc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
window.env = {
PUBLIC_URL: "http://localhost:30503",
REACT_APP_BC_BASE_MAP_TILES_URL:
"https://services.pacificclimate.org/tiles/bc-albers-lite/{z}/{x}/{y}.png",
appTitle: "BC Station Data - PCDS",
baseMap: "BC",

// Uses swarm based dev url by default
sdsUrl:
"https://beehive.pacificclimate.org/station-data-portal/pcds/metadata/",

// Currently deployed metadata backends do not respond to provinces QP.
// When they do, we can invert the commenting out below.
//stationsQpProvinces: BC
stationFilters: 'histories[0].province = "BC"',

// Always necessary for CRMP database
networkFilters: 'name != "PCIC Climate Variables"',

// Uses monsoon database
pdpDataUrl:
"https://beehive.pacificclimate.org/station-data-portal/pcds/data/",
// Uses new database
//pdpDataUrl: http://docker-dev02.pcic.uvic.ca:???
};
26 changes: 26 additions & 0 deletions docker/config.ynwt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Example environment config for a YNWT based deployment

window.env = {
PUBLIC_URL: "http://localhost:30503",
REACT_APP_YNWT_BASE_MAP_TILES_URL:
"https://services.pacificclimate.org/tiles/yukon-albers-lite/{z}/{x}/{y}.png",
appTitle: "YNWT Station Data",
baseMap: "YNWT",

// sdsUrl values will be replaced by prod URLs when they become ready.
// For now, we have a dev instance.
// Uses monsoon database
sdsUrl:
"https://beehive.pacificclimate.org/station-data-portal/ynwt/metadata/",

// We do not at present need to filter based on province (verify!)
//stationsQpProvinces: YK,NT
// We do not at present need to filter networks (verify!)
//networkFilters: ???

// pdpDataUrl values will be replaced by prod URLs when they become ready.
// For now, we have a dev instance.
// Uses monsoon database
pdpDataUrl:
"https://beehive.pacificclimate.org/station-data-portal/ynwt/data/",
};
10 changes: 1 addition & 9 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#
# `SDP_TAG`: Image tag
# `SDP_PORT`: External port to map to
# `SDP_PUBLIC_URL`: Public URL of app
# Note: These values are set as part of the makefile, initialize the container
# Using it.
Nospamas marked this conversation as resolved.
Show resolved Hide resolved
#
Expand All @@ -19,14 +18,7 @@ services:
dockerfile: ./docker/Dockerfile
#image: pcic/station-data-portal-frontend:${SDP_TAG}
container_name: station-data-portal-frontend
environment:
- PUBLIC_URL=${SDP_PUBLIC_URL}
env_file:
- bc.env
volumes:
- type: bind
source: ./bc-config.yaml
target: /app/public/config.yaml
read_only: true
- ./config.bc.js:/app/config.js
ports:
- "${SDP_PORT}:8080"
27 changes: 19 additions & 8 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# We build the app as part of the container startup so that the build process
# can consume the runtime environment variables. (CRA apps can only access
# environment variables at build time, not at run time.) This makes starting a
# container a lot heavier, but we don't spin up many instances, or often,
# so it doesn't matter.

npm run build
serve -s build -l 8080
#!/bin/bash

# Note: this pulls the public url by a combination of grep and cut and relies on
# PUBLIC_URL to be on its own line with the value and in the format of PUBLIC_URL="http://localhost:8080"
# Fragile to additional quotes due to us looking for index 2
PUBLIC_URL=$(grep PUBLIC_URL config.js | cut -d'"' -f 2)

# update static files with the public url
rpl -iR \
-x **/*.js \
-x **/*.html \
-x **/*.css \
-x **/*.json \
"%REPLACE_PUBLIC_URL%" $PUBLIC_URL .

# It is possible that the above could be replaced by a node.js based
# script which may prove more resillient long term
Nospamas marked this conversation as resolved.
Show resolved Hide resolved

serve -s . -l 8080
17 changes: 0 additions & 17 deletions docker/ynwt-config.yaml

This file was deleted.

2 changes: 0 additions & 2 deletions docker/ynwt.env

This file was deleted.

51 changes: 51 additions & 0 deletions docs/developer/build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Building the project

There are 3 modes of operation for the application which take slightly different build steps:

### Local

Everything in the project should be set up for easy development with defaults provided that allow
execution without modification to configuration. This execution is done via `npm run start`. The
project is then built via create react app and a local development server is started.

Local config is provided via [public/config.js](../public/config.js) and is loaded automatically
as a static javascript file via the local development server.

Public URL is overridden by the `.env.development` file to our expected `http://localhost:3000`

### Local Docker

Testing for deployment involves building in production mode and setting up a container as we will
in production. This allows us to ensure that dependencies are met and gives us a portable artifact
that we can set up on any docker capable machine and expect to work.

Creating the container can be done via the `make image` command. This command executes `npm run build`
creating a static version of the website. `process.env` variables are baked into the files at this
time, so it should be avoided for evironment specific configuration use. These static assests are in
the `build/` folder. Once built the [Dockerfile](../../docker/Dockerfile) pulls in these files along
with dependencies to generate a docker image.

Running the created docker image can be done via `make up`. This brings up the image based on the
specification in the [docker-compose.yaml](../../docker/docker-compose.yaml). This specification also
overrides our local development configuration values by mounting an alternative configuration. Two examples
are provided `config.bc.js` and `config.ynwt.js` representing our two common production versions. `bc`
is used by default.

`PUBLIC_URL` is handled in two steps. During the build process we define a replacement value in `.env.production`
which is injected into any locations where the public URL is required. When the container starts we replace
these instances with the public URL defined in whatever `/app/config.js` within the container has for the
`PUBLIC_URL` value. The specific implementation of this replacement can be found in the
[entrypoint.sh](../../docker/entrypoint.sh) file which is used as the default entrypoint for the container
when it starts.

### Production Docker

Production docker essentially follows the same steps as above (what good would a local test be otherwise!)
but is executed via a github workflow. The resulting image is uploaded to our
[docker hub](https://registry.hub.docker.com/r/pcic/station-data-portal-frontend) for use where desired.

Specific steps are defined in the [github workflow](../../.github/workflows/docker-publish.yml) file.

When running in production we need to provide environment specific config, this config will closely
resemble the templates defined in the `config.bc.js` and `config.ynwt.js` files noted above and should be
mounted to `/app/config.js` within the container.
Loading
Loading