mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-20 19:25:52 +00:00
f7bf921ce7
* fix(eks): keep derived ELBv2 names under 32 chars and surface CREATE_FAILED reason Long cluster names made the derived "eks-<name>[-cp|-konn]" NLB/target-group names exceed the ELBv2 32-char limit, failing cluster creation asynchronously with no visible cause. safeELBv2Name now deterministically truncates the name and appends a stable hash of the full cluster name when needed, so the same name is derived on every call (create, lookup, delete). DescribeCluster also now surfaces ClusterMeta.StatusReason as a Health.Issues entry when a cluster is FAILED, instead of leaving callers to guess why. * fix(eks): plumb per-nodegroup Ready-node counts through state reports The on-VM state-report script now emits nodegroup_ready, a per-nodegroup Ready count keyed by the eks.amazonaws.com/nodegroup label value, alongside the existing cluster-wide node_count. ServerStateReport, the ClusterReconciler's observe step, and SetClusterHealthState now carry this map through to ClusterMeta.NodegroupNodeCounts, so per-nodegroup consumers (wired in the next commit) can gate on a nodegroup's own workers instead of the cluster total. * fix(eks): scope nodegroup Ready-gate per nodegroup and retry failed worker launches waitWorkersReady compared the cluster-wide Ready-node count against a nodegroup's baseline+desired, so in a multi-nodegroup cluster one nodegroup's Ready workers could mask another whose own workers never registered. It now reads meta.NodegroupNodeCounts[ng], scoped to nodes carrying the eks.amazonaws.com/nodegroup=<name> label. Separately, launchNodegroupInfra never retried a failed worker launch (a transient QMP timeout or host capacity pressure), leaving the nodegroup stuck CREATING with zero workers. The new launchWorkersUntilDesired wrapper relaunches only the shortfall on failure, logging each retry, until the desired count is reached or workerLaunchRetryTimeout elapses. Both fixes are covered by regression tests: a two-nodegroup scenario where only one has Ready workers, a transient-failure-then-success relaunch, and an exhausted-retry-budget CREATE_FAILED path. Not covered here: a worker that dies after the nodegroup is already ACTIVE — that needs an ongoing reconciler, which this change does not add. * fix(eks): tolerate GPU NoSchedule taint in konnectivity-agent DaemonSet A GPU-only worker is tainted nvidia.com/gpu=present:NoSchedule, so the konnectivity-agent DaemonSet (no tolerations) showed DESIRED=0 there and kubectl logs/exec against pods on that node failed "No agent available". Adds an Exists toleration for nvidia.com/gpu:NoSchedule. Live-cluster validation (DESIRED count, kubectl exec) is deferred — no cluster available to test against right now. * fix: tolerate nvidia.com/gpu taint on ebs-csi-node and coredns DaemonSets so GPU workers get storage and DNS
242 lines
6.6 KiB
YAML
242 lines
6.6 KiB
YAML
# Mulga-owned CoreDNS for the eks-node AMI. Replaces k3s's bundled CoreDNS
|
|
# (suppressed via a coredns.yaml.skip marker staged by k3s.initd) so DNS is
|
|
# node-local and never depends on the cross-node pod overlay: a DaemonSet runs
|
|
# CoreDNS on every worker node and kube-dns uses internalTrafficPolicy=Local, so
|
|
# each worker resolves through its own CoreDNS. Mirroring AWS EKS, CoreDNS runs
|
|
# on workers only (nodeAffinity excludes control-plane): the managed control
|
|
# plane never hosts kube-dns, and the worker<->CP overlay cannot cross the VPC
|
|
# boundary, so a CP-resident CoreDNS would be unreachable from worker pods.
|
|
#
|
|
# Faithful to k3s v1.32.5+k3s1 (image, Corefile, RBAC, Service) except the two
|
|
# locality changes above. Refresh image/Corefile when bumping K3S_VERSION in
|
|
# setup.sh.
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: coredns
|
|
namespace: kube-system
|
|
labels:
|
|
kubernetes.io/cluster-service: "true"
|
|
addonmanager.kubernetes.io/mode: Reconcile
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRole
|
|
metadata:
|
|
labels:
|
|
kubernetes.io/bootstrapping: rbac-defaults
|
|
addonmanager.kubernetes.io/mode: Reconcile
|
|
name: system:coredns
|
|
rules:
|
|
- apiGroups:
|
|
- ""
|
|
resources:
|
|
- endpoints
|
|
- services
|
|
- pods
|
|
- namespaces
|
|
verbs:
|
|
- list
|
|
- watch
|
|
- apiGroups:
|
|
- discovery.k8s.io
|
|
resources:
|
|
- endpointslices
|
|
verbs:
|
|
- list
|
|
- watch
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
annotations:
|
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
|
labels:
|
|
kubernetes.io/bootstrapping: rbac-defaults
|
|
addonmanager.kubernetes.io/mode: EnsureExists
|
|
name: system:coredns
|
|
roleRef:
|
|
apiGroup: rbac.authorization.k8s.io
|
|
kind: ClusterRole
|
|
name: system:coredns
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: coredns
|
|
namespace: kube-system
|
|
---
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: coredns
|
|
namespace: kube-system
|
|
labels:
|
|
addonmanager.kubernetes.io/mode: EnsureExists
|
|
data:
|
|
Corefile: |
|
|
.:53 {
|
|
errors
|
|
health
|
|
ready
|
|
kubernetes cluster.local in-addr.arpa ip6.arpa {
|
|
pods insecure
|
|
fallthrough in-addr.arpa ip6.arpa
|
|
}
|
|
hosts /etc/coredns/NodeHosts {
|
|
ttl 60
|
|
reload 15s
|
|
fallthrough
|
|
}
|
|
prometheus :9153
|
|
forward . /etc/resolv.conf
|
|
cache 30
|
|
loop
|
|
reload
|
|
loadbalance
|
|
import /etc/coredns/custom/*.override
|
|
}
|
|
import /etc/coredns/custom/*.server
|
|
NodeHosts: ""
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: DaemonSet
|
|
metadata:
|
|
name: coredns
|
|
namespace: kube-system
|
|
labels:
|
|
k8s-app: kube-dns
|
|
kubernetes.io/name: "CoreDNS"
|
|
spec:
|
|
selector:
|
|
matchLabels:
|
|
k8s-app: kube-dns
|
|
updateStrategy:
|
|
type: RollingUpdate
|
|
rollingUpdate:
|
|
maxUnavailable: 1
|
|
template:
|
|
metadata:
|
|
labels:
|
|
k8s-app: kube-dns
|
|
spec:
|
|
priorityClassName: system-cluster-critical
|
|
serviceAccountName: coredns
|
|
# AWS-EKS parity: CoreDNS runs on worker nodes only. The control plane is
|
|
# managed and never hosts kube-dns; each worker resolves through its own
|
|
# node's CoreDNS (internalTrafficPolicy=Local), so DNS never crosses the
|
|
# worker<->CP overlay boundary. No CP toleration is carried, and
|
|
# anti-control-plane nodeAffinity keeps the DaemonSet off the K3s server VMs.
|
|
affinity:
|
|
nodeAffinity:
|
|
requiredDuringSchedulingIgnoredDuringExecution:
|
|
nodeSelectorTerms:
|
|
- matchExpressions:
|
|
- key: node-role.kubernetes.io/control-plane
|
|
operator: DoesNotExist
|
|
- key: node-role.kubernetes.io/master
|
|
operator: DoesNotExist
|
|
nodeSelector:
|
|
kubernetes.io/os: linux
|
|
# With internalTrafficPolicy=Local each worker resolves through its OWN
|
|
# CoreDNS pod, so a GPU-only worker (tainted nvidia.com/gpu=present:
|
|
# NoSchedule) with no local pod would have no DNS at all for its pods.
|
|
tolerations:
|
|
- key: nvidia.com/gpu
|
|
operator: Exists
|
|
effect: NoSchedule
|
|
containers:
|
|
- name: coredns
|
|
image: rancher/mirrored-coredns-coredns:1.12.1
|
|
imagePullPolicy: IfNotPresent
|
|
resources:
|
|
limits:
|
|
memory: 170Mi
|
|
requests:
|
|
cpu: 100m
|
|
memory: 70Mi
|
|
args: ["-conf", "/etc/coredns/Corefile"]
|
|
volumeMounts:
|
|
- name: config-volume
|
|
mountPath: /etc/coredns
|
|
readOnly: true
|
|
- name: custom-config-volume
|
|
mountPath: /etc/coredns/custom
|
|
readOnly: true
|
|
ports:
|
|
- containerPort: 53
|
|
name: dns
|
|
protocol: UDP
|
|
- containerPort: 53
|
|
name: dns-tcp
|
|
protocol: TCP
|
|
- containerPort: 9153
|
|
name: metrics
|
|
protocol: TCP
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
add:
|
|
- NET_BIND_SERVICE
|
|
drop:
|
|
- all
|
|
readOnlyRootFilesystem: true
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8080
|
|
scheme: HTTP
|
|
initialDelaySeconds: 60
|
|
timeoutSeconds: 5
|
|
successThreshold: 1
|
|
failureThreshold: 5
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ready
|
|
port: 8181
|
|
scheme: HTTP
|
|
dnsPolicy: Default
|
|
volumes:
|
|
- name: config-volume
|
|
configMap:
|
|
name: coredns
|
|
items:
|
|
- key: Corefile
|
|
path: Corefile
|
|
- key: NodeHosts
|
|
path: NodeHosts
|
|
- name: custom-config-volume
|
|
configMap:
|
|
name: coredns-custom
|
|
optional: true
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: kube-dns
|
|
namespace: kube-system
|
|
annotations:
|
|
prometheus.io/port: "9153"
|
|
prometheus.io/scrape: "true"
|
|
labels:
|
|
k8s-app: kube-dns
|
|
kubernetes.io/cluster-service: "true"
|
|
kubernetes.io/name: "CoreDNS"
|
|
spec:
|
|
selector:
|
|
k8s-app: kube-dns
|
|
clusterIP: 10.43.0.10
|
|
# Local: kube-proxy routes each node's 10.43.0.10 queries only to that node's
|
|
# CoreDNS DaemonSet pod, so DNS never crosses the worker<->CP boundary.
|
|
internalTrafficPolicy: Local
|
|
ports:
|
|
- name: dns
|
|
port: 53
|
|
protocol: UDP
|
|
targetPort: 53
|
|
- name: dns-tcp
|
|
port: 53
|
|
protocol: TCP
|
|
targetPort: 53
|
|
- name: metrics
|
|
port: 9153
|
|
protocol: TCP
|
|
targetPort: 9153
|