本文由 AI 分析生成
Summary
A Reddit discussion from an experienced sysadmin managing 500 on-premise VMs, who has successfully integrated Ansible playbooks with a self-hosted GitLab CI/CD instance but is struggling to cleanly separate dev/test/prod stages. The core problem is that environment promotion logic must span both playbooks and roles stored in separate repositories, and the current group-based inventory approach feels fragile.
這是一場關於如何在 GitLab CI/CD 與 Ansible 環境中實作多階段(dev/test/prod)工作流的社群討論。核心問題在於:當 Ansible roles 分散在多個 repo 時,如何安全地將變更從開發環境推進到生產環境,同時確保每個環境使用的程式碼版本是可追蹤且一致的。
Key Points
- Branch-per-environment promotion: Use
development→test→mainbranches; GitLab CI variable${CI_COMMIT_BRANCH}dynamically selects the correct inventory group, enabling a single reusable CI job across all environments. - Version-tag roles, not branches: Reference roles by Git tags (e.g.
v1.2.3) inrequirements.ymlinstead of branch names. This locks higher environments to a known-good version and prevents role code from shifting beneath deployed playbooks. - Two-step role promotion flow: Cut a new tag when a role changes → update playbook
requirements.ymlto point to the new tag → promote that requirements change through dev → test → prod. Higher environments stay pinned to the previous tag until the new tag is validated below. - One inventory, group-based separation: Dev/test/prod can share a single inventory file with hosts organized into groups; the pipeline limits runs with
--limitagainst the relevant group, which is simpler than separate inventory files at this scale. - Static vs dynamic inventory trade-off: Static inventory works but becomes painful at scale; a dynamic inventory source (e.g. from a CMDB or cloud API) with good group filtering is the long-term recommendation.
- Delayed branch merges cause drift: A common failure mode is accumulating too many changes in a lower environment branch that then become difficult to selectively promote — rigorously short-lived feature branches help.
- Ansible Tower / AWX as deployment trigger: For environments with approval gates, AWX job templates can be triggered from GitLab CI after manual approval, keeping the actual playbook execution separate from the pipeline runner.
- Collections as an alternative to per-role repos: Grouping related roles into an Ansible Collection provides better versioning semantics than one-role-per-repo when the roles are tightly coupled.
Insights
The fundamental tension in this thread is between idempotency (Ansible’s strength) and change propagation (CI/CD’s job). Ansible ensures a host reaches a desired state, but the pipeline must still decide when to re-run a playbook against hosts that had it applied previously. There is no built-in trigger: if role ntp_settings changes, nothing automatically re-runs deploy_nextcloud against the servers that use it. The community’s answer is discipline — a requirements.yml tag bump is the explicit signal that a role change needs to propagate.
The version-tag-per-environment pattern mirrors how container image tags work in Kubernetes CD pipelines: the image: field in a deployment manifest is the explicit coupling between the code and the environment, and merging a bump to that field is the promotion act. Teams comfortable with that mental model will find the Ansible equivalent natural.
The discussion also reveals a gap in the Ansible ecosystem: there is no native equivalent of helm diff or kubectl diff that shows what would change on which hosts before a run. The --check --diff flag helps but is not pipeline-native in the same way.
Connections
- git-flow-vs-trunk-based-for-cicd
- ansible-with-docker-automate-container-management
- 如何從頭打造專屬的-gitlab-cicd-pin-yi
- 為什麼你應該改用-gitlab-cicd-components-艦長你有事嗎
Raw Excerpt
I think you should refer to your roles by a version tag. That way when you’re consuming a given role within a playbook, and promoting that version through your environments, you’re always getting the same role-code. I.E. it won’t shift out from under you as the role continues to be developed separately in its own repo.
You have a two-step process then. When you make changes to the role-code, you cut a new tag. Then you update the playbooks that consume that role with the new tag, by promoting that tag-change from dev to test to prod. All the higher environments are locked to the previous version of the role, until the commit with the role’s new tag has been successfully promoted from the lower environments.