diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 0000000..fe456c1 --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,88 @@ +name: ci-build +run-name: Building ${{ github.ref_name }} +env: + version: 1.11.3 +permissions: + contents: read + packages: write +on: + push: + branches: + - "**" + pull_request: +jobs: + lint: + runs-on: ubuntu-24.04 + name: Run Hadolint + steps: + - uses: actions/checkout@v4 + - uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile + docker: + runs-on: ubuntu-24.04 + name: Build, Scan, and Push Docker Image + needs: + - lint + + steps: + - 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: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=raw,value=${{ env.version }} + type=sha + labels: | + org.opencontainers.image.title=${{ github.repository }} + org.opencontainers.image.version=${{ env.version }} + org.opencontainers.image.source=${{ github.repositoryUrl }} + org.opencontainers.image.created=${{ github.event.head_commit.timestamp }} + + - name: Build Docker image (no push) + uses: docker/build-push-action@v5 + with: + context: . + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + MEDIAMTX_VERSION=${{ env.version }} + load: true # for Trivy + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ghcr.io/${{ github.repository }}:${{ env.version }} + format: table + exit-code: '1' + severity: CRITICAL,HIGH + + - name: Push Docker image (if scan passed) + if: success() + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + provenance: true + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 0000000..d939006 --- /dev/null +++ b/.trivyignore @@ -0,0 +1,4 @@ +# github.com/golang-jwt/jwt/v5 +# Fixed in https://github.com/bluenviron/mediamtx/commit/3f1237a0 +# Can be removed after v1.11.3. +CVE-2025-30204 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e4a5bad --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +ARG MEDIAMTX_VERSION=latest + +FROM bluenviron/mediamtx:${MEDIAMTX_VERSION} AS mediamtx-builder + +FROM alpine:3.21 + +RUN apk add --no-cache curl=8.12.1-r1 + +COPY --from=mediamtx-builder /mediamtx /usr/bin/mediamtx + +ENTRYPOINT ["/usr/bin/mediamtx"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9ea8198 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Rob Watson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..731161f --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# mediamtx-alpine + +Dockerfile which bundles +[MediaMTX](https://github.com/bluenviron/mediamtx) with curl in an Alpine +container. + +The image version maps directly to the MediaMTX version. + +[![Trivy Scan](https://github.com/rfwatson/mediamtx-alpine/actions/workflows/ci-build.yml/badge.svg?branch=main)](https://github.com/rfwatson/mediamtx-alpine/actions/workflows/ci-build.yml) +[![Docker Image](https://img.shields.io/badge/image-ghcr.io%2Frfwatson%2Fmediamtx--alpine-blue)](https://ghcr.io/rfwatson/mediamtx-alpine) +![Version](https://img.shields.io/badge/version-1.11.3-blue) + +## FAQ + +#### Why? + +When deploying in a containerized environment, curl or some other HTTP client +is required in the MediaMTX container for running health checks. + +The provided MediaMTX Docker image is a scratch image that has no additional +tooling. + +#### Why base the final image on Alpine, instead of copying curl and mediamtx binaries to another scratch image? + +The default build of curl as installed by Alpine is dynamically linked and does +not run on a scratch image due to lack of supporting libraries. + +On the surface the size difference between the two images is about 13MB. It +would probably be possible to use a static build of curl instead, but that +would have trade-offs in terms of build complexity and supply chain trust.