diff --git a/cmd/kube-proxy/app/server.go b/cmd/kube-proxy/app/server.go index 019b6b9c151..5319736b4e4 100644 --- a/cmd/kube-proxy/app/server.go +++ b/cmd/kube-proxy/app/server.go @@ -62,7 +62,7 @@ type ProxyServerConfig struct { ProxyMode string IptablesSyncPeriod time.Duration ConfigSyncPeriod time.Duration - nodeRef *api.ObjectReference // Reference to this node. + NodeRef *api.ObjectReference // Reference to this node. MasqueradeAll bool CleanupAndExit bool KubeApiQps float32 @@ -71,9 +71,11 @@ type ProxyServerConfig struct { } type ProxyServer struct { + Client *kubeclient.Client Config *ProxyServerConfig IptInterface utiliptables.Interface Proxier proxy.ProxyProvider + Broadcaster record.EventBroadcaster Recorder record.EventRecorder } @@ -129,15 +131,19 @@ func NewProxyConfig() *ProxyServerConfig { } func NewProxyServer( + client *kubeclient.Client, config *ProxyServerConfig, iptInterface utiliptables.Interface, proxier proxy.ProxyProvider, + broadcaster record.EventBroadcaster, recorder record.EventRecorder, ) (*ProxyServer, error) { return &ProxyServer{ + Client: client, Config: config, IptInterface: iptInterface, Proxier: proxier, + Broadcaster: broadcaster, Recorder: recorder, }, nil } @@ -207,7 +213,6 @@ func NewProxyServerDefault(config *ProxyServerConfig) (*ProxyServer, error) { hostname := nodeutil.GetHostname(config.HostnameOverride) eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "kube-proxy", Host: hostname}) - eventBroadcaster.StartRecordingToSink(client.Events("")) var proxier proxy.ProxyProvider var endpointsHandler proxyconfig.EndpointsConfigHandler @@ -269,13 +274,13 @@ func NewProxyServerDefault(config *ProxyServerConfig) (*ProxyServer, error) { endpointsConfig.Channel("api"), ) - config.nodeRef = &api.ObjectReference{ + config.NodeRef = &api.ObjectReference{ Kind: "Node", Name: hostname, UID: types.UID(hostname), Namespace: "", } - return NewProxyServer(config, iptInterface, proxier, recorder) + return NewProxyServer(client, config, iptInterface, proxier, eventBroadcaster, recorder) } // Run runs the specified ProxyServer. This should never exit (unless CleanupAndExit is set). @@ -290,6 +295,8 @@ func (s *ProxyServer) Run(_ []string) error { return nil } + s.Broadcaster.StartRecordingToSink(s.Client.Events("")) + // Birth Cry after the birth is successful s.birthCry() @@ -353,5 +360,5 @@ func mayTryIptablesProxy(proxyMode string, client nodeGetter, hostname string) b } func (s *ProxyServer) birthCry() { - s.Recorder.Eventf(s.Config.nodeRef, "Starting", "Starting kube-proxy.") + s.Recorder.Eventf(s.Config.NodeRef, "Starting", "Starting kube-proxy.") } diff --git a/cmd/kubemark/hollow-node.go b/cmd/kubemark/hollow-node.go index c48ece46799..ba5c4239c44 100644 --- a/cmd/kubemark/hollow-node.go +++ b/cmd/kubemark/hollow-node.go @@ -22,12 +22,18 @@ import ( "time" docker "github.com/fsouza/go-dockerclient" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/record" client "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "k8s.io/kubernetes/pkg/kubelet/cadvisor" "k8s.io/kubernetes/pkg/kubelet/dockertools" "k8s.io/kubernetes/pkg/kubemark" + proxyconfig "k8s.io/kubernetes/pkg/proxy/config" "k8s.io/kubernetes/pkg/util" + fakeiptables "k8s.io/kubernetes/pkg/util/iptables/testing" + "k8s.io/kubernetes/pkg/util/sets" "github.com/golang/glog" "github.com/spf13/pflag" @@ -37,16 +43,20 @@ type HollowNodeConfig struct { KubeconfigPath string KubeletPort int KubeletReadOnlyPort int + Morph string NodeName string ServerPort int } +var knownMorphs = sets.NewString("kubelet", "proxy") + func (c *HollowNodeConfig) addFlags(fs *pflag.FlagSet) { fs.StringVar(&c.KubeconfigPath, "kubeconfig", "/kubeconfig/kubeconfig", "Path to kubeconfig file.") fs.IntVar(&c.KubeletPort, "kubelet-port", 10250, "Port on which HollowKubelet should be listening.") fs.IntVar(&c.KubeletReadOnlyPort, "kubelet-read-only-port", 10255, "Read-only port on which Kubelet is listening.") fs.StringVar(&c.NodeName, "name", "fake-node", "Name of this Hollow Node.") fs.IntVar(&c.ServerPort, "api-server-port", 443, "Port on which API server is listening.") + fs.StringVar(&c.Morph, "morph", "", fmt.Sprintf("Specifies into which Hollow component this binary should morph. Allowed values: %v", knownMorphs.List())) } func createClientFromFile(path string) (*client.Client, error) { @@ -75,25 +85,48 @@ func main() { config.addFlags(pflag.CommandLine) util.InitFlags() - // create a client for Kubelet to communicate with API server. + if !knownMorphs.Has(config.Morph) { + glog.Fatal("Unknown morph: %v. Allowed values: %v", config.Morph, knownMorphs.List()) + } + + // create a client to communicate with API server. cl, err := createClientFromFile(config.KubeconfigPath) if err != nil { glog.Fatal("Failed to create a Client. Exiting.") } - cadvisorInterface := new(cadvisor.Fake) - fakeDockerClient := &dockertools.FakeDockerClient{} - fakeDockerClient.VersionInfo = docker.Env{"ApiVersion=1.18"} - fakeDockerClient.ContainerMap = make(map[string]*docker.Container) - fakeDockerClient.EnableSleep = true + if config.Morph == "kubelet" { + cadvisorInterface := new(cadvisor.Fake) - hollowKubelet := kubemark.NewHollowKubelet( - config.NodeName, - cl, - cadvisorInterface, - fakeDockerClient, - config.KubeletPort, - config.KubeletReadOnlyPort, - ) - hollowKubelet.Run() + fakeDockerClient := &dockertools.FakeDockerClient{} + fakeDockerClient.VersionInfo = docker.Env{"ApiVersion=1.18"} + fakeDockerClient.ContainerMap = make(map[string]*docker.Container) + fakeDockerClient.EnableSleep = true + + hollowKubelet := kubemark.NewHollowKubelet( + config.NodeName, + cl, + cadvisorInterface, + fakeDockerClient, + config.KubeletPort, + config.KubeletReadOnlyPort, + ) + hollowKubelet.Run() + } + + if config.Morph == "proxy" { + eventBroadcaster := record.NewBroadcaster() + recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "kube-proxy", Host: config.NodeName}) + + iptInterface := fakeiptables.NewFake() + + serviceConfig := proxyconfig.NewServiceConfig() + serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) + + endpointsConfig := proxyconfig.NewEndpointsConfig() + endpointsConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) + + hollowProxy := kubemark.NewHollowProxyOrDie(config.NodeName, cl, endpointsConfig, serviceConfig, iptInterface, eventBroadcaster, recorder) + hollowProxy.Run() + } } diff --git a/pkg/kubemark/hollow-proxy.go b/pkg/kubemark/hollow-proxy.go new file mode 100644 index 00000000000..5d42db188ff --- /dev/null +++ b/pkg/kubemark/hollow-proxy.go @@ -0,0 +1,89 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubemark + +import ( + "time" + + proxyapp "k8s.io/kubernetes/cmd/kube-proxy/app" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/record" + client "k8s.io/kubernetes/pkg/client/unversioned" + proxyconfig "k8s.io/kubernetes/pkg/proxy/config" + "k8s.io/kubernetes/pkg/types" + utiliptables "k8s.io/kubernetes/pkg/util/iptables" + + "github.com/golang/glog" +) + +type HollowProxy struct { + ProxyServer *proxyapp.ProxyServer +} + +type FakeProxyHandler struct{} + +func (*FakeProxyHandler) OnServiceUpdate(services []api.Service) {} +func (*FakeProxyHandler) OnEndpointsUpdate(endpoints []api.Endpoints) {} + +type FakeProxier struct{} + +func (*FakeProxier) OnServiceUpdate(services []api.Service) {} +func (*FakeProxier) Sync() {} +func (*FakeProxier) SyncLoop() { + select {} +} + +func NewHollowProxyOrDie( + nodeName string, + client *client.Client, + endpointsConfig *proxyconfig.EndpointsConfig, + serviceConfig *proxyconfig.ServiceConfig, + iptInterface utiliptables.Interface, + broadcaster record.EventBroadcaster, + recorder record.EventRecorder, +) *HollowProxy { + // Create and start Hollow Proxy + config := proxyapp.NewProxyConfig() + config.OOMScoreAdj = 0 + config.ResourceContainer = "" + config.NodeRef = &api.ObjectReference{ + Kind: "Node", + Name: nodeName, + UID: types.UID(nodeName), + Namespace: "", + } + proxyconfig.NewSourceAPI( + client, + 30*time.Second, + serviceConfig.Channel("api"), + endpointsConfig.Channel("api"), + ) + + hollowProxy, err := proxyapp.NewProxyServer(client, config, iptInterface, &FakeProxier{}, broadcaster, recorder) + if err != nil { + glog.Fatalf("Error while creating ProxyServer: %v\n", err) + } + return &HollowProxy{ + ProxyServer: hollowProxy, + } +} + +func (hp *HollowProxy) Run() { + if err := hp.ProxyServer.Run(make([]string, 0)); err != nil { + glog.Fatalf("Error while running proxy: %v\n", err) + } +} diff --git a/pkg/util/iptables/testing/fake.go b/pkg/util/iptables/testing/fake.go new file mode 100644 index 00000000000..52c007f5d8b --- /dev/null +++ b/pkg/util/iptables/testing/fake.go @@ -0,0 +1,71 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import "k8s.io/kubernetes/pkg/util/iptables" + +// no-op implemenatation of iptables Interface +type fake struct{} + +func NewFake() *fake { + return &fake{} +} + +func (*fake) EnsureChain(table iptables.Table, chain iptables.Chain) (bool, error) { + return true, nil +} + +func (*fake) FlushChain(table iptables.Table, chain iptables.Chain) error { + return nil +} + +func (*fake) DeleteChain(table iptables.Table, chain iptables.Chain) error { + return nil +} + +func (*fake) EnsureRule(position iptables.RulePosition, table iptables.Table, chain iptables.Chain, args ...string) (bool, error) { + return true, nil +} + +func (*fake) DeleteRule(table iptables.Table, chain iptables.Chain, args ...string) error { + return nil +} + +func (*fake) IsIpv6() bool { + return false +} + +func (*fake) Save(table iptables.Table) ([]byte, error) { + return make([]byte, 0), nil +} + +func (*fake) SaveAll() ([]byte, error) { + return make([]byte, 0), nil +} + +func (*fake) Restore(table iptables.Table, data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error { + return nil +} + +func (*fake) RestoreAll(data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error { + return nil +} +func (*fake) AddReloadFunc(reloadFunc func()) {} + +func (*fake) Destroy() {} + +var _ = iptables.Interface(&fake{}) diff --git a/test/kubemark/common.sh b/test/kubemark/common.sh index 9cbf826a5ca..032dffdaa4e 100644 --- a/test/kubemark/common.sh +++ b/test/kubemark/common.sh @@ -14,8 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -source "${KUBE_ROOT}/cluster/kubemark/util.sh" source "${KUBE_ROOT}/cluster/kubemark/config-default.sh" +source "${KUBE_ROOT}/cluster/kubemark/util.sh" detect-project &> /dev/null export PROJECT diff --git a/test/kubemark/hollow-kubelet_template.json b/test/kubemark/hollow-node_template.json similarity index 59% rename from test/kubemark/hollow-kubelet_template.json rename to test/kubemark/hollow-node_template.json index 404203cd8db..86ca15a38fc 100644 --- a/test/kubemark/hollow-kubelet_template.json +++ b/test/kubemark/hollow-node_template.json @@ -2,20 +2,20 @@ "kind": "ReplicationController", "apiVersion": "v1", "metadata": { - "name": "hollow-kubelet", + "name": "hollow-node", "labels": { - "name": "hollow-kubelet" + "name": "hollow-node" } }, "spec": { "replicas": ##numreplicas##, "selector": { - "name": "hollow-kubelet" + "name": "hollow-node" }, "template": { "metadata": { "labels": { - "name": "hollow-kubelet" + "name": "hollow-node" } }, "spec": { @@ -27,7 +27,8 @@ } } ], - "containers": [{ + "containers": [ + { "name": "hollow-kubelet", "image": "gcr.io/##project##/kubemark:latest", "ports": [ @@ -39,7 +40,8 @@ "./kubemark.sh" ], "args": [ - "--v=3" + "--v=3", + "--morph=kubelet" ], "volumeMounts": [ { @@ -53,6 +55,30 @@ "memory": "100M" } } + + }, + { + "name": "hollow-proxy", + "image": "gcr.io/##project##/kubemark:latest", + "command": [ + "./kubemark.sh" + ], + "args": [ + "--v=3", + "--morph=proxy" + ], + "volumeMounts": [ + { + "name": "kubeconfig-volume", + "mountPath": "/kubeconfig" + } + ], + "resources": { + "requests": { + "cpu": "20m", + "memory": "100M" + } + } }] } } diff --git a/test/kubemark/start-kubemark.sh b/test/kubemark/start-kubemark.sh index 9b5ca9c325e..65da35641bc 100755 --- a/test/kubemark/start-kubemark.sh +++ b/test/kubemark/start-kubemark.sh @@ -200,11 +200,11 @@ contexts: current-context: kubemark-context EOF -sed "s/##numreplicas##/${NUM_MINIONS:-10}/g" ${KUBE_ROOT}/test/kubemark/hollow-kubelet_template.json > ${KUBE_ROOT}/test/kubemark/hollow-kubelet.json -sed -i'' -e "s/##project##/${PROJECT}/g" ${KUBE_ROOT}/test/kubemark/hollow-kubelet.json +sed "s/##numreplicas##/${NUM_MINIONS:-10}/g" ${KUBE_ROOT}/test/kubemark/hollow-node_template.json > ${KUBE_ROOT}/test/kubemark/hollow-node.json +sed -i'' -e "s/##project##/${PROJECT}/g" ${KUBE_ROOT}/test/kubemark/hollow-node.json kubectl create -f ${KUBE_ROOT}/test/kubemark/kubemark-ns.json kubectl create -f ${KUBECONFIG_SECRET} --namespace="kubemark" -kubectl create -f ${KUBE_ROOT}/test/kubemark/hollow-kubelet.json --namespace="kubemark" +kubectl create -f ${KUBE_ROOT}/test/kubemark/hollow-node.json --namespace="kubemark" rm ${KUBECONFIG_SECRET}