Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
db8606a
WIP
rtuck99 May 19, 2026
d0613c2
WIP
rtuck99 May 19, 2026
9a6496a
Update entrypoint
rtuck99 May 20, 2026
7c23fd4
Changes to build docker image
rtuck99 May 21, 2026
6f62839
Mostly working:
rtuck99 May 22, 2026
2d251fd
Update initialise_scratch to pip install mx-bluesky
rtuck99 May 26, 2026
bb094f2
Additional debugging for initContainer
rtuck99 May 26, 2026
a196466
More debugging of initialise script
rtuck99 May 26, 2026
df563bb
Update dockerfile to add user, group creation
rtuck99 May 26, 2026
676c25d
Change ownership of image directories
rtuck99 May 26, 2026
f6a32fc
Tweak dockerfile for ownership
rtuck99 May 26, 2026
53d8faf
Add dodal to the dockerfile
rtuck99 May 26, 2026
5d53b05
Update image, initialisation to check out dodal
rtuck99 May 26, 2026
93cd674
fix git dir
rtuck99 May 26, 2026
4f700c8
Fixes/more debugging of entrypoint script
rtuck99 May 26, 2026
88ec648
More debuggablility
rtuck99 May 26, 2026
512983b
Fix PYTHONPATH to import mx-bluesky, dodal
rtuck99 May 27, 2026
cf219ed
Tidy the initContainer script
rtuck99 May 27, 2026
fef7074
Convert to statefulset
rtuck99 May 27, 2026
14b7c8d
Fix scratch initialisation
rtuck99 May 27, 2026
1ef7a4c
Hyperion supervisor starts, revert statefulset back to deployment
rtuck99 May 27, 2026
c13f55a
Initial attempt at callbacks
rtuck99 May 27, 2026
2181b55
More tweaks for callbacks, remove entrypoint script
rtuck99 May 27, 2026
e09b391
Tidy up values, deployment files
rtuck99 May 28, 2026
5bfd86d
Remove temporary scripts that we don't need
rtuck99 May 28, 2026
c24e057
Add some docs on the hyperion container setup
rtuck99 May 28, 2026
7d7907c
Update uv.lock
rtuck99 May 28, 2026
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
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
.ruff_cache
**/__pycache__/

# _version.py updated when image is built
**/_version.py

# virtualenv stuff - this gets built by the docker script
.venv
activate

tmp
4 changes: 2 additions & 2 deletions .github/workflows/_container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ jobs:
images: |
ghcr.io/${{ github.repository }}
labels: |
org.opencontainers.image.title=mx-bluesky
org.opencontainers.image.title=hyperion
org.opencontainers.image.description=Hyperion service for MX Unattended Data Collection
annotations: |
org.opencontainers.image.title=mx-bluesky
org.opencontainers.image.title=hyperion
org.opencontainers.image.description=Hyperion service for MX Unattended Data Collection
tags: |
type=ref,event=tag
Expand Down
87 changes: 50 additions & 37 deletions Dockerfile.hyperion
Original file line number Diff line number Diff line change
@@ -1,46 +1,59 @@
FROM python:3.11 AS build
# This is the Dockerfile for building the image for hyperion-supervisor and hyperion-callbacks

# The image will contain the directory structure:
# /app/mx-bluesky/.venv
# /app/mx-bluesky/.git
# /app/dodal/.git
# /app/mx-bluesky/scripts
# but we don't include the source folder structure for mx-bluesky or dodal since these will be
# deployed in a separate volume by the initContainer for the scratch folder

FROM python:3.12 AS base-image

ARG DEBIAN_FRONTEND=noninteractive
ARG SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MX_BLUESKY

# Need:
# libgl, libglib2.0 for python cv2 dependency
RUN apt update -y && \
apt upgrade -y && \
apt install -y libgl1 libglib2.0-0
RUN apt-get update -y && \
apt-get upgrade -y && \
apt-get install -y libgl1 libglib2.0-0

