Science Gateway
The Science Gateway website consists of two core components, the frontend UI and the backend API. The backend interacts with external services (amongst other things), and provides endpoints in the form of a REST API. The frontend interacts with the backend endpoints via the REST API, and provides a web-based Graphical User Interface to the end-user.
The Science Gateway website can be deployed on a local machine for development or in a production environment.
Deployment prerequisites
IAM Configuration
For this service, the scopes required are:
`openid`
`profile`
For the Grant types:
Ensure authorization_code and refresh_token grants are checked.
Follow the next instructions to create and manage the IAM Client Configuration, including these scopes and grant types.
One saved, get the Client ID
and Client Secret
, to include them into your configuration file for .env or docker-compose.yml.
Docker
The frontend and backend components of the Science Gateway are containerised using docker. At the time of writing, there is one container for the frontend and two for the backend (one for the core API and another for the Gateway database). The backend containers are grouped as a service to conveniently specify shared resources.
To install docker refer to the official documentation. Follow the instructions that applies to the OS on your local machine.
Note
This guide will make use of Docker CLI commands. Feel free to use the desktop UI application if it is more convenient however, instructions are not provided for that method in this guide.
Cloning the source repositories
Repositories containing the Science Gateway source code are hosted on Gitlab.
Clone the backend repository:
$ git clone https://gitlab.com/ska-telescope/src/src-api/ska-src-api-gateway
Clone the frontend repository:
$ git clone https://gitlab.com/ska-telescope/src/src-ui/ska-src-ui-gateway
Deploying the gateway on a local machine for development
The Science Gateway can be deployed on a local machine. This provides a quick and flexible way to make changes (e.g. to code, UI elements) and test the results. This is especially useful for SRCNet developers working on the Science Gateway.
Both the frontend and backend can be deployed on a local machine, and both are required for the Science Gateway to work as designed.
Prerequisites
SKA IAM Account
A SKA IAM user account with the necessary permissions for each service used by the backend API is required. The frontend obtains a code following a succesful IAM login. The frontend uses the code to obtain and exchange access tokens via the backend API. The tokens are used to access services external to the Science Gateway via the backend API.
Register for an IAM account on this website:
https://ska-iam.stfc.ac.uk/login
The IAM account should belong to the following permissions groups to use all of the Science Gateway features:
services/gateway-backend-api
services/site-capabilities-api
services/data-management-api
Deploying the backend API locally
Ensure that port 8080
is not in use on your local machine. This port is used to host
the backend API.
In your terminal, navigate to the directory of the backend repository.
$ cd ./path/to/ska-src-api-gateway
Edit the docker-compose.yml
contents to look as follows for local deployments:
version: "3.5"
services:
db:
container_name: gateway-backend-db
image: mysql:8.0
cap_add:
- SYS_NICE
restart: always
environment:
- MYSQL_DATABASE=gatewaysettings
- MYSQL_ROOT_PASSWORD=V1Lv5FxUde
ports:
- '3306:3306'
volumes:
- db:/var/lib/mysql
- ./db/init/init.sql:/docker-entrypoint-initdb.d/init.sql
core:
container_name: gateway-backend-core
image: gateway-backend-core:latest
build:
context: .
dockerfile: Dockerfile
depends_on:
- db
environment:
DISABLE_AUTHENTICATION: "no"
API_ROOT_PATH:
API_SCHEME: http
IAM_CLIENT_CONF_URL: https://ska-iam.stfc.ac.uk/.well-known/openid-configuration
API_IAM_CLIENT_ID: some-uuid
API_IAM_CLIENT_SECRET:
API_IAM_CLIENT_SCOPES: openid profile
API_IAM_CLIENT_AUDIENCE: gateway-backend-api
PERMISSIONS_API_URL: https://permissions.srcdev.skao.int/api/v1
PERMISSIONS_SERVICE_NAME: gateway-backend-api
PERMISSIONS_SERVICE_VERSION: 1
DB_HOST: db
DB_PORT: 3306
DB_USER: root
DB_PASSWORD: V1Lv5FxUde
DB_NAME: gatewaysettings
ports:
- 8080:8080
volumes:
db:
driver: local
Add values for the environment variables API_IAM_CLIENT_ID
and
API_IAM_CLIENT_SECRET
to the docker-compose.yml
file based on the IAM client
created earlier.
Set the value of the environment variable RUN_MODE
in docker-compose.yml
to
DEV
.
Create a file called docker-compose.local.yml
with the following contents:
version: "3.5"
services:
core:
extends:
file: docker-compose.yml
service: core
environment:
DISABLE_AUTHENTICATION: "no"
volumes:
- $../:/opt/ska-src-api-gateway
Deploy the docker service:
$ docker-compose up -d
Access the database container and create the required tables:
$ docker exec -ti gateway-backend-db /bin/bash
$ mysql -u root -p # will prompt for a password, use V1Lv5FxUde
$ mysql> USE gatewaysettings
$ mysql> CREATE TABLE Users ( ID int NOT NULL AUTO_INCREMENT, IAM_ID varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE Preferences ( ID int NOT NULL AUTO_INCREMENT, UserID int, DarkMode tinyint, Language varchar(10), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE Services ( ID int NOT NULL AUTO_INCREMENT, Service_ID varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE ServiceTokens ( ID int NOT NULL AUTO_INCREMENT, UserID int, ServiceID int, Username varchar(255), Token varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE DataManagementJobs ( ID int NOT NULL AUTO_INCREMENT, UserID int, JobID varchar(32), ToStorageAreaUUID varchar(255), Status varchar(255), PRIMARY KEY (ID) );
Check that the tables were created:
$ mysql> SHOW TABLES;
Type exit
and enter twice to leave MySQL and the container.
Testing the local backend deployment
Check that the service containers are running in docker:
$ docker container ls
You should see output similar to the following:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bc0189ee3037 mysql:8.0 "docker-entrypoint.s…" 8 days ago Up 2 days 0.0.0.0:3306->3306/tcp, 33060/tcp gateway-backend-db b54d97c4723b gateway-backend-core:latest "/bin/bash etc/docke…" 8 days ago Up 9 seconds 0.0.0.0:8080->8080/tcp gateway-backend-core
Test the backend API by using its
ping
endpoint by navigating to http://localhost:8080/v1/ping in your web browser. Your browser should display output similar to the following:{"status":"UP","version":"0.1.1"}
Test the backend API by navigating to http://localhost:8080/v1/www/docs/oper in your browser to view the swagger frontend.
Deploying the frontend web UI locally
Ensure that port 3000
is not in use on your local machine. It is used to host the
frontend website.
In your terminal, navigate to the directory of the backend repository:
$ cd ./path/to/ska-src-ui-gateway
Edit the Dockerfile so that its contents looks as follows:
FROM node:lts
RUN mkdir -p /app
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm", "run", "start"]
This ensures that the frontend react app will run in development mode, which means
it will access the backend API via http://localhost:8080
.
Build the frontend docker image:
$ docker build . --tag 'ska-src-ui-gateway'
Create a container using the image and run it in the background:
$ docker run --name 'gateway-ui' -p 3000:3000 -ti -d ska-src-ui-gateway
Testing the local frontend deployment
Navigate to http://localhost:3000/ in your web browser. Login using your SKA IAM Account created earlier.
Deploying the gateway in a production environment
The current deployment of the gateway (both frontend and backend) is spread over two nodes. The deployment of new versions is handled through CI/CD. Here, we will describe the relevant aspects of the setup of the nodes.
Deployment systems
Both systems (to which we will respectively refer as test
and production
systems) run on the STFC cloud. The production
system (for which the CI/CD system
is used to push the main
branch of the corresponding repositories) is called
srcnet-esap
, and is accessible through the URL https://gateway.srcdev.skao.int.
The test deployment, to which any branch can be deployed manually, runs on the
srcnet-esap-test
node, accessible through https://gateway.srcdev-test.skao.int.
The configuration of the proxies that forward the traffic from the URL to the node is
such that any traffic coming in on port 443
on the externally-facing URL is sent to
port 80
on the host.
Prerequisites
Traefik
To route traffic within the host, we use Traefik. We detail the installation here.
To access the node, an account on the STFC system is required. Access via ssh is granted
through the bastion
host. We will assume you have been granted access, know how
to access the system, and are logged in to a terminal on the host with root privileges.
For deployments, we use a user called gitlab_deploy
. So to manage the Traefik setup,
change to that user, and go to the directory holding the docker-compose file with the
configuration:
$ sudo su gitlab_deploy
$ cd ~/deploy-traefik
In this directory, you will find several artifacts. The first one being a docker-compose
file (a nice feature of Traefik is that it can run inside a docker container, while
proxying other docker containers. You will see in the docker-compose file that this is
achieved by linking in the docker socket in the docker container). The
docker-compose.yml
file looks like:
services:
traefik:
image: traefik:2.10 # or any later version
ports:
- "80:80" # http
- "8081:8081" # Traefik Dashboard
- "3001:3001" # compute API
volumes:
- $PWD/traefik/local.yml:/etc/traefik/traefik.yml
- /var/run/docker.sock:/var/run/docker.sock # see Security considerations below
networks:
- esap_network
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=PathPrefix(`/dashboard`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.entryPoints=dashboard"
The ports
section tells us that Traefik will proxy traffic coming in through port 80
(for both the gateway frontend and backend). Port 8081
exposes the Traefik dashboard,
which is a nice debugging tool. However, the dashboard is only accessible from
within the internal network of the node (so some proxying is needed to look at it). The
last port exposed is 3001
which is used for the compute API demonstrator (which for
practical reasons also runs in a container on this host, but is mapped to a different
URL than the gateway).
Apart from the aforementioned Docker socket object, the Traefik configuration file is
linked as a volume (NB In principle the configuration could also have been fully
done using docker labels rather than a yml file, keeping everything in one place, this
is really a matter of taste of the deployer). We will come back to the .yml
file
later.
The container is coupled to a network, currently called esap_network for historical reasons. At the bottom you see that the network is of type external, meaning that it has to be manually created and is not managed by docker-compose:
$ docker network create esap_network
The labels
block define some of the configuration. In this configuration, Traefik
is enable, and the dashboard (which connects to an entrypoint called dashboard
).
Finally, the Traefik .yml
configuration looks like this:
entryPoints:
web:
address: :80
dashboard:
address: :8081
compute-api:
address: :3001
log:
level: DEBUG
providers:
docker:
exposedByDefault: false # explicitly make container available using labels
network: esap_network # should match the (external) network created earlier
api:
dashboard: true
The first block defines entrypoints
which essentially are the ports to which the
Traefik application is listening (unsurprisingly those are the same as the ports opened
in the docker-compose file). Each docker container connecting to Traefik will need to
configure the entrypoint it will use so that Traefik knows from what incoming port on
the host to forward the requests. The log level is set to debug. There is only one
provider
(source of applications): the docker provider. The first
exposedByDefault
setting makes it required for any container to explicitly announce
it wants to be routed by Traefik through labels. The network
setting tells Traefik
what the internal Docker network is that needs to be connected (unsurprisingly this
matches the name of the network in the docker-compose file). The final setting tells
Traefik to run the API so that it can be connected to.
Deploying the backend API
In your terminal, navigate to the directory of the backend repository.
$ cd ./path/to/ska-src-api-gateway
Add values for the environment variables API_IAM_CLIENT_ID
and
API_IAM_CLIENT_SECRET
to the docker-compose.yml
file based on the IAM client
created earlier.
Check that the value of the environment variable RUN_MODE
in docker-compose.yml
is set to PROD
.
Deploy the docker service:
$ docker-compose up -d
Access the database container and create the required tables:
$ docker exec -ti gateway-backend-db /bin/bash
$ mysql -u root -p # will prompt for a password, use V1Lv5FxUde
$ mysql> USE gatewaysettings
$ mysql> CREATE TABLE Users ( ID int NOT NULL AUTO_INCREMENT, IAM_ID varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE Preferences ( ID int NOT NULL AUTO_INCREMENT, UserID int, DarkMode tinyint, Language varchar(10), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE Services ( ID int NOT NULL AUTO_INCREMENT, Service_ID varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE ServiceTokens ( ID int NOT NULL AUTO_INCREMENT, UserID int, ServiceID int, Username varchar(255), Token varchar(255), PRIMARY KEY (ID) );
$ mysql> CREATE TABLE DataManagementJobs ( ID int NOT NULL AUTO_INCREMENT, UserID int, JobID varchar(32), ToStorageAreaUUID varchar(255), Status varchar(255), PRIMARY KEY (ID) );
Check that the tables were created:
$ mysql> SHOW TABLES;
Type exit
twice to leave MySQL and the container.
Deploying the frontend web UI
In your terminal, navigate to the directory of the backend repository:
$ cd ./path/to/ska-src-ui-gateway
Build the frontend docker image:
$ docker build . --tag 'ska-src-ui-gateway'
Create a docker-compose.yml
file with the following contents:
services:
esap_api:
container_name: tangerinenet
image: ska-src-ui-gateway
expose:
- "3000"
networks:
- esap_network
restart: always
labels:
# Enables traefik to connect to the API
- "traefik.enable=true"
- "traefik.http.routers.tangerinenet.entryPoints=web"
- "traefik.http.routers.tangerinenet.rule=PathPrefix(`/`)"
- "traefik.http.routers.tangerinenet.service=tangerinenet"
- "traefik.http.services.tangerinenet.loadbalancer.server.port=3000"
networks:
esap_network:
external: true
Deploy the docker service:
$ docker-compose up -d