Het kernprincipe: snel en pijnloos releases maken, en je zult vaker loslaten. Dit is van cruciaal belang voor wendbare ontwikkeling - snelle, betrouwbare implementaties zorgen voor de snelle feedback lus die u nodig hebt. Bij het implementeren is eng of traag, teams batch up veranderingen, toenemende risico's. Bij het implementeren is saai en automatisch, u verzenden van kleine veranderingen vaak.
Deze gids behandelt de release strategieën die ik gebruik in de productie, van eenvoudige tag-based implementaties tot multi-package monorepo publishing. Alle voorbeelden komen van echte GitHub-acties workflows in deze repository.
Alvorens in details te duiken, hier is hoe gemeenschappelijke strategieën vergelijken:
Strategie Beste voor Complexiteit Gemeenschappelijk In |----------|----------|------------|-----------| | Tag-based Applicaties, expliciete releases Laag Opstarten, solo devs, volwassen teams | Branch-based Voortdurende implementatie Laag Startups, snelbewegende teams | GitFlow Gereglementeerde releases, meerdere versies Hoge Enterprise, naleving zwaar | Op basis van trunk + feature-vlaggen Hoge-snelheidsteams Medium Big tech, volwassen startups | Monorepo multi-package Websites, gedeelde codebases, platformteams, OSS-projecten
Startups & kleine teams: Start met tag-based of branch-based implementatie. Houd het eenvoudig - je kunt altijd complexiteit later toevoegen. Trunk-gebaseerde ontwikkeling met functievlaggen is populair op schaal, maar overkill voor kleine teams.
Onderneming: Vaak vereist GitFlow of vergelijkbaar voor compliance, audit trails, en release management. Meerdere omgevingen (dev, QA, enscenering, prod) met goedkeuring poorten. Artifact attesten steeds meer nodig voor de beveiliging van de supply chain.
Solo-ontwikkelaars: Tag-based is ideaal. Druk een tag, implementatie gebeurt. Geen ceremonie, geen overhead.
Platform/bibliotheekteams: Noodzaak van monorepo strategieën met onafhankelijke versiering per pakket. Semantische versiering is cruciaal voor downstream consumenten.
De eenvoudigste en meest betrouwbare strategie. Verschillende tag prefixes route naar verschillende omgevingen of leiden tot verschillende acties.
on:
push:
tags:
- 'release-*' # Production
- 'local-*' # Dev environment
- name: Build Docker image
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
if [[ "$TAG_NAME" == local-* ]]; then
docker build -t myapp:local .
else
docker build -t myapp:latest -t myapp:$(date +%s) .
fi
Waarom het werkt: Eenvoudig mentaal model, expliciete implementaties, gemakkelijke terugrol via timestamped tags.
# Deploy to production
git tag release-v2024.12.01 && git push origin release-v2024.12.01
# Deploy to dev
git tag local-feature-test && git push origin local-feature-test
Voor monorepos met meerdere publiceerbare pakketten, gebruik tag prefixes om te bepalen welk pakket te vrijgeven:
# Different workflows, different tag patterns
# umami-net.yml
on:
push:
tags: ['umamiv*.*.*'] # e.g., umamiv1.0.5
# fetchextension.yml
on:
push:
tags: ['fetchextension-v*.*.*'] # e.g., fetchextension-v1.2.0
Pak de versie uit en gebruik deze overal:
- name: Extract version
run: echo "VERSION=${GITHUB_REF#refs/tags/umamiv}" >> $GITHUB_OUTPUT
- name: Build & Pack
run: |
dotnet build -c Release -p:Version=${{ steps.version.outputs.VERSION }}
dotnet pack -c Release -p:PackageVersion=${{ steps.version.outputs.VERSION }}
Voor automatische versiering, MinVer berekent versies van Git-tags:
<PackageReference Include="MinVer" Version="6.0.0" PrivateAssets="all" />
<PropertyGroup>
<MinVerTagPrefix>umamiv</MinVerTagPrefix>
</PropertyGroup>
Inschakelen automatisch wanneer code landt op specifieke branches. Gemeenschappelijk in startups en snel bewegende teams.
on:
push:
branches: [main] # → Production
# branches: [develop] # → Staging
Voordelen: Geen handmatige stap, zet in op merge Cons: Toevallige inzet mogelijk, minder expliciete geschiedenis
Ik gebruik een hybride aanpak - voortbouwen op branch push (CI verificatie), maar alleen publiceren op tags:
on:
push:
tags: ['scheduler-*']
branches: [main, local]
jobs:
build:
# Always build
publish:
if: startsWith(github.ref, 'refs/tags/') # Only publish on tags
Voor self-hosted implementaties, Watchtower Trekt automatisch nieuwe afbeeldingen aan:
services:
app:
image: myapp:latest
labels:
- "com.centurylinklabs.watchtower.enable=true"
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 300 # Check every 5 minutes
Implementatiestroom: Push tag → GitHub Acties builds → Push to registry → Watchtower pulls → Container herstart. Totale tijd: ~5 minuten.
Snelle implementaties zijn nutteloos als je bugs inzet. Elke workflow moet poorten bevatten:
- name: Run tests
run: dotnet test --configuration Release
- name: Build
run: dotnet build --configuration Release
# Tests or build fail → workflow stops → no publish
Voor multi-framework pakketten, bouw alle doelstellingen:
- run: dotnet build -c Release --framework net8.0
- run: dotnet build -c Release --framework net9.0
Moderne aanpak - geen geheimen om te roteren, geen sleutels om te lekken:
permissions:
id-token: write
contents: read
- uses: NuGet/login@v1
with:
user: 'myusername'
- run: dotnet nuget push *.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }}
GitHub wisselt zijn OIDC token uit voor een kortstondige NuGet API sleutel. Configureer vertrouwen op NuGet.org om dit in te schakelen.
Artificiële attesten Bewijs dat je artefacten zijn gebouwd in CI, niet geknoeid met... in toenemende mate vereist door bedrijven.
permissions:
id-token: write
attestations: write
- uses: docker/build-push-action@v6
id: push
with:
push: true
tags: myapp:latest
- uses: actions/attest-build-provenance@v2
with:
subject-name: index.docker.io/myuser/myapp
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
De consument gaat na of: gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser
Dit bereikt SLSA Niveau 2. Voor niveau 3 gebruiken herbruikbare workflows.
Teams hebben stakeholders nodig om veranderingen te bekijken voordat ze worden samengevoegd.
Ondernemingsaanpak - Branch-based preview omgevingen:
on:
pull_request:
types: [opened, synchronize]
- run: |
BRANCH=$(echo ${{ github.head_ref }} | sed 's/[^a-zA-Z0-9]/-/g')
docker build -t myapp:preview-$BRANCH .
# Deploy to k8s namespace, cloud platform, etc.
Opstart/solo-aanpak - Tunnel uw lokale machine:
# Cloudflare Tunnel (free)
cloudflared tunnel run --url http://localhost:5000 my-preview
# → https://my-preview.cfargotunnel.com
Of gebruik Wireguard VPN voor interne teamtoegang tot uw dev machine.
Tag opruimen: Git-tags blijven voor altijd hangen.
git tag -d old-test-tag # Delete local
git push origin :refs/tags/old-test-tag # Delete remote
Naamgevingsverdragen: Wees consistent.
release-YYYY.MM.DD voor productielocal-feature-name voor devpackagev1.2.3 voor bibliothekenGeheimen: Bewaren in GitHub-geheimen, nooit in code. Vereiste geheimen meestal:
DOCKER_HUB_ACCESS_TOKENNUGET_API_KEY (of gebruik OIDC)NPM_TOKENOntwikkeling van Monorepo: Gebruik projectverwijzingen tijdens de ontwikkeling, schakel over naar pakketverwijzingen voor implementatieverificatie:
<ProjectReference Include="..\MyLib\MyLib.csproj" />
<!-- <PackageReference Include="MyLib" Version="1.0.0" /> -->
Dezelfde principes, verschillende tools:
Docker componeert Kubernetes |----------------|------------| Watchtower ArgoCD / Flux | Docker-compose.yml omgevingen Namespaces Opnieuw opstarten van de container Rolling deployment GitOps rollback
De hier getoonde workflows draaien in deze repository - controleren .github/workflows/ voor volledige implementaties.
Vergeet niet: Snelle, betrouwbare implementaties zijn de basis van agile ontwikkeling. Investeer in uw release pijplijn vroeg.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.