diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..fdaa3c2 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,123 @@ +name: Build and Publish Docker Image + +on: + push: + workflow_dispatch: + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + os: ubuntu-latest + + - platform: linux/arm64 + os: ubuntu-24.04-arm + permissions: + contents: read + packages: write + steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create lowercased repo env + run: | + echo "REPO=${GITHUB_REPOSITORY@L}" >> "${GITHUB_ENV}" + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ env.REPO }} + tags: | + type=ref,event=branch + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + tags: ghcr.io/${{ env.REPO }} + 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 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create lowercased repo env + run: | + echo "REPO=${GITHUB_REPOSITORY@L}" >> "${GITHUB_ENV}" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ env.REPO }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=raw,value=latest,enable={{is_default_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 'ghcr.io/${{ env.REPO }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ghcr.io/${{ env.REPO }}:${{ steps.meta.outputs.version }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e6eb165 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM debian:bookworm-slim AS build + +# Prevent initramfs and ldconfig runs in CI, speeds up the build +RUN dpkg-divert --local --rename --add /usr/sbin/update-initramfs \ + && dpkg-divert --local --rename --add /sbin/ldconfig \ + && dpkg-divert --local --rename --add /usr/sbin/ldconfig \ + && ln -sf /bin/true /usr/sbin/update-initramfs \ + && ln -sf /bin/true /sbin/ldconfig \ + && ln -sf /bin/true /usr/sbin/ldconfig + +# Install build dependencies +# eatmydata ignores fsck calls which arent needed in CI, speeds up the build +RUN apt update \ + && apt install -o APT::Install-Suggests=false -y eatmydata \ + && eatmydata apt install -o APT::Install-Suggests=false -y \ + gcc \ + meson \ + libsocketcan-dev \ + libconfig-dev + +# Build and strip +WORKDIR /src +COPY . . +RUN meson setup -Dlibconfig=true --buildtype=release build \ + && meson compile -C build \ + && meson install -C build + +# Collect only needed runtime files (arch-independent) +RUN mkdir -p /minimal-root/usr/local/sbin /minimal-root/lib /minimal-root/lib64 /minimal-root/etc \ + # The binary + && cp /usr/local/sbin/socketcand /minimal-root/usr/local/sbin/ \ + # Get interpreter from ELF header and copy + && interp=$(readelf -l /usr/local/sbin/socketcand | awk -F ': ' '/interpreter/ {print $2}' | tr -d ']') \ + && mkdir -p "/minimal-root$(dirname $interp)" \ + && cp "$interp" "/minimal-root$interp" \ + # Copy linked shared libraries + && ldd /usr/local/sbin/socketcand | awk '{print $3}' | grep '^/' | sort -u | xargs -I '{}' cp -v --parents '{}' /minimal-root/ \ + # Minimal /etc + && cp -a /etc/nsswitch.conf /minimal-root/etc/ \ + && cp -a /etc/hosts /minimal-root/etc/ \ + && cp -a /etc/resolv.conf /minimal-root/etc/ + +# Build minimal image +FROM scratch +COPY --from=build /minimal-root/ / +ENTRYPOINT ["/usr/local/sbin/socketcand"] diff --git a/README.md b/README.md index d29bbff..fcaf7a3 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,14 @@ Execute the following commands to configure, build, and install the software: $ meson compile -C build $ meson install -C build -Service discovery ------------------ - -The daemon uses a simple UDP beacon mechanism for service discovery. A beacon containing the service name, type and address is sent to the broadcast address (port 42000) at minimum every 3 seconds. A client only has to listen for messages of this type to detect all SocketCAN daemons in the local network. +Docker image +------------ +Prebuild docker images are available. +Note this image still needs a host kernel with SocketCAN modules. +The CAN interface needs to be configured on the host and made available to the container using the `--network=host` option. + +Example usage: +`docker run --rm --network=host -it ghcr.io/linux-can/socketcand:latest -v -i can0` Usage ----- @@ -46,6 +50,11 @@ Usage * **-d** (set this flag if you want log to syslog instead of STDOUT) * **-h** (prints this message) +Service discovery +----------------- + +The daemon uses a simple UDP beacon mechanism for service discovery. A beacon containing the service name, type and address is sent to the broadcast address (port 42000) at minimum every 3 seconds. A client only has to listen for messages of this type to detect all SocketCAN daemons in the local network. + License -------