My DocOps project uses two repositories. The first stores articles, site templates, validators, and the build pipeline. The second stores Kubernetes manifests and the container image version that should run in the cluster.

An author changes Markdown only in the documentation repository. After review, the change is merged into the main branch, and automation controls the rest of the publication process: the pipeline validates the site, creates a release, publishes an image, and updates the GitOps repository.

Flux watches only the GitOps repository. It does not read the repository containing the articles and does not directly know that an article was merged.

The complete path looks like this:

Merge Request with an article
→ merge into the documentation repository
→ validation and build
→ container image publication
→ automated commit to the GitOps repository
→ Flux reconciliation
→ Kubernetes rollout
→ updated site

This sequence shows that CI and Flux do not duplicate each other. Each component receives the result of the previous stage and owns one part of delivery.

Two repositories store different kinds of state

The documentation repository answers one question: what are we building? It contains Markdown files, Jekyll templates, validators, build configuration, and release rules.

The GitOps repository answers another question: what should be running in the environment? It contains Kubernetes resources, environment configuration, and the image version that the Deployment should use.

These are not competing sources of truth. The site content lives in one repository, while the desired state of the environment lives in another.

This separation keeps article history apart from deployment history. The first repository shows how the site changed, while the second shows which versions were selected for Kubernetes.

A merge only starts publication

In this article, merge means merging an article into the main branch of the documentation repository. There is no second user-created Merge Request during publication: the pipeline later updates the GitOps repository automatically.

The article is not available to users immediately after the merge. The pipeline must validate the source again, build the static site, determine a version, and publish a container image.

That version must then be selected for the environment, recorded in the GitOps repository, and applied to Kubernetes. The merge starts this chain but does not confirm that it has finished.

CI prepares a deployable artifact

The Merge Request pipeline validates Markdown, article metadata, commit messages, internal validators, and the Jekyll build. The same checks run again after the change reaches the main branch.

Release automation then determines the next version. The site is built and packaged as a container image:

registry.example.org/docs:v1.2.3

The image is pushed to the registry. At this point, CI has completed its main responsibility: it has validated the change and produced a deployable artifact.

The environment has not changed yet. Kubernetes is still running the version recorded in the GitOps repository.

Publishing an image is therefore not the same as deploying it.

CD begins when a version is selected for the environment

After publishing the image, the documentation pipeline clones the GitOps repository and changes the version in its Kustomize configuration:

images:
  - name: docs-image
    newName: registry.example.org/docs
    newTag: v1.2.3

The pipeline then creates an automated commit in the main branch of the GitOps repository. No user performs another manual merge at this stage.

The new version is not running in Kubernetes yet, but the deployment decision has already been made. Git now records which artifact should be used in the environment.

This is where CD begins. Before the GitOps change, the system produces an artifact. After the change, it delivers the selected artifact to an environment.

Flux applies the recorded decision

Flux watches the main branch of the GitOps repository. When a new commit appears, it retrieves the updated desired state, renders the final Kubernetes manifests, and applies them to the cluster.

Changing the image version updates the Pod template in the Deployment. Kubernetes creates a new ReplicaSet and starts Pods with the new version of the site.

Flux does not validate Markdown, run Jekyll, determine a release version, or build a container image. It also does not select an image from the registry: the pipeline has already made that decision and recorded it in Git.

Flux therefore does not start with the source or the build output. It receives an existing description of what should be running in Kubernetes.

Flux maintains state after deployment

Flux continues working after the new version is first applied. It keeps comparing the actual Kubernetes state with the state recorded in Git.

If someone manually changes a managed resource, a later reconciliation returns it to the desired configuration. If a resource is removed from the GitOps repository, Flux can remove it from the cluster.

If Flux becomes temporarily unavailable, the existing site continues serving requests. New versions are not applied, however, and manual drift is not corrected.

Flux is not part of the user request path. It is responsible for delivering and maintaining environment state.

Flux is part of CD, not the entire process

In my project, responsibility is divided as follows:

CI:
source → validated container image

Version selection:
container image → GitOps repository update

Flux:
GitOps repository → Kubernetes state

Kubernetes:
new Pod template → running site version

CD begins before Flux receives the change. The pipeline first selects a version for the environment and records that decision in Git. Flux then applies it and keeps the cluster aligned with the GitOps repository.

The phrase “Flux deploys the documentation” therefore simplifies the process. Flux performs an important part of deployment, but it does not build the product or decide which version should be deployed.

A green pipeline does not mean the site is available

In the current implementation, the deployment job finishes after pushing a commit to the GitOps repository. It confirms that the new desired state has been recorded in Git, but it does not wait for Flux to retrieve the commit, reconciliation to succeed, or the Kubernetes rollout to finish.

The pipeline also does not verify that the site returns a successful HTTP response. Its green status confirms that responsibility was handed off to the next system, not that the new version is fully available to users.

There is another limitation. A commit to the GitOps repository starts its CI pipeline and becomes visible to Flux at the same time, but Flux does not wait for those checks to finish. The GitOps pipeline is therefore not a deployment gate in this design.

This requires a separate solution when failed validation must prevent configuration from being applied. It does not, however, change the main boundary between CI and Flux.

Clear boundaries make failures easier to investigate

Without understanding the full chain, almost any failure can be described as either a CI problem or a Flux problem. In practice, it may occur during Markdown validation, the Jekyll build, version creation, image publication, the GitOps update, reconciliation, or the Kubernetes rollout.

Each stage has different states, logs, and verification methods. Flux cannot apply a version that the pipeline never recorded in the GitOps repository. A successful GitOps commit also does not help when Kubernetes cannot pull the image.

Understanding the boundaries shows which component has completed its work and where responsibility moved next.

Conclusion

In my DocOps project, publication starts when an article is merged into the documentation repository. CI validates the change, builds the site, and publishes a container image.

CD begins when the pipeline selects that image for the environment and records the new version in a separate GitOps repository. Flux retrieves the recorded state, applies it to Kubernetes, and corrects later drift.

A merge, a green pipeline, and a successful GitOps commit confirm different stages of the process. None of them alone proves that the new version is already available to users.

Publishing documentation is not a single job after a merge. It is a sequence of responsibility handoffs between two repositories, pipelines, Flux, and Kubernetes.