diff --git a/cluster/gce/configure-vm.sh b/cluster/gce/configure-vm.sh index 415cd55f737..54d8a76c85b 100644 --- a/cluster/gce/configure-vm.sh +++ b/cluster/gce/configure-vm.sh @@ -494,8 +494,10 @@ EOF token-url = ${TOKEN_URL} project-id = ${PROJECT_ID} EOF + EXTERNAL_IP=$(curl --fail --silent -H 'Metadata-Flavor: Google' "http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip") cat <>/etc/salt/minion.d/grains.conf cloud_config: /etc/gce.conf + advertise_address: '${EXTERNAL_IP}' EOF fi } diff --git a/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest b/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest index 07e45c639e4..e2932ac2896 100644 --- a/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest +++ b/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest @@ -22,6 +22,11 @@ {% endif -%} +{% set advertise_address = "" -%} +{% if grains.advertise_address is defined -%} + {% set advertise_address = "--advertise-address=" + grains.advertise_address -%} +{% endif -%} + {% set address = "--address=127.0.0.1" -%} {% set cluster_name = "" -%} @@ -29,9 +34,9 @@ {% set cluster_name = "--cluster_name=" + pillar['instance_prefix'] -%} {% endif -%} -{% set publicAddressOverride = "" -%} +{% set bind_address = "" -%} {% if grains.publicAddressOverride is defined -%} - {% set publicAddressOverride = "--public_address_override=" + grains.publicAddressOverride -%} + {% set bind_address = "--bind-address=" + grains.publicAddressOverride -%} {% endif -%} {% set etcd_servers = "--etcd_servers=http://127.0.0.1:4001" -%} @@ -75,8 +80,7 @@ {% endif -%} {% set params = address + " " + etcd_servers + " " + cloud_provider + " " + cloud_config + " " + runtime_config + " " + admission_control + " " + service_cluster_ip_range + " " + client_ca_file + " " + basic_auth_file -%} -{% set params = params + " " + cluster_name + " " + cert_file + " " + key_file + " --secure_port=" + secure_port + " " + token_auth_file + " " + publicAddressOverride + " " + pillar['log_level'] -%} - +{% set params = params + " " + cluster_name + " " + cert_file + " " + key_file + " --secure_port=" + secure_port + " " + token_auth_file + " " + bind_address + " " + pillar['log_level'] + " " + advertise_address -%} { "apiVersion": "v1beta3", diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index b5ad55535c2..d27b5098f24 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -58,6 +58,7 @@ type APIServer struct { InsecureBindAddress util.IP InsecurePort int BindAddress util.IP + AdvertiseAddress util.IP ReadOnlyPort int SecurePort int ExternalHost string @@ -145,8 +146,14 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) { "Defaults to localhost.") fs.Var(&s.InsecureBindAddress, "address", "DEPRECATED: see --insecure-bind-address instead") fs.Var(&s.BindAddress, "bind-address", ""+ - "The IP address on which to serve the --read-only-port and --secure-port ports. This "+ - "address must be reachable by the rest of the cluster. If blank, all interfaces will be used.") + "The IP address on which to serve the --read-only-port and --secure-port ports. The "+ + "associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+ + "clients. If blank, all interfaces will be used (0.0.0.0).") + fs.Var(&s.AdvertiseAddress, "advertise-address", ""+ + "The IP address on which to advertise the apiserver to members of the cluster. This "+ + "address must be reachable by the rest of the cluster. If blank, the --bind-address "+ + "will be used. If --bind-address is unspecified, the host's default interface will "+ + "be used.") fs.Var(&s.BindAddress, "public-address-override", "DEPRECATED: see --bind-address instead") fs.IntVar(&s.ReadOnlyPort, "read-only-port", s.ReadOnlyPort, ""+ "The port on which to serve read-only resources. If 0, don't serve read-only "+ @@ -234,6 +241,13 @@ func newEtcd(etcdConfigFile string, etcdServerList util.StringList, storageVersi func (s *APIServer) Run(_ []string) error { s.verifyClusterIPFlags() + // If advertise-address is not specified, use bind-address. If bind-address + // is also unset (or 0.0.0.0), setDefaults() in pkg/master/master.go will + // do the right thing and use the host's default interface. + if s.AdvertiseAddress == nil || net.IP(s.AdvertiseAddress).IsUnspecified() { + s.AdvertiseAddress = s.BindAddress + } + if (s.EtcdConfigFile != "" && len(s.EtcdServerList) != 0) || (s.EtcdConfigFile == "" && len(s.EtcdServerList) == 0) { glog.Fatalf("specify either --etcd-servers or --etcd-config") } @@ -356,7 +370,7 @@ func (s *APIServer) Run(_ []string) error { CorsAllowedOriginList: s.CorsAllowedOriginList, ReadOnlyPort: s.ReadOnlyPort, ReadWritePort: s.SecurePort, - PublicAddress: net.IP(s.BindAddress), + PublicAddress: net.IP(s.AdvertiseAddress), Authenticator: authenticator, SupportsBasicAuth: len(s.BasicAuthFile) > 0, Authorizer: authorizer, @@ -443,6 +457,7 @@ func (s *APIServer) Run(_ []string) error { if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { s.TLSCertFile = path.Join(s.CertDirectory, "apiserver.crt") s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "apiserver.key") + // TODO (cjcullen): Is PublicAddress the right address to sign a cert with? if err := util.GenerateSelfSignedCert(config.PublicAddress.String(), s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { diff --git a/pkg/master/master.go b/pkg/master/master.go index 577b93a9e16..3dc7e0f96ef 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -125,7 +125,9 @@ type Config struct { // ExternalHost is the host name to use for external (public internet) facing URLs (e.g. Swagger) ExternalHost string - // If nil, the first result from net.InterfaceAddrs will be used. + // PublicAddress is the IP address where members of the cluster (kubelet, + // kube-proxy, services, etc.) can reach the master. + // If nil or 0.0.0.0, the host's default interface will be used. PublicAddress net.IP // Control the interval that pod, node IP, and node heath status caches