GitHub Actions Tutorial — Docker Actions
Docker Actions
Docker actions run inside a container, giving you full control over the runtime — any language, any tool, any OS packages. The trade-off is slower startup (image pull) and Linux-only support.
When to Use Docker Actions
| Use Case | Example |
|---|---|
| Non-JavaScript language | Python, Go, Rust, Ruby |
| Specific OS packages | Custom binaries, system libraries |
| Consistent environment | Exact tool versions across all runners |
| Complex toolchains | Multi-step builds with specific dependencies |
Project Structure
my-docker-action/
├── action.yml # metadata
├── Dockerfile
├── entrypoint.sh # entry point script
└── README.md
Basic Docker Action
action.yml:
name: 'Lint Markdown'
description: 'Lint markdown files using markdownlint'
inputs:
path:
description: 'Path to lint'
required: false
default: '.'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.path }}
Dockerfile:
FROM node:20-alpine
RUN npm install -g markdownlint-cli
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh:
#!/bin/sh
set -e
LINT_PATH="${1:-.}"
echo "Linting markdown files in: $LINT_PATH"
markdownlint "$LINT_PATH" --config .markdownlint.json || true
Pre-Built Image
Skip the build step by pointing to a pre-built image:
runs:
using: 'docker'
image: 'docker://ghcr.io/my-org/my-action:v1'
args:
- ${{ inputs.path }}
Pros: Faster (no Docker build during the workflow). Cons: Must maintain and publish the image separately.
Environment Variables and Inputs
Docker actions receive inputs as environment variables prefixed with INPUT_:
inputs:
config-file:
description: 'Config file path'
required: true
Inside the container, the input is available as:
INPUT_CONFIG-FILE(with theINPUT_prefix, uppercased)
In your entrypoint script:
#!/bin/sh
CONFIG="${INPUT_CONFIG-FILE}"
echo "Using config: $CONFIG"
Docker Action Limitations
| Limitation | Detail |
|---|---|
| Linux only | Docker actions only run on Linux runners |
| Slower startup | Image build or pull adds 10-60 seconds |
| File system | Workspace is mounted at /github/workspace |
| Networking | Container shares the runner’s network |
| No services | Can’t define services: inside a Docker action |
Common Mistakes
| Mistake | Fix |
|---|---|
| Action fails on Windows/macOS | Docker actions are Linux-only |
| Entrypoint not executable | Add RUN chmod +x /entrypoint.sh |
| Files not found | Workspace is at /github/workspace inside the container |
| Slow action | Use a pre-built image instead of building from Dockerfile |
Quick Reference
| Concept | Detail |
|---|---|
| Runtime | using: 'docker' |
| Local image | image: 'Dockerfile' |
| Pre-built | image: 'docker://registry/image:tag' |
| Arguments | args: array passed to ENTRYPOINT |
| Inputs | Available as INPUT_<NAME> env vars |
| Platform | Linux runners only |
← Previous: JavaScript Actions
Next: Action Metadata →