# Install matching uv binaries for our python distro
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

RUN pip install --no-cache-dir --no-compile setuptools_scm
# Create the hyperion user and group which will be needed in the deployment securityContext
RUN groupadd -r -g 1000 hyperion && \
useradd -r -u 1000 -g hyperion -d /app hyperion

ADD --chown=hyperion:hyperion .git /app/mx-bluesky/.git
RUN mkdir -p /app/scripts && \
chown hyperion:hyperion /app/scripts

#############################################################################
FROM base-image as uv-staging

Check warning on line 34 in Dockerfile.hyperion

View workflow job for this annotation

GitHub Actions / container / build

The 'as' keyword should match the case of the 'from' keyword

FromAsCasing: 'as' and 'FROM' keywords' casing do not match More info: https://docs.docker.com/go/dockerfile/rule/from-as-casing/

# Copy the pyproject.toml and install dependencies for better caching when developing
# & rerunning deployment scripts
COPY pyproject.toml /app/hyperion/
WORKDIR "/app/hyperion"
RUN mkdir -p src/mx_bluesky

# This enables us to cache the pip install without needing _version.py
# see https://setuptools-scm.readthedocs.io/en/latest/usage/
RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MX_BLUESKY=1.0.0 pip install \
--no-cache-dir --no-compile -e .

# Check out and install dodal locally with no dependencies as this may be a different version to what
# is referred to in the setup.cfg, but we don't care as it will be overridden by bind mounts in the
# running container
RUN mkdir ../dodal && \
git clone https://github.com/DiamondLightSource/dodal.git ../dodal && \
pip install --no-cache-dir --no-compile --no-deps -e ../dodal

#
# Everything above this line should be in the image cache unless pyproject.toml changes
#
ADD .git /app/hyperion/.git
# Restore the repository at the current commit instead of copying, to exclude uncommitted changes
# This is so that if you build a developer image from this dockerfile then _version.py will not
# append the dirty workdir hash, which causes complications during deployments that mount from a clean folder.
RUN git restore .

# Regenerate _version.py with the correct version - this should run quickly since we already have our dependencies
RUN rm src/mx_bluesky/_version.py
RUN pip install --no-cache-dir --no-compile --no-deps -e .

ENTRYPOINT ["/app/hyperion/utility_scripts/docker/entrypoint.sh"]

EXPOSE 5005
WORKDIR "/app/mx-bluesky"
COPY pyproject.toml uv.lock ./
RUN mkdir -p src/mx_bluesky && \
git config --global --add safe.directory /app/mx-bluesky && \
git restore . && \
uv sync --no-cache --locked

#############################################################################
FROM base-image as build

Check warning on line 46 in Dockerfile.hyperion

View workflow job for this annotation

GitHub Actions / container / build

The 'as' keyword should match the case of the 'from' keyword

FromAsCasing: 'as' and 'FROM' keywords' casing do not match More info: https://docs.docker.com/go/dockerfile/rule/from-as-casing/

WORKDIR "/app/mx-bluesky"
RUN mkdir /scratch && \
chown hyperion:hyperion /scratch

USER hyperion:hyperion

RUN git clone --bare https://github.com/DiamondLightSource/dodal.git /app/dodal/.git

COPY --chown=hyperion:hyperion --from=uv-staging /app/mx-bluesky/.venv /app/mx-bluesky/.venv
COPY --chown=hyperion:hyperion utility_scripts/docker/initialise_scratch.sh /app/scripts/

EXPOSE 5006
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,32 @@ Containerised mx-bluesky

There are currently two images associated with this repository which are pushed on release: hyperion, and mx-bluesky-blueapi.

The Hyperion image exists because Hyperion was developed before BlueAPI was production-ready, and so doesn't use BlueAPI to schedule plans. This image is only really relevant for i03, and currently isn't used in production anywhere
The Hyperion image is the image that provides ``hyperion-supervisor`` and ``hyperion-callbacks``. These are launched as applications in their own right; ``hyperion-supervisor`` makes use of BlueAPI client but does not expose blueapi plans. ``hyperion-callbacks`` does not use BlueAPI. Which application is launched depends on whether ``hyperion`` or ``hyperion-callbacks`` is specified in the container launch command.

