Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
dcb9b4b5
Commit
dcb9b4b5
authored
Dec 16, 2017
by
Brendan Burns
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
By default block service proxy to external IP addresses.
Service proxy uses redirects to Pods instead of direct access.
parent
ddea2dd5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
68 additions
and
9 deletions
+68
-9
kube_features.go
pkg/features/kube_features.go
+10
-0
storage_core.go
pkg/registry/core/rest/storage_core.go
+1
-1
BUILD
pkg/registry/core/service/BUILD
+6
-0
rest.go
pkg/registry/core/service/rest.go
+51
-8
rest_test.go
pkg/registry/core/service/rest_test.go
+0
-0
No files found.
pkg/features/kube_features.go
View file @
dcb9b4b5
...
@@ -168,6 +168,13 @@ const (
...
@@ -168,6 +168,13 @@ const (
// Enable nodes to exclude themselves from service load balancers
// Enable nodes to exclude themselves from service load balancers
ServiceNodeExclusion
utilfeature
.
Feature
=
"ServiceNodeExclusion"
ServiceNodeExclusion
utilfeature
.
Feature
=
"ServiceNodeExclusion"
// owner @brendandburns
// stable: v1.10
//
// Enable the service proxy to contact external IP addresses. Note this feature is present
// only for backward compatability, it will be removed in the 1.11 release.
ServiceProxyAllowExternalIPs
utilfeature
.
Feature
=
"ServiceProxyAllowExternalIPs"
// owner: @jsafrane
// owner: @jsafrane
// alpha: v1.9
// alpha: v1.9
//
//
...
@@ -268,4 +275,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
...
@@ -268,4 +275,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
// unintentionally on either side:
apiextensionsfeatures
.
CustomResourceValidation
:
{
Default
:
true
,
PreRelease
:
utilfeature
.
Beta
},
apiextensionsfeatures
.
CustomResourceValidation
:
{
Default
:
true
,
PreRelease
:
utilfeature
.
Beta
},
// backward compatability features that enable backwards compatability but should be removed soon.
ServiceProxyAllowExternalIPs
:
{
Default
:
false
,
PreRelease
:
utilfeature
.
Beta
},
}
}
pkg/registry/core/rest/storage_core.go
View file @
dcb9b4b5
...
@@ -172,7 +172,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
...
@@ -172,7 +172,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
controllerStorage
:=
controllerstore
.
NewStorage
(
restOptionsGetter
)
controllerStorage
:=
controllerstore
.
NewStorage
(
restOptionsGetter
)
serviceRest
:=
service
.
NewStorage
(
serviceRegistry
,
endpointRegistry
,
ServiceClusterIPAllocator
,
ServiceNodePortAllocator
,
c
.
ProxyTransport
)
serviceRest
:=
service
.
NewStorage
(
serviceRegistry
,
endpointRegistry
,
podStorage
.
Pod
,
ServiceClusterIPAllocator
,
ServiceNodePortAllocator
,
c
.
ProxyTransport
)
restStorageMap
:=
map
[
string
]
rest
.
Storage
{
restStorageMap
:=
map
[
string
]
rest
.
Storage
{
"pods"
:
podStorage
.
Pod
,
"pods"
:
podStorage
.
Pod
,
...
...
pkg/registry/core/service/BUILD
View file @
dcb9b4b5
...
@@ -23,7 +23,9 @@ go_library(
...
@@ -23,7 +23,9 @@ go_library(
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/features:go_default_library",
"//pkg/registry/core/endpoint:go_default_library",
"//pkg/registry/core/endpoint:go_default_library",
"//pkg/registry/core/pod/storage:go_default_library",
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/registry/core/service/portallocator:go_default_library",
"//pkg/registry/core/service/portallocator:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
...
@@ -39,6 +41,7 @@ go_library(
...
@@ -39,6 +41,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
],
)
)
...
@@ -54,6 +57,7 @@ go_test(
...
@@ -54,6 +57,7 @@ go_test(
"//pkg/api/service:go_default_library",
"//pkg/api/service:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/registry/core/pod/storage:go_default_library",
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/registry/core/service/portallocator:go_default_library",
"//pkg/registry/core/service/portallocator:go_default_library",
"//pkg/registry/registrytest:go_default_library",
"//pkg/registry/registrytest:go_default_library",
...
@@ -65,7 +69,9 @@ go_test(
...
@@ -65,7 +69,9 @@ go_test(
"//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/rand:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/rand:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
],
],
)
)
...
...
pkg/registry/core/service/rest.go
View file @
dcb9b4b5
...
@@ -35,11 +35,14 @@ import (
...
@@ -35,11 +35,14 @@ import (
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apimachinery/pkg/watch"
genericapirequest
"k8s.io/apiserver/pkg/endpoints/request"
genericapirequest
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/registry/rest"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
apiservice
"k8s.io/kubernetes/pkg/api/service"
apiservice
"k8s.io/kubernetes/pkg/api/service"
api
"k8s.io/kubernetes/pkg/apis/core"
api
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/registry/core/endpoint"
"k8s.io/kubernetes/pkg/registry/core/endpoint"
podstore
"k8s.io/kubernetes/pkg/registry/core/pod/storage"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
)
)
...
@@ -57,6 +60,7 @@ type REST struct {
...
@@ -57,6 +60,7 @@ type REST struct {
serviceIPs
ipallocator
.
Interface
serviceIPs
ipallocator
.
Interface
serviceNodePorts
portallocator
.
Interface
serviceNodePorts
portallocator
.
Interface
proxyTransport
http
.
RoundTripper
proxyTransport
http
.
RoundTripper
pods
*
podstore
.
REST
}
}
// ServiceNodePort includes protocol and port number of a service NodePort.
// ServiceNodePort includes protocol and port number of a service NodePort.
...
@@ -70,7 +74,7 @@ type ServiceNodePort struct {
...
@@ -70,7 +74,7 @@ type ServiceNodePort struct {
}
}
// NewStorage returns a new REST.
// NewStorage returns a new REST.
func
NewStorage
(
registry
Registry
,
endpoints
endpoint
.
Registry
,
serviceIPs
ipallocator
.
Interface
,
func
NewStorage
(
registry
Registry
,
endpoints
endpoint
.
Registry
,
pods
*
podstore
.
REST
,
serviceIPs
ipallocator
.
Interface
,
serviceNodePorts
portallocator
.
Interface
,
proxyTransport
http
.
RoundTripper
)
*
ServiceRest
{
serviceNodePorts
portallocator
.
Interface
,
proxyTransport
http
.
RoundTripper
)
*
ServiceRest
{
rest
:=
&
REST
{
rest
:=
&
REST
{
registry
:
registry
,
registry
:
registry
,
...
@@ -78,6 +82,7 @@ func NewStorage(registry Registry, endpoints endpoint.Registry, serviceIPs ipall
...
@@ -78,6 +82,7 @@ func NewStorage(registry Registry, endpoints endpoint.Registry, serviceIPs ipall
serviceIPs
:
serviceIPs
,
serviceIPs
:
serviceIPs
,
serviceNodePorts
:
serviceNodePorts
,
serviceNodePorts
:
serviceNodePorts
,
proxyTransport
:
proxyTransport
,
proxyTransport
:
proxyTransport
,
pods
:
pods
,
}
}
return
&
ServiceRest
{
return
&
ServiceRest
{
Service
:
rest
,
Service
:
rest
,
...
@@ -425,19 +430,57 @@ func (rs *REST) ResourceLocation(ctx genericapirequest.Context, id string) (*url
...
@@ -425,19 +430,57 @@ func (rs *REST) ResourceLocation(ctx genericapirequest.Context, id string) (*url
}
}
for
i
:=
range
ss
.
Ports
{
for
i
:=
range
ss
.
Ports
{
if
ss
.
Ports
[
i
]
.
Name
==
portStr
{
if
ss
.
Ports
[
i
]
.
Name
==
portStr
{
// Pick a random address.
addrSeed
:=
rand
.
Intn
(
len
(
ss
.
Addresses
))
ip
:=
ss
.
Addresses
[
rand
.
Intn
(
len
(
ss
.
Addresses
))]
.
IP
// This is a little wonky, but it's expensive to test for the presence of a Pod
port
:=
int
(
ss
.
Ports
[
i
]
.
Port
)
// So we repeatedly try at random and validate it, this means that for an invalid
return
&
url
.
URL
{
// service with a lot of endpoints we're going to potentially make a lot of calls,
Scheme
:
svcScheme
,
// but in the expected case we'll only make one.
Host
:
net
.
JoinHostPort
(
ip
,
strconv
.
Itoa
(
port
)),
for
try
:=
0
;
try
<
len
(
ss
.
Addresses
);
try
++
{
},
rs
.
proxyTransport
,
nil
addr
:=
ss
.
Addresses
[(
addrSeed
+
try
)
%
len
(
ss
.
Addresses
)]
if
!
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
ServiceProxyAllowExternalIPs
)
{
if
err
:=
isValidAddress
(
ctx
,
&
addr
,
rs
.
pods
);
err
!=
nil
{
glog
.
Errorf
(
"Address %v isn't valid (%v)"
,
addr
,
err
)
continue
}
}
ip
:=
addr
.
IP
port
:=
int
(
ss
.
Ports
[
i
]
.
Port
)
return
&
url
.
URL
{
Scheme
:
svcScheme
,
Host
:
net
.
JoinHostPort
(
ip
,
strconv
.
Itoa
(
port
)),
},
rs
.
proxyTransport
,
nil
}
glog
.
Errorf
(
"Failed to find a valid address, skipping subset: %v"
,
ss
)
}
}
}
}
}
}
return
nil
,
nil
,
errors
.
NewServiceUnavailable
(
fmt
.
Sprintf
(
"no endpoints available for service %q"
,
id
))
return
nil
,
nil
,
errors
.
NewServiceUnavailable
(
fmt
.
Sprintf
(
"no endpoints available for service %q"
,
id
))
}
}
func
isValidAddress
(
ctx
genericapirequest
.
Context
,
addr
*
api
.
EndpointAddress
,
pods
*
podstore
.
REST
)
error
{
if
addr
.
TargetRef
==
nil
{
return
fmt
.
Errorf
(
"Address has no target ref, skipping: %v"
,
addr
)
}
if
genericapirequest
.
NamespaceValue
(
ctx
)
!=
addr
.
TargetRef
.
Namespace
{
return
fmt
.
Errorf
(
"Address namespace doesn't match context namespace"
)
}
obj
,
err
:=
pods
.
Get
(
ctx
,
addr
.
TargetRef
.
Name
,
&
metav1
.
GetOptions
{})
if
err
!=
nil
{
return
err
}
pod
,
ok
:=
obj
.
(
*
api
.
Pod
)
if
!
ok
{
return
fmt
.
Errorf
(
"failed to cast to pod: %v"
,
obj
)
}
if
pod
==
nil
{
return
fmt
.
Errorf
(
"pod is missing, skipping (%s/%s)"
,
addr
.
TargetRef
.
Namespace
,
addr
.
TargetRef
.
Name
)
}
if
pod
.
Status
.
PodIP
!=
addr
.
IP
{
return
fmt
.
Errorf
(
"pod ip doesn't match endpoint ip, skipping: %s vs %s (%s/%s)"
,
pod
.
Status
.
PodIP
,
addr
.
IP
,
addr
.
TargetRef
.
Namespace
,
addr
.
TargetRef
.
Name
)
}
return
nil
}
// This is O(N), but we expect haystack to be small;
// This is O(N), but we expect haystack to be small;
// so small that we expect a linear search to be faster
// so small that we expect a linear search to be faster
func
containsNumber
(
haystack
[]
int
,
needle
int
)
bool
{
func
containsNumber
(
haystack
[]
int
,
needle
int
)
bool
{
...
...
pkg/registry/core/service/rest_test.go
View file @
dcb9b4b5
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment