Home

Awesome

Docker images are basically zip files, why should building them take any more privileges than writing files? This is a zero-privilege, zero-capability, zero-permission, zero-container, zero-chroot, tiny OCI image creator.

All it can do is take a base image and add files to it, updating standard metadata (command, environment, ports), and pushing the result somewhere.

It's has both a CLI command and a public API for use in other Go code.

Installation

go install github.com/andrewbaxter/dinker

Usage

Terraform (via Terrars)

See https://github.com/andrewbaxter/terrars/tree/master/helloworld which has an example of creating a statically linked binary and publishing it as a minimal Docker image.

Github Actions

In order to push images you need to set Settings / Code and automation / Actions / General / Workflow permissions to Read and write permissions.

Add this workflow (using rust, for example) in .github/workflows/build.yaml:

name: Build
on:
  push:
    tags:
      - "*"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          target: x86_64-unknown-linux-musl
      - uses: actions-rs/cargo@v1
        with:
          command: build
          args: --target x86_64-unknown-linux-musl --release
      - env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          cat > dinker.json << ELEPHANT
          {
            "dests": [
              {
                "ref": "docker://ghcr.io/andrewbaxter/somewords:$GITHUB_REF_NAME",
                "user": "$GITHUB_ACTOR",
                "password": "$GITHUB_TOKEN"
              },
              {
                "ref": "docker://ghcr.io/andrewbaxter/somewords:latest",
                "user": "$GITHUB_ACTOR",
                "password": "$GITHUB_TOKEN"
              }
            ],
            "arch": "amd64",
            "os": "linux",
            "files": [
              {
                "source": "target/x86_64-unknown-linux-musl/release/somewords",
                "mode": "755"
              }
            ]
          }
          ELEPHANT
      - uses: docker://ghcr.io/andrewbaxter/dinker:latest
        with:
          args: /dinker dinker.json

Command line

This is an example, where I have a Go binary hello in my current directory.

  1. Create a config file named dinker.json like

    {
      "from": "alpine.tar",
      "from_pull": "docker://alpine:3.17.0",
      "dests": [
        {
          "ref": "docker-daemon:hello:latest",
          "host": "unix:///var/run/docker2.sock"
        }
      ],
      "files": [
        {
          "source": "hello",
          "dest": "hello",
          "mode": "755"
        }
      ],
      "cmd": ["/hello"]
    }
    

    This says to base the image on Alpine, add hello at the root of the filesystem, and by default run it.

    If alpine.tar doesn't exist locally, pull it from the public registry.

    When built, push it to my private registry at localhost:5000.

  2. Run dinker dinker.json

  3. Done!

Library

There's one function: dinkerlib.BuildImage()

It takes a path to a local oci-image tar file, and an output directory name. It returns a hash of the inputs as used in the interpolation of dest on the command line above.

The image is constructed in the directory with the OCI layout, but it isn't put into a tar file or pushed anywhere - you can convert it to other formats or upload it using Image in "github.com/containers/image/v5/copy", with a source reference generated using Transport.ParseReference in "github.com/containers/image/v5/copy".

Json reference

The json file has these options:

Required

Required if no from

Optional