Merge pull request #67297 from mkumatag/update_peer_finder

Automatic merge from submit-queue (batch tested with PRs 65251, 67255, 67224, 67297, 68105). If you want to cherry-pick this change to another branch, please follow the instructions here: https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md.

Sync peer-finder code from contrib repo

**What this PR does / why we need it**:

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes https://github.com/kubernetes/contrib/issues/2643

**Special notes for your reviewer**:
This is just an code sync up PR from https://github.com/kubernetes/contrib/pull/2644

**Release note**:

```release-note
NONE
```
pull/8/head
Kubernetes Submit Queue 2018-08-31 19:25:36 -07:00 committed by GitHub
commit 7ea1e19931
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 7 deletions

View File

@ -6,13 +6,13 @@ All it does is watch DNS for changes in the set of endpoints that are part of th
of the PetSet. It periodically looks up the SRV record of the DNS entry that corresponds to a Kubernetes
Service which enumerates the set of peers for this the specified service.
Be sure to use the `publishNotReadyAddresses` field on the governing service
Be sure to use the `service.alpha.kubernetes.io/tolerate-unready-endpoints` on the governing service
of the StatefulSet so that all peers are listed in endpoints before any peers are started.
There are several ways to bundle it with your main application.
1. In an [init container](http://kubernetes.io/docs/user-guide/pods/init-container/),
to help your pod determine its peers when it it first started (determine the desired set of
to help your pod determine its peers when it first started (determine the desired set of
peers from the governing service of the StatefulSet. For this use case, the `--on-start` option
can be used, but the `--on-change` option should not be used since the init container will no
longer be running after the pod is started. An example of an `--on-start` script would be to
@ -33,7 +33,14 @@ Options 1 and 2 and 4 may be preferable since they do not require changes to the
Option 3 is useful is signalling is necessary.
The peer-finder tool is intended to help legacy applications run in containers on Kubernetes.
If possible, it may be preferable to modify an applications to poll DNS itself to determine its peer set.
If possible, it may be preferable to modify an application to poll its own DNS to determine its peer set.
Not all StatefulSets are able to be scaled. For unscalable StatefulSets, only the on-start message is needed, and
so option 1 is a good choice.
## DNS Considerations
Unless specified by the `-domain` argument, `peer-finder` will determine the FQDN of the pod by examining the
`/etc/resolv.conf` file, looking for a `search` line and looking for the best match.
If your pod is not using the default `dnsPolicy` value which is `ClusterFirst` as the DNS policy, you may need
to provide the `-domain` argument. In most common configurations, `-domain=cluster.local` will be the correct setting.

View File

@ -1 +1 @@
1.1
1.2

View File

@ -25,6 +25,7 @@ import (
"net"
"os"
"os/exec"
"regexp"
"sort"
"strings"
"time"
@ -41,7 +42,7 @@ var (
onStart = flag.String("on-start", "", "Script to run on start, must accept a new line separated list of peers via stdin.")
svc = flag.String("service", "", "Governing service responsible for the DNS records of the domain this pod is in.")
namespace = flag.String("ns", "", "The namespace this pod is running in. If unspecified, the POD_NAMESPACE env var is used.")
domain = flag.String("domain", "cluster.local", "The Cluster Domain which is used by the Cluster.")
domain = flag.String("domain", "", "The Cluster Domain which is used by the Cluster, if not set tries to determine it from /etc/resolv.conf file.")
)
func lookup(svcName string) (sets.String, error) {
@ -99,9 +100,53 @@ func main() {
if err != nil {
log.Fatalf("Failed to get hostname: %s", err)
}
var domainName string
svcLocalSuffix := strings.Join([]string{"svc", *domain}, ".")
myName := strings.Join([]string{hostname, *svc, ns, svcLocalSuffix}, ".")
// If domain is not provided, try to get it from resolv.conf
if *domain == "" {
resolvConfBytes, err := ioutil.ReadFile("/etc/resolv.conf")
resolvConf := string(resolvConfBytes)
if err != nil {
log.Fatal("Unable to read /etc/resolv.conf")
}
var re *regexp.Regexp
if ns == "" {
// Looking for a domain that looks like with *.svc.**
re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?P<goal>[a-zA-Z0-9-]{1,63}.svc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`)
} else {
// Looking for a domain that looks like svc.**
re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?P<goal>svc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`)
}
if err != nil {
log.Fatalf("Failed to create regular expression: %v", err)
}
groupNames := re.SubexpNames()
result := re.FindStringSubmatch(resolvConf)
for k, v := range result {
if groupNames[k] == "goal" {
if ns == "" {
// Domain is complete if ns is empty
domainName = v
} else {
// Need to convert svc.** into ns.svc.**
domainName = ns + "." + v
}
break
}
}
log.Printf("Determined Domain to be %s", domainName)
} else {
domainName = strings.Join([]string{ns, "svc", *domain}, ".")
}
if *svc == "" || domainName == "" || (*onChange == "" && *onStart == "") {
log.Fatalf("Incomplete args, require -on-change and/or -on-start, -service and -ns or an env var for POD_NAMESPACE.")
}
myName := strings.Join([]string{hostname, *svc, domainName}, ".")
script := *onStart
if script == "" {
script = *onChange
@ -114,6 +159,7 @@ func main() {
continue
}
if newPeers.Equal(peers) || !newPeers.Has(myName) {
log.Printf("Have not found myself in list yet.\nMy Hostname: %s\nHosts in list: %s", myName, strings.Join(newPeers.List(), ", "))
continue
}
peerList := newPeers.List()