matrix: add docker file for bridge (#556)

* matrix: add docker file for bridge

* matrix: address review comments

* matrix: address review comments

* matrix: address review comments

* matrix: address review comments

* matrix: address review comments
This commit is contained in:
l5y
2025-12-16 08:53:01 +01:00
committed by GitHub
parent 872bcbd529
commit 175a8f368f
6 changed files with 173 additions and 10 deletions

View File

@@ -43,7 +43,7 @@ jobs:
strategy:
matrix:
service: [web, ingestor]
service: [web, ingestor, matrix-bridge]
architecture:
- { name: linux-amd64, platform: linux/amd64, label: "Linux x86_64", os: linux, architecture: amd64 }
- { name: linux-arm64, platform: linux/arm64, label: "Linux ARM64", os: linux, architecture: arm64 }
@@ -109,8 +109,8 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
file: ./${{ matrix.service == 'web' && 'web/Dockerfile' || 'data/Dockerfile' }}
target: production
file: ${{ matrix.service == 'web' && './web/Dockerfile' || matrix.service == 'ingestor' && './data/Dockerfile' || './matrix/Dockerfile' }}
target: ${{ matrix.service == 'matrix-bridge' && 'runtime' || 'production' }}
platforms: ${{ matrix.architecture.platform }}
push: true
tags: |
@@ -119,12 +119,12 @@ jobs:
${{ steps.tagging.outputs.include_latest == 'true' && format('{0}/{1}-{2}-{3}:latest', env.REGISTRY, env.IMAGE_PREFIX, matrix.service, matrix.architecture.name) || '' }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.description=PotatoMesh ${{ matrix.service == 'web' && 'Web Application' || 'Python Ingestor' }} for ${{ matrix.architecture.label }}
org.opencontainers.image.description=PotatoMesh ${{ matrix.service == 'web' && 'Web Application' || matrix.service == 'ingestor' && 'Python Ingestor' || 'Matrix Bridge' }} for ${{ matrix.architecture.label }}
org.opencontainers.image.licenses=Apache-2.0
org.opencontainers.image.version=${{ steps.version.outputs.version }}
org.opencontainers.image.created=${{ github.event.head_commit.timestamp }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.title=PotatoMesh ${{ matrix.service == 'web' && 'Web' || 'Ingestor' }} (${{ matrix.architecture.label }})
org.opencontainers.image.title=PotatoMesh ${{ matrix.service == 'web' && 'Web' || matrix.service == 'ingestor' && 'Ingestor' || 'Matrix Bridge' }} (${{ matrix.architecture.label }})
org.opencontainers.image.vendor=PotatoMesh
org.opencontainers.image.architecture=${{ matrix.architecture.architecture }}
org.opencontainers.image.os=${{ matrix.architecture.os }}
@@ -208,6 +208,19 @@ jobs:
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Determine tagging strategy
id: tagging
run: |
VERSION="${{ steps.version.outputs.version }}"
if echo "$VERSION" | grep -E -- '-(rc|beta|alpha|dev)'; then
INCLUDE_LATEST=false
else
INCLUDE_LATEST=true
fi
echo "include_latest=$INCLUDE_LATEST" >> $GITHUB_OUTPUT
- name: Publish release summary
run: |
echo "## 🚀 PotatoMesh Images Published to GHCR" >> $GITHUB_STEP_SUMMARY
@@ -235,3 +248,12 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
fi
# Matrix bridge images
echo "### 🧩 Matrix Bridge" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.tagging.outputs.include_latest }}" = "true" ]; then
echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-matrix-bridge-linux-amd64:latest\` - Linux x86_64" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-matrix-bridge-linux-arm64:latest\` - Linux ARM64" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-matrix-bridge-linux-armv7:latest\` - Linux ARMv7" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi

View File

@@ -76,6 +76,21 @@ x-ingestor-base: &ingestor-base
memory: 128M
cpus: '0.1'
x-matrix-bridge-base: &matrix-bridge-base
image: ghcr.io/l5yth/potato-mesh-matrix-bridge-${POTATOMESH_IMAGE_ARCH:-linux-amd64}:${POTATOMESH_IMAGE_TAG:-latest}
volumes:
- potatomesh_matrix_bridge_state:/app
- ./matrix/Config.toml:/app/Config.toml:ro
restart: unless-stopped
deploy:
resources:
limits:
memory: 128M
cpus: '0.1'
reservations:
memory: 64M
cpus: '0.05'
services:
web:
<<: *web-base
@@ -109,6 +124,24 @@ services:
profiles:
- bridge
matrix-bridge:
<<: *matrix-bridge-base
network_mode: host
depends_on:
- web
extra_hosts:
- "web:127.0.0.1"
matrix-bridge-bridge:
<<: *matrix-bridge-base
container_name: potatomesh-matrix-bridge
networks:
- potatomesh-network
depends_on:
- web-bridge
profiles:
- bridge
volumes:
potatomesh_data:
driver: local
@@ -116,6 +149,8 @@ volumes:
driver: local
potatomesh_logs:
driver: local
potatomesh_matrix_bridge_state:
driver: local
networks:
potatomesh-network:

View File

@@ -1,19 +1,20 @@
[potatomesh]
# Base domain (with or without trailing slash)
base_url = "https://potatomesh.net/"
base_url = "https://potatomesh.net"
# Poll interval in seconds
poll_interval_secs = 60
[matrix]
# Homeserver base URL (client API) without trailing slash
homeserver = "https://matrix.example.org"
homeserver = "https://matrix.dod.ngo"
# Appservice access token (from your registration.yaml)
as_token = "YOUR_APPSERVICE_AS_TOKEN"
as_token = "INVALID_TOKEN_NOT_WORKING"
# Server name (domain) part of Matrix user IDs
server_name = "example.org"
server_name = "dod.ngo"
# Room ID to send into (must be joined by the appservice / puppets)
room_id = "!yourroomid:example.org"
room_id = "!sXabOBXbVObAlZQEUs:c-base.org" # "#potato-bridge:c-base.org"
[state]
# Where to persist last seen message id (optional but recommended)
state_file = "bridge_state.json"

42
matrix/Dockerfile Normal file
View File

@@ -0,0 +1,42 @@
# Copyright © 2025-26 l5yth & contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM rust:1.79-bookworm AS builder
WORKDIR /app
COPY matrix/Cargo.toml matrix/Cargo.lock ./
COPY matrix/src ./src
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
cargo build --release --locked
FROM debian:bookworm-slim AS runtime
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates gosu \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --uid 10001 --shell /usr/sbin/nologin potatomesh
WORKDIR /app
COPY --from=builder /app/target/release/potatomesh-matrix-bridge /usr/local/bin/potatomesh-matrix-bridge
COPY matrix/Config.toml /app/Config.example.toml
COPY matrix/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

View File

@@ -170,6 +170,36 @@ target/release/potatomesh-matrix-bridge
---
## Docker
Build the container from the repo root with the included `matrix/Dockerfile`:
```bash
docker build -f matrix/Dockerfile -t potatomesh-matrix-bridge .
```
Provide your config at `/app/Config.toml` and persist the bridge state file by mounting volumes. Minimal example:
```bash
docker run --rm \
-v bridge_state:/app \
-v "$(pwd)/matrix/Config.toml:/app/Config.toml:ro" \
potatomesh-matrix-bridge
```
If you prefer to isolate the state file from the config, mount it directly instead of the whole `/app` directory:
```bash
docker run --rm \
-v bridge_state:/app \
-v "$(pwd)/matrix/Config.toml:/app/Config.toml:ro" \
potatomesh-matrix-bridge
```
The image ships `Config.example.toml` for reference, but the bridge will exit if `/app/Config.toml` is not provided.
---
## Run
Ensure `Config.toml` is present and valid, then:

View File

@@ -0,0 +1,33 @@
#!/bin/sh
# Copyright © 2025-26 l5yth & contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
# Default state file path from Config.toml unless overridden.
STATE_FILE="${STATE_FILE:-/app/bridge_state.json}"
STATE_DIR="$(dirname "$STATE_FILE")"
# Ensure state directory exists and is writable by the non-root user without
# touching the read-only config bind mount.
if [ ! -d "$STATE_DIR" ]; then
mkdir -p "$STATE_DIR"
fi
# Best-effort ownership fix; ignore if the underlying volume is read-only.
chown potatomesh:potatomesh "$STATE_DIR" 2>/dev/null || true
touch "$STATE_FILE" 2>/dev/null || true
chown potatomesh:potatomesh "$STATE_FILE" 2>/dev/null || true
exec gosu potatomesh potatomesh-matrix-bridge "$@"