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.
This commit is contained in:
Graham McIntire 2026-02-17 16:11:27 -06:00
parent 4366fa36da
commit a637b3b87c
No known key found for this signature in database
11 changed files with 296 additions and 0 deletions

View file

@ -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

140
k8s/deployment.yaml Normal file
View file

@ -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

View file

@ -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

14
k8s/flux/imagepolicy.yaml Normal file
View file

@ -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<ts>[0-9]+)-[a-f0-9]+$'
extract: '$ts'
policy:
numerical:
order: asc

View file

@ -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

View file

@ -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

View file

@ -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

8
k8s/kustomization.yaml Normal file
View file

@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: aprs
resources:
- namespace.yaml
- deployment.yaml
- service.yaml
- service-headless.yaml

4
k8s/namespace.yaml Normal file
View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: aprs

16
k8s/service-headless.yaml Normal file
View file

@ -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

13
k8s/service.yaml Normal file
View file

@ -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