From 735088266ae0cc43d7ec9e2cd4dd9c451d25dc07 Mon Sep 17 00:00:00 2001 From: EdwinWiseOne Date: Thu, 7 Mar 2024 11:42:21 -0600 Subject: [PATCH 1/2] Create Panel core example --- Core/Panel/.gitignore | 7 ++ Core/Panel/Dockerfile | 56 +++++++++ Core/Panel/README.md | 177 +++++++++++++++++++++++++++ Core/Panel/bootstrap.py | 70 +++++++++++ Core/Panel/ci/__main__.py | 122 ++++++++++++++++++ Core/Panel/dev_settings.json.example | 10 ++ Core/Panel/src/app.py | 94 ++++++++++++++ Core/Panel/src/startup-script.sh | 13 ++ Panel/ci/__main__.py | 2 +- 9 files changed, 550 insertions(+), 1 deletion(-) create mode 100644 Core/Panel/.gitignore create mode 100644 Core/Panel/Dockerfile create mode 100644 Core/Panel/README.md create mode 100644 Core/Panel/bootstrap.py create mode 100644 Core/Panel/ci/__main__.py create mode 100644 Core/Panel/dev_settings.json.example create mode 100644 Core/Panel/src/app.py create mode 100755 Core/Panel/src/startup-script.sh diff --git a/Core/Panel/.gitignore b/Core/Panel/.gitignore new file mode 100644 index 0000000..4d84f63 --- /dev/null +++ b/Core/Panel/.gitignore @@ -0,0 +1,7 @@ +/dev_settings.json +/dev_settings.json.disabled +*.zbundle +__pycache__/ +.DS_Store +*.sqlite +*.sqlite-journal diff --git a/Core/Panel/Dockerfile b/Core/Panel/Dockerfile new file mode 100644 index 0000000..b8f977e --- /dev/null +++ b/Core/Panel/Dockerfile @@ -0,0 +1,56 @@ +# This is the Dockerfile for the Enthought Edge "Panel" core example. +# +# We use "edm-centos-7" as the base image. This is a Centos-7 based image +# which includes EDM. +# +# EDM dependencies for the app are brought in via a .zbundle file. This avoids +# the need to pass your EDM token and/or a custom edm.yaml into the Dockerfile. +# +# We perform a two-stage build, to avoid including the .zbundle in the layers +# of the published image. + + +# IMPORTANT: Please do not define any of the EDGE_* environment variables, or +# any of the JUPYTERHUB_* variables, directly in this file. They will be set +# automatically when running in Edge, or by the "ci" module when running +# locally. + +# First stage + +ARG BASE_IMAGE=quay.io/enthought/edm-centos-7:3.4.0 + +FROM $BASE_IMAGE as stage_one + +ARG EDGE_BUNDLE=app_environment.zbundle +COPY $EDGE_BUNDLE /tmp/app_environment.zbundle + +RUN adduser app +USER app +WORKDIR /home/app + +# Create a default EDM environment using the enthought_edge bundle +RUN edm env import -f /tmp/app_environment.zbundle edm && edm cache purge --yes + + +# Second stage + +FROM $BASE_IMAGE as stage_two + +RUN adduser app +USER app +WORKDIR /home/app + +COPY --from=stage_one --chown=app /home/app/.edm /home/app/.edm + +# Make any global changes (yum install, e.g.) in the second stage. +# Don't change the user, and in particular don't make the user "root". + +# Copy startup script and application. +# Note: the startup script must be placed in /home/app for the base image +# machinery to pick it up. + +COPY --chown=app ./src/startup-script.sh /home/app/startup-script.sh +RUN chmod +x /home/app/startup-script.sh +COPY --chown=app ./src/app.py /home/app/app.py + +CMD ["/home/app/startup-script.sh"] diff --git a/Core/Panel/README.md b/Core/Panel/README.md new file mode 100644 index 0000000..cb6602d --- /dev/null +++ b/Core/Panel/README.md @@ -0,0 +1,177 @@ +# Panel example + +This example shows how to develop an application for Edge using the Panel +library. You can read more about Panel at their official site: +https://panel.holoviz.org/. + + +## Before you begin + +Before starting, ensure you have the following installed: + +* [Docker](https://docker.com) +* [EDM](https://www.enthought.com/edm/), the Enthought Deployment Manager + +Finally, ensure your ``edm.yaml`` file lists ``enthought/edge`` as an egg +repository, along with ``enthought/free`` and ``enthought/lgpl``. This will be +necessary to use EdgeSession in the example. + + +## Quick start + +1. Run ``python bootstrap.py``. This will create a development environment + and activate it, dropping you into a development shell. + +2. From within the development shell, build the example by running + ``python -m ci build``. This will produce a Docker image. + +3. Run the Docker image via ``python -m ci run``. The app will serve on + http://127.0.0.1:9000 in a local development mode. + + +## Modifying the example for your use case + +Please note these are the minimal changes necessary to make the example your +own. Depending on your use case you may wish to add additional "ci" commands, +install different items in the Dockerfile, etc. + +* In ``ci/__main__.py``, change the constants IMAGE, VERSION, and + APP_DEPENDENCIES as appropriate. +* In ``bootstrap.py``, consider changing the name of the development + environment (ENV_NAME) to avoid conflicts with other examples. + + +## Publishing your app + +1. Ensure you are logged in (via ``docker login``) to DockerHub, Quay.io, or + another Docker registry. + +2. Run ``python -m ci publish`` to push your app's image to the registry. + +Once you have published your Docker image, you are ready to register that +version of your app with Edge. + +As a quick reminder, in Edge, there is a distinction between an _app_ and an +_app version_. Your organization administrator can define an _app_, and then +developers are free to register _app versions_ associated with that app. This +ensures that org administrators have full control over what shows up on the +dashboard, but gives developers freedom to publish new versions by themselves. + +The easiest way to register a new app version is by logging in to Edge, going +to the gear icon in the upper-right corner, and navigating to the app in +question. There is a form to fill out which asks for the version, Quay.io or +DockerHub URL for the image, and some other information. + +It is also possible to register app versions programmatically, for example +from within a GitHub Actions workflow. See the example at the end of this +README. + + +## Getting EdgeSession to work in development + +When you run your app on Edge, you can create an EdgeSession object simply by +calling the constructor (``mysession = EdgeSession()``). This works by +collecting environment variables set by Edge when the container is launched. + +When developing locally, it's also convenient to have an EdgeSession. You +can get the "ci" module to inject the appropriate environment variables, so +that your ``EdgeSession()`` call will work with ``python -m ci run`` and +``python -m ci preflight``. + +To do so, follow this procedure: + +* Copy the "dev_settings.json.example" file to "dev_settings.json". +* Define EDGE_API_SERVICE_URL in that file. The typical value here is + ``"https://edge.enthought.com/services/api"``. +* Define EDGE_API_ORG in that file. This is the "short name" displayed in + the URL bar when you log into an organization, for example, ``"default"``. +* Define EDGE_API_TOKEN. You can get one of these by going to the + ``/hub/token`` endpoint on the Edge server. + +Be sure *not* to check the "dev_settings.json" file into source control, as it +contains your API token. + + +## Viewing console output + +When running with ``python -m ci run``, the app's output will be displayed +on the console where you launched it. + +## Guidelines for your Dockerfile + +Edge will run your app next to a built-in reverse proxy, which allows +you to skip a lot of work in the development process. This includes stripping +the prefix from requests, handling the OAuth2 login flow, pinging JupyterHub +for container activity, and more. But, there are a few guidelines you will +need to follow in your own Dockerfile. + +* Don't change the user to anything other than ``app`` (for example, by the + Dockerfile ``USER`` command). If you need to run ``yum`` for some reason, + use ``sudo``. +* Your app should bind to ``127.0.0.1``, *not* ``0.0.0.0``, and it should serve + on port 9000. The Edge machinery will respond to requests on port 8888 and + forward them to your app. + + +## Publishing versions from CI (e.g. GitHub Actions) + +You can register your app version programmatically. This is particularly +convenient during the development process, for automated builds. A general +example looks like this, for an app whose ID is ``my-app-id``: + + +``` +from edge.api import EdgeSession +from edge.apps.application import Application +from edge.apps.app_version import AppKindEnum, AppVersion +from edge.apps.server_info import ServerInfo + +# Create an Edge session. +edge = EdgeSession( + service_url="https://edge.enthought.com/services/api", + organization="", + api_token="" +) + +# Register the application version. + +# Icon is a base64-encoded PNG. +# It should be square, any size; 64x64 or 128x128 are common. +ICON = ( + "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAk1BMVEUAAA" + "AMfIYAdnwAdnwAd3wAc3kAdntYsb8AdnwAdn0AdXwAdXsAd30Ad3xYsb8A" + "d30AdntYsL8Ad30AdnsAd30AdnwAd3wAd30AdnxYssBYsb5Ysr9Zs70Adn" + "tYsr9Ysb9Ysb9Ysr8AdnxXs75Ysb4AdXsAd3wAdnxYsb8AeoAAfYMAf4Vb" + "t8Zfv84Ad31ixtVevMuy+odXAAAAJ3RSTlMABPr88Shd+4pmkXyDbfB0Xy" + "dWTy0h9TLnkYv+IJmX9uigNzOIf5LOQ2WlAAAC/ElEQVR42sXX7VLiMBiG" + "4aTBDwQVEJSPXdkF3dAi1fM/uoXp7DyzIzHEm7bvT6Dc16SlDQbObG5anf" + "nHx4tpcea7q6sdWQPeXyyIgPc3+7nazQwY3N8sWhLM9uu/+Sd4NmBQvxog" + "YH0g4P2qLMFvAwb0WxE8q9+CwJqX96W6muV7U9fB8NfbsRV4u1ubhubHQf" + "C5PzQNjZXg/741dY8EdxKAPhTQPhfQPhfQPheQPhcM9wLa54KG+jYoCPZt" + "M4Llspn+KlRZr0PvrM7Z/7m9DHVCr19ub87Zd4UEX436hZeA9zPnJTix7z" + "IJcN97CU7tey8B70twev9Mgj+HvgQJ/fMIbqq+BCl9CXhfgpS+BLwvQUpf" + "At6XIN7nAvWTBOpDgfppgm6uPhGonyaw00LHAIH6qYLJNA8KeD8usF8Irk" + "E/SdChAvXbEajfjkD9dgTqtyNQv0XB9aFPBRcRAexzQXo/q1MQ77uyqHEN" + "4v2smPby0qUKHoOC1H7eGZtB4VMF47AgtX+hrU4Ngmj/cWzs+QU2rW/qFc" + "T7lSA/o6BvbEq/+rpRuuApiwvi/doE0X72pA/VJYj36xXE+7UL+sf7Tn0s" + "WPncBQTh51/Z0fV3oiDvBtegU/rQ/eC1OIpz5XRirEkQOFfch/8ulEfNru" + "gZcx8QVI+AuECnoGtM8NEc6N8aY0OC7ESB+qdvDdS33xQ8aH9A+0igfj74" + "Zh8K9BMEfSxwPgd9KKj6o8S+V58KaJ8LXJk/gD4WeM/6XMD6XDCC558LYJ" + "8LYJ8LQB8IYJ8IeD9+eG9LBPH7PxTgPhbQPhfwPhek932gDwTRfnjLyAW0" + "zwW8H5+IAPa5gPa5gPa5gPa5gPa5gPa5gPa5gPa5gPa5APa5gPW5YDJBfS" + "6YTkmfC1xZukb6NiiAfS4AfSAAfSQoHOpzwes2Q30+fQla6VsJQB8LeJ8L" + "wv0B6AMB6AMB6HMB7XMB7XMB7XMB7XMB7XMB7XMB7XMB7XMB7XMB7XMB7H" + "NBjvpccH0L+38B6kvWH2wXIe8AAAAASUVORK5CYII=" +) +version = AppVersion( + app_id="my-app-id", # Specified when the app is created + version="1.0.0", # or whatever version you have + title="My Application Title", + description="This Is An Example Edge Application", + icon=ICON, + kind=AppKindEnum.Native, + link="quay.io//YOUR_IMAGE_NAME_HERE:TAG", + recommended_profile="edge.medium" +) +edge.applications.add_app_version(version) +``` \ No newline at end of file diff --git a/Core/Panel/bootstrap.py b/Core/Panel/bootstrap.py new file mode 100644 index 0000000..8132564 --- /dev/null +++ b/Core/Panel/bootstrap.py @@ -0,0 +1,70 @@ +# Enthought product code +# +# (C) Copyright 2010-2022 Enthought, Inc., Austin, TX +# All rights reserved. +# +# This file and its contents are confidential information and NOT open source. +# Distribution is prohibited. + +""" + Bootstrap file, which builds the local EDM development environment for this + example. +""" + +import argparse +import subprocess + +ENV_NAME = "edge-panel-core" +EDM_DEPS = ["click", "pip", "setuptools"] +PIP_DEPS = ["sqlalchemy<2", "dockerspawner"] + + +def bootstrap(ci_mode): + """Create and populate dev env. + + Will automatically activate the environment, unless ci_mode is True. + """ + + if ENV_NAME not in _list_edm_envs(): + print(f"Creating development environment {ENV_NAME}...") + cmd = ["edm", "envs", "create", ENV_NAME, "--version", "3.8", "--force"] + subprocess.run(cmd, check=True) + + cmd = ["edm", "install", "-e", ENV_NAME, "-y"] + EDM_DEPS + subprocess.run(cmd, check=True) + + cmd = ["edm", "run", "-e", ENV_NAME, "--", "pip", "install"] + PIP_DEPS + subprocess.run(cmd, check=True) + + print("Bootstrap complete.") + + else: + print("Environment already exists; reusing.") + + if not ci_mode: + print(f"Activating dev environment {ENV_NAME}") + subprocess.run(["edm", "shell", "-e", ENV_NAME]) + + +def _list_edm_envs(): + cmd = ["edm", "envs", "list"] + proc = subprocess.run( + cmd, check=True, capture_output=True, encoding="utf-8", errors="ignore" + ) + envs = [] + for line in proc.stdout.split("\n"): + parts = line.split() + if len(parts) < 6: + continue + if parts[0] == "*": + envs.append(parts[1]) + else: + envs.append(parts[0]) + return envs + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--ci", action="store_true") + args = parser.parse_args() + bootstrap(args.ci) diff --git a/Core/Panel/ci/__main__.py b/Core/Panel/ci/__main__.py new file mode 100644 index 0000000..6ec2517 --- /dev/null +++ b/Core/Panel/ci/__main__.py @@ -0,0 +1,122 @@ +# Enthought product code +# +# (C) Copyright 2010-2022 Enthought, Inc., Austin, TX +# All rights reserved. +# +# This file and its contents are confidential information and NOT open source. +# Distribution is prohibited. + +""" + This is the "ci" module for the Core Panel example. +""" + +import click +import os.path as op +import subprocess +import sys +import os +import json + +SRC_ROOT = op.abspath(op.join(op.dirname(__file__), "..")) + +# Docker image will be tagged "IMAGE:VERSION" +IMAGE = "quay.io/enthought/edge-panel-core" +VERSION = "1.1.0" + +# These will go into the built Docker image. You may wish to modify this +# minimal example to pin the dependencies, or use a bundle file to define them. +APP_DEPENDENCIES = [ + "enthought_edge>=2.6.0", + "appdirs", + "packaging", + "pip", + "pyparsing", + "setuptools", + "six", + "panel", + "numpy", + "pandas", + "matplotlib", +] + +# This will be used when running locally ("run" or "preflight" commands). +# We just use the last component of the full image URL. +CONTAINER_NAME = IMAGE.split("/")[-1] + + +@click.group() +def cli(): + """Group for Click commands""" + pass + + +@cli.command() +@click.option("--rebuild-zbundle", default=False, is_flag=True) +def build(rebuild_zbundle): + """Build the Docker image""" + + # First, we build a "zbundle" which contains all the eggs needed to + # build the environment within the Docker image. + fname = "app_environment.zbundle" + if rebuild_zbundle or not op.exists(op.join(SRC_ROOT, fname)): + cmd = [ + "edm", + "bundle", + "generate", + "-i", + "--version", + "3.8", + "--platform", + "rh7-x86_64", + "-m", + "2.0", + "-f", + fname, + ] + APP_DEPENDENCIES + subprocess.run(cmd, check=True, cwd=SRC_ROOT) + + # Second, we run Docker. The Dockerfile will copy the zbundle into + # a temp folder and install it. + cmd = ["docker", "build", "-t", f"{IMAGE}:{VERSION}", "."] + subprocess.run(cmd, check=True, cwd=SRC_ROOT) + + +@cli.command() +def run(): + """Run the Docker image for testing""" + + # Get values from the dev settings file (API tokens for testing, etc.) + envs = _load_dev_settings() + + cmd = ["docker", "run", "--rm", "-p", "9000:9000", "--name", CONTAINER_NAME] + for key, value in envs.items(): + cmd += ["--env", f"{key}={value}"] + cmd += ["--env", "HOST_ADDRESS=0.0.0.0"] + cmd += [f"{IMAGE}:{VERSION}"] + + subprocess.run(cmd, check=True, cwd=SRC_ROOT) + + +@cli.command() +def publish(): + """Publish the Docker image for use with Edge""" + cmd = ["docker", "push", f"{IMAGE}:{VERSION}"] + subprocess.run(cmd, check=True) + + +def _load_dev_settings(): + """Load dev_settings.json file. + + Returns a dict with "EDGE_*" key/value pairs, or an empty dict if the + file doesn't exist. Any other keys are filtered out. + """ + fpath = op.join(SRC_ROOT, "dev_settings.json") + if not op.exists(fpath): + return {} + with open(fpath, "r") as f: + data = json.load(f) + return {k: v for k, v in data.items() if k.startswith("EDGE_")} + + +if __name__ == "__main__": + cli() diff --git a/Core/Panel/dev_settings.json.example b/Core/Panel/dev_settings.json.example new file mode 100644 index 0000000..96f38f5 --- /dev/null +++ b/Core/Panel/dev_settings.json.example @@ -0,0 +1,10 @@ +{ + "?0": "This is an *optional* settings file to make development more convenient.", + "?1": "Make a copy of this file, named 'dev_settings.json', and fill in the values.", + "?2": "This will allow EdgeSession() to work locally for testing/development.", + "?3": "DO NOT CHECK THE dev_settings.json FILE INTO SOURCE CONTROL!", + + "EDGE_API_TOKEN": "", + "EDGE_API_ORG": "", + "EDGE_API_SERVICE_URL": "https://edge.enthought.com/services/api" +} \ No newline at end of file diff --git a/Core/Panel/src/app.py b/Core/Panel/src/app.py new file mode 100644 index 0000000..866b9eb --- /dev/null +++ b/Core/Panel/src/app.py @@ -0,0 +1,94 @@ +# Enthought product code +# +# (C) Copyright 2010-2022 Enthought, Inc., Austin, TX +# All rights reserved. +# +# This file and its contents are confidential information and NOT open source. +# Distribution is prohibited. + +""" + Example Panel application for Edge. +""" +import os + +import matplotlib as mpl +import numpy as np +import pandas as pd +import panel as pn + +from edge.api import EdgeSession +from matplotlib.figure import Figure + + +def get_edge_session(): + """Helper function to get an EdgeSession object. + + EdgeSession will auto-load environment variables, including the API token, + location of the Edge server, etc. Please note: + + 1. In production, they are set by Edge itself; you don't have to do anything. + 2. In testing, you can set values in "dev_settings.json" + + Returns an EdgeSession object if one can be constructed, or None if the + required information is missing. + """ + + def is_set(name): + return name in os.environ + + if ( + is_set("EDGE_API_SERVICE_URL") + and is_set("EDGE_API_ORG") + and (is_set("EDGE_API_TOKEN") or is_set("JUPYTERHUB_API_TOKEN")) + ): + return EdgeSession() + + return None + + +csv_file = ( + "https://raw.githubusercontent.com/holoviz/panel/main/examples/assets/occupancy.csv" +) +data = pd.read_csv(csv_file, parse_dates=["date"], index_col="date") + +mpl.use("agg") + + +def mpl_plot(avg, highlight): + fig = Figure() + ax = fig.add_subplot() + avg.plot(ax=ax) + if len(highlight): + highlight.plot(style="o", ax=ax) + return fig + + +def find_outliers(variable="Temperature", window=30, sigma=10, view_fn=mpl_plot): + avg = data[variable].rolling(window=window).mean() + residual = data[variable] - avg + std = residual.rolling(window=window).std() + outliers = np.abs(residual) > std * sigma + return view_fn(avg, avg[outliers]) + + +hello = pn.pane.Markdown("Edge Panel Example") + +edge = get_edge_session() +if edge is not None: + whoami = edge.whoami() + user_name = whoami.user_name + greeting = pn.pane.Markdown(f"Logged in as {user_name}") +else: + greeting = pn.pane.Markdown(f"No EdgeSession available; see the README.") + + +pn.extension() + +window = pn.widgets.IntSlider(name="window", value=30, start=1, end=60) +sigma = pn.widgets.IntSlider(name="sigma", value=10, start=0, end=20) + +interactive = pn.bind(find_outliers, window=window, sigma=sigma) + +first_app = pn.Column(hello, greeting, window, sigma, interactive) + +first_app.servable() diff --git a/Core/Panel/src/startup-script.sh b/Core/Panel/src/startup-script.sh new file mode 100755 index 0000000..4fc2431 --- /dev/null +++ b/Core/Panel/src/startup-script.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +# Your app must bind to 127.0.0.1 on port 9000 for the Edge proxy to work. +# However, for local docker execution without a proxy, we need to bind to 0.0.0.0 + +if [ -z $HOST_ADDRESS ]; then + # Provide a default if not specified explicitly + export HOST_ADDRESS='127.0.0.1'; +fi + +exec edm run -- panel serve app.py --address=${HOST_ADDRESS} --port=9000 --prefix=$JUPYTERHUB_SERVICE_PREFIX --allow-websocket-origin=* --log-level=debug diff --git a/Panel/ci/__main__.py b/Panel/ci/__main__.py index fcaecfd..7329532 100644 --- a/Panel/ci/__main__.py +++ b/Panel/ci/__main__.py @@ -7,7 +7,7 @@ # Distribution is prohibited. """ - This is the "ci" module for the Streamlit example. + This is the "ci" module for the Panel example. """ import click From bbf03f46abe6de76d9122301d5c637f1914ab103 Mon Sep 17 00:00:00 2001 From: EdwinWiseOne Date: Tue, 12 Mar 2024 08:51:13 -0500 Subject: [PATCH 2/2] Updates per review. --- Core/Panel/Dockerfile | 2 +- Core/Panel/README.md | 10 +++------- Core/Streamlit/Dockerfile | 2 +- Core/Streamlit/README.md | 10 +++------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Core/Panel/Dockerfile b/Core/Panel/Dockerfile index b8f977e..4ff6c69 100644 --- a/Core/Panel/Dockerfile +++ b/Core/Panel/Dockerfile @@ -17,7 +17,7 @@ # First stage -ARG BASE_IMAGE=quay.io/enthought/edm-centos-7:3.4.0 +ARG BASE_IMAGE=quay.io/enthought/edm-centos-7:latest FROM $BASE_IMAGE as stage_one diff --git a/Core/Panel/README.md b/Core/Panel/README.md index cb6602d..1682e23 100644 --- a/Core/Panel/README.md +++ b/Core/Panel/README.md @@ -75,8 +75,7 @@ collecting environment variables set by Edge when the container is launched. When developing locally, it's also convenient to have an EdgeSession. You can get the "ci" module to inject the appropriate environment variables, so -that your ``EdgeSession()`` call will work with ``python -m ci run`` and -``python -m ci preflight``. +that your ``EdgeSession()`` call will work with ``python -m ci run``. To do so, follow this procedure: @@ -85,8 +84,8 @@ To do so, follow this procedure: ``"https://edge.enthought.com/services/api"``. * Define EDGE_API_ORG in that file. This is the "short name" displayed in the URL bar when you log into an organization, for example, ``"default"``. -* Define EDGE_API_TOKEN. You can get one of these by going to the - ``/hub/token`` endpoint on the Edge server. +* Define EDGE_API_TOKEN. You can get one of these from the ``My Profile``page + in the Edge UI. Be sure *not* to check the "dev_settings.json" file into source control, as it contains your API token. @@ -105,9 +104,6 @@ the prefix from requests, handling the OAuth2 login flow, pinging JupyterHub for container activity, and more. But, there are a few guidelines you will need to follow in your own Dockerfile. -* Don't change the user to anything other than ``app`` (for example, by the - Dockerfile ``USER`` command). If you need to run ``yum`` for some reason, - use ``sudo``. * Your app should bind to ``127.0.0.1``, *not* ``0.0.0.0``, and it should serve on port 9000. The Edge machinery will respond to requests on port 8888 and forward them to your app. diff --git a/Core/Streamlit/Dockerfile b/Core/Streamlit/Dockerfile index e422e32..52a305f 100644 --- a/Core/Streamlit/Dockerfile +++ b/Core/Streamlit/Dockerfile @@ -17,7 +17,7 @@ # First stage -ARG BASE_IMAGE=quay.io/enthought/edm-centos-7:3.4.0 +ARG BASE_IMAGE=quay.io/enthought/edm-centos-7:latest FROM $BASE_IMAGE as stage_one diff --git a/Core/Streamlit/README.md b/Core/Streamlit/README.md index f4ea5af..12ed85b 100644 --- a/Core/Streamlit/README.md +++ b/Core/Streamlit/README.md @@ -76,8 +76,7 @@ collecting environment variables set by Edge when the container is launched. When developing locally, it's also convenient to have an EdgeSession. You can get the "ci" module to inject the appropriate environment variables, so -that your ``EdgeSession()`` call will work with ``python -m ci run`` and -``python -m ci preflight``. +that your ``EdgeSession()`` call will work with ``python -m ci run``. To do so, follow this procedure: @@ -86,8 +85,8 @@ To do so, follow this procedure: ``"https://edge.enthought.com/services/api"``. * Define EDGE_API_ORG in that file. This is the "short name" displayed in the URL bar when you log into an organization, for example, ``"default"``. -* Define EDGE_API_TOKEN. You can get one of these by going to the - ``/hub/token`` endpoint on the Edge server. +* Define EDGE_API_TOKEN. You can get one of these from the ``My Profile``page + in the Edge UI. Be sure *not* to check the "dev_settings.json" file into source control, as it contains your API token. @@ -106,9 +105,6 @@ the prefix from requests, handling the OAuth2 login flow, pinging JupyterHub for container activity, and more. But, there are a few guidelines you will need to follow in your own Dockerfile. -* Don't change the user to anything other than ``app`` (for example, by the - Dockerfile ``USER`` command). If you need to run ``yum`` for some reason, - use ``sudo``. * Your app should bind to ``127.0.0.1``, *not* ``0.0.0.0``, and it should serve on port 9000. The Edge machinery will respond to requests on port 8888 and forward them to your app.