Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #37
15 KiB
name, description, activation-gate, category, impact
| name | description | activation-gate | category | impact |
|---|---|---|---|---|
| gitops-update | Setting up GitOps version updates: GitOps-repo workflow template, code repo dispatch, secret requirements, and two-repo commit-status pattern. Activates when the user needs to wire up artifact builds to GitOps configuration updates. | User mentions GitOps update, gitops-update, dispatch to another repo, two-repo version bump, cross-repo deployment, or wiring build output to config repo. | ci | high |
GitOps Update — Provider-palvelu
scripts/gitops-update.sh ja scripts/dispatch-workflow.sh muodostavat
GitOps-päivityspalvelun. Artifact buildataan code repossa, minkä jälkeen
code repo dispatchaa GitOps-repoon, joka päivittää konfiguraatiotiedoston
ja pushaa muutoksen.
Arkkitehtuuri
Kaksi erillistä repoa, eristetyt oikeudet:
Code repo GitOps repo
(build & push artifact) (konfiguraatiot)
build & push onnistuu (v0.2.3)
│
│ dispatch ci-main.yml
│ {file, yq_tpl, version, source_repo, source_commit}
│
└────────────────────────────────────→┐
│
dispatch-workflow.sh pollaa ←─────────┘
│
code repo asettaa │ git clone, yq update,
oman commit-statusnsa │ git commit + push
dispatchin exit-koodilla │ status GitOps-repoon
Token-periaate: Vain GitOps-repoon kirjoitetaan. Code repo asettaa oman commit-statusnsa dispatch-kutsun exit-koodin perusteella omalla auto-tokenillaan. GitOps-repon auto-token ei tarvitse oikeuksia code repoon.
GitOps-repon workflow (ci-main.yml)
GitOps-repoon luodaan .gitea/workflows/ci-main.yml:
name: GitOps Update
run-name: "GitOps Service (${{ inputs.dispatch_id || 'manual' }})"
on:
workflow_dispatch:
inputs:
file:
required: true
type: string
yq_tpl:
required: true
type: string
version:
required: true
type: string
source_repo:
required: true
type: string
source_commit:
required: true
type: string
dispatch_id:
required: false
type: string
git_tag_prefix:
required: false
type: string
env:
INPUT_FILE: ${{ inputs.file }}
YQ_TPL: ${{ inputs.yq_tpl }}
VERSION: ${{ inputs.version }}
SOURCE_REPO: ${{ inputs.source_repo }}
SOURCE_COMMIT: ${{ inputs.source_commit }}
GITOPS_REPO: ${{ github.repository }}
GITOPS_BRANCH: ${{ github.ref_name }}
GITEA_API_URL: ${{ gitea.server_url }}
GIT_TAG_PREFIX: ${{ inputs.git_tag_prefix || '' }}
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: niko/gitea-ci-library
path: .ci
- name: Install yq
run: |
wget -qO /usr/local/bin/yq \
https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
chmod +x /usr/local/bin/yq
- name: Run GitOps update
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
bash .ci/scripts/gitops-update.sh
Huomiot:
GITEA_TOKENon Gitean auto-token — scopeutuu GitOps-repoon, riittää cloneen, committiin, pushiin ja commit-statusiin GitOps-repossarun-namejadispatch_idmahdollistavat dispatchaavan skriptin tunnistaa tämän workflow-runin yksiselitteisestidisplay_title-kentästä, vaikka samassa repossa olisi samanaikaisia ajoja- yq ladataan lennossa (kompromissi, ks. "Tuleva CI-kontti")
Tulossa: custom CI-kontti
Nykyinen job lataa yq:n lennossa. Myöhemmin rakennetaan oma kontti
(ci-gitops), jossa on nodejs + git + yq valmiina. Sama patterni kuin
ci-bats ja ci-cucumber. Ks. skills/ci-container-build/SKILL.md.
Code-repon dispatch-step
Code repo dispatchaa GitOps-repon workflown artifact buildin onnistuttua:
gitops-update:
needs: [helm-build-push]
if: success()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: niko/gitea-ci-library
path: .ci
- name: Dispatch GitOps update
id: dispatch
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
INPUTS=$(jq -nc \
--arg file "dev/Chart.yaml" \
--arg yq_tpl '(.dependencies[] | select(.name == "agent-platform-helm") | .version) = "{{VERSION}}"' \
--arg version "${{ needs.check-version.outputs.version }}" \
--arg source_repo "${{ github.repository }}" \
--arg source_commit "${{ github.sha }}" \
'{file: $file, yq_tpl: $yq_tpl, version: $version, source_repo: $source_repo, source_commit: $source_commit}')
OUTPUT=$(bash .ci/scripts/dispatch-workflow.sh \
"niko/agent-platform-gitops" \
"ci-main.yml" \
"main" \
"$INPUTS" \
"${{ fromJson(needs.load-config.outputs.env_json).GITEA_API_URL }}" \
"${{ secrets.GITEA_TOKEN }}" \
"30")
echo "$OUTPUT"
GITOPS_COMMIT=$(echo "$OUTPUT" | grep '^GITOPS_COMMIT=' | cut -d= -f2)
echo "gitops_commit=$GITOPS_COMMIT" >> "$GITHUB_OUTPUT"
Multi-artifact pipeline (kontti + helm)
Yksi main-haaran build tuottaa usein sekä Docker-imagen että Helm-chartin. Kumpikin artefakti dispatchaa oman GitOps-päivityksensä rinnakkain:
gitops-helm:
needs: [helm-build-push]
if: success()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: niko/gitea-ci-library
path: .ci
- name: Update helm version
id: helm
run: |
INPUTS=$(jq -nc \
--arg file "dev/Chart.yaml" \
--arg yq_tpl '(.dependencies[] | select(.name == "git-pages") | .version) = "{{VERSION}}"' \
--arg version "${{ needs.check-version.outputs.version }}" \
--arg source_repo "${{ github.repository }}" \
--arg source_commit "${{ github.sha }}" \
--arg git_tag_prefix "helm" \
'{dispatch_id: "", file: $file, yq_tpl: $yq_tpl, version: $version, source_repo: $source_repo, source_commit: $source_commit, git_tag_prefix: $git_tag_prefix}')
OUTPUT=$(bash .ci/scripts/dispatch-workflow.sh \
"niko/gitea-ci-gitops-tests" "gitops-service.yaml" "main" \
"$INPUTS" "${{ fromJson(needs.load-config.outputs.env_json).GITEA_API_URL }}" \
"${{ secrets.GITOPS_DISPATCH_TOKEN }}" "30")
echo "$OUTPUT"
echo "helm_commit=$(echo "$OUTPUT" | grep '^GITOPS_COMMIT=' | cut -d= -f2)" >> "$GITHUB_OUTPUT"
gitops-docker:
needs: [docker-build-push]
if: success()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: niko/gitea-ci-library
path: .ci
- name: Update docker tag
id: docker
run: |
INPUTS=$(jq -nc \
--arg file "dev/values.yaml" \
--arg yq_tpl '.service.tag = "{{VERSION}}"' \
--arg version "${{ needs.check-version.outputs.version }}" \
--arg source_repo "${{ github.repository }}" \
--arg source_commit "${{ github.sha }}" \
--arg git_tag_prefix "docker" \
'{dispatch_id: "", file: $file, yq_tpl: $yq_tpl, version: $version, source_repo: $source_repo, source_commit: $source_commit, git_tag_prefix: $git_tag_prefix}')
OUTPUT=$(bash .ci/scripts/dispatch-workflow.sh \
"niko/gitea-ci-gitops-tests" "gitops-service.yaml" "main" \
"$INPUTS" "${{ fromJson(needs.load-config.outputs.env_json).GITEA_API_URL }}" \
"${{ secrets.GITOPS_DISPATCH_TOKEN }}" "30")
echo "$OUTPUT"
echo "docker_commit=$(echo "$OUTPUT" | grep '^GITOPS_COMMIT=' | cut -d= -f2)" >> "$GITHUB_OUTPUT"
Kaksi dispatchia, kaksi eri tiedostoa, kaksi eri GIT_TAG_PREFIX-arvoa.
Kummallakin on oma commit-status-linja ja oma summary-rivi.
dispatch-workflow.sh hoitaa rinnakkaisuuden display_title-matchauksella.
GITEA_TOKEN dispatch-vaiheessa: Tarvitaan manuaalinen token,
jolla on write-oikeus GitOps-repoon (esim. org-tason token).
Code-repon auto-token ei oikeuta dispatchaamaan toiseen repoon.
Token luodaan Giteassa: Settings → Applications → Generate Token
ja asetetaan code-repoon Actions Secretiksi.
Commit-status dispatchin perusteella
dispatch-workflow.sh tulostaa GITOPS_COMMIT=<sha> stdoutiin onnistuneen
GitOps-päivityksen jälkeen. Code repo parsii sen ja asettaa commit-statusin
linkillä GitOps-committiin:
- name: Set commit-status with GitOps link
if: always()
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_API_URL: ${{ fromJson(needs.load-config.outputs.env_json).GITEA_API_URL }}
GITOPS_COMMIT: ${{ steps.dispatch.outputs.gitops_commit }}
VERSION: ${{ needs.check-version.outputs.version }}
run: |
GITOPS_URL="${GITEA_API_URL}/niko/agent-platform-gitops/commit/${GITOPS_COMMIT}"
CTX="gitops/$(basename ${{ github.repository }})"
DESC="Deploy to dev ${VERSION}"
if [ -n "$GITOPS_COMMIT" ]; then
bash .ci/scripts/report-status.sh success "$DESC" "$CTX" "" "$GITOPS_URL"
else
bash .ci/scripts/report-status.sh success "$DESC" "$CTX"
fi
dispatch-workflow.sh palauttaa:
- exit 0 = GitOps-päivitys onnistui (+
GITOPS_COMMIT=<sha>) - exit 1 = GitOps-päivitys failasi
- exit 124 = aikakatkaisu (360 min oletus)
Loppuraportti (report-summary)
Code-repon viimeinen job (report-summary) lisää GitOps-päivityksestä
rivin GITHUB_STEP_SUMMARYyn:
- name: GitOps summary
if: always()
env:
GITEA_API_URL: ${{ fromJson(needs.load-config.outputs.env_json).GITEA_API_URL }}
GITOPS_COMMIT: ${{ steps.dispatch.outputs.gitops_commit }}
VERSION: ${{ needs.check-version.outputs.version }}
run: |
if [ -n "$GITOPS_COMMIT" ]; then
LINK="${GITEA_API_URL}/niko/agent-platform-gitops/commit/${GITOPS_COMMIT}"
else
LINK="#"
fi
cat >> "$GITHUB_STEP_SUMMARY" << 'GITOPS'
## GitOps updates
| Component | Version | Status | Commit |
|-----------|---------|--------|--------|
| agent-platform-helm | __VERSION__ | __STATUS__ | [link](__LINK__) |
GITOPS
sed -i "s|__VERSION__|${VERSION}|; s|__STATUS__|${{ job.status }}|; s|__LINK__|${LINK}|" \
"$GITHUB_STEP_SUMMARY"
Secretit ja tokenit
| Secret | Missä | Scope | Kuvaus |
|---|---|---|---|
GITEA_TOKEN (auto) |
Code repo | Vain code repo | Asettaa commit-statusin dispatchin jälkeen |
GITEA_TOKEN (auto) |
GitOps repo | Vain GitOps repo | Klooni, push, commit-status GitOps-repossa |
GITOPS_DISPATCH_TOKEN (manuaalinen) |
Code repo | Write GitOps-repoon | Dispatchaa GitOps-repon workflow |
Tokenin luonti:
- Gitea →
Settings→Applications→Generate Token - Valitse repo-oikeudet: valitse GitOps-repo, anna write-oikeudet
- Token asetetaan code-repoon:
{repo} → Settings → Actions Secrets - Salaisuuden nimi: esim.
GITOPS_DISPATCH_TOKEN
Provider-skriptit
scripts/gitops-update.sh
Ajaan GitOps-repon workflow'ssa. Päivittää konfiguraatiotiedoston yq:llä, committaa ja pushaa. Asettaa commit-statuksen vain GitOps-repoon.
Input-ympäristömuuttujat:
| Muuttuja | Pakollinen | Kuvaus |
|---|---|---|
INPUT_FILE |
Kyllä | Tiedosto GitOps-repossa (esim. dev/Chart.yaml) |
YQ_TPL |
Kyllä | yq-lauseke {{VERSION}}-placeholderilla |
VERSION |
Kyllä | Uusi versio (esim. 0.2.3) |
SOURCE_REPO |
Kyllä | Code-repo slug (esim. org/app) |
SOURCE_COMMIT |
Kyllä | Code-repon commit SHA |
GITOPS_REPO |
Kyllä | GitOps-repo slug |
GITEA_API_URL |
Kyllä | Gitean API-URL |
GITEA_TOKEN |
Kyllä | Gitea API-token (write GitOps-repoon) |
GITOPS_BRANCH |
Ei | Branch (oletus main) |
GIT_TAG_PREFIX |
Ei | Komponentin tag-prefix status-nimeämiseen (esim. agent-platform-helm) |
GITOPS_CLONE_URL |
Ei | Yliajaa clone-URL (esim. eri protokolla) |
GITOPS_TARGET_DIR |
Ei | Yliajaa clone-kohdehakemisto |
Commit-status muoto:
GitOps-repoon asetetaan commit-status:
| Kenttä | Formaatti | Esimerkki |
|---|---|---|
| Context | {repo}/{GIT_TAG_PREFIX} {RUN_ID} tai {repo} {RUN_ID} |
gitea-ci-library/agent-platform-helm 473 |
| Description | Install to {env} {version} |
Install to dev 0.2.0 |
| Target URL | Linkki code-repon committiin | /niko/gitea-ci-library/commit/abc123 |
Jos tiedosto on jo halutussa versiossa (ei muutoksia), status saa descriptionin Install to {env} {version} — no change. Commit-pushia ei tehdä, GitOps-repo pysyy muuttumattomana.
{env}parsitaanINPUT_FILE:stä (dev/Chart.yaml→dev){repo}parsitaanSOURCE_REPO:sta (niko/gitea-ci-library→gitea-ci-library){GIT_TAG_PREFIX}tulee env-varista (sama kuingitea-env.conf:ssa)
scripts/dispatch-workflow.sh
Dispatchaa workflow_dispatchin kohderepoon ja pollaa valmistumista.
Generoi automaattisesti dispatch_id-tunnisteen, lisää sen dispatch-
inputteihin ja tunnistaa workflow-runin kohdereposta display_title-
kentän perusteella. Toimii luotettavasti vaikka samassa repossa olisi
useita samanaikaisia dispatch-attribuutioita.
Argumentit:
| # | Pakollinen | Kuvaus |
|---|---|---|
| 1 | Kyllä | Kohderepo (esim. niko/agent-platform-gitops) |
| 2 | Kyllä | Workflow-tiedosto (esim. ci-main.yml) |
| 3 | Kyllä | Branch/ref |
| 4 | Kyllä | Inputs JSON |
| 5 | Kyllä | Gitea API URL |
| 6 | Kyllä | Gitea token |
| 7 | Ei | Aikakatkaisu minuutteina (oletus 360) |
Kutsujan ei tarvitse välittää dispatch_id:tä — skripti generoi sen
itse ja lisää inputteihin ennen dispatchia.
[skip ci]
Commit-viestissä on [skip ci], joka estää GitActions-runneria
triggeröimästä uutta CI-ajoa GitOps-repoon pushista. Näin vältetään
ääretön trigger-loop.
Race condition
dispatch-workflow.sh tunnistaa jokaisen dispatchatun runin uniikilla
dispatch_id-tunnisteella display_title-kentästä. Vaikka useampi
artifakti dispatchaisi samaan aikaan ja useita workflow-runeja olisi
käynnissä rinnakkain, jokainen skripti löytää oikean runinsa.
Sääntöjä
- Token ei kirjoita code repoon. GitOps-repon workflow ei tarvitse oikeuksia code repoon. Kaikki status-kutsut kohdistuvat vain GitOps-repoon. Code repo asettaa oman statusnsa itse.
- Ei provider-workflowta. GitOps-päivitys ei ole reusable workflow.
GitOps-repo ajaa
scripts/gitops-update.sh:n suoraan. - Vain
workflow_dispatch. GitOps-repon workflow:ta ei triggeröidä pushista — se laukeaa vain dispatch-kutsusta. - **Dispatch ei palauta tarkkaa SHA:**ta. Code repo ei tiedä GitOps- commitin SHA:ta ennen dispatch-valmistumista. Status asetetaan dispatchin exit-koodin perusteella, ei GitOps-commitin tiedoilla.
dispatch_idon pakollinen kohde-workflow'ssa — ilman sitädispatch-workflow.shei löydä oikeaa runia moniajo-tilanteessa.[skip ci]commit-viestissä. Pakollinen trigger-loopin estoon.