Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
121 changes: 117 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
name: Build Reticulum

env:
REGISTRY_IMAGE: ghcr.io/${{ github.repository_owner }}/reticulum

on:
push:
branches:
branches:
- '*'
tags:
- "[0-9]+.[0-9]+.[0-9]+*"
pull_request:
branches:
branches:
- master
paths-ignore:
- .gitignore
Expand All @@ -16,7 +19,7 @@ on:
permissions:
contents: write

concurrency:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

Expand All @@ -33,7 +36,6 @@ jobs:

package:
needs: test
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
environment: ${{ contains(github.ref, '-') && 'development' || 'production' }}
steps:
Expand Down Expand Up @@ -94,3 +96,114 @@ jobs:
generate_release_notes: true
prerelease: ${{ contains(github.ref, '-') }}
fail_on_unmatched_files: true

build-containers-release:
needs: package
runs-on: ubuntu-latest
permissions:
packages: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
- linux/arm/v7
- linux/arm/v6
environment: ${{ contains(github.ref, '-') && 'development' || 'production' }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# # Uncomment to use QEMU emulation, if niche architectures are needed
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: .artifacts

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.release
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.REGISTRY_IMAGE }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

container-manifest-merge:
runs-on: ubuntu-latest
permissions:
packages: write
needs:
- build-containers-release
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=ref,event=tag
type=ref,event=pr
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ tests/rnsconfig/storage
tests/rnsconfig/logfile*
*.data
*.result
.vscode
30 changes: 30 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ARG python_version=3.13

FROM python:${python_version}-alpine AS build

#RUN apk add --no-cache build-base linux-headers libffi-dev libressl-dev cargo

ENV PIP_ROOT_USER_ACTION=ignore
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV PIP_NO_CACHE_DIR=1
RUN pip install rns

#FROM python:${python_version}-alpine
#ARG python_version

# Only copy the necessary files from the build stage, to improve layer efficiency
#COPY --from=build /usr/local/bin/rn* /usr/local/bin/
#COPY --from=build /usr/local/lib/python${python_version}/site-packages/ /usr/local/lib/python${python_version}/site-packages/

RUN mkdir /config

RUN addgroup -S rns --gid 1000 && adduser -S rns --uid 1000 -G rns
RUN chown rns:rns /config

USER rns:rns

VOLUME ["/config"]

ENV PYTHONUNBUFFERED=1

ENTRYPOINT ["/usr/local/bin/rnsd", "--config", "/config"]
32 changes: 32 additions & 0 deletions docker/Dockerfile.release
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
ARG python_version=3.13

FROM python:${python_version}-alpine AS build

RUN apk add --no-cache build-base linux-headers libffi-dev libressl-dev cargo

ADD .artifacts/package/rns-*.whl /tmp/

ENV PIP_ROOT_USER_ACTION=ignore
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV PIP_NO_CACHE_DIR=1
RUN pip install /tmp/rns-*.whl

FROM python:${python_version}-alpine
ARG python_version

# Only copy the necessary files from the build stage, to improve layer efficiency
COPY --from=build /usr/local/bin/rn* /usr/local/bin/
COPY --from=build /usr/local/lib/python${python_version}/site-packages/ /usr/local/lib/python${python_version}/site-packages/

RUN mkdir /config

RUN addgroup -S rns --gid 1000 && adduser -S rns --uid 1000 -G rns
RUN chown rns:rns /config

USER rns:rns

VOLUME ["/config"]

ENV PYTHONUNBUFFERED=1

ENTRYPOINT ["/usr/local/bin/rnsd", "--config", "/config"]
50 changes: 50 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Docker Images

Docker resources Reticulum service and tooling

## End-user

As an end-user you can either:

- grab prebuilt docker images from the github container registry @ `ghcr.io/markqvist/reticulum:latest`
- use of the `Dockerfile` to create a simple docker image based on the latest `rns` package available at [PyPi](https://pypi.org/project/rns/)

### Building from `Dockerfile`

To build the image, choose one:

- Copy the `Dockerfile` to a directory and in that directory run:
- `docker build -t reticulum:latest .`

- From the root of this repository run:
- `docker build -t reticulum:latest -f docker/Dockerfile .`

### Running

#### Docker Run
You can run the container in various ways, a quick way to test would be interactively:

- Create a directory to hold the configuration and other files - `mkdir config`
- Start the container - `docker run --rm --name reticulum -v ./config:/config -it reticulum:latest`

Replace the image name to match either the one you built or pre-built github versions.

This will create a container named `reticulum`, mount the config directory to the directory you created above in your current working directory (`./config`) and automatically delete que container (`--rm`) when you detach from the session (files in the config directory will be retained)

You can edit the config file at `./config/config` to configure rns as usual

Once the container is running, you can use other rns tools via `docker exec`:

`docker exec -it reticulum rnpath`


#### Docker Compose

You can also use the included example `docker-compose.yml` file to manage the container in a more automated way. It has some comments but if you are not familiar with it, it is probably a good idea to read the [official `docker compose` docs](https://docs.docker.com/compose/)


## Developer

The file `Dockerfile.release` is meant to be used for CI, its similar to the end-user Dockerfile except that it will grab and install wheel files from the artifacts generated by the `package` job in the build workflow.

There are image builds available for both releases and pushes to branches to facilitate quick testing.
35 changes: 35 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
services:
reticulum:
container_name: reticulum
image: ghcr.io/markqvist/reticulum:latest
restart: unless-stopped
# You can mount devices, make sure to add the user to the group id
# which has rw access to the device on the host
devices:
- /dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0:/dev/ttyACM0
group_add:
- 986
# Mount the config directory on the host in the same location as the docker-compose.yml
# to allow data persistency
volumes:
- ./config:/config:rw
# Define ports to expose, for example a default TCP Listener
ports:
- "4242:4242/tcp"
networks:
- reticulum
# Define resource limits, useful if more services exist on the same host
# to avoid accidental resource contention, monitor and adjust as needed
deploy:
resources:
limits:
memory: "200M"

# We define a custom network to allow easy communication between containers,
# for example if you want to run a nomadnet node and make use of the reticulum
# running in this container, you can add nomadnet container to this same network
# and use the service name as the hostname (eg: "reticulum")
# see: https://docs.docker.com/compose/how-tos/networking/#use-a-pre-existing-network
networks:
reticulum:
name: reticulum