Video Thumbnail for Lesson
6.5: Container Actions

Container actions

Container actions let you pick any runtime or dependency stack. GitHub can build the image from a local Dockerfile, or you can point to a registry-hosted image to avoid rebuilding on every run.

name: Hello (Python)
description: Greet someone and expose a greeting output
inputs:
  who-to-greet:
    description: Name to greet
    required: true
    default: World
outputs:
  greeting:
    description: The greeting that was printed
runs:
  using: docker
  # Option A – let GitHub build from Dockerfile each run
  image: Dockerfile
  # Option B – use a pre-built image to avoid rebuilds:
  # image: docker://ghcr.io/your-org/hello-python-action:v1
  args:
    - ${{ inputs.who-to-greet }}

The entrypoint script has to speak “workflow command” by printing specific strings and writing to files such as GITHUB_OUTPUT:

#!/usr/bin/env python3
import os, datetime as dt

# GitHub injects INPUT_WHO_TO_GREET based on the input name
name = os.getenv("INPUT_WHO_TO_GREET", "World")

# Alternatively, you could read it from the args list using its position
# (you would need to import sys package above)
# name = sys.argv[1] if len(sys.argv) > 1 else "World"

greeting = f"Hello, {name}! Time is {dt.datetime.now(dt.timezone.utc):%H:%M:%S} UTC."
print(greeting)

# We can use workflow commands from: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions
# For example, to emit a GitHub-Actions NOTICE annotation
print(f"::notice file=entrypoint.py,line=17::{greeting}")

# Expose an output for downstream steps/jobs
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
    fh.write(f"greeting={greeting}\n")

The container action workflow showcases three approaches:

  • Building a Bash-based container action on the fly.
  • Reusing a pre-built shell action image to skip the build step (nearly 2Ă— faster).
  • Building and running the Python container action above.
jobs:
  shell-dockerfile:
    runs-on: ubuntu-latest
    name: Shell Container Action (dynamic Dockerfile build)
    steps:
      - name: Checkout
        uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
        with:
          submodules: true
      - name: Run container action
        uses: ./06-authoring-actions/container-actions/shell-container-action
        id: hello
        with:
          who-to-greet: "from a container github action đź‘‹"
      - name: Get the output greeting
        run: echo "The greeting was ${{ steps.hello.outputs.greeting }}"

  shell-public-container-image:
    runs-on: ubuntu-latest
    name: Shell Container Action (public container image)
    steps:
      - name: Checkout
        uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
      - name: Run container action
        uses: ./06-authoring-actions/container-actions/shell-container-action-prebuilt
        id: hello
        with:
          who-to-greet: "from a container github action đź‘‹"
      - name: Get the output greeting
        run: echo "The greeting was ${{ steps.hello.outputs.greeting }}"

  python-dockerfile:
    runs-on: ubuntu-latest
    name: Python Container Action (dynamic Dockerfile build)
    steps:
      - name: Checkout
        uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
      - name: Run container action
        uses: ./06-authoring-actions/container-actions/python-container-action
        id: hello
        with:
          who-to-greet: "from a container github action đź‘‹"
      - name: Get the output time
        run: echo "The time was ${{ steps.hello.outputs.greeting }}"