add args: startup_timeout for kubernetes plugin (#7068)

Signed-off-by: mangoyhuang <mangoyhuang@tencent.com>
Co-authored-by: mangoyhuang <mangoyhuang@tencent.com>
This commit is contained in:
Dave Brown
2025-06-12 02:22:07 +08:00
committed by GitHub
parent cbb318f4d0
commit ab74d3acf2
4 changed files with 69 additions and 4 deletions

View File

@@ -43,6 +43,7 @@ kubernetes [ZONES...] {
fallthrough [ZONES...]
ignore empty_service
multicluster [ZONES...]
startup_timeout DURATION
}
```
@@ -106,6 +107,8 @@ kubernetes [ZONES...] {
Services API (MCS-API). Specifying this option is generally paired with the
installation of an MCS-API implementation and the ServiceImport and ServiceExport
CRDs. The plugin MUST be authoritative for the zones listed here.
* `startup_timeout` specifies the **DURATION** value that limits the time to wait for informer cache synced
when the kubernetes plugin starts. If not specified, the default timeout will be 5s.
Enabling zone transfer is done by using the *transfer* plugin.
@@ -115,7 +118,7 @@ When CoreDNS starts with the *kubernetes* plugin enabled, it will delay serving
until it can connect to the Kubernetes API and synchronize all object watches. If this cannot happen within
5 seconds, then CoreDNS will start serving DNS while the *kubernetes* plugin continues to try to connect
and synchronize all object watches. CoreDNS will answer SERVFAIL to any request made for a Kubernetes record
that has not yet been synchronized.
that has not yet been synchronized. You can also determine how long to wait by specifying `startup_timeout`.
## Monitoring Kubernetes Endpoints

View File

@@ -48,7 +48,8 @@ type Kubernetes struct {
opts dnsControlOpts
primaryZoneIndex int
localIPs []net.IP
autoPathSearch []string // Local search path from /etc/resolv.conf. Needed for autopath.
autoPathSearch []string // Local search path from /etc/resolv.conf. Needed for autopath.
startupTimeout time.Duration // startupTimeout set timeout of startup
}
// Upstreamer is used to resolve CNAME or other external targets
@@ -276,8 +277,7 @@ func (k *Kubernetes) InitKubeCache(ctx context.Context) (onStart func() error, o
k.APIConn.Run()
}()
timeout := 5 * time.Second
timeoutTicker := time.NewTicker(timeout)
timeoutTicker := time.NewTicker(k.startupTimeout)
defer timeoutTicker.Stop()
logDelay := 500 * time.Millisecond
logTicker := time.NewTicker(logDelay)

View File

@@ -7,6 +7,7 @@ import (
"slices"
"strconv"
"strings"
"time"
"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
@@ -112,6 +113,7 @@ func ParseStanza(c *caddy.Controller) (*Kubernetes, error) {
k8s.Upstream = upstream.New()
k8s.startupTimeout = time.Second * 5
for c.NextBlock() {
switch c.Val() {
case "endpoint_pod_names":
@@ -231,6 +233,17 @@ func ParseStanza(c *caddy.Controller) (*Kubernetes, error) {
k8s.ClientConfig = config
case "multicluster":
k8s.opts.multiclusterZones = plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), []string{})
case "startup_timeout":
args := c.RemainingArgs()
if len(args) == 0 {
return nil, c.ArgErr()
} else {
var err error
k8s.startupTimeout, err = time.ParseDuration(args[0])
if err != nil {
return nil, fmt.Errorf("failed to parse startup_timeout: %v, %s", args[0], err)
}
}
default:
return nil, c.Errf("unknown property '%s'", c.Val())
}

View File

@@ -4,6 +4,7 @@ import (
"slices"
"strings"
"testing"
"time"
"github.com/coredns/caddy"
"github.com/coredns/coredns/plugin/pkg/fall"
@@ -11,6 +12,8 @@ import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var defaultStartupTimeout = time.Second * 5
func TestKubernetesParse(t *testing.T) {
tests := []struct {
input string // Corefile data as string
@@ -22,6 +25,7 @@ func TestKubernetesParse(t *testing.T) {
expectedNamespaceLabelSelector string // expected namespace label selector value
expectedPodMode string
expectedFallthrough fall.F
expectedStartupTimeout time.Duration
}{
// positive
{
@@ -34,6 +38,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local test.local`,
@@ -45,6 +50,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -57,6 +63,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -70,6 +77,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -83,6 +91,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -96,6 +105,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -109,6 +119,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -122,6 +133,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -135,6 +147,7 @@ func TestKubernetesParse(t *testing.T) {
"istio-injection=enabled",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -149,6 +162,7 @@ func TestKubernetesParse(t *testing.T) {
"istio-injection=enabled",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local test.local {
@@ -165,6 +179,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Root,
defaultStartupTimeout,
},
// negative
{
@@ -179,6 +194,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -192,6 +208,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -205,6 +222,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -218,6 +236,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
// pods disabled
{
@@ -232,6 +251,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
// pods insecure
{
@@ -246,6 +266,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeInsecure,
fall.Zero,
defaultStartupTimeout,
},
// pods verified
{
@@ -260,6 +281,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeVerified,
fall.Zero,
defaultStartupTimeout,
},
// pods invalid
{
@@ -274,6 +296,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeVerified,
fall.Zero,
defaultStartupTimeout,
},
// fallthrough with zones
{
@@ -288,6 +311,7 @@ func TestKubernetesParse(t *testing.T) {
"",
podModeDisabled,
fall.F{Zones: []string{"ip6.arpa.", "inaddr.arpa.", "foo.com."}},
defaultStartupTimeout,
},
// More than one Kubernetes not allowed
{
@@ -301,6 +325,7 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -314,6 +339,7 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -327,6 +353,7 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -340,6 +367,7 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
@@ -353,6 +381,22 @@ kubernetes cluster.local`,
"",
podModeDisabled,
fall.Zero,
defaultStartupTimeout,
},
{
`kubernetes coredns.local {
kubeconfig file context
startup_timeout 1s
}`,
false,
"",
1,
0,
"",
"",
podModeDisabled,
fall.Zero,
time.Second * 1,
},
}
@@ -414,6 +458,11 @@ kubernetes cluster.local`,
if !k8sController.Fall.Equal(test.expectedFallthrough) {
t.Errorf("Test %d: Expected kubernetes controller to be initialized with fallthrough '%v'. Instead found fallthrough '%v' for input '%s'", i, test.expectedFallthrough, k8sController.Fall, test.input)
}
// startupTimeout
if k8sController.startupTimeout.String() != test.expectedStartupTimeout.String() {
t.Errorf("Test %d: Expected kubernetes controller to be initialized with startupTimeout '%v'. Instead found startupTimeout '%v' for input '%s'", i, test.expectedStartupTimeout, k8sController.startupTimeout, test.input)
}
}
}