From 04461a10e50981108c691c6712a5f84c2800037a Mon Sep 17 00:00:00 2001 From: automation Date: Mon, 14 Sep 2026 10:08:07 +0300 Subject: [PATCH] =?UTF-8?q?seed:=20devroadmap-demo=20=E2=80=94=20self-host?= =?UTF-8?q?ed=20CI=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .forgejo/workflows/ci.yml | 56 +++++++++++++++++++++++++++++++++++++++ Dockerfile | 17 ++++++++++++ README.md | 27 +++++++++++++++++++ deploy/deployment.yaml | 34 ++++++++++++++++++++++++ deploy/kustomization.yaml | 21 +++++++++++++++ deploy/service.yaml | 14 ++++++++++ site/index.html | 44 ++++++++++++++++++++++++++++++ 7 files changed, 213 insertions(+) create mode 100644 .forgejo/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 deploy/deployment.yaml create mode 100644 deploy/kustomization.yaml create mode 100644 deploy/service.yaml create mode 100644 site/index.html diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..e77f728 --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,56 @@ +name: build-and-deploy + +# Build the image, push to Harbor, bump the deploy tag, push back → ArgoCD deploys. +# paths-ignore avoids an infinite loop: the tag-bump commit only touches deploy/. +on: + push: + branches: [main] + paths-ignore: + - "deploy/**" + - "**.md" + +env: + IMAGE: harbor.devroadmap.ru/homelab/devroadmap-demo + +jobs: + build-deploy: + runs-on: k8s-arm64 # act_runner label → docker:27-cli, DinD at localhost:2375 + env: + DOCKER_HOST: tcp://localhost:2375 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Short SHA + id: sha + run: echo "value=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + + - name: Login to Harbor + run: | + echo "${{ secrets.HARBOR_ROBOT_PASSWORD }}" \ + | docker login harbor.devroadmap.ru -u "${{ secrets.HARBOR_ROBOT_USER }}" --password-stdin + + - name: Build and push (native arm64) + run: | + docker build \ + --build-arg GIT_SHA="${{ steps.sha.outputs.value }}" \ + --build-arg BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + -t "$IMAGE:${{ steps.sha.outputs.value }}" \ + -t "$IMAGE:latest" . + docker push "$IMAGE:${{ steps.sha.outputs.value }}" + docker push "$IMAGE:latest" + + - name: Bump deploy tag (GitOps) and push back + run: | + sed -i "s#newTag:.*#newTag: \"${{ steps.sha.outputs.value }}\"#" deploy/kustomization.yaml + git config user.name "forgejo-ci" + git config user.email "ci@git.devroadmap.ru" + git add deploy/kustomization.yaml + git commit -m "ci: deploy ${{ steps.sha.outputs.value }} [skip ci]" || { echo "no change"; exit 0; } + git push "http://ci:${{ secrets.FORGEJO_TOKEN }}@forgejo.forgejo.svc/${{ github.repository }}.git" HEAD:main + + - name: Summary + run: | + echo "Built $IMAGE:${{ steps.sha.outputs.value }} → Harbor; deploy/ bumped → ArgoCD will sync." >> "$GITHUB_STEP_SUMMARY" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a046c4a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Trimmed devroadmap demo — a static landing served by nginx. Deliberately light +# so the arm64 in-cluster build is fast/reliable (the demo is the CI/CD LOOP, not +# a heavy build). Swap in the full Astro SSR build (node:22-alpine + pnpm, RU npm +# mirror registry.npmmirror.com) later — the pipeline stays identical. +FROM docker.io/library/nginx:1.27-alpine + +ARG GIT_SHA=dev +ARG BUILD_DATE=unknown + +COPY site/ /usr/share/nginx/html/ + +# "build" step: stamp the commit + date into the page so every deploy is visibly +# different — proves the loop end-to-end from the browser. +RUN sed -i "s/__GIT_SHA__/${GIT_SHA}/g; s/__BUILD_DATE__/${BUILD_DATE}/g" \ + /usr/share/nginx/html/index.html + +EXPOSE 80 diff --git a/README.md b/README.md new file mode 100644 index 0000000..cd000d4 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# devroadmap-demo — self-hosted CI/CD loop demo + +Seed for the Forgejo repo `devroadmap-demo`. It demonstrates a **fully +self-hosted** build→deploy loop with no GitHub in the path: + +``` +push to Forgejo → Forgejo Actions (act_runner + DinD) build arm64 image + → push to Harbor (harbor.devroadmap.ru) → bump deploy/ image tag → push back + → ArgoCD (watching this repo) syncs → live in k3s (ns devroadmap-demo, VIP .233) +``` + +This is a **trimmed** derivative of the `developer-roadmap` project: a static +landing served by nginx, kept light so the in-cluster arm64 build is fast and +reliable. The point is the pipeline, not the build weight — swap in the full +Astro SSR build (Node 22 + pnpm, RU npm mirror) later by replacing the Dockerfile. + +## Layout +- `Dockerfile` — nginx:alpine; stamps the commit SHA + build date into the page. +- `site/` — the static site. +- `.forgejo/workflows/ci.yml` — the loop (build → Harbor → tag bump → push). +- `deploy/` — the k8s manifests ArgoCD renders (`kustomization` + `deployment` + `service`). + +## Bootstrap +This repo is created and pushed during the Forgejo bring-up — see +`homelab-gitops/docs/forgejo.md` for the full runbook (repo secrets +`HARBOR_ROBOT_USER`/`HARBOR_ROBOT_PASSWORD`/`FORGEJO_TOKEN`, the runner, and the +ArgoCD Application that watches this repo). diff --git a/deploy/deployment.yaml b/deploy/deployment.yaml new file mode 100644 index 0000000..2c6255b --- /dev/null +++ b/deploy/deployment.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: devroadmap-demo +spec: + replicas: 1 + template: + spec: + nodeSelector: + kubernetes.io/arch: arm64 # image built native arm64 on the runner + containers: + - name: web + image: harbor.devroadmap.ru/homelab/devroadmap-demo:bootstrap + ports: + - name: http + containerPort: 80 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 3 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 20 + resources: + requests: + cpu: 10m + memory: 16Mi + limits: + memory: 64Mi diff --git a/deploy/kustomization.yaml b/deploy/kustomization.yaml new file mode 100644 index 0000000..93fc279 --- /dev/null +++ b/deploy/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# Rendered by ArgoCD from THIS Forgejo repo (path: deploy). The CI pipeline bumps +# newTag on every push, then Argo syncs the new image into k3s. + +namespace: devroadmap-demo + +labels: + - includeSelectors: true + pairs: + app.kubernetes.io/name: devroadmap-demo + app.kubernetes.io/instance: devroadmap-demo + +resources: + - deployment.yaml + - service.yaml + +images: + - name: harbor.devroadmap.ru/homelab/devroadmap-demo + newTag: "bootstrap" # bumped to the short SHA by .forgejo/workflows/ci.yml diff --git a/deploy/service.yaml b/deploy/service.yaml new file mode 100644 index 0000000..ce6b762 --- /dev/null +++ b/deploy/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: devroadmap-demo + annotations: + # LAN VIP (allocation table: docs/k3s-app-standard.md). .235-.237 are argo + # metrics LBs — do not reuse. + metallb.io/loadBalancerIPs: 192.168.2.233 +spec: + type: LoadBalancer + ports: + - name: http + port: 80 + targetPort: http diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..89abbb1 --- /dev/null +++ b/site/index.html @@ -0,0 +1,44 @@ + + + + + + devroadmap-demo · self-hosted CI/CD + + + +
+

devroadmap-demo

+

fully self-hosted build → deploy loop

+

+ push to ForgejoForgejo Actions (act_runner + DinD) build + arm64 → push Harbor → bump tag → ArgoCD deploys to k3s. + No GitHub in the path. +

+
+
commit
__GIT_SHA__
+
built
__BUILD_DATE__
+
+
+ +