From c47634bb8be33d54cb018c76e72b40b4cd569bd7 Mon Sep 17 00:00:00 2001 From: Anthony Fitzroy <101649764+AntFMoJ@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:58:12 +0100 Subject: [PATCH] Migrate rshiny-open-source-base image from data platform (#2) * migrate-image-build * fixed linting pt.1 * fixed linting pt.2 * fixed linting pt.3 * Update Makefile * Update Makefile Co-authored-by: Jacob Woffenden * update README * Update README.md Co-authored-by: Jacob Woffenden --------- Co-authored-by: Gary H <26419401+Gary-H9@users.noreply.github.com> Co-authored-by: Jacob Woffenden Co-authored-by: Emterry <123941245+Emterry@users.noreply.github.com> --- .devcontainer/devcontainer.json | 2 +- .github/workflows/scan-image.yml | 6 +- Dockerfile | 100 ++++++++++++++++++---------- Makefile | 39 +++++++---- README.md | 107 ++++++++---------------------- gather_env_vars.py | 29 ++++++++ shiny-server.conf | 23 +++++++ shiny-server.sh | 15 +++++ test/container-structure-test.yml | 12 ++-- 9 files changed, 195 insertions(+), 138 deletions(-) create mode 100644 gather_env_vars.py create mode 100644 shiny-server.conf create mode 100755 shiny-server.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 175f026..8d7316d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "analytical-platform-image-build-template", + "name": "analytical-platform-rshiny-open-source-base", "image": "ghcr.io/ministryofjustice/devcontainer-base:latest", "features": { "ghcr.io/devcontainers/features/docker-in-docker:2": {}, diff --git a/.github/workflows/scan-image.yml b/.github/workflows/scan-image.yml index 7c21ecb..82c6522 100644 --- a/.github/workflows/scan-image.yml +++ b/.github/workflows/scan-image.yml @@ -26,13 +26,13 @@ jobs: with: push: false load: true - tags: analytical-platform-image-build-template + tags: analytical-platform-rshiny-open-source-base - name: Scan Image id: scan_image uses: aquasecurity/trivy-action@d710430a6722f083d3b36b8339ff66b32f22ee55 # v0.19.0 with: - image-ref: analytical-platform-image-build-template + image-ref: analytical-platform-rshiny-open-source-base exit-code: 1 format: sarif output: trivy-results.sarif @@ -51,7 +51,7 @@ jobs: id: scan_image_on_failure uses: aquasecurity/trivy-action@d710430a6722f083d3b36b8339ff66b32f22ee55 # v0.19.0 with: - image-ref: analytical-platform-image-build-template + image-ref: analytical-platform-rshiny-open-source-base exit-code: 1 format: table severity: CRITICAL diff --git a/Dockerfile b/Dockerfile index 4063e61..1ace0bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,49 +1,77 @@ # checkov:skip=CKV_DOCKER_2:Healthcheck instructions have not been added to container images -# This image is an example base image for this template and can be replaced to fit user needs -FROM public.ecr.aws/ubuntu/ubuntu@sha256:12fb86d81bc4504d8261a91c83c54b9e5dcdf1d833ba0fe42ec9e0ee09a2b0ba +# checkov:skip=CKV_DOCKER_3:"Ensure that a user for the container has been created" +# hadolint global ignore=DL3008 -LABEL org.opencontainers.image.vendor="Ministry of Justice" \ - org.opencontainers.image.authors="Analytical Platform (analytical-platform@digital.justice.gov.uk)"\ - org.opencontainers.image.title="{image title}" \ - org.opencontainers.image.description="{decription}" \ - org.opencontainers.image.url="{your repo url}" +ARG r=4.3.2 +FROM rocker/r-ver:${r} -ENV CONTAINER_USER="analyticalplatform" \ - CONTAINER_UID="1000" \ - CONTAINER_GROUP="analyticalplatform" \ - CONTAINER_GID="1000" \ - DEBIAN_FRONTEND="noninteractive" +ARG shinyserver=1.5.20.1002 +ENV SHINY_SERVER_VERSION=${shinyserver} +ENV PANDOC_VERSION=default +RUN /rocker_scripts/install_shiny_server.sh -SHELL ["/bin/bash", "-e", "-u", "-o", "pipefail", "-c"] +ENV STRINGI_DISABLE_PKG_CONFIG=true \ + AWS_DEFAULT_REGION=eu-west-1 \ + TZ=Etc/UTC \ + LC_ALL=C.UTF-8 -# User -RUN < -```text -├── .devcontainer -│ ├── devcontainer.json -│ └── devcontainer-lock.json -├── Dockerfile -├── .editorconfig -├── .github -│ ├── CODEOWNERS -│ ├── dependabot.yml -│ └── workflows -│ ├── build-and-test.yml -│ ├── dependency-review.yml -│ ├── release.yml -│ ├── scan-image.yml -│ └── super-linter.yml -├── .gitignore -├── LICENSE -├── Makefile -├── README.md -└── test - └── container-structure-test.yml -``` - -## Setup Instructions - -Once you've created your repository using this template, perform the following steps: - -### Update README - -Edit this README.md file to document your project accurately. Take the time to create a clear, engaging, and informative README.md file. Include information like what your project does, how to install and run it, how to contribute, and any other pertinent details. - -### Update repository description - -After you've created your repository, GitHub provides a brief description field that appears on the top of your repository's main page. This is a summary that gives visitors quick insight into the project. Using this field to provide a succinct overview of your repository is highly recommended. - -This description and your README.md will be one of the first things people see when they visit your repository. It's a good place to make a strong, concise first impression. Remember, this is often visible in search results on GitHub and search engines, so it's also an opportunity to help people discover your project. - -### Grant Team Permissions - -Assign permissions to the appropriate Ministry of Justice teams. Ensure at least one team is granted Admin permissions. Whenever possible, assign permissions to teams rather than individual users. +This repository contains the GitHub RShiny Open Source Base container image for use in the Analytical Platform. -### Read about the GitHub Repository Standards +## Running Locally -Familiarise yourself with the Ministry of Justice GitHub Repository Standards. These standards ensure consistency, maintainability, and best practices across all our repositories. +### Build -You can find the standards [here](https://operations-engineering.service.justice.gov.uk/documentation/services/repository-standards.html). - -Please read and understand these standards thoroughly and enable them when you feel comfortable. - -### Modify the GitHub Repository Standards Badge - -Once you've ensured that all the [GitHub Repository Standards](https://operations-engineering.service.justice.gov.uk/documentation/services/repository-standards.html) have been applied to your repository, it's time to update the Ministry of Justice (MoJ) Compliance Badge located in the README file. - -The badge demonstrates that your repository is compliant with MoJ's standards. Please follow these [instructions](https://operations-engineering.service.justice.gov.uk/documentation/runbooks/services/add-repo-badge.html) to modify the badge URL to reflect the status of your repository correctly. - -**Please note** the badge will not function correctly if your repository is internal or private. In this case, you may remove the badge from your README. - -### Manage Outside Collaborators - -To add an Outside Collaborator to the repository, follow the guidelines detailed [here](https://github.com/ministryofjustice/github-collaborators). +```bash +docker build --platform linux/amd64 --file Dockerfile --tag analytical-platform.service.justice.gov.uk/rshiny-open-source-base:local . +``` -### Update CODEOWNERS +### Run -(Optional) Modify the CODEOWNERS file to specify the teams or users authorized to approve pull requests. +```bash +docker run -it --rm \ + --platform linux/amd64 \ + --name analytical-platform-rshiny-open-source-base \ + analytical-platform.service.justice.gov.uk/rshiny-open-source-base:local +``` +## Versions -### Configure Dependabot +### Ubuntu -Adapt the dependabot.yml file to match your project's [dependency manager](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem) and to enable [automated pull requests for package updates](https://docs.github.com/en/code-security/supply-chain-security). +Generally Dependabot does this, but the following command will return the digest: -### Dependency Review +```bash +docker pull --platform linux/amd64 rocker/r-ver:{R_VERSION} -If your repository is private with no GitHub Advanced Security license, remove the `.github/workflows/dependency-review.yml` file. +docker image inspect --format='{{index .RepoDigests 0}}' rocker/r-ver:{R_VERSION} +``` -### Dockerfile +### APT Packages -Make sure to add your own build logic to the bottom of the `Dockerfile`. +To find latest APT package versions, you can run the following: -### Tests +```bash +docker run -it --rm --platform linux/amd64 rocker/r-ver:{R_VERSION} -> [!NOTE] -> No application testing has been added to this template, this is to be implemented by the developer as required. +apt-get update -Please make sure to add any additional container structure tests needed to the `container-structure-test.yml`. +apt-cache policy ${PACKAGE} # for example curl, git or gpg +``` diff --git a/gather_env_vars.py b/gather_env_vars.py new file mode 100644 index 0000000..661a75d --- /dev/null +++ b/gather_env_vars.py @@ -0,0 +1,29 @@ +"""Module for writing RENV files out.""" + +import os + +R_ENV_FILE_NAME = "/srv/shiny-server/.Renviron" +R_ENV_FILE_NAME1 = "/home/shiny/.Renviron" + + +def gather_env_vars_to_renv_file(): + """ + Writes RENV files out. + """ + with open( # pylint: disable=unspecified-encoding + R_ENV_FILE_NAME, "a" + ) as file_handler: + for name, value in os.environ.items(): + file_handler.write(f'{name}="{value}"') + file_handler.write("\n") + + with open( # pylint: disable=unspecified-encoding + R_ENV_FILE_NAME1, "a" + ) as file_handler: + for name, value in os.environ.items(): + file_handler.write(f'{name}="{value}"') + file_handler.write("\n") + + +if __name__ == "__main__": + gather_env_vars_to_renv_file() diff --git a/shiny-server.conf b/shiny-server.conf new file mode 100644 index 0000000..831e024 --- /dev/null +++ b/shiny-server.conf @@ -0,0 +1,23 @@ +# Instruct Shiny Server to run applications as the user "shiny" +run_as shiny; + +app_init_timeout 600; + +# Define a server that listens on port 9999 +server { + listen 9999; + + # Define a location at the base URL + location / { + + # Host the directory of Shiny Apps stored in this directory + site_dir /srv/shiny-server; + + # Log all Shiny output to files in this directory + log_dir /var/log/shiny-server; + + # When a user visits the base URL rather than a particular application, + # an index of the applications available in this directory will be shown. + directory_index on; + } +} diff --git a/shiny-server.sh b/shiny-server.sh new file mode 100755 index 0000000..df1a2a2 --- /dev/null +++ b/shiny-server.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Make sure the directory for individual app logs exists +mkdir -p /var/log/shiny-server +chown shiny.shiny /var/log/shiny-server + +if [ "$APPLICATION_LOGS_TO_STDOUT" != "false" ]; then + # push the "real" application logs to stdout with xtail in detached mode + exec xtail /var/log/shiny-server/ & +fi + +python3 ./gather_env_vars.py + +# start shiny server +exec shiny-server 2>&1 diff --git a/test/container-structure-test.yml b/test/container-structure-test.yml index 8948a04..3275686 100644 --- a/test/container-structure-test.yml +++ b/test/container-structure-test.yml @@ -2,7 +2,7 @@ schemaVersion: 2.0.0 containerRunOptions: - user: "analyticalplatform" + user: "shiny" commandTests: - name: "ubuntu" @@ -12,14 +12,14 @@ commandTests: - name: "whoami" command: "whoami" - expectedOutput: ["analyticalplatform"] + expectedOutput: ["shiny"] - name: "user" command: "id" - args: ["--user", "analyticalplatform"] - expectedOutput: ["1000"] + args: ["--user", "shiny"] + expectedOutput: ["998"] - name: "groups" command: "id" - args: ["--groups", "analyticalplatform"] - expectedOutput: ["100"] + args: ["--groups", "shiny"] + expectedOutput: ["998"]