flock M1 scaffold: CNI plugin + agent + NodeConfig CRD
Build flock Image / build (push) Has been cancelled

- cmd/flock + cmd/flock-agent: build cleanly; CNI ADD/DEL/CHECK return
  ErrInternal stubs until M2; agent boots, opens unix socket, logs JSON.
- pkg/agent/state.go: durable allocations.json (atomic write + fsync +
  parent fsync); pending/committed lifecycle. Tests cover round-trip,
  replace-by-cid, version mismatch, no-leak-on-tmp.
- pkg/embed/suffix.go: ip-algo IID embedding. Tests cover the /48-/96
  nibble distribution table from the design doc, determinism, prefix
  preservation, N-nibble isolation, digest-vs-fallback divergence.
- pkg/api/v1alpha1: minimal NodeConfig types (no controller-runtime yet).
- deploy/: NodeConfig CRD, empty ServiceAccount/ClusterRole, DaemonSet
  pinned to flock.fritzlab.net/agent="" label so it only runs on opted-in
  nodes.
- .gitea/workflows/main.yaml + Dockerfile: build + push to
  code.fritzlab.net/fritzlab/flock; runs go test in CI.

Design doc: dfritzlab/k8s-manager/dfritz-cni.md.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Donavan Fritz
2026-04-24 21:17:42 -05:00
commit 20f47916af
22 changed files with 1460 additions and 0 deletions
@@ -0,0 +1,72 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: nodeconfigs.flock.fritzlab.net
spec:
group: flock.fritzlab.net
scope: Cluster
names:
kind: NodeConfig
listKind: NodeConfigList
singular: nodeconfig
plural: nodeconfigs
shortNames:
- fnc
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
type: object
required: [bgp]
properties:
cidr6:
type: array
items:
type: string
description: IPv6 CIDR owned and aggregate-advertised by this node.
cidr4:
type: array
items:
type: string
description: IPv4 CIDR owned and aggregate-advertised by this node.
bgp:
type: object
required: [asn, peers]
properties:
asn:
type: integer
format: int64
minimum: 1
maximum: 4294967295
description: This node's local ASN.
peers:
type: array
minItems: 1
items:
type: object
required: [address, asn]
properties:
address:
type: string
description: Peer IP (IPv6 or IPv4).
asn:
type: integer
format: int64
minimum: 1
maximum: 4294967295
additionalPrinterColumns:
- name: ASN
type: integer
jsonPath: .spec.bgp.asn
- name: CIDR6
type: string
jsonPath: .spec.cidr6
- name: CIDR4
type: string
jsonPath: .spec.cidr4
+84
View File
@@ -0,0 +1,84 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: flock-agent
namespace: kube-system
labels:
app: flock-agent
spec:
selector:
matchLabels:
app: flock-agent
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
app: flock-agent
spec:
serviceAccountName: flock-agent
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
priorityClassName: system-node-critical
# M1: opt-in per-node via this label. Remove the nodeSelector when
# ready to roll flock to all nodes.
nodeSelector:
flock.fritzlab.net/agent: ""
# Tolerate the cni-test taint applied during migration.
tolerations:
- key: fritzlab.net/cni-test
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
containers:
- name: flock-agent
image: code.fritzlab.net/fritzlab/flock:latest
imagePullPolicy: Always
args:
- --node=$(NODE_NAME)
- --state=/var/lib/flock/allocations.json
- --socket=/run/flock/flock.sock
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
# M1: no privileged caps. M2 adds NET_ADMIN/NET_RAW for netlink.
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: lib-flock
mountPath: /var/lib/flock
- name: run-flock
mountPath: /run/flock
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
memory: 128Mi
volumes:
- name: lib-flock
hostPath:
path: /var/lib/flock
type: DirectoryOrCreate
- name: run-flock
hostPath:
path: /run/flock
type: DirectoryOrCreate
imagePullSecrets:
- name: code-fritzlab-net
+184
View File
@@ -0,0 +1,184 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: nodeconfigs.flock.fritzlab.net
spec:
group: flock.fritzlab.net
scope: Cluster
names:
kind: NodeConfig
listKind: NodeConfigList
singular: nodeconfig
plural: nodeconfigs
shortNames:
- fnc
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
type: object
required: [bgp]
properties:
cidr6:
type: array
items:
type: string
description: IPv6 CIDR owned and aggregate-advertised by this node.
cidr4:
type: array
items:
type: string
description: IPv4 CIDR owned and aggregate-advertised by this node.
bgp:
type: object
required: [asn, peers]
properties:
asn:
type: integer
format: int64
minimum: 1
maximum: 4294967295
description: This node's local ASN.
peers:
type: array
minItems: 1
items:
type: object
required: [address, asn]
properties:
address:
type: string
description: Peer IP (IPv6 or IPv4).
asn:
type: integer
format: int64
minimum: 1
maximum: 4294967295
additionalPrinterColumns:
- name: ASN
type: integer
jsonPath: .spec.bgp.asn
- name: CIDR6
type: string
jsonPath: .spec.cidr6
- name: CIDR4
type: string
jsonPath: .spec.cidr4
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flock-agent
namespace: kube-system
---
# M1 RBAC: empty. The agent does not yet read any Kubernetes objects.
# M2+ will add Pod, NetworkPolicy, and NodeConfig permissions here.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: flock-agent
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: flock-agent
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flock-agent
subjects:
- kind: ServiceAccount
name: flock-agent
namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: flock-agent
namespace: kube-system
labels:
app: flock-agent
spec:
selector:
matchLabels:
app: flock-agent
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
app: flock-agent
spec:
serviceAccountName: flock-agent
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
priorityClassName: system-node-critical
# M1: opt-in per-node via this label. Remove the nodeSelector when
# ready to roll flock to all nodes.
nodeSelector:
flock.fritzlab.net/agent: ""
# Tolerate the cni-test taint applied during migration.
tolerations:
- key: fritzlab.net/cni-test
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
containers:
- name: flock-agent
image: code.fritzlab.net/fritzlab/flock:latest
imagePullPolicy: Always
args:
- --node=$(NODE_NAME)
- --state=/var/lib/flock/allocations.json
- --socket=/run/flock/flock.sock
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
# M1: no privileged caps. M2 adds NET_ADMIN/NET_RAW for netlink.
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: lib-flock
mountPath: /var/lib/flock
- name: run-flock
mountPath: /run/flock
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
memory: 128Mi
volumes:
- name: lib-flock
hostPath:
path: /var/lib/flock
type: DirectoryOrCreate
- name: run-flock
hostPath:
path: /run/flock
type: DirectoryOrCreate
imagePullSecrets:
- name: code-fritzlab-net
+26
View File
@@ -0,0 +1,26 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: flock-agent
namespace: kube-system
---
# M1 RBAC: empty. The agent does not yet read any Kubernetes objects.
# M2+ will add Pod, NetworkPolicy, and NodeConfig permissions here.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: flock-agent
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: flock-agent
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flock-agent
subjects:
- kind: ServiceAccount
name: flock-agent
namespace: kube-system