* Dynamically load Element Web modules in Docker entrypoint
* Iterate
* Drop environment for PR runs
* Iterate
---------
(cherry picked from commit 8ef84349b5)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
committed by
GitHub
parent
8c4996b437
commit
05b8fff58a
37
.github/workflows/docker.yaml
vendored
37
.github/workflows/docker.yaml
vendored
@@ -3,6 +3,7 @@ on:
|
|||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
push:
|
push:
|
||||||
tags: [v*]
|
tags: [v*]
|
||||||
|
pull_request: {}
|
||||||
schedule:
|
schedule:
|
||||||
# This job can take a while, and we have usage limits, so just publish develop only twice a day
|
# This job can take a while, and we have usage limits, so just publish develop only twice a day
|
||||||
- cron: "0 7/12 * * *"
|
- cron: "0 7/12 * * *"
|
||||||
@@ -12,10 +13,12 @@ jobs:
|
|||||||
buildx:
|
buildx:
|
||||||
name: Docker Buildx
|
name: Docker Buildx
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
environment: dockerhub
|
environment: ${{ github.event_name != 'pull_request' && 'dockerhub' || '' }}
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # needed for signing the images with GitHub OIDC Token
|
id-token: write # needed for signing the images with GitHub OIDC Token
|
||||||
packages: write # needed for publishing packages to GHCR
|
packages: write # needed for publishing packages to GHCR
|
||||||
|
env:
|
||||||
|
TEST_TAG: vectorim/element-web:test
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -23,6 +26,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install Cosign
|
- name: Install Cosign
|
||||||
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3
|
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3
|
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3
|
||||||
@@ -34,20 +38,48 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and load
|
||||||
|
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.TEST_TAG }}
|
||||||
|
|
||||||
|
- name: Test the image
|
||||||
|
run: |
|
||||||
|
# Make a fake module to test the image
|
||||||
|
MODULE_PATH="modules/module_name/index.js"
|
||||||
|
mkdir -p $(dirname $MODULE_PATH)
|
||||||
|
echo 'alert("Testing");' > $MODULE_PATH
|
||||||
|
|
||||||
|
# Spin up a container of the image
|
||||||
|
CONTAINER_ID=$(docker run --rm -dp 80:80 -v $(pwd)/modules:/tmp/element-web-modules ${{ env.TEST_TAG }})
|
||||||
|
|
||||||
|
# Run some smoke tests
|
||||||
|
wget --retry-connrefused --tries=5 -q --wait=3 --spider http://localhost:80/modules/module_name/index.js
|
||||||
|
MODULE_1=$(curl http://localhost:80/config.json | jq -r .modules[0])
|
||||||
|
test "$MODULE_1" = "/${MODULE_PATH}"
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
docker stop "$CONTAINER_ID"
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5
|
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
vectorim/element-web
|
vectorim/element-web
|
||||||
@@ -61,6 +93,7 @@ jobs:
|
|||||||
- name: Build and push
|
- name: Build and push
|
||||||
id: build-and-push
|
id: build-and-push
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
@@ -72,6 +105,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||||
TAGS: ${{ steps.meta.outputs.tags }}
|
TAGS: ${{ steps.meta.outputs.tags }}
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
images=""
|
images=""
|
||||||
for tag in ${TAGS}; do
|
for tag in ${TAGS}; do
|
||||||
@@ -81,6 +115,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Update repo description
|
- name: Update repo description
|
||||||
uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4
|
uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# syntax=docker.io/docker/dockerfile:1.7-labs
|
||||||
|
|
||||||
# Builder
|
# Builder
|
||||||
FROM --platform=$BUILDPLATFORM node:22-bullseye AS builder
|
FROM --platform=$BUILDPLATFORM node:22-bullseye AS builder
|
||||||
|
|
||||||
@@ -8,7 +10,7 @@ ARG JS_SDK_BRANCH="master"
|
|||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
COPY . /src
|
COPY --exclude=docker . /src
|
||||||
RUN /src/scripts/docker-link-repos.sh
|
RUN /src/scripts/docker-link-repos.sh
|
||||||
RUN yarn --network-timeout=200000 install
|
RUN yarn --network-timeout=200000 install
|
||||||
RUN /src/scripts/docker-package.sh
|
RUN /src/scripts/docker-package.sh
|
||||||
@@ -19,11 +21,15 @@ RUN cp /src/config.sample.json /src/webapp/config.json
|
|||||||
# App
|
# App
|
||||||
FROM nginx:alpine-slim
|
FROM nginx:alpine-slim
|
||||||
|
|
||||||
|
# Install jq and moreutils for sponge, both used by our entrypoints
|
||||||
|
RUN apk add jq moreutils
|
||||||
|
|
||||||
COPY --from=builder /src/webapp /app
|
COPY --from=builder /src/webapp /app
|
||||||
|
|
||||||
# Override default nginx config. Templates in `/etc/nginx/templates` are passed
|
# Override default nginx config. Templates in `/etc/nginx/templates` are passed
|
||||||
# through `envsubst` by the nginx docker image entry point.
|
# through `envsubst` by the nginx docker image entry point.
|
||||||
COPY /docker/nginx-templates/* /etc/nginx/templates/
|
COPY /docker/nginx-templates/* /etc/nginx/templates/
|
||||||
|
COPY /docker/docker-entrypoint.d/* /docker-entrypoint.d/
|
||||||
|
|
||||||
# Tell nginx to put its pidfile elsewhere, so it can run as non-root
|
# Tell nginx to put its pidfile elsewhere, so it can run as non-root
|
||||||
RUN sed -i -e 's,/var/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf
|
RUN sed -i -e 's,/var/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf
|
||||||
|
|||||||
34
docker/docker-entrypoint.d/18-load-element-modules.sh
Executable file
34
docker/docker-entrypoint.d/18-load-element-modules.sh
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Loads modules from `/tmp/element-web-modules` into config.json's `modules` field
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
entrypoint_log() {
|
||||||
|
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
|
||||||
|
echo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy these config files as a base
|
||||||
|
mkdir /tmp/element-web-config
|
||||||
|
cp /app/config*.json /tmp/element-web-config/
|
||||||
|
|
||||||
|
# If there are modules to be loaded
|
||||||
|
if [ -d "/tmp/element-web-modules" ]; then
|
||||||
|
cd /tmp/element-web-modules
|
||||||
|
|
||||||
|
for MODULE in *
|
||||||
|
do
|
||||||
|
# If the module has a package.json, use its main field as the entrypoint
|
||||||
|
ENTRYPOINT="index.js"
|
||||||
|
if [ -f "/tmp/element-web-modules/$MODULE/package.json" ]; then
|
||||||
|
ENTRYPOINT=$(jq -r '.main' "/tmp/element-web-modules/$MODULE/package.json")
|
||||||
|
fi
|
||||||
|
|
||||||
|
entrypoint_log "Loading module $MODULE with entrypoint $ENTRYPOINT"
|
||||||
|
|
||||||
|
# Append the module to the config
|
||||||
|
jq ".modules += [\"/modules/$MODULE/$ENTRYPOINT\"]" /tmp/element-web-config/config.json | sponge /tmp/element-web-config/config.json
|
||||||
|
done
|
||||||
|
fi
|
||||||
@@ -18,8 +18,12 @@ server {
|
|||||||
}
|
}
|
||||||
# covers config.json and config.hostname.json requests as it is prefix.
|
# covers config.json and config.hostname.json requests as it is prefix.
|
||||||
location /config {
|
location /config {
|
||||||
|
root /tmp/element-web-config;
|
||||||
add_header Cache-Control "no-cache";
|
add_header Cache-Control "no-cache";
|
||||||
}
|
}
|
||||||
|
location /modules {
|
||||||
|
alias /tmp/element-web-modules;
|
||||||
|
}
|
||||||
# redirect server error pages to the static page /50x.html
|
# redirect server error pages to the static page /50x.html
|
||||||
#
|
#
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ on other runtimes may require root privileges. To resolve this, either run the
|
|||||||
image as root (`docker run --user 0`) or, better, change the port that nginx
|
image as root (`docker run --user 0`) or, better, change the port that nginx
|
||||||
listens on via the `ELEMENT_WEB_PORT` environment variable.
|
listens on via the `ELEMENT_WEB_PORT` environment variable.
|
||||||
|
|
||||||
|
[Element Web Modules](https://github.com/element-hq/element-modules/tree/main/packages/element-web-module-api) can be dynamically loaded
|
||||||
|
by being made available (e.g. via bind mount) in a directory within `/tmp/element-web-modules/`.
|
||||||
|
The default entrypoint will be index.js in that directory but can be overridden if a package.json file is found with a `main` directive.
|
||||||
|
These modules will be presented in a `/modules` subdirectory within the webroot, and automatically added to the config.json `modules` field.
|
||||||
|
|
||||||
|
If you wish to use docker in read-only mode,
|
||||||
|
you should follow the [upstream instructions](https://hub.docker.com/_/nginx#:~:text=Running%20nginx%20in%20read%2Donly%20mode)
|
||||||
|
but additionally include the following directories:
|
||||||
|
|
||||||
|
- /tmp/element-web-config/
|
||||||
|
- /etc/nginx/conf.d/
|
||||||
|
|
||||||
The behaviour of the docker image can be customised via the following
|
The behaviour of the docker image can be customised via the following
|
||||||
environment variables:
|
environment variables:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user