hetzner: Create cluster without DNS or Gossip

This commit is contained in:
Ciprian Hacman 2022-10-23 12:38:20 +03:00
parent ad9c9fcad8
commit 4e5ded6dc3
29 changed files with 194 additions and 159 deletions

View File

@ -337,9 +337,10 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
})
// DNS
cmd.Flags().StringVar(&options.DNSType, "dns", options.DNSType, "DNS type to use: public or private")
supportedDnsTypes := []string{"public", "private", "none"}
cmd.Flags().StringVar(&options.DNSType, "dns", options.DNSType, "DNS type to use: "+strings.Join(supportedDnsTypes, ", "))
cmd.RegisterFlagCompletionFunc("dns", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"public", "private"}, cobra.ShellCompDirectiveNoFileComp
return supportedDnsTypes, cobra.ShellCompDirectiveNoFileComp
})
// Bastion

View File

@ -276,7 +276,7 @@ func TestMinimal_v1_26(t *testing.T) {
// TestHetzner runs the test on a minimum configuration
func TestHetzner(t *testing.T) {
t.Setenv("HCLOUD_TOKEN", "REDACTED")
newIntegrationTest("minimal.k8s.local", "minimal_hetzner").
newIntegrationTest("minimal.example.com", "minimal_hetzner").
runTestTerraformHetzner(t)
}
@ -1462,7 +1462,6 @@ func (i *integrationTest) runTestTerraformHetzner(t *testing.T) {
"aws_s3_object_nodeupconfig-nodes-fsn1_content",
"aws_s3_object_"+i.clusterName+"-addons-bootstrap_content",
"aws_s3_object_"+i.clusterName+"-addons-coredns.addons.k8s.io-k8s-1.12_content",
"aws_s3_object_"+i.clusterName+"-addons-dns-controller.addons.k8s.io-k8s-1.12_content",
"aws_s3_object_"+i.clusterName+"-addons-hcloud-cloud-controller.addons.k8s.io-k8s-1.22_content",
"aws_s3_object_"+i.clusterName+"-addons-hcloud-csi-driver.addons.k8s.io-k8s-1.22_content",
"aws_s3_object_"+i.clusterName+"-addons-kops-controller.addons.k8s.io-k8s-1.16_content",

View File

@ -77,7 +77,7 @@ kops create cluster [CLUSTER] [flags]
--container-runtime string Container runtime to use: containerd, docker
--disable-subnet-tags Disable automatic subnet tagging
--discovery-store string A public location where we publish OIDC-compatible discovery information under a cluster-specific directory. Enables IRSA in AWS.
--dns string DNS type to use: public or private (default "Public")
--dns string DNS type to use: public, private, none
--dns-zone string DNS hosted zone (defaults to longest matching zone)
--dry-run If true, only print the object that would be sent, without sending it. This flag can be used to create a cluster YAML or JSON manifest.
--encrypt-etcd-storage Generate key in AWS KMS and use it for encrypt etcd volumes

View File

@ -30,32 +30,31 @@ var _ fi.ModelBuilder = &EtcHostsBuilder{}
// Build is responsible for configuring the gossip DNS tasks.
func (b *EtcHostsBuilder) Build(c *fi.ModelBuilderContext) error {
useGossip := b.Cluster.IsGossip()
if !useGossip {
return nil
task := &nodetasks.UpdateEtcHostsTask{
Name: "control-plane-address",
}
if b.IsMaster {
task := &nodetasks.UpdateEtcHostsTask{
Name: "control-plane-bootstrap",
}
if b.Cluster.Spec.MasterInternalName != "" {
task.Records = append(task.Records, nodetasks.HostRecord{
Hostname: b.Cluster.Spec.MasterInternalName,
Addresses: []string{"127.0.0.1"},
})
}
if b.IsMaster && b.Cluster.IsGossip() {
task.Records = append(task.Records, nodetasks.HostRecord{
Hostname: b.Cluster.Spec.MasterInternalName,
Addresses: []string{"127.0.0.1"},
})
if b.Cluster.Spec.MasterPublicName != "" {
task.Records = append(task.Records, nodetasks.HostRecord{
Hostname: b.Cluster.Spec.MasterPublicName,
Addresses: []string{"127.0.0.1"},
})
}
} else if b.Cluster.UsesNoneDNS() {
task.Records = append(task.Records, nodetasks.HostRecord{
Hostname: b.Cluster.Spec.MasterInternalName,
Addresses: []string{b.BootConfig.APIServer},
})
}
if len(task.Records) != 0 {
c.AddTask(task)
}
if len(task.Records) != 0 {
c.AddTask(task)
}
return nil

View File

@ -367,7 +367,9 @@ func (b *KubeAPIServerBuilder) writeServerCertificate(c *fi.ModelBuilderContext,
}
// Names specified in the cluster spec
alternateNames = append(alternateNames, b.Cluster.Spec.MasterPublicName)
if b.Cluster.Spec.MasterPublicName != "" {
alternateNames = append(alternateNames, b.Cluster.Spec.MasterPublicName)
}
alternateNames = append(alternateNames, b.Cluster.Spec.MasterInternalName)
alternateNames = append(alternateNames, b.Cluster.Spec.AdditionalSANs...)
@ -726,12 +728,16 @@ func (b *KubeAPIServerBuilder) buildAnnotations() map[string]string {
annotations := make(map[string]string)
annotations["kubectl.kubernetes.io/default-container"] = "kube-apiserver"
if b.Cluster.UsesNoneDNS() {
return annotations
}
if b.Cluster.Spec.API != nil {
if b.Cluster.Spec.API.LoadBalancer == nil || !b.Cluster.Spec.API.LoadBalancer.UseForInternalAPI {
annotations["dns.alpha.kubernetes.io/internal"] = b.Cluster.Spec.MasterInternalName
}
if b.Cluster.Spec.API.DNS != nil {
if b.Cluster.Spec.API.DNS != nil && b.Cluster.Spec.MasterPublicName != "" {
annotations["dns.alpha.kubernetes.io/external"] = b.Cluster.Spec.MasterPublicName
}
}

View File

@ -807,10 +807,6 @@ func (c *Cluster) FillDefaults() error {
c.Spec.MasterInternalName = "api.internal." + c.ObjectMeta.Name
}
if c.Spec.MasterPublicName == "" {
c.Spec.MasterPublicName = "api." + c.ObjectMeta.Name
}
return nil
}
@ -903,6 +899,27 @@ func (c *Cluster) IsGossip() bool {
return false
}
func (c *Cluster) UsesPublicDNS() bool {
if c.Spec.Topology == nil || c.Spec.Topology.DNS == nil || c.Spec.Topology.DNS.Type == DNSTypePublic {
return true
}
return false
}
func (c *Cluster) UsesPrivateDNS() bool {
if c.Spec.Topology != nil && c.Spec.Topology.DNS != nil && c.Spec.Topology.DNS.Type == DNSTypePrivate {
return true
}
return false
}
func (c *Cluster) UsesNoneDNS() bool {
if c.Spec.Topology != nil && c.Spec.Topology.DNS != nil && c.Spec.Topology.DNS.Type == DNSTypeNone {
return true
}
return false
}
func (c *ClusterSpec) IsIPv6Only() bool {
return utils.IsIPv6CIDR(c.NonMasqueradeCIDR)
}

View File

@ -29,6 +29,7 @@ var SupportedTopologies = []string{
var SupportedDnsTypes = []string{
string(DNSTypePublic),
string(DNSTypePrivate),
string(DNSTypeNone),
}
type TopologySpec struct {
@ -58,4 +59,5 @@ type DNSType string
const (
DNSTypePublic DNSType = "Public"
DNSTypePrivate DNSType = "Private"
DNSTypeNone DNSType = "None"
)

View File

@ -429,6 +429,9 @@ func validateTopology(c *kops.Cluster, topology *kops.TopologySpec, fieldPath *f
if topology.DNS != nil {
value := string(topology.DNS.Type)
allErrs = append(allErrs, IsValidValue(fieldPath.Child("dns", "type"), &value, kops.SupportedDnsTypes)...)
if value == string(kops.DNSTypeNone) && c.Spec.GetCloudProvider() != kops.CloudProviderHetzner {
allErrs = append(allErrs, field.Invalid(fieldPath.Child("dns", "type"), &value, fmt.Sprintf("not supported for %q", c.Spec.GetCloudProvider())))
}
}
return allErrs
@ -1613,8 +1616,8 @@ func validateExternalDNS(cluster *kops.Cluster, spec *kops.ExternalDNSConfig, fl
}
if spec.Provider == kops.ExternalDNSProviderExternalDNS {
if cluster.IsGossip() {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("provider"), "external-dns does not support gossip clusters"))
if cluster.IsGossip() || cluster.UsesNoneDNS() {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("provider"), "external-dns requires public or private DNS topology"))
}
}

View File

@ -90,6 +90,8 @@ type BootConfig struct {
ConfigBase *string `json:",omitempty"`
// ConfigServer holds the configuration for the configuration server.
ConfigServer *ConfigServerOptions `json:",omitempty"`
// APIServer is the API server IP address.
APIServer string `json:",omitempty"`
// InstanceGroupName is the name of the instance group.
InstanceGroupName string `json:",omitempty"`
// InstanceGroupRole is the instance group role.

View File

@ -58,6 +58,11 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
useELBName = true
}
// If the cluster has DNS disabled, must use the load balancer name
if cluster.UsesNoneDNS() {
useELBName = true
}
// If the DNS is set up as a private HostedZone, but here we have to be
// careful that we aren't accessing the API over DirectConnect (or a VPN).
// We differentiate using the heuristic that if we have an internal ELB
@ -86,7 +91,7 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
sort.Strings(targets)
if len(targets) == 0 {
klog.Warningf("Did not find API endpoint for gossip hostname; may not be able to reach cluster")
klog.Warningf("Did not find API endpoint; may not be able to reach cluster")
} else {
if len(targets) != 1 {
klog.Warningf("Found multiple API endpoints (%v), choosing arbitrarily", targets)

View File

@ -519,7 +519,7 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
}
}
if b.Cluster.IsGossip() || b.UsePrivateDNS() {
if b.Cluster.IsGossip() || b.Cluster.UsesPrivateDNS() || b.Cluster.UsesNoneDNS() {
// Ensure the LB hostname is included in the TLS certificate,
// if we're not going to use an alias for it
clb.ForAPIServer = true

View File

@ -34,7 +34,7 @@ type DNSModelBuilder struct {
var _ fi.ModelBuilder = &DNSModelBuilder{}
func (b *DNSModelBuilder) ensureDNSZone(c *fi.ModelBuilderContext) error {
if b.Cluster.IsGossip() {
if b.Cluster.IsGossip() || b.Cluster.UsesNoneDNS() {
return nil
}
@ -72,22 +72,10 @@ func (b *DNSModelBuilder) ensureDNSZone(c *fi.ModelBuilderContext) error {
func (b *DNSModelBuilder) Build(c *fi.ModelBuilderContext) error {
// Add a HostedZone if we are going to publish a dns record that depends on it
if b.UsePrivateDNS() {
// Check to see if we are using a bastion DNS record that points to the hosted zone
// If we are, we need to make sure we include the hosted zone as a task
if !b.Cluster.IsGossip() && !b.Cluster.UsesNoneDNS() {
if err := b.ensureDNSZone(c); err != nil {
return err
}
} else {
// We now create the DNS Zone for AWS even in the case of public zones;
// it has to exist for the IAM record anyway.
// TODO: We can now rationalize the code paths
if !b.Cluster.IsGossip() {
if err := b.ensureDNSZone(c); err != nil {
return err
}
}
}
var targetLoadBalancer awstasks.DNSTarget
@ -106,7 +94,7 @@ func (b *DNSModelBuilder) Build(c *fi.ModelBuilderContext) error {
// This will point our external DNS record to the load balancer, and put the
// pieces together for kubectl to work
if !b.Cluster.IsGossip() {
if !b.Cluster.IsGossip() && !b.Cluster.UsesNoneDNS() {
if err := b.ensureDNSZone(c); err != nil {
return err
}
@ -136,7 +124,7 @@ func (b *DNSModelBuilder) Build(c *fi.ModelBuilderContext) error {
// This will point the internal API DNS record to the load balancer.
// This means kubelet connections go via the load balancer and are more HA.
if !b.Cluster.IsGossip() {
if !b.Cluster.IsGossip() && !b.Cluster.UsesNoneDNS() {
if err := b.ensureDNSZone(c); err != nil {
return err
}
@ -176,8 +164,10 @@ func (b *DNSModelBuilder) Build(c *fi.ModelBuilderContext) error {
// is similar to others, but I would like to keep it on it's own in case we need
// to change anything.
if err := b.ensureDNSZone(c); err != nil {
return err
if !b.Cluster.IsGossip() && !b.Cluster.UsesNoneDNS() {
if err := b.ensureDNSZone(c); err != nil {
return err
}
}
}

View File

@ -236,7 +236,7 @@ func (b *IAMModelBuilder) buildIAMRolePolicy(role iam.Subject, iamName string, i
},
}
if !b.Cluster.IsGossip() {
if !b.Cluster.IsGossip() && !b.Cluster.UsesNoneDNS() {
// This is slightly tricky; we need to know the hosted zone id,
// but we might be creating the hosted zone dynamically.
// We create a stub-reference which will be combined by the execution engine.

View File

@ -80,7 +80,7 @@ func (b *APILoadBalancerModelBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(lb)
if b.Cluster.IsGossip() || b.UsePrivateDNS() {
if b.Cluster.IsGossip() || b.Cluster.UsesPrivateDNS() || b.Cluster.UsesNoneDNS() {
lb.ForAPIServer = true
}

View File

@ -182,7 +182,7 @@ func (b *BootstrapScript) buildEnvironmentVariables(cluster *kops.Cluster) (map[
}
}
if cluster.Spec.GetCloudProvider() == kops.CloudProviderHetzner {
if cluster.Spec.GetCloudProvider() == kops.CloudProviderHetzner && (b.ig.IsMaster() || cluster.IsGossip()) {
hcloudToken := os.Getenv("HCLOUD_TOKEN")
if hcloudToken != "" {
env["HCLOUD_TOKEN"] = hcloudToken

View File

@ -44,13 +44,5 @@ func (b *DefaultsOptionsBuilder) BuildOptions(o interface{}) error {
}
}
if options.ExternalDNS == nil {
options.ExternalDNS = &kops.ExternalDNSConfig{}
}
if options.ExternalDNS.Provider == "" {
options.ExternalDNS.Provider = kops.ExternalDNSProviderDNSController
}
return nil
}

View File

@ -71,7 +71,7 @@ func (b *DiscoveryOptionsBuilder) BuildOptions(o interface{}) error {
return fmt.Errorf("locationStore=%q is of unexpected type %T", store, base)
}
} else {
if supportsPublicJWKS(clusterSpec) {
if supportsPublicJWKS(clusterSpec) && clusterSpec.MasterPublicName != "" {
serviceAccountIssuer = "https://" + clusterSpec.MasterPublicName
} else {
serviceAccountIssuer = "https://" + clusterSpec.MasterInternalName

View File

@ -292,25 +292,6 @@ func (b *KopsModelContext) APILoadBalancerClass() kops.LoadBalancerClass {
return kops.LoadBalancerClassClassic
}
// UsePrivateDNS checks if we are using private DNS
func (b *KopsModelContext) UsePrivateDNS() bool {
topology := b.Cluster.Spec.Topology
if topology != nil && topology.DNS != nil {
switch topology.DNS.Type {
case kops.DNSTypePublic:
return false
case kops.DNSTypePrivate:
return true
default:
klog.Warningf("Unknown DNS type %q", topology.DNS.Type)
return false
}
}
return false
}
// UseClassicLoadBalancer checks if we are using Classic LoadBalancer
func (b *KopsModelContext) UseClassicLoadBalancer() bool {
return b.Cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassClassic

View File

@ -77,7 +77,7 @@ func (b *APILoadBalancerModelBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(loadbalancer)
// Temporarily do not know the role of the following function
if b.Cluster.IsGossip() || b.UsePrivateDNS() {
if b.Cluster.IsGossip() || b.Cluster.UsesPrivateDNS() || b.Cluster.UsesNoneDNS() {
// Ensure the LB hostname is included in the TLS certificate,
// if we're not going to use an alias for it
loadbalancer.ForAPIServer = true

View File

@ -304,7 +304,7 @@ func (b *ServerGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
}
c.AddTask(lbfipTask)
if b.Cluster.IsGossip() || b.UsePrivateDNS() {
if b.Cluster.IsGossip() || b.Cluster.UsesPrivateDNS() || b.Cluster.UsesNoneDNS() {
b.associateFIPToKeypair(lbfipTask)
}

View File

@ -113,7 +113,9 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
"localhost",
serviceName,
strings.Join([]string{serviceName, b.Cluster.Name}, "."),
strings.Join([]string{serviceName, b.Cluster.Spec.DNSZone}, "."),
}
if b.Cluster.Spec.DNSZone != "" {
alternateNames = append(alternateNames, strings.Join([]string{serviceName, b.Cluster.Spec.DNSZone}, "."))
}
// @note: the certificate used by the node authorizers

View File

@ -124,16 +124,15 @@ func NewClusterValidator(cluster *kops.Cluster, cloud fi.Cloud, instanceGroupLis
func (v *clusterValidatorImpl) Validate() (*ValidationCluster, error) {
ctx := context.TODO()
clusterName := v.cluster.Name
dnsProvider := kops.ExternalDNSProviderDNSController
if v.cluster.Spec.ExternalDNS != nil && v.cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
dnsProvider = kops.ExternalDNSProviderExternalDNS
}
validation := &ValidationCluster{}
// Do not use if we are running gossip
if !v.cluster.IsGossip() {
// Do not use if we are running gossip or without dns
if !v.cluster.IsGossip() && !v.cluster.UsesNoneDNS() {
dnsProvider := kops.ExternalDNSProviderDNSController
if v.cluster.Spec.ExternalDNS != nil && v.cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
dnsProvider = kops.ExternalDNSProviderExternalDNS
}
hasPlaceHolderIPAddress, err := hasPlaceHolderIP(v.host)
if err != nil {
return nil, err
@ -168,7 +167,7 @@ func (v *clusterValidatorImpl) Validate() (*ValidationCluster, error) {
readyNodes, nodeInstanceGroupMapping := validation.validateNodes(cloudGroups, v.instanceGroups)
if err := validation.collectPodFailures(ctx, v.k8sClient, readyNodes, nodeInstanceGroupMapping); err != nil {
return nil, fmt.Errorf("cannot get pod health for %q: %v", clusterName, err)
return nil, fmt.Errorf("cannot get pod health for %q: %v", v.cluster.Name, err)
}
return validation, nil

View File

@ -301,7 +301,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
if cluster.Spec.KubernetesVersion == "" {
return fmt.Errorf("KubernetesVersion not set")
}
if cluster.Spec.DNSZone == "" && !cluster.IsGossip() {
if cluster.Spec.DNSZone == "" && !cluster.IsGossip() && !cluster.UsesNoneDNS() {
return fmt.Errorf("DNSZone not set")
}
@ -482,9 +482,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
modelContext.SSHPublicKeys = sshPublicKeys
modelContext.Region = cloud.Region()
if cluster.IsGossip() {
klog.V(2).Infof("Gossip DNS: skipping DNS validation")
} else {
if !cluster.IsGossip() && !cluster.UsesNoneDNS() {
err = validateDNS(cluster, cloud)
if err != nil {
return err
@ -791,7 +789,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
return fmt.Errorf("error running tasks: %v", err)
}
if cluster.IsGossip() {
if cluster.IsGossip() || cluster.UsesNoneDNS() {
shouldPrecreateDNS = false
}
@ -1417,6 +1415,25 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, apiserverAddit
config.ApiserverAdditionalIPs = apiserverAdditionalIPs
}
// Set API server address to an IP from the cluster network CIDR
if cluster.UsesNoneDNS() {
for _, networkCIDR := range append(cluster.Spec.AdditionalNetworkCIDRs, cluster.Spec.NetworkCIDR) {
_, cidr, err := net.ParseCIDR(networkCIDR)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse network CIDR %q: %w", networkCIDR, err)
}
for _, additionalIP := range apiserverAdditionalIPs {
if cidr.Contains(net.ParseIP(additionalIP)) {
bootConfig.APIServer = additionalIP
break
}
}
if bootConfig.APIServer != "" {
break
}
}
}
for _, manifest := range n.assetBuilder.StaticManifests {
match := false
for _, r := range manifest.Roles {

View File

@ -486,32 +486,12 @@ func (b *BootstrapChannelBuilder) buildAddons(c *fi.ModelBuilderContext) (*Addon
})
}
if b.Cluster.Spec.ExternalDNS == nil || b.Cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderDNSController {
{
key := "dns-controller.addons.k8s.io"
location := key + "/k8s-1.12.yaml"
id := "k8s-1.12"
addons.Add(&channelsapi.AddonSpec{
Name: fi.String(key),
Selector: map[string]string{"k8s-addon": key},
Manifest: fi.String(location),
Id: id,
})
}
// Generate dns-controller ServiceAccount IAM permissions.
// Gossip clsuters do not require any cloud permissions.
if b.UseServiceAccountExternalPermissions() && !b.Cluster.IsGossip() {
serviceAccountRoles = append(serviceAccountRoles, &dnscontroller.ServiceAccount{})
}
} else if b.Cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
{
key := "external-dns.addons.k8s.io"
if !b.Cluster.UsesNoneDNS() {
if b.Cluster.Spec.ExternalDNS == nil || b.Cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderDNSController {
{
location := key + "/k8s-1.19.yaml"
id := "k8s-1.19"
key := "dns-controller.addons.k8s.io"
location := key + "/k8s-1.12.yaml"
id := "k8s-1.12"
addons.Add(&channelsapi.AddonSpec{
Name: fi.String(key),
@ -521,8 +501,30 @@ func (b *BootstrapChannelBuilder) buildAddons(c *fi.ModelBuilderContext) (*Addon
})
}
if b.UseServiceAccountExternalPermissions() {
serviceAccountRoles = append(serviceAccountRoles, &externaldns.ServiceAccount{})
// Generate dns-controller ServiceAccount IAM permissions.
// Gossip clsuters do not require any cloud permissions.
if b.UseServiceAccountExternalPermissions() && !b.Cluster.IsGossip() {
serviceAccountRoles = append(serviceAccountRoles, &dnscontroller.ServiceAccount{})
}
} else if b.Cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
{
key := "external-dns.addons.k8s.io"
{
location := key + "/k8s-1.19.yaml"
id := "k8s-1.19"
addons.Add(&channelsapi.AddonSpec{
Name: fi.String(key),
Selector: map[string]string{"k8s-addon": key},
Manifest: fi.String(location),
Id: id,
})
}
if b.UseServiceAccountExternalPermissions() {
serviceAccountRoles = append(serviceAccountRoles, &externaldns.ServiceAccount{})
}
}
}
}

View File

@ -107,7 +107,7 @@ func PerformAssignments(c *kops.Cluster, cloud fi.Cloud) error {
}
// TODO: Unclear this should be here - it isn't too hard to change
if c.Spec.MasterPublicName == "" && c.ObjectMeta.Name != "" {
if c.UsesPublicDNS() && c.Spec.MasterPublicName == "" && c.ObjectMeta.Name != "" {
c.Spec.MasterPublicName = "api." + c.ObjectMeta.Name
}

View File

@ -29,8 +29,6 @@ import (
"k8s.io/kops/dnsprovider/pkg/dnsprovider/rrstype"
"k8s.io/kops/pkg/apis/kops"
apimodel "k8s.io/kops/pkg/apis/kops/model"
"k8s.io/kops/pkg/model"
"k8s.io/kops/pkg/model/iam"
"k8s.io/kops/upup/pkg/fi"
)
@ -54,6 +52,9 @@ func findZone(cluster *kops.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {
if err != nil {
return nil, fmt.Errorf("error building DNS provider: %v", err)
}
if dns == nil {
return nil, nil
}
zonesProvider, ok := dns.Zones()
if !ok {
@ -92,13 +93,8 @@ func findZone(cluster *kops.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {
}
func validateDNS(cluster *kops.Cluster, cloud fi.Cloud) error {
kopsModelContext := &model.KopsModelContext{
IAMModelContext: iam.IAMModelContext{Cluster: cluster},
// We are not initializing a lot of the fields here; revisit once UsePrivateDNS is "real"
}
if kopsModelContext.UsePrivateDNS() {
klog.V(2).Infof("Private DNS: skipping DNS validation")
if cluster.IsGossip() || cluster.UsesPrivateDNS() || cluster.UsesNoneDNS() {
klog.V(2).Infof("Skipping DNS validation for non-public DNS")
return nil
}
@ -106,6 +102,9 @@ func validateDNS(cluster *kops.Cluster, cloud fi.Cloud) error {
if err != nil {
return err
}
if zone == nil {
return nil
}
dnsName := strings.TrimSuffix(zone.Name(), ".")
klog.V(2).Infof("Doing DNS lookup to verify NS records for %q", dnsName)
@ -137,8 +136,8 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
// This avoids hitting negative TTL on DNS lookups, which tend to be very long
// If we get the names wrong here, it doesn't really matter (extra DNS name, slower boot)
// Nothing to do for Gossip clusters
if cluster.IsGossip() {
// Nothing to do for Gossip clusters and clusters without DNS
if cluster.IsGossip() || cluster.UsesNoneDNS() {
return nil
}
@ -153,6 +152,9 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
if err != nil {
return err
}
if zone == nil {
return nil
}
rrs, ok := zone.ResourceRecordSets()
if !ok {
@ -219,7 +221,7 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
}
}
if !foundTXT {
if cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
if cluster.Spec.ExternalDNS != nil && cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
changeset.Add(rrs.New(recordKey.hostname, []string{fmt.Sprintf("\"heritage=external-dns,external-dns/owner=kops-%s\"", cluster.ObjectMeta.Name)}, PlaceholderTTL, rrstype.TXT))
}
}

View File

@ -239,8 +239,8 @@ func (c *hetznerCloudImplementation) GetVolumes(clusterName string) ([]*hcloud.V
}
func (c *hetznerCloudImplementation) DNS() (dnsprovider.Interface, error) {
// TODO(hakman): implement me
panic("implement me")
// Hetzner LB has a stable internal IP and can use that instead of creating a record for api.internal.
return nil, nil
}
func (c *hetznerCloudImplementation) DeleteInstance(instance *cloudinstances.CloudInstance) error {
@ -428,14 +428,9 @@ func (c *hetznerCloudImplementation) FindClusterStatus(cluster *kops.Cluster) (*
}
func (c *hetznerCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error) {
if cluster.Spec.MasterPublicName == "" {
return nil, nil
}
lbName := "api." + cluster.Name
client := c.LoadBalancerClient()
// TODO(hakman): Get load balancer info using label selector instead instead of name?
lb, _, err := client.GetByName(context.TODO(), lbName)
if err != nil {
return nil, fmt.Errorf("failed to get info for load balancer %q: %w", lbName, err)

View File

@ -166,7 +166,6 @@ func (o *NewClusterOptions) InitDefaults() {
o.AdminAccess = []string{"0.0.0.0/0", "::/0"}
o.Networking = "kubenet"
o.Topology = api.TopologyPublic
o.DNSType = string(api.DNSTypePublic)
o.InstanceManager = "cloudgroups"
}
@ -1226,7 +1225,7 @@ func setupTopology(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.S
bastionGroup.Spec.MinSize = fi.Int32(1)
bastions = append(bastions, bastionGroup)
if !cluster.IsGossip() {
if !cluster.IsGossip() && !cluster.UsesNoneDNS() {
cluster.Spec.Topology.Bastion = &api.BastionSpec{
PublicName: "bastion." + cluster.Name,
}
@ -1262,10 +1261,20 @@ func setupTopology(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.S
cluster.Spec.Topology.DNS = &api.DNSSpec{}
switch strings.ToLower(opt.DNSType) {
case "public", "":
case "":
if cluster.IsGossip() {
cluster.Spec.Topology.DNS.Type = api.DNSTypePrivate
} else if cluster.Spec.GetCloudProvider() == api.CloudProviderHetzner {
cluster.Spec.Topology.DNS.Type = api.DNSTypeNone
} else {
cluster.Spec.Topology.DNS.Type = api.DNSTypePublic
}
case "public":
cluster.Spec.Topology.DNS.Type = api.DNSTypePublic
case "private":
cluster.Spec.Topology.DNS.Type = api.DNSTypePrivate
case "none":
cluster.Spec.Topology.DNS.Type = api.DNSTypeNone
default:
return nil, fmt.Errorf("unknown DNSType: %q", opt.DNSType)
}
@ -1290,7 +1299,7 @@ func setupAPI(opt *NewClusterOptions, cluster *api.Cluster) error {
} else {
switch cluster.Spec.Topology.Masters {
case api.TopologyPublic:
if cluster.IsGossip() {
if cluster.IsGossip() || cluster.UsesNoneDNS() {
// gossip DNS names don't work outside the cluster, so we use a LoadBalancer instead
cluster.Spec.API.LoadBalancer = &api.LoadBalancerAccessSpec{}
} else {

View File

@ -219,24 +219,36 @@ func (c *populateClusterSpec) run(clientset simple.Clientset) error {
klog.V(2).Infof("Normalizing kubernetes version: %q -> %q", cluster.Spec.KubernetesVersion, versionWithoutV)
cluster.Spec.KubernetesVersion = versionWithoutV
}
if cluster.Spec.DNSZone == "" && !cluster.IsGossip() {
if cluster.Spec.DNSZone == "" && !cluster.IsGossip() && !cluster.UsesNoneDNS() {
dns, err := cloud.DNS()
if err != nil {
return err
}
if dns != nil {
dnsType := kopsapi.DNSTypePublic
if cluster.Spec.Topology != nil && cluster.Spec.Topology.DNS != nil && cluster.Spec.Topology.DNS.Type != "" {
dnsType = cluster.Spec.Topology.DNS.Type
}
dnsType := kopsapi.DNSTypePublic
if cluster.Spec.Topology != nil && cluster.Spec.Topology.DNS != nil && cluster.Spec.Topology.DNS.Type != "" {
dnsType = cluster.Spec.Topology.DNS.Type
dnsZone, err := FindDNSHostedZone(dns, cluster.ObjectMeta.Name, dnsType)
if err != nil {
return fmt.Errorf("error determining default DNS zone: %v", err)
}
klog.V(2).Infof("Defaulting DNS zone to: %s", dnsZone)
cluster.Spec.DNSZone = dnsZone
}
}
dnsZone, err := FindDNSHostedZone(dns, cluster.ObjectMeta.Name, dnsType)
if err != nil {
return fmt.Errorf("error determining default DNS zone: %v", err)
if !cluster.UsesNoneDNS() {
if cluster.Spec.DNSZone != "" && cluster.Spec.MasterPublicName == "" {
cluster.Spec.MasterPublicName = "api." + cluster.Name
}
if cluster.Spec.ExternalDNS == nil {
cluster.Spec.ExternalDNS = &kopsapi.ExternalDNSConfig{
Provider: kopsapi.ExternalDNSProviderDNSController,
}
}
klog.V(2).Infof("Defaulting DNS zone to: %s", dnsZone)
cluster.Spec.DNSZone = dnsZone
}
if cluster.Spec.KubernetesVersion == "" {