Skip to content
ohsudo, Home

CI/CD Pipeline Generator

GitHub Actions and GitLab CI pipelines: build, test, push images and deploy.

● Runs 100% in your browser — nothing you type leaves this page.

Platform
Test

Optional; runs before the tests.

Docker image

Needs a Dockerfile in the repository root. Dockerfile Generator →

Lowercase, without a tag: the pipeline tags it with the commit, the version and latest.

Deploy
.github/workflows/ci.yml
# Generated by OhSudo — https://ohsudo.com/tools/cicd-pipeline-generator/
name: CI
# Runs on pushes to the main branch, on version tags, and on pull requests
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
# The token gets read-only access by default; a job asks for more only if it needs it
permissions:
contents: read
env:
IMAGE: ghcr.io/acme/myapp
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Dependencies are cached between runs, keyed on the lock file
- uses: actions/setup-node@v7
with:
node-version: '24'
cache: npm
- run: npm ci
- run: npm test
# Builds and pushes the image; never for pull or merge requests, which must not reach your registry
build:
needs: test
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
# Credentials come from the platform’s secrets, never from this file
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v4
# Image tags: the full commit SHA, the version (from a v1.2.3 tag), and latest on the default branch
- uses: docker/metadata-action@v6
id: meta
with:
images: ${{ env.IMAGE }}
tags: |
type=sha,format=long,prefix=
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
- uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

Add it to the repository

$ mkdir -p .github/workflows
$ git add .github/workflows/ci.yml
$ git commit -m "Add CI pipeline"
$ git push

Tags that start with v (v1.2.3) also build a version image. A private image needs registry credentials on the server or in the cluster.

The address bar updates as you go, so you can bookmark or share the result.

How to use it

  1. Pick the platform and the main branch.
  2. Choose the language and the commands: tests run on every push to the main branch and on every pull or merge request.
  3. Turn on the Docker build and choose the registry. It needs a Dockerfile in the repository root — the Dockerfile Generator writes one.
  4. Choose how to deploy: over SSH with Docker Compose, or to Kubernetes, when the main branch changes or when you push a version tag.
  5. Add the secrets listed under the result, save the file, commit and push.

What you get

Every combination of options is checked automatically: with actionlint and shellcheck, and against the official GitHub Actions and GitLab CI schemas. Every action and image the pipelines name must exist. Those checks prove the files are valid, not that your project’s build passes: your first run is the real test.

Common commands

Terminal window
gh run list --limit 5 # recent GitHub Actions runs
gh run watch # follow the current run
gh secret set DEPLOY_HOST # add a repository secret
docker pull ghcr.io/acme/myapp:latest # try the image the pipeline pushed
kubectl rollout status deployment/myapp # did the new version start?
kubectl rollout undo deployment/myapp # go back to the previous version

Warning

Credentials on a CI server deserve their own limits. Use an SSH key made only for deploys, a registry token instead of your password, and a kubeconfig that can only update this one Deployment. Anyone who can change the pipeline on a branch with access to those secrets can read them, so protect your main branch and the production environment.

FAQ

The build fails with “failed to compute cache key … not found”, but it works on my machine

CI only has what’s in git, so a file you built or kept locally isn’t there. See failed to compute cache key, and check your .gitignore and .dockerignore.

Git says “detected dubious ownership” in my job

It means the repository folder belongs to another user than the one running Git, which is common inside CI containers. The safe fix is in detected dubious ownership.

The pipeline pushed the image, but the pods show ImagePullBackOff

The cluster has no credentials for your private registry, or the image name doesn’t match. See ImagePullBackOff. The Kubernetes Manifest Generator writes the Deployment this pipeline updates.

Why does the deploy use the commit SHA and not latest?

latest keeps moving: you can’t tell which version runs, and Kubernetes doesn’t see a change when the tag stays the same. A SHA always points to one exact build, and rolling back is just deploying the previous one.

