From a637b3b87c3ffbd27c0864a94533a50b23ed2c3b Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 17 Feb 2026 16:11:27 -0600 Subject: [PATCH] Add k8s deployment manifests and FluxCD GitOps config Kubernetes manifests for deploying to home cluster in the aprs namespace with Forgejo Actions CI pipeline for building and pushing container images to git.mcintire.me registry. --- .forgejo/workflows/build.yaml | 42 +++++++++ k8s/deployment.yaml | 140 ++++++++++++++++++++++++++++ k8s/flux/gitrepository.yaml | 12 +++ k8s/flux/imagepolicy.yaml | 14 +++ k8s/flux/imagerepository.yaml | 10 ++ k8s/flux/imageupdateautomation.yaml | 24 +++++ k8s/flux/kustomization.yaml | 13 +++ k8s/kustomization.yaml | 8 ++ k8s/namespace.yaml | 4 + k8s/service-headless.yaml | 16 ++++ k8s/service.yaml | 13 +++ 11 files changed, 296 insertions(+) create mode 100644 .forgejo/workflows/build.yaml create mode 100644 k8s/deployment.yaml create mode 100644 k8s/flux/gitrepository.yaml create mode 100644 k8s/flux/imagepolicy.yaml create mode 100644 k8s/flux/imagerepository.yaml create mode 100644 k8s/flux/imageupdateautomation.yaml create mode 100644 k8s/flux/kustomization.yaml create mode 100644 k8s/kustomization.yaml create mode 100644 k8s/namespace.yaml create mode 100644 k8s/service-headless.yaml create mode 100644 k8s/service.yaml diff --git a/.forgejo/workflows/build.yaml b/.forgejo/workflows/build.yaml new file mode 100644 index 0000000..0e900d2 --- /dev/null +++ b/.forgejo/workflows/build.yaml @@ -0,0 +1,42 @@ +name: Build and Push + +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Login to Forgejo Registry + uses: docker/login-action@v3 + with: + registry: git.mcintire.me + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Generate image tags + id: tags + run: | + TIMESTAMP=$(date +%s) + SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) + TAG="main-${TIMESTAMP}-${SHORT_SHA}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "Building image with tag: ${TAG}" + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: | + git.mcintire.me/graham/aprs.me:${{ steps.tags.outputs.tag }} + git.mcintire.me/graham/aprs.me:latest + cache-from: type=registry,ref=git.mcintire.me/graham/aprs.me:latest + cache-to: type=inline diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..526cae0 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,140 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: aprs + namespace: aprs +spec: + replicas: 2 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 100% + maxUnavailable: 0 + minReadySeconds: 10 + selector: + matchLabels: + app: aprs + template: + metadata: + labels: + app: aprs + spec: + priorityClassName: system-cluster-critical + terminationGracePeriodSeconds: 90 + imagePullSecrets: + - name: forgejo-registry + securityContext: + runAsNonRoot: true + runAsUser: 1001 + fsGroup: 1001 + seccompProfile: + type: RuntimeDefault + containers: + - name: aprs + image: git.mcintire.me/graham/aprs.me:main-0000000000-0000000 # {"$imagepolicy": "flux-system:aprs-me"} + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1001 + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + ports: + - containerPort: 4000 + name: http + - containerPort: 4369 + name: epmd + - containerPort: 9000 + name: dist + lifecycle: + preStop: + exec: + command: + - /bin/sh + - -c + - sleep 20 + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: RELEASE_DISTRIBUTION + value: "name" + - name: RELEASE_NODE + value: "aprsme@$(POD_IP)" + - name: CLUSTER_ENABLED + value: "true" + - name: PORT + value: "4000" + - name: PHX_HOST + value: "aprs.me" + - name: MIX_ENV + value: "prod" + - name: POOL_SIZE + value: "5" + - name: PACKET_RETENTION_DAYS + value: "1" + - name: APRS_CALLSIGN + value: "w5isp-1" + - name: APRS_PORT + value: "10152" + - name: RELEASE_COOKIE + valueFrom: + secretKeyRef: + name: aprs-secrets + key: RELEASE_COOKIE + - name: SECRET_KEY_BASE + valueFrom: + secretKeyRef: + name: aprs-secrets + key: SECRET_KEY_BASE + - name: APRS_PASSCODE + valueFrom: + secretKeyRef: + name: aprs-secrets + key: APRS_PASSCODE + envFrom: + - secretRef: + name: aprs-db + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + startupProbe: + httpGet: + path: /health + port: 4000 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 12 + livenessProbe: + httpGet: + path: /health + port: 4000 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /health + port: 4000 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 2 diff --git a/k8s/flux/gitrepository.yaml b/k8s/flux/gitrepository.yaml new file mode 100644 index 0000000..4237e8f --- /dev/null +++ b/k8s/flux/gitrepository.yaml @@ -0,0 +1,12 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: aprs-me + namespace: flux-system +spec: + interval: 1m + url: https://git.mcintire.me/graham/aprs.me.git + ref: + branch: main + secretRef: + name: forgejo-git-credentials diff --git a/k8s/flux/imagepolicy.yaml b/k8s/flux/imagepolicy.yaml new file mode 100644 index 0000000..87e50a2 --- /dev/null +++ b/k8s/flux/imagepolicy.yaml @@ -0,0 +1,14 @@ +apiVersion: image.toolkit.fluxcd.io/v1beta2 +kind: ImagePolicy +metadata: + name: aprs-me + namespace: flux-system +spec: + imageRepositoryRef: + name: aprs-me + filterTags: + pattern: '^main-(?P[0-9]+)-[a-f0-9]+$' + extract: '$ts' + policy: + numerical: + order: asc diff --git a/k8s/flux/imagerepository.yaml b/k8s/flux/imagerepository.yaml new file mode 100644 index 0000000..27b4fc4 --- /dev/null +++ b/k8s/flux/imagerepository.yaml @@ -0,0 +1,10 @@ +apiVersion: image.toolkit.fluxcd.io/v1beta2 +kind: ImageRepository +metadata: + name: aprs-me + namespace: flux-system +spec: + image: git.mcintire.me/graham/aprs.me + interval: 1m + secretRef: + name: forgejo-registry diff --git a/k8s/flux/imageupdateautomation.yaml b/k8s/flux/imageupdateautomation.yaml new file mode 100644 index 0000000..f317030 --- /dev/null +++ b/k8s/flux/imageupdateautomation.yaml @@ -0,0 +1,24 @@ +apiVersion: image.toolkit.fluxcd.io/v1beta2 +kind: ImageUpdateAutomation +metadata: + name: aprs-me + namespace: flux-system +spec: + interval: 1m + sourceRef: + kind: GitRepository + name: aprs-me + git: + checkout: + ref: + branch: main + push: + branch: main + commit: + author: + name: FluxCD + email: fluxcd@aprs.me + messageTemplate: 'chore: update aprs.me image to {{range .Changed.Changes}}{{.NewValue}}{{end}} [skip ci]' + update: + path: ./k8s + strategy: Setters diff --git a/k8s/flux/kustomization.yaml b/k8s/flux/kustomization.yaml new file mode 100644 index 0000000..27eac96 --- /dev/null +++ b/k8s/flux/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: aprs-app + namespace: flux-system +spec: + interval: 5m + sourceRef: + kind: GitRepository + name: aprs-me + path: ./k8s + prune: true + targetNamespace: aprs diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml new file mode 100644 index 0000000..ef23ab3 --- /dev/null +++ b/k8s/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: aprs +resources: + - namespace.yaml + - deployment.yaml + - service.yaml + - service-headless.yaml diff --git a/k8s/namespace.yaml b/k8s/namespace.yaml new file mode 100644 index 0000000..c9b9181 --- /dev/null +++ b/k8s/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: aprs diff --git a/k8s/service-headless.yaml b/k8s/service-headless.yaml new file mode 100644 index 0000000..fec27fd --- /dev/null +++ b/k8s/service-headless.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: aprs-headless + namespace: aprs +spec: + clusterIP: None + selector: + app: aprs + ports: + - name: epmd + port: 4369 + targetPort: 4369 + - name: dist + port: 9000 + targetPort: 9000 diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..75051d9 --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: aprs + namespace: aprs +spec: + selector: + app: aprs + ports: + - name: http + port: 4000 + targetPort: 4000 + type: ClusterIP