gowerc
gowerc

Reputation: 1099

How to use a variable docker image in github-actions?

I am trying to write a custom github-action that runs some commands in a docker container but allows the user to select which docker container they are run in (i.e. so I can run the same build instructions across different versions of the runtime environment)

My gut instinct was to have my .github/actions/main/action.yml file as

name: 'Docker container command execution'
inputs:
  dockerfile:
    default: Dockerfile_r_latest
runs:
  using: 'docker' 
  image: '${{ inputs.dockerfile }}'
  args:
   - /scripts/commands.sh

However this errors with: ##[error](Line: 7, Col: 10): Unrecognized named-value: 'inputs'. Located at position 1 within expression: inputs.dockerfile

Any help would be appreciated !

File References

My .github/workflow/build_and_test.yml file is:

name: Test Package

on: 
  [push, pull_request]

jobs:

  R_latest:

    name: Test on latest
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
        name: Checkout project

      - uses: ./.github/actions/main
        name: Build and test
        with:
          dockerfile: Dockerfile_r_latest

And my Dockerfile .github/actions/main/Dockerfile_r_latest is:

FROM rocker/verse:latest
ADD scripts /scripts
ENTRYPOINT [ "bash", "-c" ]

Upvotes: 10

Views: 8677

Answers (3)

Stephen G Tuggy
Stephen G Tuggy

Reputation: 1141

Here is another approach. The Docker image to use is passed to a cibuild shell script that takes care of pulling the right image.

GitHub workflow file:

name: 'GH Actions CI'

on:
  push:
    branches: ['*master', '*0.[0-9]?.x']
  pull_request:
    # The branches below must be a subset of the branches above
    branches: ['*master', '*0.[0-9]?.x']

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest

    strategy:
      fail-fast: true
      matrix:
        include:
          - FROM:     'ubuntu:focal'
          - FROM:     'ubuntu:bionic'
          - FROM:     'ubuntu:xenial'
          - FROM:     'debian:buster'
          - FROM:     'debian:stretch'
          - FROM:     'opensuse/leap'
          - FROM:     'fedora:33'
          - FROM:     'fedora:32'
          - FROM:     'centos:8'

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2
      with:
        # We must fetch at least the immediate parents so that if this is
        # a pull request then we can checkout the head.
        fetch-depth: 2

    # If this run was triggered by a pull request event, then checkout
    # the head of the pull request instead of the merge commit.
    - run: git checkout HEAD^2
      if: ${{ github.event_name == 'pull_request' }}

    - name: Run CI
      env:
        FROM: ${{ matrix.FROM }}
      run: script/cibuild

Bash script script/cibuild:

#!/bin/bash

set -e

docker run --name my-docker-container $FROM script/custom-script.sh
docker cp my-docker-container:/usr/src/my-workdir/my-outputs .
docker rm my-docker-container

echo "cibuild Done!"

Put your custom commands in script/custom-script.sh.

Upvotes: 1

mehdio
mehdio

Reputation: 396

In addition to @peterevans answer, I would add there's a 3rd option where you can use a simple docker run command and pass any env that you have defined.

That helped to solve 3 things :

  • Reuse a custom docker image being build within the steps for testing actions. It seems not possible to do so with uses as it first tries to pull that image that doesn't exist yet in a Setup job step that occurs before any steps of the job.
  • This specific image can also be stored in a private docker registry
  • Be able to use a variable for the docker image

My workflow looks like this :

name: Build-Test-Push
on:
push:
    branches:
    - master
env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY }}
    ECR_REPOSITORY: myproject/myimage
    IMAGE_TAG: ${{ github.sha }}

jobs:

build-and-push:
    runs-on: ubuntu-latest
    steps:
    - name: Checking out
    uses: actions/checkout@v2
    with:
        ref: master

    - name: Login to AWS ECR
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

    - name: Build
    run: |
        docker pull $ECR_REGISTRY/$ECR_REPOSITORY || true
        docker build . -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -t $ECR_REGISTRY/$ECR_REPOSITORY:latest

    - name: Test
    run: |
        docker run $ECR_REGISTRY/$ECR_REPOSITORY:latest /bin/bash -c "make test"

    - name: Push
    run: |
        docker push $ECR_REGISTRY/$ECR_REPOSITORY

Upvotes: 2

peterevans
peterevans

Reputation: 41900

Interesting approach! I'm not sure if it's possible to use expressions in the image field of the action metadata. I would guess that the only fields that can take expressions instead of hardcoded strings are the args for the image so that the inputs can be passed.

For reference this is the args section of the action.yml metadata. https://help.github.com/en/articles/metadata-syntax-for-github-actions#args

I think there are other ways to achieve what you want to do. Have you tried using the jobs.<job_id>.container syntax? That allows you to specify an image that the steps of a job will run in. It will require that you publish the image to a public repository, though. So take care not to include any secrets.

For example, if you published your image to Docker Hub at gowerc/r-latest your workflow might look something like this:

name: Test Package

on: 
  [push, pull_request]

jobs:

  R_latest:

    name: Test on latest
    runs-on: ubuntu-latest
    container: gowerc/r-latest
    steps:
      - uses: actions/checkout@master
        name: Checkout project

      - name: Build and test
        run: ./scripts/commands.sh

ref: https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idcontainer

Alternatively, you can also specify your image at the step level with uses. You could then pass a command via args to execute your script.

name: my workflow
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Check container
        uses: docker://alpine:3.8
        with:
          args: /bin/sh -c "cat /etc/alpine-release"

ref: https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#example-using-a-docker-hub-action

Upvotes: 5

Related Questions