Does GitLab’s Docker build work on my own runner?

The build uses Docker-in-Docker, which GitLab.com’s shared runners support. On your own runner, the Docker executor must run with privileged = true.

A step fails with “Resource not accessible by integration”

The job’s GITHUB_TOKEN lacks a permission for what that step does. See Resource not accessible by integration.

A job says “Cannot connect to the Docker daemon”

A container has no daemon of its own. See Cannot connect to the Docker daemon.

A GitLab job says “This job is stuck”

No runner that’s online may take it, often because of its tags. See This job is stuck.

Articles

Learn more

pull access denied
Docker & Containers

Docker "pull access denied": the repository doesn't exist, or you're not logged in

Fix Docker "pull access denied, repository does not exist or may require docker login": check the image name and tag, log in to the right registry, handle rate limits.

Beginner · 4 min read

exec format error
Docker & Containers

Docker "exec format error": the wrong CPU architecture, or a script with no shebang

Fix Docker "exec /app: exec format error": an image built for another architecture (arm64 vs amd64) or a script with no shebang. Check it, then build with buildx.

Intermediate · 4 min read

This job is stuck
CI/CD

GitLab CI "This job is stuck": why no runner picks it up, and how to fix it

Fix GitLab CI "This job is stuck because you don't have any active runners": match the job's tags, enable shared runners, check runner status and protected branches.

Beginner · 5 min read

Cannot connect to the Docker daemon
Docker & Containers

"Cannot connect to the Docker daemon. Is the docker daemon running?": every cause

Fix "Cannot connect to the Docker daemon. Is the docker daemon running?": start the service, read why it failed, check DOCKER_HOST, contexts, Docker Desktop and WSL.

Beginner · 5 min read

Resource not accessible
CI/CD

GitHub Actions "Resource not accessible by integration": give the token the right permission

Fix GitHub Actions "Resource not accessible by integration" (HTTP 403): add the right permissions to GITHUB_TOKEN, and handle fork pull requests and Dependabot safely.

Intermediate · 4 min read

jwt expired
Security

JWT "jwt expired" and "invalid signature": how to find out what is wrong with a token

Fix JWT "jwt expired" and "invalid signature": read the exp claim, check clock differences, the secret, HS256 vs RS256 and rotated keys, without turning verification off.

Intermediate · 5 min read

localhost:8080 was refused
Kubernetes

kubectl "The connection to the server localhost:8080 was refused": your kubeconfig is missing

Fix kubectl "The connection to the server localhost:8080 was refused": kubectl has no kubeconfig. Set it up for kubeadm, k3s, minikube, EKS, GKE or AKS, and under sudo.

Beginner · 3 min read

failed to compute cache key: … not found
Docker & Containers

Docker build "failed to compute cache key: … not found": why COPY can't see your file

Fix "failed to compute cache key … not found" and "COPY failed": the file is outside the build context, excluded by .dockerignore, or missing in CI.

Beginner · 4 min read

fatal: detected dubious ownership in repository
CI/CD

Git "fatal: detected dubious ownership in repository": fix it without turning the check off

Fix Git "detected dubious ownership in repository": run Git as the owner, fix the ownership, or trust one path with safe.directory, on servers, Docker and CI.

Beginner · 3 min read

! [rejected] main -> main (fetch first)
CI/CD

Git "! [rejected] main -> main (fetch first)": why the push failed and how to fix it safely

Fix git push "rejected (fetch first)" and "non-fast-forward": pull with rebase or merge, use --force-with-lease instead of --force, and handle protected branches.

Beginner · 4 min read

ImagePullBackOff
Kubernetes

Kubernetes ImagePullBackOff and ErrImagePull: find out why the image won’t pull

Fix ImagePullBackOff: read the pull error in kubectl describe, then fix the image name or tag, registry credentials, Docker Hub rate limits, network or architecture.

Beginner · 4 min read