mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
Merge pull request #59288 from stevesloka/apiServerDNS
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Add configuration item to allow kubeadm join to use a dns name pointing to control plane This adds a new flag (`--apiserver-advertise-dns-address`) to kubeadm which is used in node kubelet.confg to point to API server allowing users to define a DNS entry instead of an IP address. Fixes kubernetes/kubeadm#411 ```release-note Adds new flag `--apiserver-advertise-dns-address` which is used in node kubelet.confg to point to API server ``` // @timothysc @craigtracey
This commit is contained in:
commit
d7cadf5d18
@ -124,8 +124,10 @@ type MasterConfiguration struct {
|
|||||||
|
|
||||||
// API struct contains elements of API server address.
|
// API struct contains elements of API server address.
|
||||||
type API struct {
|
type API struct {
|
||||||
// AdvertiseAddress sets the address for the API server to advertise.
|
// AdvertiseAddress sets the IP address for the API server to advertise.
|
||||||
AdvertiseAddress string
|
AdvertiseAddress string
|
||||||
|
// ControlPlaneEndpoint sets the DNS address for the API server
|
||||||
|
ControlPlaneEndpoint string
|
||||||
// BindPort sets the secure port for the API Server to bind to.
|
// BindPort sets the secure port for the API Server to bind to.
|
||||||
// Defaults to 6443.
|
// Defaults to 6443.
|
||||||
BindPort int32
|
BindPort int32
|
||||||
|
@ -116,8 +116,10 @@ type MasterConfiguration struct {
|
|||||||
|
|
||||||
// API struct contains elements of API server address.
|
// API struct contains elements of API server address.
|
||||||
type API struct {
|
type API struct {
|
||||||
// AdvertiseAddress sets the address for the API server to advertise.
|
// AdvertiseAddress sets the IP address for the API server to advertise.
|
||||||
AdvertiseAddress string `json:"advertiseAddress"`
|
AdvertiseAddress string `json:"advertiseAddress"`
|
||||||
|
// ControlPlaneEndpoint sets the DNS address for the API server
|
||||||
|
ControlPlaneEndpoint string `json:"controlPlaneEndpoint"`
|
||||||
// BindPort sets the secure port for the API Server to bind to.
|
// BindPort sets the secure port for the API Server to bind to.
|
||||||
// Defaults to 6443.
|
// Defaults to 6443.
|
||||||
BindPort int32 `json:"bindPort"`
|
BindPort int32 `json:"bindPort"`
|
||||||
|
@ -67,6 +67,7 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
|||||||
|
|
||||||
func autoConvert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion.Scope) error {
|
func autoConvert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion.Scope) error {
|
||||||
out.AdvertiseAddress = in.AdvertiseAddress
|
out.AdvertiseAddress = in.AdvertiseAddress
|
||||||
|
out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
|
||||||
out.BindPort = in.BindPort
|
out.BindPort = in.BindPort
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -78,6 +79,7 @@ func Convert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion
|
|||||||
|
|
||||||
func autoConvert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion.Scope) error {
|
func autoConvert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion.Scope) error {
|
||||||
out.AdvertiseAddress = in.AdvertiseAddress
|
out.AdvertiseAddress = in.AdvertiseAddress
|
||||||
|
out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
|
||||||
out.BindPort = in.BindPort
|
out.BindPort = in.BindPort
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ func ValidateAPIEndpoint(c *kubeadm.MasterConfiguration, fldPath *field.Path) fi
|
|||||||
|
|
||||||
endpoint, err := kubeadmutil.GetMasterEndpoint(c)
|
endpoint, err := kubeadmutil.GetMasterEndpoint(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath, endpoint, "Invalid API Endpoint"))
|
allErrs = append(allErrs, field.Invalid(fldPath, endpoint, err.Error()))
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr
|
|||||||
cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane`)
|
cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane`)
|
||||||
|
|
||||||
if properties.use == "all" || properties.use == "apiserver" {
|
if properties.use == "all" || properties.use == "apiserver" {
|
||||||
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address or DNS name the API server is accessible on")
|
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address of the API server is accessible on")
|
||||||
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on")
|
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on")
|
||||||
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The range of IP address used for service VIPs")
|
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The range of IP address used for service VIPs")
|
||||||
cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
|
cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
|
||||||
|
@ -41,6 +41,7 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
controlPlaneEndpoint: ""
|
||||||
auditPolicy:
|
auditPolicy:
|
||||||
logDir: ""
|
logDir: ""
|
||||||
path: ""
|
path: ""
|
||||||
@ -78,6 +79,7 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
controlPlaneEndpoint: ""
|
||||||
auditPolicy:
|
auditPolicy:
|
||||||
logDir: ""
|
logDir: ""
|
||||||
path: ""
|
path: ""
|
||||||
@ -120,6 +122,7 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
controlPlaneEndpoint: ""
|
||||||
auditPolicy:
|
auditPolicy:
|
||||||
logDir: ""
|
logDir: ""
|
||||||
path: ""
|
path: ""
|
||||||
|
@ -548,5 +548,10 @@ func getAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add api server dns advertise address
|
||||||
|
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||||
|
altNames.DNSNames = append(altNames.DNSNames, cfg.API.ControlPlaneEndpoint)
|
||||||
|
}
|
||||||
|
|
||||||
return altNames, nil
|
return altNames, nil
|
||||||
}
|
}
|
||||||
|
@ -261,8 +261,9 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
|
|||||||
func TestGetAltNames(t *testing.T) {
|
func TestGetAltNames(t *testing.T) {
|
||||||
hostname := "valid-hostname"
|
hostname := "valid-hostname"
|
||||||
advertiseIP := "1.2.3.4"
|
advertiseIP := "1.2.3.4"
|
||||||
|
controlPlaneEndpoint := "api.k8s.io"
|
||||||
cfg := &kubeadmapi.MasterConfiguration{
|
cfg := &kubeadmapi.MasterConfiguration{
|
||||||
API: kubeadmapi.API{AdvertiseAddress: advertiseIP},
|
API: kubeadmapi.API{AdvertiseAddress: advertiseIP, ControlPlaneEndpoint: controlPlaneEndpoint},
|
||||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||||
NodeName: hostname,
|
NodeName: hostname,
|
||||||
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95"},
|
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95"},
|
||||||
@ -273,7 +274,7 @@ func TestGetAltNames(t *testing.T) {
|
|||||||
t.Fatalf("failed calling getAltNames: %v", err)
|
t.Fatalf("failed calling getAltNames: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local"}
|
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", controlPlaneEndpoint}
|
||||||
for _, DNSName := range expectedDNSNames {
|
for _, DNSName := range expectedDNSNames {
|
||||||
found := false
|
found := false
|
||||||
for _, val := range altNames.DNSNames {
|
for _, val := range altNames.DNSNames {
|
||||||
|
@ -71,12 +71,25 @@ func TestGetKubeConfigSpecs(t *testing.T) {
|
|||||||
NodeName: "valid-node-name",
|
NodeName: "valid-node-name",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a Master Configuration pointing to the pkidir folder
|
||||||
|
cfgDNS := &kubeadmapi.MasterConfiguration{
|
||||||
|
API: kubeadmapi.API{ControlPlaneEndpoint: "api.k8s.io", BindPort: 1234},
|
||||||
|
CertificatesDir: pkidir,
|
||||||
|
NodeName: "valid-node-name",
|
||||||
|
}
|
||||||
|
|
||||||
// Executes getKubeConfigSpecs
|
// Executes getKubeConfigSpecs
|
||||||
specs, err := getKubeConfigSpecs(cfg)
|
specs, err := getKubeConfigSpecs(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getKubeConfigSpecs failed!")
|
t.Fatal("getKubeConfigSpecs failed!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Executes getKubeConfigSpecs
|
||||||
|
specsDNS, err := getKubeConfigSpecs(cfgDNS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("getKubeConfigSpecs failed!")
|
||||||
|
}
|
||||||
|
|
||||||
var assertions = []struct {
|
var assertions = []struct {
|
||||||
kubeConfigFile string
|
kubeConfigFile string
|
||||||
clientName string
|
clientName string
|
||||||
@ -136,6 +149,39 @@ func TestGetKubeConfigSpecs(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile)
|
t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assert the spec for the kubeConfigFile exists
|
||||||
|
if spec, ok := specsDNS[assertion.kubeConfigFile]; ok {
|
||||||
|
|
||||||
|
// Assert clientName
|
||||||
|
if spec.ClientName != assertion.clientName {
|
||||||
|
t.Errorf("getKubeConfigSpecs for %s clientName is %s, expected %s", assertion.kubeConfigFile, spec.ClientName, assertion.clientName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert Organizations
|
||||||
|
if spec.ClientCertAuth == nil || !reflect.DeepEqual(spec.ClientCertAuth.Organizations, assertion.organizations) {
|
||||||
|
t.Errorf("getKubeConfigSpecs for %s Organizations is %v, expected %v", assertion.kubeConfigFile, spec.ClientCertAuth.Organizations, assertion.organizations)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asserts MasterConfiguration values injected into spec
|
||||||
|
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfgDNS)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if spec.APIServer != masterEndpoint {
|
||||||
|
t.Errorf("getKubeConfigSpecs didn't injected cfg.APIServer endpoint into spec for %s", assertion.kubeConfigFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asserts CA certs and CA keys loaded into specs
|
||||||
|
if spec.CACert == nil {
|
||||||
|
t.Errorf("getKubeConfigSpecs didn't loaded CACert into spec for %s!", assertion.kubeConfigFile)
|
||||||
|
}
|
||||||
|
if spec.ClientCertAuth == nil || spec.ClientCertAuth.CAKey == nil {
|
||||||
|
t.Errorf("getKubeConfigSpecs didn't loaded CAKey into spec for %s!", assertion.kubeConfigFile)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ go_library(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/version"
|
"k8s.io/kubernetes/pkg/util/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetInitDynamicDefaults checks and sets conifugration values for Master node
|
// SetInitDynamicDefaults checks and sets configuration values for Master node
|
||||||
func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
|
func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
|
||||||
|
|
||||||
// Choose the right address for the API Server to advertise. If the advertise address is localhost or 0.0.0.0, the default interface's IP address is used
|
// Choose the right address for the API Server to advertise. If the advertise address is localhost or 0.0.0.0, the default interface's IP address is used
|
||||||
|
@ -21,12 +21,14 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMasterEndpoint returns a properly formatted Master Endpoint
|
// GetMasterEndpoint returns a properly formatted Master Endpoint
|
||||||
// or passes the error from GetMasterHostPort.
|
// or passes the error from GetMasterHostPort.
|
||||||
func GetMasterEndpoint(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
func GetMasterEndpoint(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
||||||
|
|
||||||
hostPort, err := GetMasterHostPort(cfg)
|
hostPort, err := GetMasterHostPort(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -37,15 +39,25 @@ func GetMasterEndpoint(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
|||||||
// GetMasterHostPort returns a properly formatted Master IP/port pair or error
|
// GetMasterHostPort returns a properly formatted Master IP/port pair or error
|
||||||
// if the IP address can not be parsed or port is outside the valid TCP range.
|
// if the IP address can not be parsed or port is outside the valid TCP range.
|
||||||
func GetMasterHostPort(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
func GetMasterHostPort(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
||||||
masterIP := net.ParseIP(cfg.API.AdvertiseAddress)
|
var masterIP string
|
||||||
if masterIP == nil {
|
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||||
|
errs := validation.IsDNS1123Subdomain(cfg.API.ControlPlaneEndpoint)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return "", fmt.Errorf("error parsing `ControlPlaneEndpoint` to valid dns subdomain with errors: %s", errs)
|
||||||
|
}
|
||||||
|
masterIP = cfg.API.ControlPlaneEndpoint
|
||||||
|
} else {
|
||||||
|
ip := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||||
|
if ip == nil {
|
||||||
return "", fmt.Errorf("error parsing address %s", cfg.API.AdvertiseAddress)
|
return "", fmt.Errorf("error parsing address %s", cfg.API.AdvertiseAddress)
|
||||||
}
|
}
|
||||||
|
masterIP = ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.API.BindPort < 0 || cfg.API.BindPort > 65535 {
|
if cfg.API.BindPort < 0 || cfg.API.BindPort > 65535 {
|
||||||
return "", fmt.Errorf("api server port must be between 0 and 65535")
|
return "", fmt.Errorf("api server port must be between 0 and 65535")
|
||||||
}
|
}
|
||||||
|
|
||||||
hostPort := net.JoinHostPort(masterIP.String(), strconv.Itoa(int(cfg.API.BindPort)))
|
hostPort := net.JoinHostPort(masterIP, strconv.Itoa(int(cfg.API.BindPort)))
|
||||||
return hostPort, nil
|
return hostPort, nil
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,40 @@ func TestGetMasterEndpoint(t *testing.T) {
|
|||||||
endpoint string
|
endpoint string
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "bad controlplane endpooint dns",
|
||||||
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
|
API: kubeadmapi.API{
|
||||||
|
ControlPlaneEndpoint: "bad!!cp.k8s.io",
|
||||||
|
BindPort: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
endpoint: "https://cp.k8s.io:1234",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "both DNS and IP passed",
|
||||||
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
|
API: kubeadmapi.API{
|
||||||
|
AdvertiseAddress: "1.2.3.4",
|
||||||
|
ControlPlaneEndpoint: "cp.k8s.io",
|
||||||
|
BindPort: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
endpoint: "https://cp.k8s.io:1234",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid DNS endpoint",
|
||||||
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
|
API: kubeadmapi.API{
|
||||||
|
ControlPlaneEndpoint: "cp.k8s.io",
|
||||||
|
BindPort: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
endpoint: "https://cp.k8s.io:1234",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "valid IPv4 endpoint",
|
name: "valid IPv4 endpoint",
|
||||||
cfg: &kubeadmapi.MasterConfiguration{
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
|
Loading…
Reference in New Issue
Block a user