The ``mx-bluesky-blueapi`` image exists as a minor extension of BlueAPI's image. BlueAPI's image contains the dependencies of BlueAPI, as well as the dependencies of BlueAPI, which includes dodal. When the BlueAPI service is launched, it will do a ``pip install --no deps`` of the plan repository. For MX, this means ``mx-bluesky`` gets installed without any of its dependencies. For this reason, we have created an ``mx-bluesky-blueapi`` image which installs these extra dependencies.
The ``mx-bluesky-blueapi`` image exists as a minor extension of BlueAPI's image. BlueAPI's image contains the dependencies of BlueAPI, as well as the dependencies of BlueAPI, which includes dodal. When the BlueAPI service is launched, it will do a ``pip install --no deps`` of the plan repository. For MX, this means ``mx-bluesky`` gets installed without any of its dependencies. For this reason, we have created an ``mx-bluesky-blueapi`` image which installs these extra dependencies.

This image can be used with BlueAPI's original helmchart, the only change required in the ``values.yaml`` is::

image:
repository: ghcr.io/diamondlightsource/mx-bluesky-blueapi
tag: "{desired_version}"

``hyperion-blueapi`` is launched as a standard ``mx-bluesky-blueapi`` image with configuration to load the hyperion plan and beamline modules.

Notes on the hyperion k8s deployment
------------------------------------

The hyperion Kubernetes deployment consists of a singled pod in a deployment which has 4 containers:

* ``hyperion-init``, an initContainer which runs before all other containers start.
* ``hyperion-supervisor`` which launches the supervisor
* ``hyperion-callbacks`` which launches the external callbacks
* ``hyperion-scratch`` which is present to enable hotfixes to be applied

The base ``hyperion`` container image contains only ``mx-bluesky`` and ``dodal`` bare git repos, plus the python virtual environment which provides all other library dependencies. When a new release of ``hyperion`` is first deployed to the cluster, it creates an empty Persistent Volume Claim (PVC).

``hyperion-init`` runs on pod startup and is responsible for checking out ``dodal`` and ``mx-bluesky`` to the persistent volume if they do not already exist.

``hyperion-supervisor`` and ``hyperion-callbacks`` then mount the persistent volume read-only under ``/scratch``, and then run ``hyperion`` from this.

``hyperion-scratch`` is a container that has the persistent volume mounted read-write, its only purpose is to wait for VSCode to attach to it so that you can edit the writable PVC; since ordinary ephemeral containers cannot mount PVCs directly. In this manner, hot fixes to the code can be applied either by editing in VSCode, or via the console; when the pod is restarted the changes will be retained.
2 changes: 1 addition & 1 deletion helm/hyperion/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v2
name: hyperion
description: Hyperion server
description: Hyperion Supervisor and Callbacks
type: application
# version of the chart
version: 0.0.1
33 changes: 33 additions & 0 deletions helm/hyperion/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: hyperion-supervisor-config
data:
supervisor_config.yaml: |-
# Configures the supervisor BlueAPI context to access the baton
env:
sources:
- kind: deviceManager
module: dodal.beamlines.{{ .Values.application.beamline }}_supervisor
mock: {{ .Values.application.dev }}
logging:
graylog:
url: {{ .Values.graylog.url }}
enabled: true
client_config.yaml: |-
# Configuration for the BlueAPI client running in the hyperion supervisor
api:
url: {{ .Values.blueapi.url }}
stomp:
enabled: true
url: {{ .Values.stomp.url }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: hyperion-callbacks-config
data:
blueapi_callbacks.yml: |-
stomp:
enabled: true
url: {{ .Values.stomp.url }}
Loading
Loading