Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Minio(S3) container inside a github actions yml file

I am trying to create an Minio/S3 container so I can run my test suite as an action on github. I currently have the following:

name: Run Tests
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-18.04

    services:
      postgres:
        ...

      minio:
        image: minio/minio
        volumes:
          - /data
        ports:
          - 9000:9000
        env:
          MINIO_ACCESS_KEY: minio
          MINIO_SECRET_KEY: minio123
        options: --entrypoint "minio server /data" --health-cmd "curl -f http://localhost:9000/minio/health/live" --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      ...

I have tried the following permutations to get the minio container to work but with no success:

volumes:
  - ./data:/data

volumes:
  - ./:/data

volumes:
  - .:/data

volumes:
  - /data:/data

And I even tried:

options: --entrypoint "mkdir /data; minio server /data" ...

options: --entrypoint "minio server /tmp" ...

options: --entrypoint ["minio server", "/tmp"] ...

And I have tried using the -v flag to mount volumes before the --entrypoint flag.

options: -v /s3_data:/data --entrypoint "minio server /data" ...

options: -v ${{ github.workspace }}/s3_data:/data --entrypoint "minio server /data" ...

options: -v ${{ github.workspace }}/s3_data:/data:rw --entrypoint "minio server /data" ...

In an attempt to get it to work. But unfortunately I get:

starting container process caused: exec: "minio server /data": stat minio server /data: no such file or directory: unknown

And I can't run the minio server without any argument :(

like image 724
Robert Johnstone Avatar asked Jun 10 '26 00:06

Robert Johnstone


2 Answers

TL;DR;

There exists an ongoing GitHub Actions Community thread concerning the lack of support for setting jobs.<job_id>.services.<service_id>.command and this existing question is very similar to yours.


You could extend the official image as suggested by @ahasbini then build and push your docker image to a Docker Registry and use your own image in the GitHub Actions jobs.<job_id>.services.<service_id>.image. For example:

The Dockerfile:

FROM minio/minio
CMD ["server", "/data", "--address=0.0.0.0:9000"]

Note: you can use the lazybit/minio image I built for this answer.

The job.<job_id>.services.<service_id> spec:

jobs:
  ...
  minio:
    name: minio
    runs-on: ubuntu-latest
    services:
      minio:
        image: lazybit/minio
        ports:
          - 9000:9000
        env:
          MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
          MINIO_SECRET_KEY: ${{ secrets.MINIO_SECRET_KEY }}
        volumes:
          - ${{ github.workspace }}/data:/data
        options: --name=minio --health-cmd "curl http://localhost:9000/minio/health/live"
    steps:
      - run: pip3 install minio
      - run: |
            python3 - <<'EOF'
            from minio import Minio
            from minio.error import ResponseError

            try:
                minio = Minio(
                    'localhost:9000',
                    access_key='${{ secrets.MINIO_ACCESS_KEY }}',
                    secret_key='${{ secrets.MINIO_SECRET_KEY }}',
                    secure=False
                )
            except Exception as ex:
                raise

            minio.make_bucket('foo')
            minio.make_bucket('bar')
            print(f'{minio.list_buckets()}')
            EOF

Notes:

  1. The minio/minio images do not currently have a HEALTHCHECK instruction set (docker inspect minio/minio:latest --format {{.Config.Healthcheck}}) so we need to set the --health-cmd in the jobs.<job_id>.services.<service_id>.options to hit the services livenessProbe endpoint to make sure the service is running before we start running the jobs.<job_id>.steps
  2. I had some issues connecting to the service by name so I set the minio endpoint to locahost:9000, the GitHub Actions are run in a Kubernetes Pod, they share the same network namespace and are accessible via localhost
  3. Accessing encrypted secrets in the jobs.<job_id>.services.<service_id>.env and jobs.<job_id>.steps.<step_id>.run
  4. Mounting a local directory as the volume backing the minio service using the github context's workspace

GitHub Actions minio service

like image 115
masseyb Avatar answered Jun 11 '26 20:06

masseyb


I don't recommend this solution, but want to leave it out there in case somebody else is banging their head against a brick wall and wants a quick but convoluted solution.


In our workflow we added:

    services:
      minio:
        # fixme: let's not depend on external unofficial image
        image: lazybit/minio
        ports:
          - 9000:9000
        env:
          MINIO_ROOT_USER: accesskey
          MINIO_ROOT_PASSWORD: password
        options: --name=minio --health-cmd "curl http://localhost:9000/minio/health/live"
    steps:
      - run: wget https://dl.min.io/client/mc/release/linux-amd64/mc
      - run: chmod +x ./mc
      - run: ./mc alias set minio http://127.0.0.1:9000 accesskey password
      - run: ./mc mb --ignore-existing minio/MY_BUCKET

I used the unofficial lazybit/minio image as the official one would not run.

The Github Action creates one image with all the other images "merged". One can access the minio service at http://localhost:9000.

Alas, there is no easy way to set a default bucket via environment variable. Instead, we had to create the bucket via the minio client mc.


A few gotchas:

  • Minio uses endpoint over url in its config
  • minio requires your use_path_style_endpoint to be set to true

In our case, we had a Laravel app so we had to define the filesystem config like this:

<?php


$envUsingMinIo = ['local', 'testing-local'];
$usesMinIo = in_array(
    needle: env('APP_ENV'),
    haystack: $envUsingMinIo,
    strict: true
);

return [
    'disks' => [
        ...,
        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION', 'eu-west-1'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            // the below 'endpoint' url is actually used for minio:
            'endpoint' => env('AWS_URL'),
            // use older urls:
            'use_path_style_endpoint' => $usesMinIo,
        ],
    ],
];

It may differ for your client.

like image 25
k0pernikus Avatar answered Jun 11 '26 18:06

k0pernikus