DevOps: what is CI/CD?

Mascote do LinuxPro colocando uma caixa de container Docker na esteira de CI/CD, entre a estação do Git, o portal de testes e o rack Kubernetes, com o cachorro caramelo ao lado

Note (2026): Original text from December 2019 — a CI/CD glossary still in Jenkins/Red Hat vocabulary, with the note “it will be improved soon”. Seven years later, YAML in Git became the standard (GitHub Actions, GitLab CI, Forgejo/Gitea Actions), CD on Kubernetes became GitOps (Argo CD / Flux), and the pipeline itself became a target for supply chain attacks. The concept didn't change; the tool and the threat did. Revised in 05/10/2026 with current versions and a diagram of the flow.

CI/CD isn't a product. It's the habit of integrating, testing and releasing software in short cycles, with as many automatic steps as possible. The “merge day” of 2019 remains the antipattern. What changed is where the YAML resides, who runs the job, and what happens after the pipeline goes green.

CI, delivery and deployment — the three CDs

CI (continuous integration): every push or merge request becomes automatic build and test on the shared trunk. The conflict shows up today, not on release Friday.

Continuous delivery: the approved artifact (binary, OCI image, package) goes on its own to a registry and is ready for production. The rollout still depends on a human pressing the button — or on a criterion: tag, approval, change window.

Continuous deployment: the same artifact goes up on its own to production if the tests passed. User feedback arrives in minutes. It requires tests you actually trust, not an empty green job.

There's no point arguing over the acronym. It's worth designing the pipeline: what's automatic, what's a gate, and how rollback is performed.

Diagrama do pipeline: desenvolvedor faz push, o runner de CI roda lint, testes, build e assinatura, envia a imagem ao registry e atualiza o repositório GitOps; Argo CD ou Flux sincronizam o Kubernetes, e a observabilidade fecha o ciclo de feedback
CI produces and signs the artifact; CD takes the desired state from Git to the cluster; metrics and alerts return the feedback.

The pipeline in 2026: YAML in Git

Jenkins with plugins still runs a lot of legacy. The starting point on Linux today is a file in the repository, a container runner, and the artifact in a registry.

GitHub Actions — the standard for those already on GitHub. Pin every action by Commit SHA, not by floating tag: in March 2025 the action's tags tj-actions/changed-files were repointed to a malicious commit that dumped secrets into the logs (CVE-2025-30066). Those using @v45 ran the attacker's code; those who had pinned the SHA did not.

# .github/workflows/ci.yml
name: ci
on:
  pull_request:
  push:
    branches: [main]
permissions:
  contents: read
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - run: make test

The block permissions reduces the job token to the minimum necessary — without it, the default can be broader than the test needs.

GitLab CI — which the companion post from 2019 already used for Terraform. A .gitlab-ci.yml and your own runners, if you want sovereignty:

# .gitlab-ci.yml
stages: [test, image]

test:
  stage: test
  image: golang:1.27
  script:
    - go test ./...

image:
  stage: image
  image: docker:29
  services: [docker:29-dind]
  script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

The variables CI_REGISTRY* are filled in by GitLab itself for the project's registry: no password is written into the YAML.

Forgejo Actions / Gitea Actions — syntax largely compatible with GitHub Actions, running self-hosted, without sending the code to someone else's cloud. The step-by-step with runner is in the post about the Gitea with Actions and runner. Woodpecker is the other lightweight option. In the Linux homelab, this competes with GitLab CE.

The Docker course remains a prerequisite: the modern job é a container. Infrastructure as code follows the same spirit: Ansible and the pipeline for Terraform on GitLab.

CD became GitOps

Deploying to Kubernetes in 2026 rarely means kubectl apply inside the CI job. CI builds the image, signs it, pushes it to the registry, and updates Git (tag or digest). The cluster pulls the desired state:

  • Argo CD — applications declared in Git, drift detection, and synchronization. The 3.5 (2026) line brought mTLS to the repo-server and an optional, still alpha, check of source integrity in the hydrator.
  • Flux — the other graduated CNCF project for GitOps, with controllers inside the cluster.

Git becomes the source of truth. The runner no longer holds eternal production credentials: OIDC for the cloud, short-lived tokens, and admission in the cluster verifying the signature (Cosign) before the pod comes up. Those still doing docker compose up on a VPS via SSH (as in Vaultwarden) is on the continuous delivery step — valid, just not GitOps. For the context of where the pieces came from, see the history of Docker and that of Kubernetes.

The pipeline as a target

In 2019 the fear was the broken merge. In 2026 the fear is the job that passes and publishes malware: compromised action, hijacked npm package, secret leaking in the log.

  • Pin actions and images by SHA or digest, never by @v3 .
  • Secrets in the vault (GitHub/GitLab, Vault, SOPS) — never in YAML.
  • Job token with the minimum permissions (permissions: in Actions).
  • SBOM and signing with Cosign (Sigstore, keyless via OIDC) on the image.
  • Provenance SLSA Build L2/L3 when the generator is the build platform, not a repository script.
  • PR coming from a fork: do not run the attacker's branch workflow with organization secrets (pull_request_target misused).

After deploy, the Prometheus tells you whether green lied.

Where to actually start

  1. Shared trunk, small PRs, CI on the PR (lint + test). Without that, the rest is theater.
  2. OCI image versioned by the commit SHA, in a private registry or on GHCR/GitLab.
  3. Automatic staging; production with a gate (tag or approval) until the tests earn continuous deployment.
  4. Only then GitOps, signing, and SLSA.

Many companies stop at step 2 and call it DevOps. It's not a sin; it's honest. Jumping straight to Argo CD without tests is painting the airplane.

If the goal is to formalize the knowledge, the post on the LPI DevOps Tools Engineer certification covers CI/CD, containers, and automation.

A visual tour

The episode of Programmer's Dictionary, from the Código Fonte TV channel, summarizes pipeline and CI/CD in a few minutes:

References

CI/CD remains the same pipeline as 2019: integrate early, test always, release in small pieces. The YAML went to Git, the cluster started pulling the state, and the green job now has to prove where the binary came from. The rest is just tooling.