├── .dockerignore ├── .editorconfig ├── .gitignore ├── .shellcheckrc ├── Dockerfile ├── README.md ├── docker-compose.yml ├── docker-install.sh ├── lib ├── bootstrap.sh ├── config.sh └── setup.sh └── update.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !docker-install.sh 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{yml,yaml}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.{sh,envsh,env,env*}] 16 | indent_style = space 17 | indent_size = 4 18 | 19 | # ShellCheck config 20 | shell_variant = bash # like -ln=bash 21 | binary_next_line = true # like -bn 22 | switch_case_indent = true # like -ci 23 | space_redirects = false # like -sr 24 | keep_padding = false # like -kp 25 | function_next_line = true # like -fn 26 | never_split = true # like -ns 27 | simplify = true 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /.shellcheckrc: -------------------------------------------------------------------------------- 1 | # See: https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md#rc-files 2 | 3 | source-path=SCRIPTDIR 4 | 5 | # Allow opening any 'source'd file, even if not specified as input 6 | external-sources=true 7 | 8 | enable=all 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #syntax=docker/dockerfile:1 2 | 3 | ARG BUILDKIT_SBOM_SCAN_CONTEXT=true 4 | 5 | FROM debian:stable-slim 6 | 7 | ARG BUILDKIT_SBOM_SCAN_STAGE=true 8 | 9 | ARG TARGETPLATFORM 10 | 11 | ARG VERSION 12 | ENV VERSION=${VERSION} 13 | 14 | ENV DEBIAN_FRONTEND=noninteractive 15 | 16 | COPY --chown=root:root ["docker-install.sh", "/root"] 17 | 18 | RUN --mount=type=cache,id=ser2net-apt-lists-${TARGETPLATFORM},target=/var/lib/apt/lists \ 19 | --mount=type=cache,id=ser2net-apt-cache-${TARGETPLATFORM},target=/var/cache/apt \ 20 | --mount=type=cache,id=ser2net-source-cache-${TARGETPLATFORM},target=/ser2net/cache \ 21 | set -ex \ 22 | && bash /root/docker-install.sh \ 23 | && rm /root/docker-install.sh 24 | 25 | ENTRYPOINT ["tini", "--", "ser2net", "-d", "-l", "-c", "/etc/ser2net/ser2net.yaml"] 26 | 27 | ARG BUILD_DATE 28 | 29 | LABEL org.opencontainers.image.authors="Christian 'Jippi' Winther " 30 | LABEL org.opencontainers.image.created=${BUILD_DATE} 31 | LABEL org.opencontainers.image.description="Easy way to run ser2net on Docker" 32 | LABEL org.opencontainers.image.documentation="https://github.com/jippi/docker-ser2net" 33 | LABEL org.opencontainers.image.licenses="MIT" 34 | LABEL org.opencontainers.image.source="https://github.com/jippi/docker-ser2net" 35 | LABEL org.opencontainers.image.title="ser2net on Docker" 36 | LABEL org.opencontainers.image.url="https://github.com/jippi/docker-ser2net" 37 | LABEL org.opencontainers.image.vendor="Christian 'Jippi' Winther " 38 | LABEL org.opencontainers.image.version=${VERSION} 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ser2net as a Docker container 2 | 3 | > ser2net is a program for allowing connections between gensio accepters and gensio connectors. Generally, this would be a network connections to serial ports or IPMI Serial Over Lan (SOL) connections, but there are lots of gensios and lots of options. See gensio(5) for information on gensios. 4 | 5 | ## Images 6 | 7 | All images are published to the following registries 8 | 9 | * 🥇 [GitHub](https://github.com/jippi/docker-ser2net/pkgs/container/docker-ser2net) as `ghcr.io/jippi/docker-ser2net` ⬅️ **Recommended** 10 | * 🥈 [AWS](https://gallery.ecr.aws/jippi/ser2net) as `public.ecr.aws/jippi/ser2net` ⬅️ Great alternative 11 | * ⚠️ [Docker Hub](https://hub.docker.com/r/jippi/ser2net/) as `jippi/docker-ser2net` ⬅️ Only use `:latest` as [tags might disappear](https://www.docker.com/blog/scaling-dockers-business-to-serve-millions-more-developers-storage/) 12 | 13 | Image tags with software specifications and version information can be found in the table below 14 | 15 | | **Tag** | **Version** | **OS (Debian)** | **Size** | 16 | |-------------------------- |---------------------------------------------------------------------------- |----------------------- |---------------- | 17 | | `latest` | [latest †](https://github.com/cminyard/ser2net/releases/latest) | bullseye (11.4) | ~60 MB | 18 | | `$version` | `$version` (tag name minus the leading `v`) | bullseye (11.4) | ~60 MB | 19 | 20 | _† Automation checks for new ser2net releases nightly (CEST, ~3am), so there might be a day or two latency for most recent release_ 21 | 22 | ### docker run 23 | 24 | ```sh 25 | touch $(pwd)/ser2net.yaml 26 | 27 | docker run \ 28 | --name ser2net \ 29 | --network=host \ 30 | --restart=unless-stopped \ 31 | --detach \ 32 | --volume $(pwd)/ser2net.yaml:/etc/ser2net/ser2net.yaml \ 33 | --device /dev/ttyUSB0 \ 34 | ghcr.io/jippi/docker-ser2net 35 | ``` 36 | 37 | ### docker-compose 38 | 39 | ```sh 40 | touch $(pwd)/ser2net.yaml 41 | ``` 42 | 43 | and add your ser2net configuration into the `ser2net.yaml` file. 44 | 45 | ```yaml 46 | version: '3.4' 47 | services: 48 | ser2net: 49 | container_name: ser2net 50 | image: ghcr.io/jippi/docker-ser2net 51 | restart: unless-stopped 52 | network_mode: host 53 | volumes: 54 | - ./ser2net.yaml:/etc/ser2net/ser2net.yaml 55 | devices: 56 | - /dev/ttyUSB0 57 | ``` 58 | 59 | ## Further help and docs 60 | 61 | For any help specific to ser2net please head over to https://github.com/cminyard/ser2net 62 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | ser2net: 3 | image: ghcr.io/jippi/docker-ser2net:latest 4 | network_mode: host 5 | restart: unless-stopped 6 | volumes: 7 | - ./ser2net.yaml:/etc/ser2net/ser2net.yaml 8 | devices: 9 | - /dev/ttyUSB0 10 | -------------------------------------------------------------------------------- /docker-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit -o nounset -o pipefail -x 4 | 5 | # Ensure we keep apt cache around in a Docker environment 6 | rm /etc/apt/apt.conf.d/docker-clean 7 | echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache 8 | 9 | declare -ar PERSISTENT_PACKAGES=( 10 | ca-certificates 11 | libgensio-dev 12 | libyaml-dev 13 | tini 14 | ) 15 | 16 | declare -ar TEMP_PACKAGES=( 17 | automake 18 | build-essential 19 | libtool 20 | make 21 | openipmi 22 | pkg-config 23 | wget 24 | ) 25 | 26 | # install basic packages required 27 | apt-get update 28 | apt-get install --no-install-recommends --yes "${TEMP_PACKAGES[@]}" "${PERSISTENT_PACKAGES[@]}" 29 | 30 | declare -xr archive="/ser2net/cache/ser2net_${VERSION:?}.tar.gz" 31 | declare -xr download_url="https://github.com/cminyard/ser2net/archive/refs/tags/v${VERSION}.tar.gz" 32 | 33 | # if file do not exists, or is invalid archive grab it again 34 | if [[ ! -e "${archive}" ]] || ! tar --list -f "${archive}" >/dev/null; then 35 | wget --output-document="${archive}" "${download_url}" 36 | fi 37 | 38 | tar zxfv "${archive}" -C /tmp 39 | cd "/tmp/ser2net-${VERSION}" 40 | 41 | ./reconf 42 | ./configure --sysconfdir=/etc 43 | make -j 44 | make -j install 45 | 46 | apt-get remove -y "${TEMP_PACKAGES[@]}" 47 | apt-get autoremove -y 48 | 49 | rm -rf /tmp/* 50 | -------------------------------------------------------------------------------- /lib/bootstrap.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | # source optional env file 6 | if [[ -e ".env" ]]; then 7 | source ".env" 8 | fi 9 | 10 | if [[ "${DEBUG:?}" -eq "2" ]]; then 11 | set -x 12 | fi 13 | 14 | function print() { 15 | echo "${OUTPUT_PREFIX:?}" "$@" 16 | } 17 | 18 | function debug() { 19 | if [[ "${DEBUG:?}" -gt "0" ]]; then 20 | echo "${OUTPUT_PREFIX}" "$@" 21 | fi 22 | } 23 | 24 | function debug_begin() { 25 | debug "🚧" "$@" 26 | } 27 | 28 | function debug_complete() { 29 | debug "✅" "$@" 30 | } 31 | 32 | function debug_fail() { 33 | debug "❌" "$@" 34 | } 35 | 36 | function has_tag() { 37 | if [[ "${REBUILD_TAGS:?}" -eq "1" ]]; then 38 | return 1 39 | fi 40 | 41 | check=$(echo "${DOCKER_TAGS:?}" | grep "^$1$") 42 | 43 | if [[ "${check}" == "" ]]; then 44 | return 1 45 | fi 46 | 47 | return 0 48 | } 49 | 50 | function docker_args_reset() { 51 | DOCKER_ARGS=() 52 | } 53 | 54 | function docker_args_append_tag_flags() { 55 | DOCKER_ARGS+=(--tag "${REPO_NAME_DOCKER_HUB}:$1") 56 | DOCKER_ARGS+=(--tag "ghcr.io/${REPO_NAME_GITHUB}:$1") 57 | DOCKER_ARGS+=(--tag "public.ecr.aws/${REPO_NAME_ECR}:$1") 58 | } 59 | 60 | function docker_args_append_build_flags() { 61 | DOCKER_ARGS+=(--pull) 62 | DOCKER_ARGS+=(--push) 63 | DOCKER_ARGS+=(--builder "${DOCKER_BUILDX_NAME}") 64 | DOCKER_ARGS+=(--sbom true) 65 | DOCKER_ARGS+=(--attest "type=provenance,mode=max") 66 | DOCKER_ARGS+=(--platform "$(array::join "," "${BUILD_PLATFORMS[@]}")") 67 | DOCKER_ARGS+=(--cache-to "type=local,dest=${DOCKER_CACHE_FOLDER}") 68 | DOCKER_ARGS+=(--cache-from "type=local,src=${DOCKER_CACHE_FOLDER}") 69 | 70 | if [[ "${DEBUG}" -gt "0" ]]; then 71 | DOCKER_ARGS+=(--progress=plain) 72 | else 73 | DOCKER_ARGS+=(--quiet) 74 | fi 75 | 76 | DOCKER_ARGS+=(--build-arg "BUILD_DATE=${BUILD_DATE:?}") 77 | DOCKER_ARGS+=(--build-arg "VERSION=$1") 78 | } 79 | 80 | function array::join() { 81 | local separator="$1" 82 | shift 83 | 84 | joined=$(printf "${separator}%s" "$@") 85 | echo "${joined#"${separator}"}" 86 | } 87 | -------------------------------------------------------------------------------- /lib/config.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | ######################################################################## 6 | # Config 7 | ######################################################################## 8 | 9 | declare -gxri DEBUG=${DEBUG:-0} 10 | declare -gxri REBUILD_TAGS=${REBUILD_TAGS:-0} 11 | declare -gxri NUMBER_OF_TAGS=${NUMBER_OF_TAGS:-10} 12 | 13 | declare -gx OUTPUT_PREFIX="[boot] " 14 | declare -gx BUILD_DATE 15 | BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) 16 | 17 | declare -gxr DOCKER_TAG_SOURCE=${DOCKER_TAG_SOURCE:-hub} 18 | declare -gxr DOCKER_CACHE_FOLDER=${DOCKER_CACHE_FOLDER:-/data/local/cache/ser2net-build-cache} 19 | declare -gxr DOCKER_BUILDX_NAME=${DOCKER_BUILDX_NAME:-ser2net-builder} 20 | declare -gxr PUBLIC_ECR_REGISTRY=${PUBLIC_ECR_REGISTRY:-jippi} 21 | 22 | # Repository names 23 | declare -gxr REPO_NAME_GITHUB=${REPO_NAME_GITHUB:-jippi/docker-ser2net} 24 | declare -gxr REPO_NAME_ECR=${REPO_NAME_ECR:-jippi/ser2net} 25 | declare -gxr REPO_NAME_DOCKER_HUB=${REPO_NAME_DOCKER_HUB:-jippi/ser2net} 26 | 27 | # List of releases to skip 28 | declare -gxrA SKIP=( 29 | [4.3.13]="doesn't build at all for some reason" 30 | ) 31 | 32 | # Docker platforms to build the multi-arch image for 33 | declare -gxra BUILD_PLATFORMS=( 34 | linux/386 35 | linux/amd64 36 | linux/amd64/v2 37 | linux/amd64/v3 38 | linux/amd64/v4 39 | linux/arm/v6 40 | linux/arm/v7 41 | linux/arm/v8 42 | linux/arm64 43 | linux/arm64/v8 44 | ) 45 | -------------------------------------------------------------------------------- /lib/setup.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | # shellcheck disable=SC2034 6 | OUTPUT_PREFIX="[setup]" 7 | 8 | ######################################################################## 9 | # Docker registry authentication 10 | ######################################################################## 11 | 12 | # ECR 13 | # shellcheck disable=SC2312 14 | if ! curl -s -S --fail --header "Authorization: Bearer $(jq -r '.auths["'public.ecr.aws'"]["auth"]' ~/.docker/config.json)" "https://public.ecr.aws/v2/${REPO_NAME_ECR:?}/manifests/latest" >/dev/null; then 15 | debug "🔒 Logging in to AWS registry ..." 16 | aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin "public.ecr.aws/${PUBLIC_ECR_REGISTRY:?}" 17 | debug_complete "Login to AWS registry successful" 18 | else 19 | debug_complete "Already logged in to AWS registry" 20 | fi 21 | 22 | # GitHub 23 | # shellcheck disable=SC2312 24 | if ! curl -s -S --fail --header "Authorization: Bearer $(jq -r '.auths["'ghcr.io'"]["auth"]' ~/.docker/config.json)" --header "Accept: application/vnd.oci.image.index.v1+json" "https://ghcr.io/v2/${REPO_NAME_GITHUB:?}/manifests/latest" >/dev/null; then 25 | debug "🔒 Logging in to GitHub registry ..." 26 | if [[ -z "${CR_PAT:?}" ]]; then 27 | debug_fail "Missing \$CR_PAT env key for GitHub login" 28 | exit 1 29 | fi 30 | 31 | echo "${CR_PAT}" | docker login ghcr.io -u jippi --password-stdin >/dev/null 32 | debug_complete "Login to GitHub registry successful" 33 | else 34 | debug_complete "Already logged in to GitHub registry" 35 | fi 36 | 37 | ######################################################################## 38 | # Build context 39 | ######################################################################## 40 | 41 | # Create buildx context 42 | ( 43 | docker buildx create --name "${DOCKER_BUILDX_NAME:?}" --driver docker-container --driver-opt image=moby/buildkit:master >/dev/null 2>&1 && 44 | docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && 45 | debug_complete "buildx container builder created" 46 | ) || debug_complete "buildx container builder exists" 47 | 48 | ######################################################################## 49 | # Remote state 50 | ######################################################################## 51 | 52 | # find most recent docker tags from Docker Hub 53 | debug_begin "Loading docker tags" 54 | 55 | declare -gx DOCKER_TAGS 56 | 57 | case ${DOCKER_TAG_SOURCE:?} in 58 | "github") 59 | # shellcheck disable=SC2312 60 | DOCKER_TAGS=$(curl -s --header "Authorization: Bearer $(jq -r '.auths["'ghcr.io'"]["auth"]' ~/.docker/config.json)" "https://ghcr.io/v2/${REPO_NAME_GITHUB:?}/tags/list?n=100" | jq -r '.tags[]' | sort --numeric-sort) 61 | ;; 62 | 63 | "ecr") 64 | # shellcheck disable=SC2312 65 | DOCKER_TAGS=$(curl -s --header "Authorization: Bearer $(jq -r '.auths["'public.ecr.aws'"]["auth"]' ~/.docker/config.json)" "https://public.ecr.aws/v2/${REPO_NAME_ECR:?}/tags/list?n=100" | jq -r '.tags[]' | sort --numeric-sort) 66 | ;; 67 | 68 | "hub") 69 | DOCKER_TAGS=$(curl -s "https://hub.docker.com/v2/repositories/${REPO_NAME_DOCKER_HUB:?}/tags/?page_size=100" | jq -r '.results[].name' | sort --numeric-sort) 70 | ;; 71 | 72 | *) 73 | echo "Unknown DOCKER_TAG_SOURCE: ${DOCKER_TAG_SOURCE}" 74 | exit 1 75 | ;; 76 | esac 77 | 78 | # find latest relases from cminyard/ser2net repository 79 | debug_begin "Loading cminyard/ser2net releases" 80 | 81 | declare -gx github_releases 82 | github_releases=$(curl -s "https://api.github.com/repos/cminyard/ser2net/tags?per_page=${NUMBER_OF_TAGS:?}" | jq -r '.[].name') 83 | declare -r github_releases 84 | 85 | declare -gx latest_release 86 | latest_release=$(echo "${github_releases}" | head -1) 87 | declare -r latest_release 88 | 89 | debug_complete "Loading cminyard/ser2net releases" 90 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | ######################################################################## 6 | # Load scripts 7 | ######################################################################## 8 | 9 | source lib/bootstrap.sh 10 | source lib/config.sh 11 | source lib/setup.sh 12 | 13 | debug "Config:" 14 | debug " DEBUG=${DEBUG}" 15 | debug " REBUILD_TAGS=${REBUILD_TAGS}" 16 | debug " NUMBER_OF_TAGS=${NUMBER_OF_TAGS}" 17 | 18 | ######################################################################## 19 | # Build docker images 20 | ######################################################################## 21 | 22 | # shellcheck disable=SC2312 23 | debug "github tags: $(echo "${github_releases:?}" | xargs)" 24 | debug "latest tag will be ${latest_release}" 25 | 26 | for the_release in ${github_releases}; do 27 | the_release="${the_release:1}" 28 | 29 | OUTPUT_PREFIX="[${the_release}/default]" 30 | 31 | debug "Considering release" 32 | if [[ -n "${SKIP[${the_release}]+skip}" ]]; then 33 | print "🚫 Skipping: ${SKIP[${the_release}]}" 34 | continue 35 | fi 36 | 37 | tag="${the_release}" 38 | suffix="" 39 | 40 | OUTPUT_PREFIX="[${the_release}/default]" 41 | debug "👷 Processing" 42 | 43 | #################################################################################### 44 | # Default build 45 | #################################################################################### 46 | 47 | # shellcheck disable=SC2310 48 | if ! has_tag "${tag}"; then 49 | docker_args_reset 50 | docker_args_append_build_flags "${the_release}" 51 | docker_args_append_tag_flags "${tag}" 52 | 53 | if [[ "v${the_release}" == "${latest_release}" ]]; then 54 | OUTPUT_PREFIX="[${the_release}/default/latest]" 55 | 56 | print "🏷️ Tagging as latest" 57 | docker_args_append_tag_flags "latest${suffix}" 58 | fi 59 | 60 | print "🚧 Building container image" 61 | debug "$ docker buildx build ${DOCKER_ARGS[*]}" "." 62 | docker buildx build "${DOCKER_ARGS[@]}" "." 63 | print "✅ Done" 64 | else 65 | print "✅ Already build" 66 | fi 67 | 68 | done 69 | 70 | if [[ "${DEBUG:?}" != "0" ]]; then 71 | debug_complete "Not flushing caches in debug mode" 72 | exit 0 73 | fi 74 | 75 | print "🚧 Pruning buildx caches" 76 | docker buildx inspect --bootstrap "${DOCKER_BUILDX_NAME}" >/dev/null && docker buildx prune --all --force --builder "${DOCKER_BUILDX_NAME}" 77 | print "✅ Done" 78 | 79 | if [[ -d "${DOCKER_CACHE_FOLDER}/ingest" ]]; then 80 | print "🚧 Pruning buildx exports" 81 | rm -rf -v "${DOCKER_CACHE_FOLDER}" 82 | print "✅ Done" 83 | fi 84 | 85 | # This might not be needed in once https://github.com/moby/moby/releases/tag/v26.0.0-rc2 is released! 86 | print "🚧 Removing buildx builder to free up disk space" 87 | docker buildx rm --force --builder "${DOCKER_BUILDX_NAME:?}" || : 88 | print "✅ Done" 89 | --------------------------------------------------------------------------------