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.
# 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 requestson: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 itpermissions:contents: readenv:IMAGE: ghcr.io/acme/myappjobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v7# Dependencies are cached between runs, keyed on the lock file- uses: actions/setup-node@v7with: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 registrybuild:needs: testif: github.event_name != 'pull_request'runs-on: ubuntu-latestpermissions:contents: readpackages: writesteps:- uses: actions/checkout@v7# Credentials come from the platform’s secrets, never from this file- uses: docker/login-action@v4with:registry: ghcr.iousername: ${{ 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@v6id: metawith: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@v7with:context: .push: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }}cache-from: type=ghacache-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 pushTags 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
- Pick the platform and the main branch.
- Choose the language and the commands: tests run on every push to the main branch and on every pull or merge request.
- Turn on the Docker build and choose the registry. It needs a Dockerfile in the repository root — the Dockerfile Generator writes one.
- Choose how to deploy: over SSH with Docker Compose, or to Kubernetes, when the main branch changes or when you push a version tag.
- Add the secrets listed under the result, save the file, commit and push.
What you get
- Jobs in the right order: test, then build, then deploy. A failed job stops the ones after it, so a broken commit never reaches production.
- Pull requests only run tests. They never push an image or deploy, and the pipeline doesn’t hand them your registry or server credentials.
- Least privilege on GitHub: the token is read-only by default, and only the build job gets
packages: write, only when it pushes to GitHub’s registry. - Traceable images: every image is tagged with the full commit SHA, a
v1.2.3tag also gives1.2.3, and the main branch getslatest. Deploys use the SHA, so you always know what’s running. - One deploy at a time, through a
productionenvironment you can protect with required reviewers. - Dependency and layer caches, so runs don’t start from zero.
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
gh run list --limit 5 # recent GitHub Actions runsgh run watch # follow the current rungh secret set DEPLOY_HOST # add a repository secretdocker pull ghcr.io/acme/myapp:latest # try the image the pipeline pushedkubectl rollout status deployment/myapp # did the new version start?kubectl rollout undo deployment/myapp # go back to the previous versionWarning
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
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
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
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. 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
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 "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
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
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
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
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
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