delete kubemark

This commit is contained in:
upodroid committed 2026-10-06 00:30:23 +01:00
1 parent 7708623c1a
commit 8739d508bd
72 files changed
+32 -3924

No files matched your search

-2
View File
@@ -122,8 +122,6 @@ dependencies:
refPaths:
- path: test/e2e_node/image_list.go
match: const defaultImage
- path: test/kubemark/resources/hollow-node_template.yaml
match: registry.k8s.io/node-problem-detector/node-problem-detector
#- path: cluster/gce/windows/k8s-node-setup.psm1
# match: DEFAULT_NPD_VERSION
@@ -21,8 +21,6 @@ spec:
capabilities:
drop:
- all
# When updating version also bump it in:
# - test/kubemark/resources/manifests/kube-addon-manager.yaml
image: registry.k8s.io/addon-manager/kube-addon-manager:v9.1.8
command:
- /bin/bash
-24
View File
@@ -1,24 +0,0 @@
# Copyright 2016 The Kubernetes Authors.
#
# 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.
# The line below points to the latest go-runner image, a wrapper around
# gcr.io/distroless/static which adds the go-runner command that we need
# for redirecting log output.
#
# See https://console.cloud.google.com/gcr/images/k8s-staging-build-image/global/go-runner
# for a list of available versions. This base image should be updated
# periodically.
FROM registry.k8s.io/build-image/go-runner:v2.3.1-go1.17.2-bullseye.0
COPY kubemark /kubemark
-36
View File
@@ -1,36 +0,0 @@
# Copyright 2016 The Kubernetes Authors.
#
# 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.
# build Kubemark image from currently built binaries containing both 'real' master and Hollow Node.
# This makefile assumes that the kubemark binary is present in this directory.
# Allow the caller to override this. Beware make's precedence. This:
# REGISTRY=$VAR make
# .. is not the same as:
# make REGISTRY=$VAR
REGISTRY := $(if $(REGISTRY),$(REGISTRY),staging-k8s.gcr.io)
IMAGE_TAG := $(if $(IMAGE_TAG),$(IMAGE_TAG),latest)
all: gcloudpush
build:
docker build --pull -t $(REGISTRY)/kubemark:$(IMAGE_TAG) .
gcloudpush: build
docker push $(REGISTRY)/kubemark:$(IMAGE_TAG)
push: build
docker push $(REGISTRY)/kubemark:$(IMAGE_TAG)
.PHONY: all build gcloudpush push
-12
View File
@@ -1,12 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- shyamjvs
- wojtek-t
approvers:
- shyamjvs
- wojtek-t
emeritus_approvers:
- gmarek
labels:
- sig/scalability
-14
View File
@@ -1,14 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- shyamjvs
- sig-scalability-reviewers
- wojtek-t
approvers:
- shyamjvs
- sig-scalability-approvers
- wojtek-t
emeritus_approvers:
- gmarek
labels:
- sig/scalability
-61
View File
@@ -1,61 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
# A configuration for Kubemark cluster. It doesn't need to be kept in
# sync with gce/config-default.sh (except the filename, because I'm reusing
# gce/util.sh script which assumes config filename), but if some things that
# are enabled by default should not run in hollow clusters, they should be disabled here.
# shellcheck disable=SC2034 # Variables sourced in other scripts.
source "${KUBE_ROOT}/cluster/gce/config-common.sh"
CLEANUP_KUBEMARK_IMAGE=${CLEANUP_KUBEMARK_IMAGE:-true}
TEST_CLUSTER_LOG_LEVEL="${TEST_CLUSTER_LOG_LEVEL:-"--v=4"}"
# If you want to set up multiple kubemark clusters with different "names",
# you should change this env per each start-kubemark.sh invocation.
KUBE_GCE_INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX:-"default"}"
# NUM_NODES is used by start-kubemark.sh to determine a correct number of replicas.
NUM_NODES=${KUBEMARK_NUM_NODES:-10}
NUM_WINDOWS_NODES=${KUBEMARK_NUM_WINDOWS_NODES:-0}
HOLLOW_KUBELET_TEST_LOG_LEVEL="${HOLLOW_KUBELET_TEST_LOG_LEVEL:-$TEST_CLUSTER_LOG_LEVEL}"
HOLLOW_PROXY_TEST_LOG_LEVEL="${HOLLOW_PROXY_TEST_LOG_LEVEL:-$TEST_CLUSTER_LOG_LEVEL}"
# Hollow-node components' test arguments.
HOLLOW_KUBELET_TEST_ARGS="${HOLLOW_KUBELET_TEST_ARGS:-} ${HOLLOW_KUBELET_TEST_LOG_LEVEL}"
HOLLOW_PROXY_TEST_ARGS="${HOLLOW_PROXY_TEST_ARGS:-} ${HOLLOW_PROXY_TEST_LOG_LEVEL}"
# Optional: Enable cluster autoscaler.
ENABLE_KUBEMARK_CLUSTER_AUTOSCALER="${ENABLE_KUBEMARK_CLUSTER_AUTOSCALER:-false}"
# When using Cluster Autoscaler, always start with one hollow-node replica.
# NUM_NODES should not be specified by the user. Instead we use
# NUM_NODES=KUBEMARK_AUTOSCALER_MAX_NODES. This gives other cluster components
# (e.g. kubemark master, Heapster) enough resources to handle maximum cluster size.
if [[ "${ENABLE_KUBEMARK_CLUSTER_AUTOSCALER}" == "true" ]]; then
NUM_REPLICAS=1
if [[ -n "$NUM_NODES" ]]; then
echo "WARNING: Using Cluster Autoscaler, ignoring NUM_NODES parameter. Set KUBEMARK_AUTOSCALER_MAX_NODES to specify maximum size of the cluster."
fi
fi
#Optional: Enable kube dns.
ENABLE_KUBEMARK_KUBE_DNS="${ENABLE_KUBEMARK_KUBE_DNS:-true}"
KUBE_DNS_DOMAIN="${KUBE_DNS_DOMAIN:-cluster.local}"
CLEANUP_KUBEMARK_IMAGE=false
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Copyright 2018 The Kubernetes Authors.
#
# 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.
# Cloud information
RANDGEN=$(dd if=/dev/urandom bs=64 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=16 count=1 2>/dev/null | sed 's/[A-Z]//g')
# shellcheck disable=2034 # Variable sourced in other scripts.
KUBE_NAMESPACE="kubemark_${RANDGEN}"
KUBEMARK_IMAGE_TAG="${KUBEMARK_IMAGE_TAG:-2}"
KUBEMARK_IMAGE_LOCATION="${KUBEMARK_IMAGE_LOCATION:-${KUBE_ROOT}/cluster/images/kubemark}"
KUBEMARK_INIT_TAG="${KUBEMARK_INIT_TAG:-${PROJECT}:${KUBEMARK_IMAGE_TAG}}"
CLUSTER_LOCATION="${CLUSTER_LOCATION:-wdc06}"
REGISTRY_LOGIN_URL="${REGISTRY_LOGIN_URL:-https://api.ng.bluemix.net}"
# User defined
# number of real workers in spawnTester cluster
NUM_NODES="${NUM_NODES:-2}"
# spec of real workers in spawnTester cluster
NODE_SIZE=${NODE_SIZE:-u2c.2x4}
DESIRED_NODES="${DESIRED_NODES:-10}"
# number of hollow nodes
# TODO: once IKS supports `kubetest`, i.e. the base cluster provisioning implemented in `kubetest`
# we can use NUM_NODES=${KUBEMARK_NUM_NODES:-10} to avoid usage of KUBEMARK_NUM_NODES
# more context, see https://github.com/kubernetes/kubernetes/pull/76909#discussion_r277735942
KUBEMARK_NUM_NODES="${KUBEMARK_NUM_NODES:-10}"
ENABLE_KUBEMARK_CLUSTER_AUTOSCALER="${ENABLE_KUBEMARK_CLUSTER_AUTOSCALER:-true}"
ENABLE_KUBEMARK_KUBE_DNS="${ENABLE_KUBEMARK_KUBE_DNS:-false}"
KUBELET_TEST_LOG_LEVEL="${KUBELET_TEST_LOG_LEVEL:-"--v=2"}"
KUBEPROXY_TEST_LOG_LEVEL="${KUBEPROXY_TEST_LOG_LEVEL:-"--v=4"}"
USE_REAL_PROXIER=${USE_REAL_PROXIER:-false}
NODE_INSTANCE_PREFIX=${NODE_INSTANCE_PREFIX:-node}
USE_EXISTING=${USE_EXISTING:-}
@@ -1,37 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
# Configuration for landing a Kubemark cluster on a pre-existing Kubernetes
# cluster.
# Pre-existing provider expects a MASTER_IP.
# If you need to specify a port that's not the default (443), add it to MASTER_IP.
#
# Example: Connect to the Master on the secure port 6443
# MASTER_IP=192.168.122.5:6443
#
MASTER_IP="${MASTER_IP:-}"
# The container registry and project given to the kubemark container:
# $CONTAINER_REGISTRY/$PROJECT/kubemark
#
CONTAINER_REGISTRY="${CONTAINER_REGISTRY:-}"
PROJECT="${PROJECT:-}"
NUM_NODES="${NUM_NODES:-1}"
KUBELET_TEST_LOG_LEVEL="${KUBELET_TEST_LOG_LEVEL:-}"
KUBEPROXY_TEST_LOG_LEVEL="${KUBEPROXY_TEST_LOG_LEVEL:-}"
MASTER_NAME="${MASTER_NAME:-}"
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/env bash
# Copyright 2014 The Kubernetes Authors.
#
# 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.
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
source "${KUBE_ROOT}/test/kubemark/cloud-provider-config.sh"
source "${KUBE_ROOT}/cluster/${CLOUD_PROVIDER}/util.sh"
source "${KUBE_ROOT}/cluster/kubemark/${CLOUD_PROVIDER}/config-default.sh"
-8
View File
@@ -44,7 +44,6 @@ readonly gcloud_supported_providers="gce gke"
readonly master_logfiles="kube-apiserver.log kube-apiserver-audit.log kube-scheduler.log kube-controller-manager.log cloud-controller-manager.log etcd.log etcd-events.log glbc.log cluster-autoscaler.log kube-addon-manager.log konnectivity-server.log fluentd.log kubelet.cov"
readonly node_logfiles="kube-proxy.log containers/konnectivity-agent-*.log fluentd.log kubelet.cov kube-network-policies.log"
readonly node_systemd_services=""
readonly hollow_node_logfiles="kubelet-hollow-node-*.log kubeproxy-hollow-node-*.log npd-hollow-node-*.log"
readonly aws_logfiles="cloud-init-output.log"
readonly gce_logfiles="startupscript.log"
readonly kern_logfile="kern.log"
@@ -375,8 +374,6 @@ function dump_masters() {
elif [[ ! "${master_ssh_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
echo "Master SSH not supported for ${KUBERNETES_PROVIDER}"
return
elif [[ -n "${KUBEMARK_MASTER_NAME:-}" ]]; then
master_names=( "${KUBEMARK_MASTER_NAME}" )
else
if ! (detect-master); then
echo 'Master not detected. Is the cluster up?'
@@ -444,9 +441,6 @@ function dump_nodes() {
fi
node_logfiles_all="${node_logfiles}"
if [[ "${ENABLE_HOLLOW_NODE_LOGS:-}" == "true" ]]; then
node_logfiles_all="${node_logfiles_all} ${hollow_node_logfiles}"
fi
linux_nodes_selected_for_logs=()
if [[ -n "${LOGDUMP_ONLY_N_RANDOM_NODES:-}" ]]; then
@@ -543,7 +537,6 @@ function dump_nodes_with_logexporter() {
# Obtain parameters required by logexporter.
local -r service_account_credentials="$(base64 "${GOOGLE_APPLICATION_CREDENTIALS}" | tr -d '\n')"
local -r cloud_provider="${KUBERNETES_PROVIDER}"
local -r enable_hollow_node_logs="${ENABLE_HOLLOW_NODE_LOGS:-false}"
local -r logexport_sleep_seconds="$(( 90 + NUM_NODES / 3 ))"
if [[ -z "${ZONE_NODE_SELECTOR_DISABLED:-}" ]]; then
local -r node_selector="${ZONE_NODE_SELECTOR_LABEL:-topology.kubernetes.io/zone}: ${ZONE}"
@@ -560,7 +553,6 @@ function dump_nodes_with_logexporter() {
sed -i'' -e "s@{{.ServiceAccountCredentials}}@${service_account_credentials}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.CloudProvider}}@${cloud_provider}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.GCSPath}}@${gcs_artifacts_dir}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.EnableHollowNodeLogs}}@${enable_hollow_node_logs}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.DumpSystemdJournal}}@${dump_systemd_journal}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.ExtraLogFiles}}@${extra_log_files}@g" "${manifest_yaml}"
sed -i'' -e "s@{{.ExtraSystemdServices}}@${extra_systemd_services}@g" "${manifest_yaml}"
@@ -48,7 +48,6 @@ spec:
- --cloud-provider={{.CloudProvider}}
- --gcs-path={{.GCSPath}}
- --gcloud-auth-file-path=/etc/service-account/service-account.json
- --enable-hollow-node-logs={{.EnableHollowNodeLogs}}
- --dump-systemd-journal={{.DumpSystemdJournal}}
- --extra-log-files={{.ExtraLogFiles}}
- --extra-systemd-services={{.ExtraSystemdServices}}
-4
View File
@@ -1,4 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- sig/scalability
-45
View File
@@ -1,45 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
# A library of helper functions for landing kubemark containers on a
# pre-existing Kubernetes master. See test/kubemark/pre-existing/README.md
# for me details on using a pre-existing provider.
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
source "${KUBE_ROOT}/cluster/common.sh"
source "${KUBE_ROOT}/hack/lib/util.sh"
function detect-project() {
if [[ -z "${MASTER_IP:-}" ]]; then
echo "Set 'MASTER_IP' to the instance assigned to be the Kubernetes master" 1>&2
exit 1
fi
if [[ -z "${PROJECT:-}" ]]; then
echo "Set 'PROJECT' to the name of the container project: $CONTAINER_REGISTRY/$PROJECT/kubemark" >&2
exit 1
fi
if [[ -z "${SERVICE_CLUSTER_IP_RANGE:-}" ]]; then
cluster_range=$(echo "${MASTER_IP}" | awk -F '.' '{printf("%d.%d.%d.0", $1, $2, $3)}')
SERVICE_CLUSTER_IP_RANGE="${SERVICE_CLUSTER_IP_RANGE:-$cluster_range/16}"
fi
}
function create-certs {
execute-cmd-on-pre-existing-master-with-retries 'sudo cat /etc/kubernetes/admin.conf' > /tmp/kubeconfig
}
-12
View File
@@ -1,12 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- shyamjvs
- sig-scalability-reviewers
- wojtek-t
approvers:
- shyamjvs
- sig-scalability-approvers
- wojtek-t
emeritus_approvers:
- gmarek
-301
View File
@@ -1,301 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
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 app
import (
"context"
goflag "flag"
"fmt"
"time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
internalapi "k8s.io/cri-api/pkg/apis"
"k8s.io/klog/v2"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/events"
cliflag "k8s.io/component-base/cli/flag"
_ "k8s.io/component-base/metrics/prometheus/restclient" // for client metric registration
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
"k8s.io/component-base/version"
"k8s.io/component-base/version/verflag"
remote "k8s.io/cri-client/pkg"
fakeremote "k8s.io/cri-client/pkg/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/cluster/ports"
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
"k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap"
"k8s.io/kubernetes/pkg/kubelet/cm"
"k8s.io/kubernetes/pkg/kubemark"
kubemarkproxy "k8s.io/kubernetes/pkg/proxy/kubemark"
utilflag "k8s.io/kubernetes/pkg/util/flag"
)
type hollowNodeConfig struct {
KubeconfigPath string
BootstrapKubeconfigPath string
CertDirectory string
KubeletPort int
KubeletReadOnlyPort int
Morph string
NodeName string
ServerPort int
ContentType string
QPS float32
Burst int
NodeLabels map[string]string
RegisterWithTaints []v1.Taint
MaxPods int
ExtendedResources map[string]string
UseHostImageService bool
// Deprecated config; remove these with the corresponding flags
UseRealProxier bool
ProxierSyncPeriod time.Duration
ProxierMinSyncPeriod time.Duration
}
const (
maxPods = 110
podsPerCore = 0
)
// TODO(#45650): Refactor hollow-node into hollow-kubelet and hollow-proxy
// and make the config driven.
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.StringVar(&c.BootstrapKubeconfigPath, "bootstrap-kubeconfig", "", "Path to bootstrap kubeconfig file.")
fs.StringVar(&c.CertDirectory, "cert-dir", "/etc/srv/", "Path to cert directory for bootstraping.")
fs.IntVar(&c.KubeletPort, "kubelet-port", ports.KubeletPort, "Port on which HollowKubelet should be listening.")
fs.IntVar(&c.KubeletReadOnlyPort, "kubelet-read-only-port", ports.KubeletReadOnlyPort, "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()))
fs.StringVar(&c.ContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType of requests sent to apiserver.")
fs.Float32Var(&c.QPS, "kube-api-qps", 10, "QPS indicates the maximum QPS to the apiserver.")
fs.IntVar(&c.Burst, "kube-api-burst", 20, "Burst indicates maximum burst for throttle to the apiserver.")
bindableNodeLabels := cliflag.ConfigurationMap(c.NodeLabels)
fs.Var(&bindableNodeLabels, "node-labels", "Additional node labels")
fs.Var(utilflag.RegisterWithTaintsVar{Value: &c.RegisterWithTaints}, "register-with-taints", "Register the node with the given list of taints (comma separated \"<key>=<value>:<effect>\"). No-op if register-node is false.")
fs.IntVar(&c.MaxPods, "max-pods", maxPods, "Number of pods that can run on this Kubelet.")
bindableExtendedResources := cliflag.ConfigurationMap(c.ExtendedResources)
fs.Var(&bindableExtendedResources, "extended-resources", "Register the node with extended resources (comma separated \"<name>=<quantity>\")")
fs.BoolVar(&c.UseHostImageService, "use-host-image-service", true, "Set to true if the hollow-kubelet should use the host image service. If set to false the fake image service will be used")
fs.BoolVar(&c.UseRealProxier, "use-real-proxier", true, "Has no effect.")
_ = fs.MarkDeprecated("use-real-proxier", "This flag is deprecated and will be removed in a future release.")
fs.DurationVar(&c.ProxierSyncPeriod, "proxier-sync-period", 30*time.Second, "Has no effect.")
_ = fs.MarkDeprecated("proxier-sync-period", "This flag is deprecated and will be removed in a future release.")
fs.DurationVar(&c.ProxierMinSyncPeriod, "proxier-min-sync-period", 0, "Has no effect.")
_ = fs.MarkDeprecated("proxier-min-sync-period", "This flag is deprecated and will be removed in a future release.")
}
func (c *hollowNodeConfig) createClientConfigFromFile() (*restclient.Config, error) {
clientConfig, err := clientcmd.LoadFromFile(c.KubeconfigPath)
if err != nil {
return nil, fmt.Errorf("error while loading kubeconfig from file %v: %v", c.KubeconfigPath, err)
}
config, err := clientcmd.NewDefaultClientConfig(*clientConfig, &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
return nil, fmt.Errorf("error while creating kubeconfig: %v", err)
}
config.ContentType = c.ContentType
config.QPS = c.QPS
config.Burst = c.Burst
return config, nil
}
func (c *hollowNodeConfig) bootstrapClientConfig() error {
if c.BootstrapKubeconfigPath != "" {
return bootstrap.LoadClientCert(context.TODO(), c.KubeconfigPath, c.BootstrapKubeconfigPath, c.CertDirectory, types.NodeName(c.NodeName))
}
return nil
}
func (c *hollowNodeConfig) createHollowKubeletOptions() *kubemark.HollowKubeletOptions {
return &kubemark.HollowKubeletOptions{
NodeName: c.NodeName,
KubeletPort: c.KubeletPort,
KubeletReadOnlyPort: c.KubeletReadOnlyPort,
MaxPods: c.MaxPods,
PodsPerCore: podsPerCore,
NodeLabels: c.NodeLabels,
RegisterWithTaints: c.RegisterWithTaints,
}
}
// NewHollowNodeCommand creates a *cobra.Command object with default parameters
func NewHollowNodeCommand() *cobra.Command {
s := &hollowNodeConfig{
NodeLabels: make(map[string]string),
ExtendedResources: make(map[string]string),
}
cmd := &cobra.Command{
Use: "kubemark",
Long: "kubemark",
RunE: func(cmd *cobra.Command, args []string) error {
verflag.PrintAndExitIfRequested()
cliflag.PrintFlags(cmd.Flags())
return run(cmd.Context(), s)
},
Args: func(cmd *cobra.Command, args []string) error {
for _, arg := range args {
if len(arg) > 0 {
return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
}
}
return nil
},
}
fs := cmd.Flags()
fs.AddGoFlagSet(goflag.CommandLine) // for flags like --docker-only
s.addFlags(fs)
return cmd
}
func run(ctx context.Context, config *hollowNodeConfig) error {
// To help debugging, immediately log version and print flags.
klog.Infof("Version: %+v", version.Get())
if !knownMorphs.Has(config.Morph) {
return fmt.Errorf("Unknown morph: %v. allowed values: %v", config.Morph, knownMorphs.List())
}
// create a client to communicate with API server.
err := config.bootstrapClientConfig()
if err != nil {
return fmt.Errorf("Failed to bootstrap, error: %w. Exiting", err)
}
clientConfig, err := config.createClientConfigFromFile()
if err != nil {
return fmt.Errorf("Failed to create a ClientConfig, error: %w. Exiting", err)
}
if config.Morph == "kubelet" {
clientConfig.UserAgent = "hollow-kubelet"
client, err := clientset.NewForConfig(clientConfig)
if err != nil {
return fmt.Errorf("Failed to create a ClientSet, error: %w. Exiting", err)
}
f, c := kubemark.GetHollowKubeletConfig(config.createHollowKubeletOptions())
heartbeatClientConfig := *clientConfig
heartbeatClientConfig.Timeout = c.NodeStatusUpdateFrequency.Duration
// The timeout is the minimum of the lease duration and status update frequency
leaseTimeout := time.Duration(c.NodeLeaseDurationSeconds) * time.Second
if heartbeatClientConfig.Timeout > leaseTimeout {
heartbeatClientConfig.Timeout = leaseTimeout
}
heartbeatClientConfig.QPS = float32(-1)
heartbeatClient, err := clientset.NewForConfig(&heartbeatClientConfig)
if err != nil {
return fmt.Errorf("Failed to create a ClientSet, error: %w. Exiting", err)
}
cadvisorInterface := &cadvisortest.Fake{
NodeName: config.NodeName,
}
var containerManager cm.ContainerManager
if config.ExtendedResources != nil {
extendedResources := v1.ResourceList{}
for k, v := range config.ExtendedResources {
extendedResources[v1.ResourceName(k)] = resource.MustParse(v)
}
containerManager = cm.NewStubContainerManagerWithDevicePluginResource(extendedResources)
} else {
containerManager = cm.NewStubContainerManager()
}
endpoint, err := fakeremote.GenerateEndpoint()
if err != nil {
return fmt.Errorf("Failed to generate fake endpoint, error: %w", err)
}
fakeRemoteRuntime := fakeremote.NewFakeRemoteRuntime()
if err = fakeRemoteRuntime.Start(endpoint); err != nil {
return fmt.Errorf("Failed to start fake runtime, error: %w", err)
}
defer fakeRemoteRuntime.Stop()
runtimeService, err := remote.NewRemoteRuntimeServiceBuilder().
WithEndpoint(endpoint).
WithConnectionTimeout(15 * time.Second).
Build(ctx)
if err != nil {
return fmt.Errorf("Failed to init runtime service, error: %w", err)
}
var imageService internalapi.ImageManagerService = fakeRemoteRuntime.ImageService
if config.UseHostImageService {
imageService, err = remote.NewRemoteImageServiceBuilder().
WithEndpoint(c.ImageServiceEndpoint).
WithConnectionTimeout(15 * time.Second).
Build(ctx)
if err != nil {
return fmt.Errorf("Failed to init image service, error: %w", err)
}
}
hollowKubelet := kubemark.NewHollowKubelet(
f, c,
client,
heartbeatClient,
cadvisorInterface,
imageService,
runtimeService,
containerManager,
)
hollowKubelet.Run(ctx)
}
if config.Morph == "proxy" {
clientConfig.UserAgent = "hollow-proxy"
client, err := clientset.NewForConfig(clientConfig)
if err != nil {
return fmt.Errorf("Failed to create API Server client, error: %w", err)
}
eventBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1()})
recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, "kube-proxy")
hollowProxy := kubemarkproxy.NewHollowProxy(
config.NodeName,
client,
client.CoreV1(),
eventBroadcaster,
recorder,
)
return hollowProxy.Run()
}
return nil
}
-96
View File
@@ -1,96 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
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 app
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
"k8s.io/kubernetes/test/utils/ktesting"
)
const fakeKubeconfig = `
apiVersion: v1
kind: Config
clusters:
- cluster:
insecure-skip-tls-verify: true
server: %s
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
users:
- name: default
user:
username: config
`
// TestHollowNode is a naive test that attempts to start hollow node and checks if it's not crashing.
// Such test is sufficient to detect e.g. missing kubelet dependencies that are not added in
// pkg/kubemark/hollow_kubelet.go.
func TestHollowNode(t *testing.T) {
// temp dir
tmpDir, err := os.MkdirTemp("", "hollow-node")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// https server
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(200)
w.Write([]byte(`ok`))
}))
defer server.Close()
kubeconfigPath := filepath.Join(tmpDir, "config.kubeconfig")
if err := os.WriteFile(kubeconfigPath, []byte(fmt.Sprintf(fakeKubeconfig, server.URL)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
for morph := range knownMorphs {
t.Run(morph, func(t *testing.T) {
s := &hollowNodeConfig{
KubeconfigPath: kubeconfigPath,
Morph: morph,
}
errCh := make(chan error)
go func() {
data, err := os.ReadFile(kubeconfigPath)
t.Logf("read %d, err=%v\n", len(data), err)
ctx := ktesting.Init(t)
errCh <- run(ctx, s)
}()
select {
case err := <-errCh:
t.Fatalf("Run finished unexpectedly with error: %v", err)
case <-time.After(3 * time.Second):
t.Logf("Morph %q hasn't crashed for 3s. Calling success.", morph)
}
})
}
}
-30
View File
@@ -1,30 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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 main
import (
"os"
"k8s.io/component-base/cli"
"k8s.io/kubernetes/cmd/kubemark/app"
)
func main() {
command := app.NewHollowNodeCommand()
code := cli.Run(command)
os.Exit(code)
}
-3
View File
@@ -277,7 +277,6 @@ readonly KUBE_TEST_BINARIES=("${KUBE_TEST_TARGETS[@]##*/}")
readonly KUBE_TEST_BINARIES_WIN=("${KUBE_TEST_BINARIES[@]/%/.exe}")
readonly KUBE_TEST_PORTABLE=(
test/e2e/testing-manifests
test/kubemark
hack/e2e-internal
hack/get-build.sh
hack/ginkgo-e2e.sh
@@ -289,7 +288,6 @@ readonly KUBE_TEST_PORTABLE=(
# These binaries will be distributed in the kubernetes-test tarball.
kube::golang::server_test_targets() {
local targets=(
cmd/kubemark
ginkgo
)
@@ -332,7 +330,6 @@ readonly KUBE_STATIC_BINARIES=(
kubectl
kubectl-convert
kubelet
kubemark
mounter
)
-1
View File
@@ -4,7 +4,6 @@ rules:
- ''
forbiddenPrefixes:
# prevent pkg/ from depending on cmd/
# note: pkg/kubemark overrides this
- k8s.io/kubernetes/cmd
# use sigs.k8s.io/yaml instead
- github.com/ghodss/yaml
-5
View File
@@ -1,5 +0,0 @@
rules:
# override pkg/ import restriction on cmd/ for kubemark
- selectorRegexp: k8s[.]io/kubernetes/cmd
allowedPrefixes:
- k8s.io/kubernetes/cmd/kubelet/app
-14
View File
@@ -1,14 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- shyamjvs
- sig-scalability-reviewers
- wojtek-t
approvers:
- shyamjvs
- sig-scalability-approvers
- wojtek-t
emeritus_approvers:
- gmarek
labels:
- sig/scalability
-401
View File
@@ -1,401 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
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 (
"context"
"fmt"
"math/rand"
"sync"
"time"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
informersv1 "k8s.io/client-go/informers/core/v1"
kubeclient "k8s.io/client-go/kubernetes"
listersv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
)
const (
namespaceKubemark = "kubemark"
nodeGroupLabel = "autoscaling.k8s.io/nodegroup"
numRetries = 3
)
// KubemarkController is a simplified version of cloud provider for kubemark. It allows
// to add and delete nodes from a kubemark cluster and introduces nodegroups
// by applying labels to the kubemark's hollow-nodes.
type KubemarkController struct {
nodeTemplate *apiv1.ReplicationController
externalCluster externalCluster
kubemarkCluster kubemarkCluster
rand *rand.Rand
createNodeQueue chan string
nodeGroupQueueSize map[string]int
nodeGroupQueueSizeLock sync.Mutex
}
// externalCluster is used to communicate with the external cluster that hosts
// kubemark, in order to be able to list, create and delete hollow nodes
// by manipulating the replication controllers.
type externalCluster struct {
rcLister listersv1.ReplicationControllerLister
rcSynced cache.InformerSynced
podLister listersv1.PodLister
podSynced cache.InformerSynced
client kubeclient.Interface
}
// kubemarkCluster is used to delete nodes from kubemark cluster once their
// respective replication controllers have been deleted and the nodes have
// become unready. This is to cover for the fact that there is no proper cloud
// provider for kubemark that would care for deleting the nodes.
type kubemarkCluster struct {
client kubeclient.Interface
nodeLister listersv1.NodeLister
nodeSynced cache.InformerSynced
nodesToDelete map[string]bool
nodesToDeleteLock sync.Mutex
}
// NewKubemarkController creates KubemarkController using the provided clients to talk to external
// and kubemark clusters.
func NewKubemarkController(externalClient kubeclient.Interface, externalInformerFactory informers.SharedInformerFactory,
kubemarkClient kubeclient.Interface, kubemarkNodeInformer informersv1.NodeInformer) (*KubemarkController, error) {
rcInformer := externalInformerFactory.InformerFor(&apiv1.ReplicationController{}, newReplicationControllerInformer)
podInformer := externalInformerFactory.InformerFor(&apiv1.Pod{}, newPodInformer)
controller := &KubemarkController{
externalCluster: externalCluster{
rcLister: listersv1.NewReplicationControllerLister(rcInformer.GetIndexer()),
rcSynced: rcInformer.HasSynced,
podLister: listersv1.NewPodLister(podInformer.GetIndexer()),
podSynced: podInformer.HasSynced,
client: externalClient,
},
kubemarkCluster: kubemarkCluster{
nodeLister: kubemarkNodeInformer.Lister(),
nodeSynced: kubemarkNodeInformer.Informer().HasSynced,
client: kubemarkClient,
nodesToDelete: make(map[string]bool),
nodesToDeleteLock: sync.Mutex{},
},
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
createNodeQueue: make(chan string, 1000),
nodeGroupQueueSize: make(map[string]int),
nodeGroupQueueSizeLock: sync.Mutex{},
}
kubemarkNodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: controller.kubemarkCluster.removeUnneededNodes,
})
return controller, nil
}
// WaitForCacheSync waits until all caches in the controller are populated.
func (kubemarkController *KubemarkController) WaitForCacheSync(stopCh chan struct{}) bool {
return cache.WaitForNamedCacheSync("kubemark", stopCh,
kubemarkController.externalCluster.rcSynced,
kubemarkController.externalCluster.podSynced,
kubemarkController.kubemarkCluster.nodeSynced)
}
// Run populates the node template needed for creation of kubemark nodes and
// starts the worker routine for creating new nodes.
func (kubemarkController *KubemarkController) Run(stopCh chan struct{}) {
nodeTemplate, err := kubemarkController.getNodeTemplate()
if err != nil {
klog.Fatalf("failed to get node template: %s", err)
}
kubemarkController.nodeTemplate = nodeTemplate
go kubemarkController.runNodeCreation(stopCh)
<-stopCh
}
// GetNodeNamesForNodeGroup returns list of the nodes in the node group.
func (kubemarkController *KubemarkController) GetNodeNamesForNodeGroup(nodeGroup string) ([]string, error) {
selector := labels.SelectorFromSet(labels.Set{nodeGroupLabel: nodeGroup})
pods, err := kubemarkController.externalCluster.podLister.List(selector)
if err != nil {
return nil, err
}
result := make([]string, 0, len(pods))
for _, pod := range pods {
result = append(result, pod.ObjectMeta.Name)
}
return result, nil
}
// GetNodeGroupSize returns the current size for the node group as observed.
func (kubemarkController *KubemarkController) GetNodeGroupSize(nodeGroup string) (int, error) {
selector := labels.SelectorFromSet(labels.Set(map[string]string{nodeGroupLabel: nodeGroup}))
nodes, err := kubemarkController.externalCluster.rcLister.List(selector)
if err != nil {
return 0, err
}
return len(nodes), nil
}
// GetNodeGroupTargetSize returns the size of the node group as a sum of current
// observed size and number of upcoming nodes.
func (kubemarkController *KubemarkController) GetNodeGroupTargetSize(nodeGroup string) (int, error) {
kubemarkController.nodeGroupQueueSizeLock.Lock()
defer kubemarkController.nodeGroupQueueSizeLock.Unlock()
realSize, err := kubemarkController.GetNodeGroupSize(nodeGroup)
if err != nil {
return realSize, err
}
return realSize + kubemarkController.nodeGroupQueueSize[nodeGroup], nil
}
// SetNodeGroupSize changes the size of node group by adding or removing nodes.
func (kubemarkController *KubemarkController) SetNodeGroupSize(nodeGroup string, size int) error {
currSize, err := kubemarkController.GetNodeGroupTargetSize(nodeGroup)
if err != nil {
return err
}
switch delta := size - currSize; {
case delta < 0:
absDelta := -delta
nodes, err := kubemarkController.GetNodeNamesForNodeGroup(nodeGroup)
if err != nil {
return err
}
if len(nodes) < absDelta {
return fmt.Errorf("can't remove %d nodes from %s nodegroup, not enough nodes: %d", absDelta, nodeGroup, len(nodes))
}
for i, node := range nodes {
if i == absDelta {
return nil
}
if err := kubemarkController.RemoveNodeFromNodeGroup(nodeGroup, node); err != nil {
return err
}
}
case delta > 0:
kubemarkController.nodeGroupQueueSizeLock.Lock()
kubemarkController.nodeGroupQueueSize[nodeGroup] += delta
kubemarkController.nodeGroupQueueSizeLock.Unlock()
for i := 0; i < delta; i++ {
kubemarkController.createNodeQueue <- nodeGroup
}
}
return nil
}
// GetNodeGroupForNode returns the name of the node group to which the node
// belongs.
func (kubemarkController *KubemarkController) GetNodeGroupForNode(node string) (string, error) {
pod := kubemarkController.getPodByName(node)
if pod == nil {
return "", fmt.Errorf("node %s does not exist", node)
}
nodeGroup, ok := pod.ObjectMeta.Labels[nodeGroupLabel]
if ok {
return nodeGroup, nil
}
return "", fmt.Errorf("can't find nodegroup for node %s due to missing label %s", node, nodeGroupLabel)
}
func (kubemarkController *KubemarkController) addNodeToNodeGroup(nodeGroup string) error {
node := kubemarkController.nodeTemplate.DeepCopy()
node.Name = fmt.Sprintf("%s-%d", nodeGroup, kubemarkController.rand.Int63())
node.Labels = map[string]string{nodeGroupLabel: nodeGroup, "name": node.Name}
node.Spec.Template.Labels = node.Labels
var err error
for i := 0; i < numRetries; i++ {
_, err = kubemarkController.externalCluster.client.CoreV1().ReplicationControllers(node.Namespace).Create(context.TODO(), node, metav1.CreateOptions{})
if err == nil {
return nil
}
}
return err
}
func (kubemarkController *KubemarkController) RemoveNodeFromNodeGroup(nodeGroup string, node string) error {
pod := kubemarkController.getPodByName(node)
if pod == nil {
klog.Warningf("Can't delete node %s from nodegroup %s. Node does not exist.", node, nodeGroup)
return nil
}
if pod.ObjectMeta.Labels[nodeGroupLabel] != nodeGroup {
return fmt.Errorf("can't delete node %s from nodegroup %s. Node is not in nodegroup", node, nodeGroup)
}
policy := metav1.DeletePropagationForeground
var err error
for i := 0; i < numRetries; i++ {
err = kubemarkController.externalCluster.client.CoreV1().ReplicationControllers(namespaceKubemark).Delete(context.TODO(), pod.ObjectMeta.Labels["name"],
metav1.DeleteOptions{PropagationPolicy: &policy})
if err == nil {
klog.Infof("marking node %s for deletion", node)
// Mark node for deletion from kubemark cluster.
// Once it becomes unready after replication controller
// deletion has been noticed, we will delete it explicitly.
// This is to cover for the fact that kubemark does not
// take care of this itself.
kubemarkController.kubemarkCluster.markNodeForDeletion(node)
return nil
}
}
return fmt.Errorf("Failed to delete node %s: %v", node, err)
}
func (kubemarkController *KubemarkController) getReplicationControllerByName(name string) *apiv1.ReplicationController {
rcs, err := kubemarkController.externalCluster.rcLister.List(labels.Everything())
if err != nil {
return nil
}
for _, rc := range rcs {
if rc.ObjectMeta.Name == name {
return rc
}
}
return nil
}
func (kubemarkController *KubemarkController) getPodByName(name string) *apiv1.Pod {
pods, err := kubemarkController.externalCluster.podLister.List(labels.Everything())
if err != nil {
return nil
}
for _, pod := range pods {
if pod.ObjectMeta.Name == name {
return pod
}
}
return nil
}
func (kubemarkController *KubemarkController) getNodeNameForPod(podName string) (string, error) {
pods, err := kubemarkController.externalCluster.podLister.List(labels.Everything())
if err != nil {
return "", err
}
for _, pod := range pods {
if pod.ObjectMeta.Name == podName {
return pod.Labels["name"], nil
}
}
return "", fmt.Errorf("pod %s not found", podName)
}
// getNodeTemplate returns the template for hollow node replication controllers
// by looking for an existing hollow node specification. This requires at least
// one kubemark node to be present on startup.
func (kubemarkController *KubemarkController) getNodeTemplate() (*apiv1.ReplicationController, error) {
podName, err := kubemarkController.kubemarkCluster.getHollowNodeName()
if err != nil {
return nil, err
}
hollowNodeName, err := kubemarkController.getNodeNameForPod(podName)
if err != nil {
return nil, err
}
if hollowNode := kubemarkController.getReplicationControllerByName(hollowNodeName); hollowNode != nil {
nodeTemplate := &apiv1.ReplicationController{
Spec: apiv1.ReplicationControllerSpec{
Template: hollowNode.Spec.Template,
},
}
nodeTemplate.Spec.Selector = nil
nodeTemplate.Namespace = namespaceKubemark
one := int32(1)
nodeTemplate.Spec.Replicas = &one
return nodeTemplate, nil
}
return nil, fmt.Errorf("can't get hollow node template")
}
func (kubemarkController *KubemarkController) runNodeCreation(stop <-chan struct{}) {
for {
select {
case nodeGroup := <-kubemarkController.createNodeQueue:
kubemarkController.nodeGroupQueueSizeLock.Lock()
err := kubemarkController.addNodeToNodeGroup(nodeGroup)
if err != nil {
klog.Errorf("failed to add node to node group %s: %v", nodeGroup, err)
} else {
kubemarkController.nodeGroupQueueSize[nodeGroup]--
}
kubemarkController.nodeGroupQueueSizeLock.Unlock()
case <-stop:
return
}
}
}
func (kubemarkCluster *kubemarkCluster) getHollowNodeName() (string, error) {
selector, _ := labels.Parse(nodeGroupLabel)
nodes, err := kubemarkCluster.nodeLister.List(selector)
if err != nil {
return "", err
}
for _, node := range nodes {
return node.Name, nil
}
return "", fmt.Errorf("did not find any hollow nodes in the cluster")
}
func (kubemarkCluster *kubemarkCluster) removeUnneededNodes(oldObj interface{}, newObj interface{}) {
node, ok := newObj.(*apiv1.Node)
if !ok {
return
}
for _, condition := range node.Status.Conditions {
// Delete node if it is in unready state, and it has been
// explicitly marked for deletion.
if condition.Type == apiv1.NodeReady && condition.Status != apiv1.ConditionTrue {
kubemarkCluster.nodesToDeleteLock.Lock()
defer kubemarkCluster.nodesToDeleteLock.Unlock()
if kubemarkCluster.nodesToDelete[node.Name] {
kubemarkCluster.nodesToDelete[node.Name] = false
if err := kubemarkCluster.client.CoreV1().Nodes().Delete(context.TODO(), node.Name, metav1.DeleteOptions{}); err != nil {
klog.Errorf("failed to delete node %s from kubemark cluster, err: %v", node.Name, err)
}
}
return
}
}
}
func (kubemarkCluster *kubemarkCluster) markNodeForDeletion(name string) {
kubemarkCluster.nodesToDeleteLock.Lock()
defer kubemarkCluster.nodesToDeleteLock.Unlock()
kubemarkCluster.nodesToDelete[name] = true
}
func newReplicationControllerInformer(kubeClient kubeclient.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
rcListWatch := cache.NewListWatchFromClient(kubeClient.CoreV1().RESTClient(), "replicationcontrollers", namespaceKubemark, fields.Everything())
return cache.NewSharedIndexInformer(rcListWatch, &apiv1.ReplicationController{}, resyncPeriod, nil)
}
func newPodInformer(kubeClient kubeclient.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
podListWatch := cache.NewListWatchFromClient(kubeClient.CoreV1().RESTClient(), "pods", namespaceKubemark, fields.Everything())
return cache.NewSharedIndexInformer(podListWatch, &apiv1.Pod{}, resyncPeriod, nil)
}
-213
View File
@@ -1,213 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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 (
"context"
"fmt"
"time"
noopoteltrace "go.opentelemetry.io/otel/trace/noop"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
"k8s.io/mount-utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/record"
internalapi "k8s.io/cri-api/pkg/apis"
kubeletapp "k8s.io/kubernetes/cmd/kubelet/app"
"k8s.io/kubernetes/cmd/kubelet/app/options"
"k8s.io/kubernetes/pkg/kubelet"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
"k8s.io/kubernetes/pkg/kubelet/cm"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
probetest "k8s.io/kubernetes/pkg/kubelet/prober/testing"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
kubeletutil "k8s.io/kubernetes/pkg/kubelet/util"
"k8s.io/kubernetes/pkg/util/oom"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/configmap"
"k8s.io/kubernetes/pkg/volume/csi"
"k8s.io/kubernetes/pkg/volume/downwardapi"
"k8s.io/kubernetes/pkg/volume/emptydir"
"k8s.io/kubernetes/pkg/volume/fc"
"k8s.io/kubernetes/pkg/volume/git_repo"
"k8s.io/kubernetes/pkg/volume/hostpath"
"k8s.io/kubernetes/pkg/volume/iscsi"
"k8s.io/kubernetes/pkg/volume/local"
"k8s.io/kubernetes/pkg/volume/nfs"
"k8s.io/kubernetes/pkg/volume/projected"
"k8s.io/kubernetes/pkg/volume/secret"
"k8s.io/kubernetes/pkg/volume/util/hostutil"
"k8s.io/kubernetes/pkg/volume/util/subpath"
"k8s.io/kubernetes/test/utils"
)
type HollowKubelet struct {
KubeletFlags *options.KubeletFlags
KubeletConfiguration *kubeletconfig.KubeletConfiguration
KubeletDeps *kubelet.Dependencies
}
func volumePlugins() []volume.VolumePlugin {
allPlugins := []volume.VolumePlugin{}
allPlugins = append(allPlugins, emptydir.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, git_repo.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, hostpath.FakeProbeVolumePlugins(volume.VolumeConfig{})...)
allPlugins = append(allPlugins, nfs.ProbeVolumePlugins(volume.VolumeConfig{})...)
allPlugins = append(allPlugins, secret.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, configmap.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, projected.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, local.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
return allPlugins
}
func NewHollowKubelet(
flags *options.KubeletFlags,
config *kubeletconfig.KubeletConfiguration,
client *clientset.Clientset,
heartbeatClient *clientset.Clientset,
cadvisorInterface cadvisor.Interface,
imageService internalapi.ImageManagerService,
runtimeService internalapi.RuntimeService,
containerManager cm.ContainerManager) *HollowKubelet {
// Kubemark dependency construction does not have a higher-level logger.
nodeStartupLatencyTracker := kubeletutil.NewNodeStartupLatencyTracker(klog.TODO())
d := &kubelet.Dependencies{
KubeClient: client,
HeartbeatClient: heartbeatClient,
ProbeManager: probetest.FakeManager{},
RemoteRuntimeService: runtimeService,
RemoteImageService: imageService,
CAdvisorInterface: cadvisorInterface,
OSInterface: &containertest.FakeOS{},
ContainerManager: containerManager,
VolumePlugins: volumePlugins(),
TLSOptions: nil,
OOMAdjuster: oom.NewFakeOOMAdjuster(),
Mounter: &mount.FakeMounter{},
Subpather: &subpath.FakeSubpath{},
HostUtil: hostutil.NewFakeHostUtil(nil),
PodStartupLatencyTracker: kubeletutil.NewPodStartupLatencyTracker(),
NodeStartupLatencyTracker: nodeStartupLatencyTracker,
TracerProvider: noopoteltrace.NewTracerProvider(),
Recorder: &record.FakeRecorder{}, // With real recorder we attempt to read /dev/kmsg.
}
return &HollowKubelet{
KubeletFlags: flags,
KubeletConfiguration: config,
KubeletDeps: d,
}
}
// Starts this HollowKubelet and blocks.
func (hk *HollowKubelet) Run(ctx context.Context) {
if err := kubeletapp.RunKubelet(ctx, &options.KubeletServer{
KubeletFlags: *hk.KubeletFlags,
KubeletConfiguration: *hk.KubeletConfiguration,
}, hk.KubeletDeps); err != nil {
klog.Fatalf("Failed to run HollowKubelet: %v. Exiting.", err)
}
select {}
}
// HollowKubeletOptions contains settable parameters for hollow kubelet.
type HollowKubeletOptions struct {
NodeName string
KubeletPort int
KubeletReadOnlyPort int
MaxPods int
PodsPerCore int
NodeLabels map[string]string
RegisterWithTaints []v1.Taint
}
// Builds a KubeletConfiguration for the HollowKubelet, ensuring that the
// usual defaults are applied for fields we do not override.
func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, *kubeletconfig.KubeletConfiguration) {
testRootDir := utils.MakeTempDirOrDie("hollow-kubelet.", "")
podFilePath := utils.MakeTempDirOrDie("static-pods", testRootDir)
podLogsPath := utils.MakeTempDirOrDie("pod-logs", testRootDir)
klog.Infof("Using %s as root dir for hollow-kubelet", testRootDir)
// Flags struct
f := options.NewKubeletFlags()
f.RootDirectory = testRootDir
f.HostnameOverride = opt.NodeName
f.MinimumGCAge = metav1.Duration{Duration: 1 * time.Minute}
f.MaxContainerCount = 100
f.MaxPerPodContainerCount = 2
f.NodeLabels = opt.NodeLabels
// Config struct
c, err := options.NewKubeletConfiguration()
if err != nil {
panic(err)
}
c.ImageServiceEndpoint = "unix:///run/containerd/containerd.sock"
c.StaticPodURL = ""
c.EnableServer = true
c.Address = "0.0.0.0" /* bind address */
c.Port = int32(opt.KubeletPort)
c.ReadOnlyPort = int32(opt.KubeletReadOnlyPort)
c.StaticPodPath = podFilePath
c.FileCheckFrequency.Duration = 20 * time.Second
c.HTTPCheckFrequency.Duration = 20 * time.Second
c.NodeStatusUpdateFrequency.Duration = 10 * time.Second
c.NodeStatusReportFrequency.Duration = 5 * time.Minute
c.SyncFrequency.Duration = 10 * time.Second
c.EvictionPressureTransitionPeriod.Duration = 5 * time.Minute
c.MaxPods = int32(opt.MaxPods)
c.PodsPerCore = int32(opt.PodsPerCore)
c.ClusterDNS = []string{}
c.ImageGCHighThresholdPercent = 90
c.ImageGCLowThresholdPercent = 80
c.ProviderID = fmt.Sprintf("kubemark://%v", opt.NodeName)
c.VolumeStatsAggPeriod.Duration = time.Minute
c.CgroupRoot = ""
c.CPUCFSQuota = true
c.EnableControllerAttachDetach = false
c.EnableDebuggingHandlers = true
c.CgroupsPerQOS = false
// hairpin-veth is used to allow hairpin packets. Note that this deviates from
// what the "real" kubelet currently does, because there's no way to
// set promiscuous mode on docker0.
c.HairpinMode = kubeletconfig.HairpinVeth
c.MaxOpenFiles = 1024
c.RegistryBurst = 10
c.RegistryPullQPS = 5.0
c.ResolverConfig = kubetypes.ResolvConfDefault
c.KubeletCgroups = "/kubelet"
c.SerializeImagePulls = true
c.SystemCgroups = ""
c.ProtectKernelDefaults = false
c.RegisterWithTaints = opt.RegisterWithTaints
c.RegisterNode = true
c.LocalStorageCapacityIsolation = true
c.PodLogsDir = podLogsPath
return f, c
}
-6
View File
@@ -1,6 +0,0 @@
rules:
# override pkg/ import restriction on cmd/ for kubemark
- selectorRegexp: k8s[.]io/kubernetes/cmd
allowedPrefixes:
- k8s.io/kubernetes/cmd/kube-proxy/app
-14
View File
@@ -1,14 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- shyamjvs
- sig-scalability-reviewers
- wojtek-t
approvers:
- shyamjvs
- sig-scalability-approvers
- wojtek-t
emeritus_approvers:
- gmarek
labels:
- sig/scalability
-93
View File
@@ -1,93 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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 (
"context"
"fmt"
"time"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/events"
proxyapp "k8s.io/kubernetes/cmd/kube-proxy/app"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
"k8s.io/utils/ptr"
)
type HollowProxy struct {
ProxyServer *proxyapp.ProxyServer
}
type FakeProxier struct{}
func (*FakeProxier) Sync() {}
func (*FakeProxier) SyncLoop() {
select {}
}
func (*FakeProxier) OnServiceAdd(service *v1.Service) {}
func (*FakeProxier) OnServiceUpdate(oldService, service *v1.Service) {}
func (*FakeProxier) OnServiceDelete(service *v1.Service) {}
func (*FakeProxier) OnServiceSynced() {}
func (*FakeProxier) OnEndpointSliceAdd(slice *discoveryv1.EndpointSlice) {}
func (*FakeProxier) OnEndpointSliceUpdate(oldSlice, slice *discoveryv1.EndpointSlice) {}
func (*FakeProxier) OnEndpointSliceDelete(slice *discoveryv1.EndpointSlice) {}
func (*FakeProxier) OnEndpointSlicesSynced() {}
func (*FakeProxier) OnServiceCIDRsChanged(_ []string) {}
func (*FakeProxier) OnTopologyChange(_ map[string]string) {}
func NewHollowProxy(
nodeName string,
client clientset.Interface,
eventClient v1core.EventsGetter,
broadcaster events.EventBroadcaster,
recorder events.EventRecorder,
) *HollowProxy {
return &HollowProxy{
ProxyServer: &proxyapp.ProxyServer{
Config: &kubeproxyconfig.KubeProxyConfiguration{
Mode: kubeproxyconfig.ProxyMode("fake"),
ConfigSyncPeriod: metav1.Duration{Duration: 30 * time.Second},
Linux: kubeproxyconfig.KubeProxyLinuxConfiguration{
OOMScoreAdj: ptr.To[int32](0),
},
},
Client: client,
Proxier: &FakeProxier{},
Broadcaster: broadcaster,
Recorder: recorder,
NodeRef: &v1.ObjectReference{
APIVersion: "v1",
Kind: "Node",
Name: nodeName,
Namespace: "",
},
},
}
}
func (hp *HollowProxy) Run() error {
if err := hp.ProxyServer.Run(context.TODO()); err != nil {
return fmt.Errorf("Error while running proxy: %w", err)
}
return nil
}
+1 -1
View File
@@ -261,7 +261,7 @@ func verifyRemainingObjects(ctx context.Context, f *framework.Framework, objects
func gatherMetrics(ctx context.Context, f *framework.Framework) {
ginkgo.By("Gathering metrics")
var summary framework.TestDataSummary
grabber, err := e2emetrics.NewMetricsGrabber(ctx, f.ClientSet, f.KubemarkExternalClusterClientSet, f.ClientConfig(), false, false, true, false, false, false)
grabber, err := e2emetrics.NewMetricsGrabber(ctx, f.ClientSet, f.ClientConfig(), false, false, true, false, false, false)
if err != nil {
framework.Logf("Failed to create MetricsGrabber. Skipping metrics gathering.")
} else {
-1
View File
@@ -69,7 +69,6 @@ func init() {
}
gatherer, err := e2edebug.NewResourceUsageGatherer(ctx, f.ClientSet, e2edebug.ResourceGathererOptions{
InKubemark: framework.ProviderIs("kubemark"),
Nodes: nodeMode,
ResourceDataGatheringPeriod: 60 * time.Second,
ProbeDuration: 15 * time.Second,
@@ -17,7 +17,6 @@ limitations under the License.
package debug
import (
"bufio"
"bytes"
"context"
"encoding/json"
@@ -40,7 +39,6 @@ import (
kubeletstatsv1alpha1 "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
"k8s.io/kubernetes/test/e2e/framework"
e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
"k8s.io/utils/ptr"
)
@@ -177,7 +175,6 @@ type resourceGatherWorker struct {
stopCh chan struct{}
dataSeries []ResourceUsagePerContainer
finished bool
inKubemark bool
resourceDataGatheringPeriod time.Duration
probeDuration time.Duration
printVerboseLogs bool
@@ -185,29 +182,15 @@ type resourceGatherWorker struct {
func (w *resourceGatherWorker) singleProbe(ctx context.Context) {
data := make(ResourceUsagePerContainer)
if w.inKubemark {
kubemarkData := getKubemarkMasterComponentsResourceUsage(ctx)
if kubemarkData == nil {
return
}
for k, v := range kubemarkData {
data[k] = &ContainerResourceUsage{
Name: v.Name,
MemoryWorkingSetInBytes: v.MemoryWorkingSetInBytes,
CPUUsageInCores: v.CPUUsageInCores,
}
}
} else {
nodeUsage, err := getOneTimeResourceUsageOnNode(w.c, w.nodeName, w.probeDuration, func() []string { return w.containerIDs })
if err != nil {
framework.Logf("Error while reading data from %v: %v", w.nodeName, err)
return
}
for k, v := range nodeUsage {
data[k] = v
if w.printVerboseLogs {
framework.Logf("Get container %v usage on node %v. CPUUsageInCores: %v, MemoryUsageInBytes: %v, MemoryWorkingSetInBytes: %v", k, w.nodeName, v.CPUUsageInCores, v.MemoryUsageInBytes, v.MemoryWorkingSetInBytes)
}
nodeUsage, err := getOneTimeResourceUsageOnNode(w.c, w.nodeName, w.probeDuration, func() []string { return w.containerIDs })
if err != nil {
framework.Logf("Error while reading data from %v: %v", w.nodeName, err)
return
}
for k, v := range nodeUsage {
data[k] = v
if w.printVerboseLogs {
framework.Logf("Get container %v usage on node %v. CPUUsageInCores: %v, MemoryUsageInBytes: %v, MemoryWorkingSetInBytes: %v", k, w.nodeName, v.CPUUsageInCores, v.MemoryUsageInBytes, v.MemoryWorkingSetInBytes)
}
}
w.dataSeries = append(w.dataSeries, data)
@@ -351,7 +334,6 @@ type ContainerResourceGatherer struct {
// ResourceGathererOptions is a struct to hold options for resource.
type ResourceGathererOptions struct {
InKubemark bool
Nodes NodesSet
ResourceDataGatheringPeriod time.Duration
ProbeDuration time.Duration
@@ -402,20 +384,6 @@ func NewResourceUsageGatherer(ctx context.Context, c clientset.Interface, option
options: options,
}
if options.InKubemark {
g.workerWg.Add(1)
g.workers = append(g.workers, resourceGatherWorker{
inKubemark: true,
stopCh: g.stopCh,
wg: &g.workerWg,
finished: false,
resourceDataGatheringPeriod: options.ResourceDataGatheringPeriod,
probeDuration: options.ProbeDuration,
printVerboseLogs: options.PrintVerboseLogs,
})
return &g, nil
}
// Tracks kube-system pods if no valid PodList is passed in.
var err error
if pods == nil {
@@ -475,7 +443,6 @@ func NewResourceUsageGatherer(ctx context.Context, c clientset.Interface, option
containerIDs: g.containerIDs,
stopCh: g.stopCh,
finished: false,
inKubemark: false,
resourceDataGatheringPeriod: options.ResourceDataGatheringPeriod,
probeDuration: options.ProbeDuration,
printVerboseLogs: options.PrintVerboseLogs,
@@ -594,65 +561,3 @@ func (g *ContainerResourceGatherer) StopAndSummarize(percentiles []int, constrai
}
return &summary, nil
}
// kubemarkResourceUsage is a struct for tracking the resource usage of kubemark.
type kubemarkResourceUsage struct {
Name string
MemoryWorkingSetInBytes uint64
CPUUsageInCores float64
}
func getMasterUsageByPrefix(ctx context.Context, prefix string) (string, error) {
sshResult, err := e2essh.SSH(ctx, fmt.Sprintf("ps ax -o %%cpu,rss,command | tail -n +2 | grep %v | sed 's/\\s+/ /g'", prefix), framework.APIAddress()+":22", framework.TestContext.Provider)
if err != nil {
return "", err
}
return sshResult.Stdout, nil
}
// getKubemarkMasterComponentsResourceUsage returns the resource usage of kubemark which contains multiple combinations of cpu and memory usage for each pod name.
func getKubemarkMasterComponentsResourceUsage(ctx context.Context) map[string]*kubemarkResourceUsage {
result := make(map[string]*kubemarkResourceUsage)
// Get kubernetes component resource usage
sshResult, err := getMasterUsageByPrefix(ctx, "kube")
if err != nil {
framework.Logf("Error when trying to SSH to master machine. Skipping probe. %v", err)
return nil
}
scanner := bufio.NewScanner(strings.NewReader(sshResult))
for scanner.Scan() {
var cpu float64
var mem uint64
var name string
fmt.Sscanf(strings.TrimSpace(scanner.Text()), "%f %d /usr/local/bin/kube-%s", &cpu, &mem, &name)
if name != "" {
// Gatherer expects pod_name/container_name format
fullName := name + "/" + name
result[fullName] = &kubemarkResourceUsage{Name: fullName, MemoryWorkingSetInBytes: mem * 1024, CPUUsageInCores: cpu / 100}
}
}
// Get etcd resource usage
sshResult, err = getMasterUsageByPrefix(ctx, "bin/etcd")
if err != nil {
framework.Logf("Error when trying to SSH to master machine. Skipping probe")
return nil
}
scanner = bufio.NewScanner(strings.NewReader(sshResult))
for scanner.Scan() {
var cpu float64
var mem uint64
var etcdKind string
fmt.Sscanf(strings.TrimSpace(scanner.Text()), "%f %d /bin/sh -c /usr/local/bin/etcd", &cpu, &mem)
dataDirStart := strings.Index(scanner.Text(), "--data-dir")
if dataDirStart < 0 {
continue
}
fmt.Sscanf(scanner.Text()[dataDirStart:], "--data-dir=/var/%s", &etcdKind)
if etcdKind != "" {
// Gatherer expects pod_name/container_name format
fullName := "etcd/" + etcdKind
result[fullName] = &kubemarkResourceUsage{Name: fullName, MemoryWorkingSetInBytes: mem * 1024, CPUUsageInCores: cpu / 100}
}
}
return result
}
+3 -4
View File
@@ -114,10 +114,9 @@ type Framework struct {
// test multiple times in parallel.
UniqueName string
clientConfig *rest.Config
restMapper *restmapper.DeferredDiscoveryRESTMapper
ClientSet clientset.Interface
KubemarkExternalClusterClientSet clientset.Interface
clientConfig *rest.Config
restMapper *restmapper.DeferredDiscoveryRESTMapper
ClientSet clientset.Interface
DynamicClient dynamic.Interface
+3 -3
View File
@@ -31,7 +31,7 @@ func GrabBeforeEach(ctx context.Context, f *framework.Framework) (result *Collec
}
ginkgo.By("Gathering metrics before test", func() {
grabber, err := NewMetricsGrabber(ctx, f.ClientSet, f.KubemarkExternalClusterClientSet, f.ClientConfig(), !framework.ProviderIs("kubemark"), false, false, false, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
grabber, err := NewMetricsGrabber(ctx, f.ClientSet, f.ClientConfig(), true, false, false, false, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
if err != nil {
framework.Logf("Failed to create MetricsGrabber (skipping ClusterAutoscaler metrics gathering before test): %v", err)
return
@@ -55,8 +55,8 @@ func GrabAfterEach(ctx context.Context, f *framework.Framework, before *Collecti
ginkgo.By("Gathering metrics after test", func() {
// Grab apiserver, scheduler, controller-manager metrics and (optionally) nodes' kubelet metrics.
grabMetricsFromKubelets := framework.TestContext.GatherMetricsAfterTest != "master" && !framework.ProviderIs("kubemark")
grabber, err := NewMetricsGrabber(ctx, f.ClientSet, f.KubemarkExternalClusterClientSet, f.ClientConfig(), grabMetricsFromKubelets, true, true, true, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
grabMetricsFromKubelets := framework.TestContext.GatherMetricsAfterTest != "master"
grabber, err := NewMetricsGrabber(ctx, f.ClientSet, f.ClientConfig(), grabMetricsFromKubelets, true, true, true, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
if err != nil {
framework.Logf("Failed to create MetricsGrabber (skipping metrics gathering): %v", err)
return
@@ -118,7 +118,7 @@ func getKubeletMetricsFromNode(ctx context.Context, c clientset.Interface, nodeN
if c == nil {
return GrabKubeletMetricsWithoutProxy(ctx, nodeName, "/metrics")
}
grabber, err := NewMetricsGrabber(ctx, c, nil, nil, true, false, false, false, false, false)
grabber, err := NewMetricsGrabber(ctx, c, nil, true, false, false, false, false, false)
if err != nil {
return KubeletMetrics{}, err
}
+3 -17
View File
@@ -70,7 +70,6 @@ type Collection struct {
// Grabber provides functions which grab metrics from components
type Grabber struct {
client clientset.Interface
externalClient clientset.Interface
config *rest.Config
grabFromAPIServer bool
grabFromControllerManager bool
@@ -94,7 +93,7 @@ type Grabber struct {
// Collecting metrics data is an optional debug feature. Not all clusters will
// support it. If disabled for a component, the corresponding Grab function
// will immediately return an error derived from MetricsGrabbingDisabledError.
func NewMetricsGrabber(ctx context.Context, c clientset.Interface, ec clientset.Interface, config *rest.Config, kubelets bool, scheduler bool, controllers bool, apiServer bool, clusterAutoscaler bool, snapshotController bool) (*Grabber, error) {
func NewMetricsGrabber(ctx context.Context, c clientset.Interface, config *rest.Config, kubelets bool, scheduler bool, controllers bool, apiServer bool, clusterAutoscaler bool, snapshotController bool) (*Grabber, error) {
kubeScheduler := ""
kubeControllerManager := ""
snapshotControllerManager := ""
@@ -128,13 +127,9 @@ func NewMetricsGrabber(ctx context.Context, c clientset.Interface, ec clientset.
break
}
}
if clusterAutoscaler && ec == nil {
klog.Warningf("Did not receive an external client interface. Grabbing metrics from ClusterAutoscaler is disabled.")
}
return &Grabber{
client: c,
externalClient: ec,
config: config,
grabFromAPIServer: apiServer,
grabFromControllerManager: checkPodDebugHandlers(ctx, c, controllers, "kube-controller-manager", kubeControllerManager),
@@ -309,19 +304,10 @@ func (g *Grabber) GrabFromScheduler(ctx context.Context) (SchedulerMetrics, erro
// GrabFromClusterAutoscaler returns metrics from cluster autoscaler
func (g *Grabber) GrabFromClusterAutoscaler(ctx context.Context) (ClusterAutoscalerMetrics, error) {
if !g.HasControlPlanePods() && g.externalClient == nil {
if !g.HasControlPlanePods() {
return ClusterAutoscalerMetrics{}, fmt.Errorf("ClusterAutoscaler: %w", MetricsGrabbingDisabledError)
}
var client clientset.Interface
var namespace string
if g.externalClient != nil {
client = g.externalClient
namespace = "kubemark"
} else {
client = g.client
namespace = metav1.NamespaceSystem
}
output, err := g.getMetricsFromPod(ctx, client, "cluster-autoscaler", namespace, 8085)
output, err := g.getMetricsFromPod(ctx, g.client, "cluster-autoscaler", metav1.NamespaceSystem, 8085)
if err != nil {
return ClusterAutoscalerMetrics{}, err
}
@@ -1,9 +0,0 @@
# This E2E framework sub-package is currently allowed to use arbitrary
# dependencies, therefore we need to override the restrictions from
# the parent .import-restrictions file.
#
# At some point it may become useful to also check this package's
# dependencies more careful.
rules:
- selectorRegexp: ""
allowedPrefixes: [ "" ]
@@ -1,97 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
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 (
"flag"
"fmt"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubemark"
"k8s.io/kubernetes/test/e2e/framework"
)
var (
kubemarkExternalKubeConfig = flag.String(fmt.Sprintf("%s-%s", "kubemark-external", clientcmd.RecommendedConfigPathFlag), "", "Path to kubeconfig containing embedded authinfo for external cluster.")
)
func init() {
framework.RegisterProvider("kubemark", newProvider)
}
func newProvider() (framework.ProviderInterface, error) {
// Actual initialization happens when the e2e framework gets constructed.
return &Provider{}, nil
}
// Provider is a structure to handle Kubemark cluster for e2e testing
type Provider struct {
framework.NullProvider
controller *kubemark.KubemarkController
closeChannel chan struct{}
}
// ResizeGroup resizes an instance group
func (p *Provider) ResizeGroup(group string, size int32) error {
return p.controller.SetNodeGroupSize(group, int(size))
}
// GetGroupNodes returns a node name for the specified node group
func (p *Provider) GetGroupNodes(group string) ([]string, error) {
return p.controller.GetNodeNamesForNodeGroup(group)
}
// FrameworkBeforeEach prepares clients, configurations etc. for e2e testing
func (p *Provider) FrameworkBeforeEach(f *framework.Framework) {
if *kubemarkExternalKubeConfig != "" && p.controller == nil {
externalConfig, err := clientcmd.BuildConfigFromFlags("", *kubemarkExternalKubeConfig)
externalConfig.QPS = f.Options.ClientQPS
externalConfig.Burst = f.Options.ClientBurst
framework.ExpectNoError(err)
externalClient, err := clientset.NewForConfig(externalConfig)
framework.ExpectNoError(err)
f.KubemarkExternalClusterClientSet = externalClient
p.closeChannel = make(chan struct{})
externalInformerFactory := informers.NewSharedInformerFactory(externalClient, 0)
kubemarkInformerFactory := informers.NewSharedInformerFactory(f.ClientSet, 0)
kubemarkNodeInformer := kubemarkInformerFactory.Core().V1().Nodes()
go kubemarkNodeInformer.Informer().Run(p.closeChannel)
p.controller, err = kubemark.NewKubemarkController(externalClient, externalInformerFactory, f.ClientSet, kubemarkNodeInformer)
framework.ExpectNoError(err)
externalInformerFactory.Start(p.closeChannel)
if !p.controller.WaitForCacheSync(p.closeChannel) {
framework.Failf("Unable to sync caches for %v", p.controller)
}
go p.controller.Run(p.closeChannel)
}
}
// FrameworkAfterEach cleans up after e2e testing
func (p *Provider) FrameworkAfterEach(f *framework.Framework) {
if p.closeChannel != nil {
close(p.closeChannel)
p.controller = nil
p.closeChannel = nil
}
}
// GroupSize returns the size of an instance group
func (p *Provider) GroupSize(group string) (int, error) {
return p.controller.GetNodeGroupSize(group)
}
+1 -1
View File
@@ -66,7 +66,7 @@ func GetSigner(provider string) (ssh.Signer, error) {
// support.
keyfile := ""
switch provider {
case "gce", "kubemark":
case "gce":
keyfile = os.Getenv("GCE_SSH_KEY")
if keyfile == "" {
keyfile = os.Getenv("GCE_SSH_PRIVATE_KEY_FILE")
+2 -3
View File
@@ -36,14 +36,13 @@ import (
var _ = common.SIGDescribe("Metrics", func() {
f := framework.NewDefaultFramework("metrics")
f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
var c, ec clientset.Interface
var c clientset.Interface
var grabber *e2emetrics.Grabber
ginkgo.BeforeEach(func(ctx context.Context) {
var err error
c = f.ClientSet
ec = f.KubemarkExternalClusterClientSet
gomega.Eventually(ctx, func() error {
grabber, err = e2emetrics.NewMetricsGrabber(ctx, c, ec, f.ClientConfig(), true, true, true, true, true, true)
grabber, err = e2emetrics.NewMetricsGrabber(ctx, c, f.ClientConfig(), true, true, true, true, true, true)
return err
}, 5*time.Minute, 10*time.Second).Should(gomega.BeNil())
})
@@ -37,14 +37,13 @@ import (
var _ = instrumentation.SIGDescribe("MetricsGrabber", func() {
f := framework.NewDefaultFramework("metrics-grabber")
f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
var c, ec clientset.Interface
var c clientset.Interface
var grabber *e2emetrics.Grabber
ginkgo.BeforeEach(func(ctx context.Context) {
var err error
c = f.ClientSet
ec = f.KubemarkExternalClusterClientSet
gomega.Eventually(ctx, func() error {
grabber, err = e2emetrics.NewMetricsGrabber(ctx, c, ec, f.ClientConfig(), true, true, true, true, true, true)
grabber, err = e2emetrics.NewMetricsGrabber(ctx, c, f.ClientConfig(), true, true, true, true, true, true)
if err != nil {
return fmt.Errorf("failed to create metrics grabber: %w", err)
}
+1 -1
View File
@@ -291,7 +291,7 @@ var _ = common.SIGDescribe("KubeProxy", func() {
nodeName := nodes.Items[0].Name
metricName := "kubeproxy_iptables_localhost_nodeports_accepted_packets_total"
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, fr.ClientSet, nil, fr.ClientConfig(), false, false, false, false, false, false)
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, fr.ClientSet, fr.ClientConfig(), false, false, false, false, false, false)
framework.ExpectNoError(err)
// create a pod with host-network for execing
-1
View File
@@ -21,7 +21,6 @@ import (
_ "k8s.io/kubernetes/test/e2e/framework/providers/aws"
_ "k8s.io/kubernetes/test/e2e/framework/providers/azure"
_ "k8s.io/kubernetes/test/e2e/framework/providers/gce"
_ "k8s.io/kubernetes/test/e2e/framework/providers/kubemark"
_ "k8s.io/kubernetes/test/e2e/framework/providers/openstack"
_ "k8s.io/kubernetes/test/e2e/framework/providers/vsphere"
)
@@ -808,7 +808,7 @@ var _ = utils.SIGDescribe("CSI Mock selinux on mount metrics and SELinuxWarningC
// Some metrics use CSI driver name as a label, which is "csi-mock-" + the namespace name.
volumePluginLabel := "volume_plugin=\"kubernetes.io/csi/csi-mock-" + f.Namespace.Name + "\""
grabber, err := e2emetrics.NewMetricsGrabber(ctx, f.ClientSet, nil, f.ClientConfig(), true /*kubelet*/, false /*scheduler*/, true /*controllers*/, false /*apiserver*/, false /*autoscaler*/, false /*snapshotController*/)
grabber, err := e2emetrics.NewMetricsGrabber(ctx, f.ClientSet, f.ClientConfig(), true /*kubelet*/, false /*scheduler*/, true /*controllers*/, false /*apiserver*/, false /*autoscaler*/, false /*snapshotController*/)
framework.ExpectNoError(err, "creating the metrics grabber")
var nodeStageMountOpts, nodePublishMountOpts []string
+1 -1
View File
@@ -310,7 +310,7 @@ var _ = utils.SIGDescribe("CSI Mock volume snapshot", func() {
}
ginkgo.DeferCleanup(m.cleanup)
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, m.config.Framework.ClientSet, nil, f.ClientConfig(), false, false, false, false, false, true)
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, m.config.Framework.ClientSet, f.ClientConfig(), false, false, false, false, false, true)
if err != nil {
framework.Failf("Error creating metrics grabber : %v", err)
}
+1 -1
View File
@@ -125,7 +125,7 @@ func getVolumeOpCounts(ctx context.Context, c clientset.Interface, config *rest.
nodeLimit := 25
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, c, nil, config, true, false, true, false, false, false)
metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, c, config, true, false, true, false, false, false)
if err != nil {
framework.ExpectNoError(err, "Error creating metrics grabber: %v", err)
+1 -1
View File
@@ -124,7 +124,7 @@ var _ = utils.SIGDescribe("Volume metrics", func() {
VolumeMode: ptr.To(v1.PersistentVolumeBlock),
}, ns)
metricsGrabber, err = e2emetrics.NewMetricsGrabber(ctx, c, nil, f.ClientConfig(), true, false, true, false, false, false)
metricsGrabber, err = e2emetrics.NewMetricsGrabber(ctx, c, f.ClientConfig(), true, false, true, false, false, false)
if err != nil {
framework.Failf("Error creating metrics grabber : %v", err)
+2 -2
View File
@@ -54,8 +54,8 @@ func gatherTestSuiteMetrics(ctx context.Context) error {
return fmt.Errorf("error creating client: %w", err)
}
// Grab metrics for apiserver, scheduler, controller-manager, kubelet (for non-kubemark case) and cluster autoscaler (optionally).
grabber, err := e2emetrics.NewMetricsGrabber(ctx, c, nil, config, !framework.ProviderIs("kubemark"), true, true, true, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
// Grab metrics for apiserver, scheduler, controller-manager, kubelet and cluster autoscaler (optionally).
grabber, err := e2emetrics.NewMetricsGrabber(ctx, c, config, true, true, true, true, framework.TestContext.IncludeClusterAutoscalerMetrics, false)
if err != nil {
return fmt.Errorf("failed to create MetricsGrabber: %w", err)
}
-13
View File
@@ -1,13 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- sig-scalability-reviewers
- wojtek-t
approvers:
- sig-scalability-approvers
- wojtek-t
emeritus_approvers:
- gmarek
- shyamjvs
labels:
- sig/scalability
-21
View File
@@ -1,21 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
CLOUD_PROVIDER="${CLOUD_PROVIDER:-gce}"
CONTAINER_REGISTRY="${CONTAINER_REGISTRY:-gcr.io}"
PROJECT="${PROJECT:-}"
KUBEMARK_IMAGE_REGISTRY="${KUBEMARK_IMAGE_REGISTRY:-}"
KUBEMARK_IMAGE_MAKE_TARGET="${KUBEMARK_IMAGE_MAKE_TARGET:-gcloudpush}"
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
# Running cmd $RETRIES times in case of failures.
function run-cmd-with-retries {
RETRIES="${RETRIES:-3}"
for attempt in $(seq 1 "${RETRIES}"); do
local ret_val=0
exec 5>&1 # Duplicate &1 to &5 for use below.
# We don't use 'local' to declare result as then ret_val always gets value 0.
# We use tee to output to &5 (redirected to stdout) while also storing it in the variable.
result=$("$@" 2>&1 | tee >(cat - >&5)) || ret_val="$?"
if [[ "${ret_val:-0}" -ne "0" ]]; then
if [[ $(echo "${result}" | grep -c "already exists") -gt 0 ]]; then
if [[ "${attempt}" == 1 ]]; then
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_red}Failed to $1 $2 ${3:-} as the resource hasn't been deleted from a previous run.${color_norm}" >& 2
exit 1
fi
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_yellow}Succeeded to $1 $2 ${3:-} in the previous attempt, but status response wasn't received.${color_norm}"
return 0
fi
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_yellow}Attempt $attempt failed to $1 $2 ${3:-}. Retrying.${color_norm}" >& 2
sleep $((attempt * 5))
else
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_green}Succeeded to $1 $2 ${3:-}.${color_norm}"
return 0
fi
done
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_red}Failed to $1 $2 ${3:-}.${color_norm}" >& 2
exit 1
}
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 The Kubernetes Authors.
#
# 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.
# This script assumes that kubectl binary is present in PATH.
kubectl config set-cluster hollow-cluster --server=http://localhost:8080 --insecure-skip-tls-verify=true
kubectl config set-credentials "$(whoami)"
kubectl config set-context hollow-context --cluster=hollow-cluster --user="$(whoami)"
-137
View File
@@ -1,137 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../../..
source "${KUBE_ROOT}/test/kubemark/common/util.sh"
# Wrapper for gcloud compute, running it $RETRIES times in case of failures.
# Args:
# $@: all stuff that goes after 'gcloud compute'
function run-gcloud-compute-with-retries {
run-cmd-with-retries gcloud compute "$@"
}
function authenticate-docker {
echo "Configuring registry authentication"
mkdir -p "${HOME}/.docker"
gcloud beta auth configure-docker -q
}
function create-kubemark-master {
# We intentionally override env vars in subshell to preserve original values.
# shellcheck disable=SC2030,SC2031
(
# All calls to e2e-grow-cluster must share temp dir with initial e2e-up.sh.
kube::util::ensure-temp-dir
export KUBE_TEMP="${KUBE_TEMP}"
export KUBECONFIG="${RESOURCE_DIRECTORY}/kubeconfig.kubemark"
export KUBECONFIG_INTERNAL="${RESOURCE_DIRECTORY}/kubeconfig-internal.kubemark"
export CLUSTER_NAME="${CLUSTER_NAME}-kubemark"
export KUBE_CREATE_NODES=false
export KUBE_GCE_INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX}-kubemark"
# Quite tricky cidr setup: we set KUBE_GCE_ENABLE_IP_ALIASES=true to avoid creating
# cloud routes and RangeAllocator to assign cidrs by kube-controller-manager.
export KUBE_GCE_ENABLE_IP_ALIASES=true
export KUBE_GCE_NODE_IPAM_MODE=RangeAllocator
# Disable all addons. They are running outside of the kubemark cluster.
export KUBE_ENABLE_CLUSTER_AUTOSCALER=false
export KUBE_ENABLE_CLUSTER_DNS=false
export KUBE_ENABLE_NODE_LOGGING=false
export KUBE_ENABLE_METRICS_SERVER=false
export KUBE_ENABLE_L7_LOADBALANCING="none"
# Unset env variables set by kubetest for 'root cluster'. We need recompute them
# for kubemark master.
# TODO(mborsz): Figure out some better way to filter out such env variables than
# listing them here.
unset MASTER_SIZE MASTER_DISK_SIZE MASTER_ROOT_DISK_SIZE
# Set kubemark-specific overrides:
# for each defined env KUBEMARK_X=Y call export X=Y.
for var in ${!KUBEMARK_*}; do
dst_var=${var#KUBEMARK_}
val=${!var}
echo "Setting ${dst_var} to '${val}'"
export "${dst_var}"="${val}"
done
"${KUBE_ROOT}/hack/e2e-internal/e2e-up.sh"
if [[ "${KUBEMARK_HA_MASTER:-}" == "true" && -n "${KUBEMARK_MASTER_ADDITIONAL_ZONES:-}" ]]; then
for KUBE_GCE_ZONE in ${KUBEMARK_MASTER_ADDITIONAL_ZONES}; do
KUBE_GCE_ZONE="${KUBE_GCE_ZONE}" KUBE_REPLICATE_EXISTING_MASTER=true \
"${KUBE_ROOT}/hack/e2e-internal/e2e-grow-cluster.sh"
done
fi
# The e2e-up.sh script is not sourced, so we don't have access to variables that
# it sets. Instead, we read data which was written to the KUBE_TEMP directory.
# The cluster-location is either ZONE (say us-east1-a) or REGION (say us-east1).
# To get REGION from location, only first two parts are matched.
REGION=$(grep -o "^[a-z]*-[a-z0-9]*" "${KUBE_TEMP}"/cluster-location.txt)
MASTER_NAME="${KUBE_GCE_INSTANCE_PREFIX}"-master
if [[ ${GCE_PRIVATE_CLUSTER:-} == "true" ]]; then
MASTER_INTERNAL_IP=$(gcloud compute addresses describe "${MASTER_NAME}-internal-ip" \
--project "${PROJECT}" --region "${REGION}" -q --format='value(address)')
fi
MASTER_IP=$(gcloud compute addresses describe "${MASTER_NAME}-ip" \
--project "${PROJECT}" --region "${REGION}" -q --format='value(address)')
# If cluster uses private master IP, two kubeconfigs are created:
# - kubeconfig with public IP, which will be used to connect to the cluster
# from outside of the cluster network
# - kubeconfig with private IP (called internal kubeconfig), which will be
# used to create hollow nodes.
#
# Note that hollow nodes might use either of these kubeconfigs, but
# using internal one is better from performance and cost perspective, since
# traffic does not need to go through Cloud NAT.
if [[ -n "${MASTER_INTERNAL_IP:-}" ]]; then
echo "Writing internal kubeconfig to '${KUBECONFIG_INTERNAL}'"
ip_regexp=${MASTER_IP//./\\.} # escape ".", so that sed won't treat it as "any char"
sed "s/${ip_regexp}/${MASTER_INTERNAL_IP}/g" "${KUBECONFIG}" > "${KUBECONFIG_INTERNAL}"
fi
)
}
function delete-kubemark-master {
# We intentionally override env vars in subshell to preserve original values.
# shellcheck disable=SC2030,SC2031
(
export CLUSTER_NAME="${CLUSTER_NAME}-kubemark"
export KUBE_GCE_INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX}-kubemark"
export KUBE_DELETE_NETWORK=false
if [[ "${KUBEMARK_HA_MASTER:-}" == "true" && -n "${KUBEMARK_MASTER_ADDITIONAL_ZONES:-}" ]]; then
for KUBE_GCE_ZONE in ${KUBEMARK_MASTER_ADDITIONAL_ZONES}; do
KUBE_GCE_ZONE="${KUBE_GCE_ZONE}" KUBE_REPLICATE_EXISTING_MASTER=true \
"${KUBE_ROOT}/hack/e2e-internal/e2e-shrink-cluster.sh"
done
fi
"${KUBE_ROOT}/hack/e2e-internal/e2e-down.sh"
)
}
function calculate-node-labels {
echo "cloud.google.com/metadata-proxy-ready=true"
}
-54
View File
@@ -1,54 +0,0 @@
# Kubemark Pre-existing Provider Guide
**Kubemark Master**
- A set of Kubernetes control plane components running in a VM
**Kubernetes Cluster**
- A real Kubernetes Cluster that has master and nodes. The hollow-node pods
are run in this cluster, but appear as nodes to the Kubemark Master
## Introduction
Every running Kubemark setup looks like the following:
1) A running Kubernetes cluster pointed to by the local kubeconfig
2) A separate VM where the kubemark master is running
3) Some hollow-nodes that run on the Kubernetes Cluster from #1
4) The hollow-nodes are configured to talk with the kubemark master at #2
When using the pre-existing provider, the developer is responsible for creating
#1 and #2. Therefore, the kubemark scripts will not create any infrastructure
or start a kubemark master like in other providers. Instead, the existing
resources provided by the VM at $MASTER_IP will serve as the kubemark master.
## Use Case
The goal of the pre-existing provider is to use the kubemark tools with an
existing kubemark master. It's meant to provide the developer with
additional flexibility to customize the cluster infrastructure and still use
the kubemark setup tools. The pre-existing provider is an **advanced** use
case that requires the developer to have knowledge of setting up a kubemark
master.
## Requirements
To use the pre-existing provider, the expectation is that there's a kubemark
master that is reachable at $MASTER_IP. The machine that the kubemark master is
on has to be ssh able from the host that's executing the kubemark scripts. And
the user on that machine has to be 'kubernetes'.
Requirement checklist:
- Set MASTER_IP to ip address to the kubemark master
- The host where you execute the kubemark scripts must be able to ssh to
kubernetes@$MASTER_IP
## Example Configuration
_test/kubemark/cloud-provider-config.sh_
```
CLOUD_PROVIDER="pre-existing"
KUBEMARK_IMAGE_MAKE_TARGET="push"
CONTAINER_REGISTRY=docker.io
PROJECT="rthallisey"
MASTER_IP="192.168.121.29:6443"
```
-27
View File
@@ -1,27 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../../..
source "${KUBE_ROOT}/test/kubemark/common/util.sh"
# Leave the skeleton definition of execute-cmd-on-master-with-retries
# so only the pre-existing provider functions will target this.
function execute-cmd-on-pre-existing-master-with-retries() {
IP_WITHOUT_PORT=$(echo "${MASTER_IP}" | cut -f 1 -d ':') || "${MASTER_IP}"
RETRIES="${2:-1}" run-cmd-with-retries ssh kubernetes@"${IP_WITHOUT_PORT}" "${1}"
}
@@ -1,94 +0,0 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "cluster-autoscaler",
"namespace": "kubemark",
"labels": {
"tier": "cluster-management",
"component": "cluster-autoscaler"
}
},
"spec": {
"hostNetwork": true,
"containers": [
{
"name": "cluster-autoscaler",
"image": "registry.k8s.io/cluster-autoscaler:v1.0.0",
"command": [
"./run.sh",
"--kubernetes=https://{{master_ip}}:443?inClusterConfig=0&useServiceAccount=0&auth=/kubeconfig/cluster_autoscaler.kubeconfig",
"--v=4",
"--logtostderr=true",
"--write-status-configmap=true",
"--cloud-provider=kubemark",
"--nodes={{kubemark_autoscaler_min_nodes}}:{{kubemark_autoscaler_max_nodes}}:{{kubemark_autoscaler_mig_name}}"
],
"env": [
{
"name": "LOG_OUTPUT",
"value": "/var/log/cluster-autoscaler.log"
}
],
"resources": {
"requests": {
"cpu": "10m",
"memory": "300Mi"
}
},
"volumeMounts": [
{"name": "cloudconfigmount","mountPath": "/etc/gce.conf", "readOnly": true},
{
"name": "ssl-certs",
"readOnly": true,
"mountPath": "/etc/ssl/certs"
},
{
"name": "usrsharecacerts",
"readOnly": true,
"mountPath": "/usr/share/ca-certificates"
},
{
"name": "logdir",
"mountPath": "/var/log",
"readOnly": false
},
{
"name": "kubeconfig-volume",
"mountPath": "/kubeconfig"
}
],
"terminationMessagePath": "/dev/termination-log",
"imagePullPolicy": "Always"
}
],
"volumes": [
{"name": "cloudconfigmount","hostPath": {"path": "/etc/gce.conf"}},
{
"name": "ssl-certs",
"hostPath": {
"path": "/etc/ssl/certs"
}
},
{
"name": "usrsharecacerts",
"hostPath": {
"path": "/usr/share/ca-certificates"
}
},
{
"name": "logdir",
"hostPath": {
"path": "/var/log"
}
},
{
"name": "kubeconfig-volume",
"secret": {
"secretName": "kubeconfig"
}
}
],
"restartPolicy": "Always"
}
}
@@ -1,82 +0,0 @@
{
"kind": "ReplicationController",
"apiVersion": "v1",
"metadata": {
"name": "heapster-v1.3.0",
"labels": {
"k8s-app": "heapster",
"version": "v1.3.0"
}
},
"spec": {
"replicas": 1,
"selector": {
"k8s-app": "heapster",
"version": "v1.3.0"
},
"template": {
"metadata": {
"labels": {
"k8s-app": "heapster",
"version": "v1.3.0"
}
},
"spec": {
"volumes": [
{
"name": "kubeconfig-volume",
"secret": {
"secretName": "kubeconfig"
}
}
],
"containers": [
{
"name": "heapster",
"image": "registry.k8s.io/heapster:v1.3.0",
"resources": {
"requests": {
"cpu": "{{METRICS_CPU}}m",
"memory": "{{METRICS_MEM}}Mi"
}
},
"command": [
"/heapster"
],
"args": [
"--source=kubernetes:https://{{MASTER_IP}}:443?inClusterConfig=0&useServiceAccount=0&auth=/kubeconfig/heapster.kubeconfig"
],
"volumeMounts": [
{
"name": "kubeconfig-volume",
"mountPath": "/kubeconfig"
}
]
},
{
"name": "eventer",
"image": "registry.k8s.io/heapster:v1.3.0",
"resources": {
"requests": {
"memory": "{{EVENTER_MEM}}Ki"
}
},
"command": [
"/eventer"
],
"args": [
"--source=kubernetes:https://{{MASTER_IP}}:443?inClusterConfig=0&useServiceAccount=0&auth=/kubeconfig/heapster.kubeconfig"
],
"volumeMounts": [
{
"name": "kubeconfig-volume",
"mountPath": "/kubeconfig"
}
]
}]
}
}
}
}
@@ -1,138 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: hollow-node
labels:
name: hollow-node
{{kubemark_mig_config}}
spec:
replicas: {{numreplicas}}
selector:
name: hollow-node
template:
metadata:
labels:
name: hollow-node
{{kubemark_mig_config}}
spec:
initContainers:
- name: init-inotify-limit
image: busybox:1.32
command: ['sysctl', '-w', 'fs.inotify.max_user_instances=1000']
securityContext:
privileged: true
volumes:
- name: kubeconfig-volume
secret:
secretName: kubeconfig
- name: kernelmonitorconfig-volume
configMap:
name: node-configmap
- name: logs-volume
hostPath:
path: /var/log
- name: containerd
hostPath:
path: /run/containerd
- name: no-serviceaccount-access-to-real-master
emptyDir: {}
containers:
- name: hollow-kubelet
image: {{kubemark_image_registry}}/kubemark:{{kubemark_image_tag}}
ports:
- containerPort: 4194
- containerPort: 10250
- containerPort: 10255
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command: [
"/go-runner",
"-log-file=/var/log/kubelet-$(NODE_NAME).log",
"/kubemark",
"--morph=kubelet",
"--name=$(NODE_NAME)",
"--kubeconfig=/kubeconfig/kubelet.kubeconfig",
"--node-labels={{hollow_node_labels}}",
{{hollow_kubelet_params}}
]
volumeMounts:
- name: kubeconfig-volume
mountPath: /kubeconfig
readOnly: true
- name: logs-volume
mountPath: /var/log
- name: containerd
mountPath: /run/containerd
resources:
requests:
cpu: {{hollow_kubelet_millicpu}}m
memory: {{hollow_kubelet_mem_Ki}}Ki
securityContext:
privileged: true
- name: hollow-proxy
image: {{kubemark_image_registry}}/kubemark:{{kubemark_image_tag}}
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command: [
"/go-runner",
"-log-file=/var/log/kubeproxy-$(NODE_NAME).log",
"/kubemark",
"--morph=proxy",
"--name=$(NODE_NAME)",
"--kubeconfig=/kubeconfig/kubeproxy.kubeconfig",
{{hollow_proxy_params}}
]
volumeMounts:
- name: kubeconfig-volume
mountPath: /kubeconfig
readOnly: true
- name: logs-volume
mountPath: /var/log
resources:
requests:
cpu: {{hollow_proxy_millicpu}}m
memory: {{hollow_proxy_mem_Ki}}Ki
- name: hollow-node-problem-detector
image: registry.k8s.io/node-problem-detector/node-problem-detector:v1.35.2
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- /bin/sh
- -c
- /node-problem-detector --system-log-monitors=/config/kernel.monitor --apiserver-override="https://{{master_ip}}:443?inClusterConfig=false&auth=/kubeconfig/npd.kubeconfig" --alsologtostderr 1>>/var/log/npd-$(NODE_NAME).log 2>&1
volumeMounts:
- name: kubeconfig-volume
mountPath: /kubeconfig
readOnly: true
- name: kernelmonitorconfig-volume
mountPath: /config
readOnly: true
- name: no-serviceaccount-access-to-real-master
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
- name: logs-volume
mountPath: /var/log
resources:
requests:
cpu: {{npd_millicpu}}m
memory: {{npd_mem_Ki}}Ki
securityContext:
privileged: true
# Keep the pod running on unreachable node for 15 minutes.
# This time should be sufficient for a VM reboot and should
# avoid recreating a new hollow node.
# See https://github.com/kubernetes/kubernetes/issues/67120 for context.
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 900
@@ -1,20 +0,0 @@
{
"plugin": "filelog",
"pluginConfig": {
"timestamp": "dummy",
"message": "dummy",
"timestampFormat": "dummy"
},
"logPath": "/dev/null",
"lookback": "10m",
"bufferSize": 10,
"source": "kernel-monitor",
"conditions": [
{
"type": "KernelDeadlock",
"reason": "KernelHasNoDeadlock",
"message": "kernel has no deadlock"
}
],
"rules": []
}
@@ -1,187 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kubemark
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "KubeDNS"
spec:
selector:
k8s-app: kube-dns
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube-dns
namespace: kubemark
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-dns
namespace: kubemark
labels:
addonmanager.kubernetes.io/mode: EnsureExists
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-dns
namespace: kubemark
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
spec:
strategy:
rollingUpdate:
maxSurge: 10%
maxUnavailable: 0
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
priorityClassName: system-node-critical
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
volumes:
- name: kube-dns-config
configMap:
name: kube-dns
optional: true
- name: secret-volume
secret:
secretName: kubeconfig
containers:
- name: kubedns
image: registry.k8s.io/k8s-dns-kube-dns-amd64:1.14.9
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
livenessProbe:
httpGet:
path: /healthcheck/kubedns
port: 10054
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /readiness
port: 8081
scheme: HTTP
initialDelaySeconds: 3
timeoutSeconds: 5
args:
- --domain={{dns_domain}}.
- --dns-port=10053
- --config-dir=/kube-dns-config
- --kubecfg-file=/etc/secret-volume/dns.kubeconfig
- --v=2
env:
- name: PROMETHEUS_PORT
value: "10055"
ports:
- containerPort: 10053
name: dns-local
protocol: UDP
- containerPort: 10053
name: dns-tcp-local
protocol: TCP
- containerPort: 10055
name: metrics
protocol: TCP
volumeMounts:
- name: kube-dns-config
mountPath: /kube-dns-config
- name: secret-volume
mountPath: /etc/secret-volume
- name: dnsmasq
image: registry.k8s.io/k8s-dns-dnsmasq-nanny-amd64:1.14.9
livenessProbe:
httpGet:
path: /healthcheck/dnsmasq
port: 10054
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
args:
- -v=2
- -logtostderr
- -configDir=/etc/k8s/dns/dnsmasq-nanny
- -restartDnsmasq=true
- --
- -k
- --cache-size=1000
- --no-negcache
- --dns-loop-detect
- --log-facility=-
- --server=/{{dns_domain}}/127.0.0.1#10053
- --server=/in-addr.arpa/127.0.0.1#10053
- --server=/ip6.arpa/127.0.0.1#10053
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
# see: https://github.com/kubernetes/kubernetes/issues/29055 for details
resources:
requests:
cpu: 150m
memory: 20Mi
volumeMounts:
- name: kube-dns-config
mountPath: /etc/k8s/dns/dnsmasq-nanny
- name: sidecar
image: registry.k8s.io/k8s-dns-sidecar-amd64:1.14.9
livenessProbe:
httpGet:
path: /metrics
port: 10054
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
args:
- --v=2
- --logtostderr
- --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.{{dns_domain}},5,SRV
- --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.{{dns_domain}},5,SRV
ports:
- containerPort: 10054
name: metrics
protocol: TCP
resources:
requests:
memory: 20Mi
cpu: 10m
dnsPolicy: Default # Don't use cluster DNS.
serviceAccountName: kube-dns
-7
View File
@@ -1,7 +0,0 @@
{
"kind": "Namespace",
"apiVersion": "v1",
"metadata": {
"name": "kubemark"
}
}
@@ -1 +0,0 @@
These resources are used to add extra (non-default) bindings to kubemark to match users and groups that are particular to the kubemark environment. These are not standard bootstrap bindings and not standard users they are bound to, and have been adapted from cluster/addons/e2e-rbac-bindings. Tighten/loosen these access rights as required in future.
@@ -1,16 +0,0 @@
# This is the role binding for the kubemark cluster autoscaler.
# TODO: Use proper Cluster Autoscaler role (github.com/kubernetes/autoscaler/issues/383)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-autoscaler-view-binding
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:cluster-autoscaler
@@ -1,15 +0,0 @@
# This is the role binding for the kubemark heapster.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: heapster-view-binding
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:heapster
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:heapster
@@ -1,15 +0,0 @@
# This is the role binding for the kubemark kube-dns.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube-dns-view-binding
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-dns
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:kube-dns
@@ -1,18 +0,0 @@
# This is the role binding for the local kubectl, which is
# used for listing hollow-nodes in start-kubemark.sh and
# send resource creation requests, etc in run-e2e-tests.sh.
# Also useful if you manually want to use local kubectl.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubecfg-cluster-admin
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubecfg
@@ -1,18 +0,0 @@
# The Kubemark environment currently gives all kubelets a single shared credential.
#
# TODO: give each kubelet a credential in the system:nodes group with username system:node:<nodeName>,
# to exercise the Node authorizer and admission, then remove this binding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubelet-node
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubelet
@@ -1,15 +0,0 @@
# This is the role binding for the node-problem-detector.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-problem-detector-binding
labels:
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-problem-detector
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:node-problem-detector
@@ -1,43 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: kube-addon-manager
namespace: kube-system
labels:
component: kube-addon-manager
spec:
hostNetwork: true
containers:
- name: kube-addon-manager
image: {{kube_docker_registry}}/addon-manager/kube-addon-manager:v9.1.8
command:
- /bin/bash
- -c
- /opt/kube-addons-main.sh 1>>/var/log/kube-addon-manager.log 2>&1
resources:
requests:
cpu: 5m
memory: 50Mi
volumeMounts:
- name: addons
mountPath: /etc/kubernetes/
readOnly: true
- name: varlog
mountPath: /var/log/kube-addon-manager.log
- mountPath: /etc/srv/kubernetes/addon-manager/
name: srvkube
readOnly: true
env:
- name: KUBECTL_OPTS
value: '--kubeconfig=/etc/srv/kubernetes/addon-manager/kubeconfig'
volumes:
- name: addons
hostPath:
path: /etc/kubernetes/
- name: varlog
hostPath:
path: /var/log/kube-addon-manager.log
type: FileOrCreate
- hostPath:
path: /etc/srv/kubernetes/addon-manager/
name: srvkube
@@ -1,776 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 The Kubernetes Authors.
#
# 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.
# Script that starts kubelet on kubemark-master as a supervisord process
# and then runs the master components as pods using kubelet.
set -o errexit
set -o nounset
set -o pipefail
# Define key path variables.
KUBE_ROOT="/home/kubernetes"
KUBE_BINDIR="${KUBE_ROOT}/kubernetes/server/bin"
function config-ip-firewall {
echo "Configuring IP firewall rules"
# The GCI image has host firewall which drop most inbound/forwarded packets.
# We need to add rules to accept all TCP/UDP/ICMP packets.
if iptables -L INPUT | grep "Chain INPUT (policy DROP)" > /dev/null; then
echo "Add rules to accept all inbound TCP/UDP/ICMP packets"
iptables -A INPUT -w -p TCP -j ACCEPT
iptables -A INPUT -w -p UDP -j ACCEPT
iptables -A INPUT -w -p ICMP -j ACCEPT
fi
if iptables -L FORWARD | grep "Chain FORWARD (policy DROP)" > /dev/null; then
echo "Add rules to accept all forwarded TCP/UDP/ICMP packets"
iptables -A FORWARD -w -p TCP -j ACCEPT
iptables -A FORWARD -w -p UDP -j ACCEPT
iptables -A FORWARD -w -p ICMP -j ACCEPT
fi
}
function create-dirs {
echo "Creating required directories"
mkdir -p /var/lib/kubelet
mkdir -p /etc/kubernetes/manifests
mkdir -p /etc/kubernetes/addons
}
# Setup working directory for kubelet.
function setup-kubelet-dir {
echo "Making /var/lib/kubelet executable for kubelet"
mount -B /var/lib/kubelet /var/lib/kubelet/
mount -B -o remount,exec,suid,dev /var/lib/kubelet
}
# Remove any default etcd config dirs/files.
function delete-default-etcd-configs {
if [[ -d /etc/etcd ]]; then
rm -rf /etc/etcd
fi
if [[ -e /etc/default/etcd ]]; then
rm -f /etc/default/etcd
fi
if [[ -e /etc/systemd/system/etcd.service ]]; then
rm -f /etc/systemd/system/etcd.service
fi
if [[ -e /etc/init.d/etcd ]]; then
rm -f /etc/init.d/etcd
fi
}
# Compute etcd related variables.
function compute-etcd-variables {
ETCD_IMAGE="${ETCD_IMAGE:-}"
ETCD_QUOTA_BYTES=""
if [ "${ETCD_VERSION:0:2}" == "3." ]; then
# TODO: Set larger quota to see if that helps with
# 'mvcc: database space exceeded' errors. If so, pipe
# though our setup scripts.
ETCD_QUOTA_BYTES=" --quota-backend-bytes=4294967296 "
fi
}
# Formats the given device ($1) if needed and mounts it at given mount point
# ($2).
function safe-format-and-mount() {
device=$1
mountpoint=$2
# Format only if the disk is not already formatted.
if ! tune2fs -l "${device}" ; then
echo "Formatting '${device}'"
mkfs.ext4 -F "${device}"
fi
echo "Mounting '${device}' at '${mountpoint}'"
mount -o discard,defaults "${device}" "${mountpoint}"
}
# Finds a PD device with name '$1' attached to the master.
function find-attached-pd() {
local -r pd_name=$1
if [[ ! -e /dev/disk/by-id/${pd_name} ]]; then
echo ""
fi
device_info=$(ls -l "/dev/disk/by-id/${pd_name}")
relative_path=${device_info##* }
echo "/dev/disk/by-id/${relative_path}"
}
# Mounts a persistent disk (formatting if needed) to store the persistent data
# on the master. safe-format-and-mount only formats an unformatted disk, and
# mkdir -p will leave a directory be if it already exists.
function mount-pd() {
local -r pd_name=$1
local -r mount_point=$2
if [[ -z "${find-attached-pd ${pd_name}}" ]]; then
echo "Can't find ${pd_name}. Skipping mount."
return
fi
local -r pd_path="/dev/disk/by-id/${pd_name}"
echo "Mounting PD '${pd_path}' at '${mount_point}'"
# Format and mount the disk, create directories on it for all of the master's
# persistent data, and link them to where they're used.
mkdir -p "${mount_point}"
safe-format-and-mount "${pd_path}" "${mount_point}"
echo "Mounted PD '${pd_path}' at '${mount_point}'"
# NOTE: These locations on the PD store persistent data, so to maintain
# upgradeability, these locations should not change. If they do, take care
# to maintain a migration path from these locations to whatever new
# locations.
}
# Create kubeconfig for controller-manager's service account authentication.
function create-kubecontrollermanager-kubeconfig {
echo "Creating kube-controller-manager kubeconfig file"
mkdir -p "${KUBE_ROOT}/k8s_auth_data/kube-controller-manager"
cat <<EOF >"${KUBE_ROOT}/k8s_auth_data/kube-controller-manager/kubeconfig"
apiVersion: v1
kind: Config
users:
- name: kube-controller-manager
user:
token: ${KUBE_CONTROLLER_MANAGER_TOKEN}
clusters:
- name: local
cluster:
insecure-skip-tls-verify: true
server: https://localhost:443
contexts:
- context:
cluster: local
user: kube-controller-manager
name: service-account-context
current-context: service-account-context
EOF
}
function create-kubescheduler-kubeconfig {
echo "Creating kube-scheduler kubeconfig file"
mkdir -p "${KUBE_ROOT}/k8s_auth_data/kube-scheduler"
cat <<EOF >"${KUBE_ROOT}/k8s_auth_data/kube-scheduler/kubeconfig"
apiVersion: v1
kind: Config
users:
- name: kube-scheduler
user:
token: ${KUBE_SCHEDULER_TOKEN}
clusters:
- name: local
cluster:
insecure-skip-tls-verify: true
server: https://localhost:443
contexts:
- context:
cluster: local
user: kube-scheduler
name: kube-scheduler
current-context: kube-scheduler
EOF
}
function create-addonmanager-kubeconfig {
echo "Creating addonmanager kubeconfig file"
mkdir -p "${KUBE_ROOT}/k8s_auth_data/addon-manager"
cat <<EOF >"${KUBE_ROOT}/k8s_auth_data/addon-manager/kubeconfig"
apiVersion: v1
kind: Config
users:
- name: addon-manager
user:
token: ${ADDON_MANAGER_TOKEN}
clusters:
- name: local
cluster:
insecure-skip-tls-verify: true
server: https://localhost:443
contexts:
- context:
cluster: local
user: addon-manager
name: addon-manager
current-context: addon-manager
EOF
}
function assemble-docker-flags {
echo "Assemble docker command line flags"
local docker_opts="-p /var/run/docker.pid --iptables=false --ip-masq=false"
docker_opts+=" --log-level=debug" # Since it's a test cluster
# TODO(shyamjvs): Incorporate network plugin options, etc later.
echo "DOCKER_OPTS=\"${docker_opts}\"" > /etc/default/docker
echo "DOCKER_NOFILE=65536" >> /etc/default/docker # For setting ulimit -n
systemctl restart docker
}
# A helper function for loading a docker image. It keeps trying up to 5 times.
#
# $1: Full path of the docker image
function try-load-docker-image {
local -r img=$1
echo "Try to load docker image file ${img}"
# Temporarily turn off errexit, because we don't want to exit on first failure.
set +e
local -r max_attempts=5
local -i attempt_num=1
until timeout 30 docker load -i "${img}"; do
if [[ "${attempt_num}" == "${max_attempts}" ]]; then
echo "Fail to load docker image file ${img} after ${max_attempts} retries. Exit!!"
exit 1
else
attempt_num=$((attempt_num+1))
sleep 5
fi
done
# Re-enable errexit.
set -e
}
# Loads kube-system docker images. It is better to do it before starting kubelet,
# as kubelet will restart docker daemon, which may interfere with loading images.
function load-docker-images {
echo "Start loading kube-system docker images"
local -r img_dir="${KUBE_BINDIR}"
try-load-docker-image "${img_dir}/kube-apiserver.tar"
try-load-docker-image "${img_dir}/kube-controller-manager.tar"
try-load-docker-image "${img_dir}/kube-scheduler.tar"
}
# Computes command line arguments to be passed to kubelet.
function compute-kubelet-params {
local params="${KUBELET_TEST_ARGS:-}"
params+=" --cgroup-root=/"
params+=" --cloud-provider=gce"
params+=" --pod-manifest-path=/etc/kubernetes/manifests"
if [[ -n "${KUBELET_PORT:-}" ]]; then
params+=" --port=${KUBELET_PORT}"
fi
params+=" --enable-debugging-handlers=false"
params+=" --hairpin-mode=none"
echo "${params}"
}
# Creates the systemd config file for kubelet.service.
function create-kubelet-conf() {
local -r kubelet_bin="$1"
local -r kubelet_env_file="/etc/default/kubelet"
local -r flags=$(compute-kubelet-params)
echo "KUBELET_OPTS=\"${flags}\"" > "${kubelet_env_file}"
# Write the systemd service file for kubelet.
cat <<EOF >/etc/systemd/system/kubelet.service
[Unit]
Description=Kubermark kubelet
Requires=network-online.target
After=network-online.target
[Service]
Restart=always
RestartSec=10
EnvironmentFile=${kubelet_env_file}
ExecStart=${kubelet_bin} \$KUBELET_OPTS
[Install]
WantedBy=multi-user.target
EOF
}
# This function assembles the kubelet systemd service file and starts it using
# systemctl, on the kubemark master.
function start-kubelet {
# Create systemd config.
local -r kubelet_bin="/usr/bin/kubelet"
create-kubelet-conf "${kubelet_bin}"
# Flush iptables nat table
iptables -t nat -F || true
# Start the kubelet service.
systemctl start kubelet.service
}
# Create the log file and set its properties.
#
# $1 is the file to create.
function prepare-log-file {
touch "$1"
chmod 644 "$1"
chown root:root "$1"
}
# A helper function for copying addon manifests and set dir/files
# permissions.
#
# $1: addon category under /etc/kubernetes
# $2: manifest source dir
function setup-addon-manifests {
local -r src_dir="${KUBE_ROOT}/$2"
local -r dst_dir="/etc/kubernetes/$1/$2"
if [[ ! -d "${dst_dir}" ]]; then
mkdir -p "${dst_dir}"
fi
local files
files=$(find "${src_dir}" -maxdepth 1 -name "*.yaml")
if [[ -n "${files}" ]]; then
cp "${src_dir}/"*.yaml "${dst_dir}"
fi
chown -R root:root "${dst_dir}"
chmod 755 "${dst_dir}"
chmod 644 "${dst_dir}"/*
}
# Write the config for the audit policy.
# Note: This duplicates the function in cluster/gce/gci/configure-helper.sh.
# TODO: Get rid of this function when #53321 is fixed.
function create-master-audit-policy {
local -r path="${1}"
local -r policy="${2:-}"
if [[ -n "${policy}" ]]; then
echo "${policy}" > "${path}"
return
fi
# Known api groups
local -r known_apis='
- group: "" # core
- group: "admissionregistration.k8s.io"
- group: "apiextensions.k8s.io"
- group: "apiregistration.k8s.io"
- group: "apps"
- group: "authentication.k8s.io"
- group: "authorization.k8s.io"
- group: "autoscaling"
- group: "batch"
- group: "certificates.k8s.io"
- group: "extensions"
- group: "metrics"
- group: "networking.k8s.io"
- group: "policy"
- group: "rbac.authorization.k8s.io"
- group: "storage.k8s.io"'
cat <<EOF >"${path}"
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# The following requests were manually identified as high-volume and low-risk,
# so drop them.
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # core
resources: ["endpoints", "services", "services/status"]
- level: None
# Ingress controller reads 'configmaps/ingress-uid' through the unsecured port.
# TODO(#46983): Change this to the ingress controller service account.
users: ["system:unsecured"]
namespaces: ["kube-system"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["configmaps"]
- level: None
users: ["kubelet"] # legacy kubelet identity
verbs: ["get"]
resources:
- group: "" # core
resources: ["nodes", "nodes/status"]
- level: None
userGroups: ["system:nodes"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["nodes", "nodes/status"]
- level: None
users:
- system:kube-controller-manager
- system:kube-scheduler
- system:serviceaccount:kube-system:endpoint-controller
verbs: ["get", "update"]
namespaces: ["kube-system"]
resources:
- group: "" # core
resources: ["endpoints"]
- level: None
users: ["system:apiserver"]
verbs: ["get"]
resources:
- group: "" # core
resources: ["namespaces", "namespaces/status", "namespaces/finalize"]
# Don't log HPA fetching metrics.
- level: None
users:
- system:kube-controller-manager
verbs: ["get", "list"]
resources:
- group: "metrics"
# Don't log these read-only URLs.
- level: None
nonResourceURLs:
- /healthz*
- /version
- /swagger*
# Don't log events requests.
- level: None
resources:
- group: "" # core
resources: ["events"]
# node and pod status calls from nodes are high-volume and can be large, don't log responses for expected updates from nodes
- level: Request
users: ["kubelet", "system:node-problem-detector", "system:serviceaccount:kube-system:node-problem-detector"]
verbs: ["update","patch"]
resources:
- group: "" # core
resources: ["nodes/status", "pods/status"]
omitStages:
- "RequestReceived"
- level: Request
userGroups: ["system:nodes"]
verbs: ["update","patch"]
resources:
- group: "" # core
resources: ["nodes/status", "pods/status"]
omitStages:
- "RequestReceived"
# deletecollection calls can be large, don't log responses for expected namespace deletions
- level: Request
users: ["system:serviceaccount:kube-system:namespace-controller"]
verbs: ["deletecollection"]
omitStages:
- "RequestReceived"
# Secrets, ConfigMaps, TokenRequest and TokenReviews can contain sensitive & binary data,
# so only log at the Metadata level.
- level: Metadata
resources:
- group: "" # core
resources: ["secrets", "configmaps", "serviceaccounts/token"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
omitStages:
- "RequestReceived"
# Get responses can be large; skip them.
- level: Request
verbs: ["get", "list", "watch"]
resources: ${known_apis}
omitStages:
- "RequestReceived"
# Default level for known APIs
- level: RequestResponse
resources: ${known_apis}
omitStages:
- "RequestReceived"
# Default level for all other requests.
- level: Metadata
omitStages:
- "RequestReceived"
EOF
}
# Computes command line arguments to be passed to etcd.
function compute-etcd-params {
local params="${ETCD_TEST_ARGS:-}"
params+=" --name=etcd-$(hostname -s)"
params+=" --listen-peer-urls=http://127.0.0.1:2380"
params+=" --advertise-client-urls=http://127.0.0.1:2379"
params+=" --listen-client-urls=http://0.0.0.0:2379"
# Enable apiserver->etcd auth.
params+=" --client-cert-auth"
params+=" --trusted-ca-file /etc/srv/kubernetes/etcd-apiserver-ca.crt"
params+=" --cert-file /etc/srv/kubernetes/etcd-apiserver-server.crt"
params+=" --key-file /etc/srv/kubernetes/etcd-apiserver-server.key"
params+=" --data-dir=/var/etcd/data"
params+=" ${ETCD_QUOTA_BYTES}"
echo "${params}"
}
# Computes command line arguments to be passed to etcd-events.
function compute-etcd-events-params {
local params="${ETCD_TEST_ARGS:-}"
params+=" --name=etcd-$(hostname -s)"
params+=" --listen-peer-urls=http://127.0.0.1:2381"
params+=" --advertise-client-urls=http://127.0.0.1:4002"
params+=" --listen-client-urls=http://0.0.0.0:4002"
params+=" --data-dir=/var/etcd/data-events"
params+=" ${ETCD_QUOTA_BYTES}"
echo "${params}"
}
# Computes command line arguments to be passed to apiserver.
function compute-kube-apiserver-params {
local params="--insecure-bind-address=0.0.0.0"
params+=" --etcd-servers=${ETCD_SERVERS:-http://127.0.0.1:2379}"
if [[ -z "${ETCD_SERVERS:-}" ]]; then
params+=" --etcd-servers-overrides=${ETCD_SERVERS_OVERRIDES:-/events#${EVENT_STORE_URL}}"
elif [[ -n "${ETCD_SERVERS_OVERRIDES:-}" ]]; then
params+=" --etcd-servers-overrides=${ETCD_SERVERS_OVERRIDES:-}"
fi
# Enable apiserver->etcd auth.
params+=" --etcd-cafile=/etc/srv/kubernetes/etcd-apiserver-ca.crt"
params+=" --etcd-certfile=/etc/srv/kubernetes/etcd-apiserver-client.crt"
params+=" --etcd-keyfile=/etc/srv/kubernetes/etcd-apiserver-client.key"
params+=" --tls-cert-file=/etc/srv/kubernetes/server.cert"
params+=" --tls-private-key-file=/etc/srv/kubernetes/server.key"
params+=" --requestheader-client-ca-file=/etc/srv/kubernetes/aggr_ca.crt"
params+=" --requestheader-allowed-names=aggregator"
params+=" --requestheader-extra-headers-prefix=X-Remote-Extra-"
params+=" --requestheader-group-headers=X-Remote-Group"
params+=" --requestheader-username-headers=X-Remote-User"
params+=" --proxy-client-cert-file=/etc/srv/kubernetes/proxy_client.crt"
params+=" --proxy-client-key-file=/etc/srv/kubernetes/proxy_client.key"
params+=" --enable-aggregator-routing=true"
params+=" --client-ca-file=/etc/srv/kubernetes/ca.crt"
params+=" --token-auth-file=/etc/srv/kubernetes/known_tokens.csv"
params+=" --secure-port=443"
params+=" --service-cluster-ip-range=${SERVICE_CLUSTER_IP_RANGE}"
params+=" --admission-control=${CUSTOM_ADMISSION_PLUGINS}"
params+=" --authorization-mode=Node,RBAC"
params+=" --allow-privileged=true"
if [[ -n "${STORAGE_BACKEND:-}" ]]; then
params+=" --storage-backend=${STORAGE_BACKEND}"
fi
if [[ -n "${STORAGE_MEDIA_TYPE:-}" ]]; then
params+=" --storage-media-type=${STORAGE_MEDIA_TYPE}"
fi
if [[ -n "${ETCD_COMPACTION_INTERVAL_SEC:-}" ]]; then
params+=" --etcd-compaction-interval=${ETCD_COMPACTION_INTERVAL_SEC}s"
fi
if [[ -n "${KUBE_APISERVER_REQUEST_TIMEOUT:-}" ]]; then
params+=" --min-request-timeout=${KUBE_APISERVER_REQUEST_TIMEOUT}"
fi
if [[ "${NUM_NODES}" -ge 3000 ]]; then
params+=" --max-requests-inflight=3000 --max-mutating-requests-inflight=1000"
elif [[ "${NUM_NODES}" -ge 1000 ]]; then
params+=" --max-requests-inflight=1500 --max-mutating-requests-inflight=500"
fi
if [[ -n "${RUNTIME_CONFIG:-}" ]]; then
params+=" --runtime-config=${RUNTIME_CONFIG}"
fi
if [[ -n "${FEATURE_GATES:-}" ]]; then
params+=" --feature-gates=${FEATURE_GATES}"
fi
if [[ "${ENABLE_APISERVER_ADVANCED_AUDIT:-}" == "true" ]]; then
# Create the audit policy file, and mount it into the apiserver pod.
create-master-audit-policy "${audit_policy_file}" "${ADVANCED_AUDIT_POLICY:-}"
# The config below matches the one in cluster/gce/gci/configure-helper.sh.
# TODO: Currently supporting just log backend. Support webhook if needed.
params+=" --audit-policy-file=${audit_policy_file}"
params+=" --audit-log-path=/var/log/kube-apiserver-audit.log"
params+=" --audit-log-maxage=0"
params+=" --audit-log-maxbackup=0"
params+=" --audit-log-maxsize=2000000000"
fi
# Append APISERVER_TEST_ARGS to the end, which will allow for
# the above defaults to be overridden.
params+=" ${APISERVER_TEST_ARGS:-}"
echo "${params}"
}
# Computes command line arguments to be passed to controller-manager.
function compute-kube-controller-manager-params {
local params="${CONTROLLER_MANAGER_TEST_ARGS:-}"
params+=" --use-service-account-credentials"
params+=" --kubeconfig=/etc/srv/kubernetes/kube-controller-manager/kubeconfig"
params+=" --service-account-private-key-file=/etc/srv/kubernetes/server.key"
params+=" --root-ca-file=/etc/srv/kubernetes/ca.crt"
params+=" --allocate-node-cidrs=${ALLOCATE_NODE_CIDRS}"
params+=" --cluster-cidr=${CLUSTER_IP_RANGE}"
params+=" --service-cluster-ip-range=${SERVICE_CLUSTER_IP_RANGE}"
params+=" --terminated-pod-gc-threshold=${TERMINATED_POD_GC_THRESHOLD}"
echo "${params}"
}
# Computes command line arguments to be passed to scheduler.
function compute-kube-scheduler-params {
local params="${SCHEDULER_TEST_ARGS:-}"
params+=" --kubeconfig=/etc/srv/kubernetes/kube-scheduler/kubeconfig"
echo "${params}"
}
# Computes command line arguments to be passed to addon-manager.
function compute-kube-addon-manager-params {
echo ""
}
# Start a kubernetes master component '$1' which can be any of the following:
# 1. etcd
# 2. etcd-events
# 3. kube-apiserver
# 4. kube-controller-manager
# 5. kube-scheduler
# 6. kube-addon-manager
#
# It prepares the log file, loads the docker tag, calculates variables, sets them
# in the manifest file, and then copies the manifest file to /etc/kubernetes/manifests.
#
# Assumed vars:
# DOCKER_REGISTRY
function start-kubemaster-component() {
echo "Start master component $1"
local -r component=$1
prepare-log-file /var/log/"${component}".log
local -r src_file="${KUBE_ROOT}/${component}.yaml"
local -r params=$("compute-${component}-params")
# Evaluate variables.
sed -i -e "s@{{params}}@${params}@g" "${src_file}"
sed -i -e "s@{{kube_docker_registry}}@${DOCKER_REGISTRY}@g" "${src_file}"
sed -i -e "s@{{instance_prefix}}@${INSTANCE_PREFIX}@g" "${src_file}"
if [ "${component:0:4}" == "etcd" ]; then
sed -i -e "s@{{etcd_image}}@${ETCD_IMAGE}@g" "${src_file}"
elif [ "${component}" == "kube-addon-manager" ]; then
setup-addon-manifests "addons" "kubemark-rbac-bindings"
else
local -r component_docker_tag=$(cat "${KUBE_BINDIR}/${component}.docker_tag")
sed -i -e "s@{{${component}_docker_tag}}@${component_docker_tag}@g" "${src_file}"
if [ "${component}" == "kube-apiserver" ]; then
local audit_policy_config_mount=""
local audit_policy_config_volume=""
if [[ "${ENABLE_APISERVER_ADVANCED_AUDIT:-}" == "true" ]]; then
read -r -d '' audit_policy_config_mount << EOF
- name: auditpolicyconfigmount
mountPath: ${audit_policy_file}
readOnly: true
EOF
read -r -d '' audit_policy_config_volume << EOF
- name: auditpolicyconfigmount
hostPath:
path: ${audit_policy_file}
type: FileOrCreate
EOF
fi
sed -i -e "s@{{audit_policy_config_mount}}@${audit_policy_config_mount}@g" "${src_file}"
sed -i -e "s@{{audit_policy_config_volume}}@${audit_policy_config_volume}@g" "${src_file}"
fi
fi
cp "${src_file}" /etc/kubernetes/manifests
}
############################### Main Function ########################################
echo "Start to configure master instance for kubemark"
# Extract files from the server tar and setup master env variables.
cd "${KUBE_ROOT}"
if [[ ! -d "${KUBE_ROOT}/kubernetes" ]]; then
tar xzf kubernetes-server-linux-amd64.tar.gz
fi
source "${KUBE_ROOT}/kubemark-master-env.sh"
# Setup IP firewall rules, required directory structure and etcd config.
config-ip-firewall
create-dirs
setup-kubelet-dir
delete-default-etcd-configs
compute-etcd-variables
# Setup authentication tokens and kubeconfigs for kube-controller-manager and kube-scheduler,
# only if their kubeconfigs don't already exist as this script could be running on reboot.
if [[ ! -f "${KUBE_ROOT}/k8s_auth_data/kube-controller-manager/kubeconfig" ]]; then
KUBE_CONTROLLER_MANAGER_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | LC_CTYPE=C tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
echo "${KUBE_CONTROLLER_MANAGER_TOKEN},system:kube-controller-manager,uid:system:kube-controller-manager" >> "${KUBE_ROOT}/k8s_auth_data/known_tokens.csv"
create-kubecontrollermanager-kubeconfig
fi
if [[ ! -f "${KUBE_ROOT}/k8s_auth_data/kube-scheduler/kubeconfig" ]]; then
KUBE_SCHEDULER_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | LC_CTYPE=C tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
echo "${KUBE_SCHEDULER_TOKEN},system:kube-scheduler,uid:system:kube-scheduler" >> "${KUBE_ROOT}/k8s_auth_data/known_tokens.csv"
create-kubescheduler-kubeconfig
fi
ADDON_MANAGER_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | LC_CTYPE=C tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
echo "${ADDON_MANAGER_TOKEN},system:addon-manager,admin,system:masters" >> "${KUBE_ROOT}/k8s_auth_data/known_tokens.csv"
create-addonmanager-kubeconfig
# Mount master PD for etcd and create symbolic links to it.
{
main_etcd_mount_point="/mnt/disks/master-pd"
mount-pd "google-master-pd" "${main_etcd_mount_point}"
# Contains all the data stored in etcd.
mkdir -p "${main_etcd_mount_point}/var/etcd"
chmod 700 "${main_etcd_mount_point}/var/etcd"
ln -s -f "${main_etcd_mount_point}/var/etcd" /var/etcd
mkdir -p /etc/srv
# Setup the dynamically generated apiserver auth certs and keys to pd.
mkdir -p "${main_etcd_mount_point}/srv/kubernetes"
ln -s -f "${main_etcd_mount_point}/srv/kubernetes" /etc/srv/kubernetes
# Copy the files to the PD only if they don't exist (so we do it only the first time).
if [[ "$(ls -A ${main_etcd_mount_point}/srv/kubernetes/)" == "" ]]; then
cp -r "${KUBE_ROOT}"/k8s_auth_data/* "${main_etcd_mount_point}/srv/kubernetes/"
fi
# Directory for kube-apiserver to store SSH key (if necessary).
mkdir -p "${main_etcd_mount_point}/srv/sshproxy"
ln -s -f "${main_etcd_mount_point}/srv/sshproxy" /etc/srv/sshproxy
}
# Mount master PD for event-etcd (if required) and create symbolic links to it.
{
EVENT_STORE_IP="${EVENT_STORE_IP:-127.0.0.1}"
EVENT_STORE_URL="${EVENT_STORE_URL:-http://${EVENT_STORE_IP}:4002}"
if [ "${EVENT_PD:-}" == "true" ]; then
event_etcd_mount_point="/mnt/disks/master-event-pd"
mount-pd "google-master-event-pd" "${event_etcd_mount_point}"
# Contains all the data stored in event etcd.
mkdir -p "${event_etcd_mount_point}/var/etcd/events"
chmod 700 "${event_etcd_mount_point}/var/etcd/events"
ln -s -f "${event_etcd_mount_point}/var/etcd/events" /var/etcd/events
fi
}
# Setup docker flags and load images of the master components.
assemble-docker-flags
DOCKER_REGISTRY="registry.k8s.io"
load-docker-images
readonly audit_policy_file="/etc/audit_policy.config"
# Start kubelet as a supervisord process and master components as pods.
start-kubelet
if [[ -z "${ETCD_SERVERS:-}" ]]; then
start-kubemaster-component "etcd"
if [ "${EVENT_STORE_IP:-}" == "127.0.0.1" ]; then
start-kubemaster-component "etcd-events"
fi
fi
start-kubemaster-component "kube-apiserver"
start-kubemaster-component "kube-controller-manager"
start-kubemaster-component "kube-scheduler"
start-kubemaster-component "kube-addon-manager"
# Wait till apiserver is working fine or timeout.
echo -n "Waiting for apiserver to be healthy"
start=$(date +%s)
until [ "$(curl 127.0.0.1:8080/healthz 2> /dev/null)" == "ok" ]; do
echo -n "."
sleep 1
now=$(date +%s)
if [ $((now - start)) -gt 300 ]; then
echo "Timeout!"
exit 1
fi
done
echo "Done for the configuration for kubemark master"
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 The Kubernetes Authors.
#
# 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.
export KUBERNETES_PROVIDER="kubemark"
export KUBE_CONFIG_FILE="config-default.sh"
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
# We need an absolute path to KUBE_ROOT
ABSOLUTE_ROOT=$(readlink -f "${KUBE_ROOT}")
source "${KUBE_ROOT}/cluster/kubemark/util.sh"
echo "Kubemark master name: ${MASTER_NAME}"
echo "Kubemark master ip: ${KUBE_MASTER_IP}"
export KUBE_MASTER_URL="https://${KUBE_MASTER_IP}"
export KUBECONFIG="${ABSOLUTE_ROOT}/test/kubemark/resources/kubeconfig.kubemark"
export E2E_MIN_STARTUP_PODS=0
ARGS=("$@")
if [[ "${ENABLE_KUBEMARK_CLUSTER_AUTOSCALER}" == "true" ]]; then
ARGS+=("--kubemark-external-kubeconfig=${DEFAULT_KUBECONFIG}")
fi
# Running locally.
for ((i=0; i < ${#ARGS[@]}; i++)); do
ARGS[i]="$(echo "${ARGS[$i]}" | sed -e 's/\[/\\\[/g' -e 's/\]/\\\]/g' )"
done
"${KUBE_ROOT}/hack/ginkgo-e2e.sh" "--e2e-verify-service-account=false" "--dump-logs-on-failure=false" "${ARGS[@]}"
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# 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.
# This script contains the helper functions that each provider hosting
# Kubermark must implement to use test/kubemark/start-kubemark.sh and
# test/kubemark/stop-kubemark.sh scripts.
# This function should authenticate docker to be able to read/write to
# the right container registry (needed for pushing kubemark image).
function authenticate-docker {
echo "Configuring registry authentication" 1>&2
}
# This function should create kubemark master and write kubeconfig to
# "${RESOURCE_DIRECTORY}/kubeconfig.kubemark".
# If a cluster uses private master IP, create-kubemark-master might also write
# a second kubeconfig to "${RESOURCE_DIRECTORY}/kubeconfig-internal.kubemark".
# The difference between these two kubeconfigs is that the internal one uses
# private master IP, which might be better suited for setting up hollow nodes.
function create-kubemark-master {
echo "Creating cluster..."
}
# This function should delete kubemark master.
function delete-kubemark-master {
echo "Deleting cluster..."
}
# This function should return node labels.
function calculate-node-labels {
echo ""
}
# Common colors used throughout the kubemark scripts
if [[ -z "${color_start-}" ]]; then
declare -r color_start="\033["
# shellcheck disable=SC2034
declare -r color_red="${color_start}0;31m"
# shellcheck disable=SC2034
declare -r color_yellow="${color_start}0;33m"
# shellcheck disable=SC2034
declare -r color_green="${color_start}0;32m"
# shellcheck disable=SC2034
declare -r color_blue="${color_start}1;34m"
# shellcheck disable=SC2034
declare -r color_cyan="${color_start}1;36m"
# shellcheck disable=SC2034
declare -r color_norm="${color_start}0m"
fi
-255
View File
@@ -1,255 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 The Kubernetes Authors.
#
# 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.
# Script that creates a Kubemark cluster for any given cloud provider.
set -o errexit
set -o nounset
set -o pipefail
TMP_ROOT="$(dirname "${BASH_SOURCE[@]}")/../.."
KUBE_ROOT=$(readlink -e "${TMP_ROOT}" 2> /dev/null || perl -MCwd -e 'print Cwd::abs_path shift' "${TMP_ROOT}")
source "${KUBE_ROOT}/test/kubemark/skeleton/util.sh"
source "${KUBE_ROOT}/test/kubemark/cloud-provider-config.sh"
source "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/util.sh"
source "${KUBE_ROOT}/cluster/kubemark/${CLOUD_PROVIDER}/config-default.sh"
if [[ -f "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/startup.sh" ]] ; then
source "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/startup.sh"
fi
source "${KUBE_ROOT}/cluster/kubemark/util.sh"
KUBECTL="${KUBE_ROOT}/cluster/kubectl.sh"
KUBEMARK_DIRECTORY="${KUBE_ROOT}/test/kubemark"
RESOURCE_DIRECTORY="${KUBEMARK_DIRECTORY}/resources"
LOCAL_KUBECONFIG="${RESOURCE_DIRECTORY}/kubeconfig.kubemark"
INTERNAL_KUBECONFIG="${RESOURCE_DIRECTORY}/kubeconfig-internal.kubemark"
# Generate a random 6-digit alphanumeric tag for the kubemark image.
# Used to uniquify image builds across different invocations of this script.
KUBEMARK_IMAGE_TAG=$(head /dev/urandom | LC_CTYPE=C tr -dc 'a-z0-9' | fold -w 6 | head -n 1)
# Create a docker image for hollow-node and upload it to the appropriate docker registry.
function create-and-upload-hollow-node-image {
authenticate-docker
KUBEMARK_IMAGE_REGISTRY="${KUBEMARK_IMAGE_REGISTRY:-${CONTAINER_REGISTRY}/${PROJECT}}"
# Build+push the image through makefile.
build_cmd=("make" "${KUBEMARK_IMAGE_MAKE_TARGET}")
MAKE_DIR="${KUBE_ROOT}/cluster/images/kubemark"
KUBEMARK_BIN="$(kube::util::find-binary-for-platform kubemark linux/amd64)"
if [[ -z "${KUBEMARK_BIN}" ]]; then
echo 'Cannot find cmd/kubemark binary'
exit 1
fi
echo "Copying kubemark binary to ${MAKE_DIR}"
cp "${KUBEMARK_BIN}" "${MAKE_DIR}"
CURR_DIR=$(pwd)
cd "${MAKE_DIR}"
REGISTRY=${KUBEMARK_IMAGE_REGISTRY} IMAGE_TAG=${KUBEMARK_IMAGE_TAG} run-cmd-with-retries "${build_cmd[@]}"
rm kubemark
cd "$CURR_DIR"
echo "Created and uploaded the kubemark hollow-node image to docker registry."
# Cleanup the kubemark image after the script exits.
if [[ "${CLEANUP_KUBEMARK_IMAGE:-}" == "true" ]]; then
trap delete-kubemark-image EXIT
fi
}
function delete-kubemark-image {
delete-image "${KUBEMARK_IMAGE_REGISTRY}/kubemark:${KUBEMARK_IMAGE_TAG}"
}
# Generate secret and configMap for the hollow-node pods to work, prepare
# manifests of the hollow-node and heapster replication controllers from
# templates, and finally create these resources through kubectl.
function create-kube-hollow-node-resources {
# Create kubemark namespace.
"${KUBECTL}" create -f "${RESOURCE_DIRECTORY}/kubemark-ns.json"
# Create configmap for configuring hollow- kubelet, proxy and npd.
"${KUBECTL}" create configmap "node-configmap" --namespace="kubemark" \
--from-file=kernel.monitor="${RESOURCE_DIRECTORY}/kernel-monitor.json"
# Create secret for passing kubeconfigs to kubelet, kubeproxy and npd.
# It's bad that all component shares the same kubeconfig.
# TODO(https://github.com/kubernetes/kubernetes/issues/79883): Migrate all components to separate credentials.
"${KUBECTL}" create secret generic "kubeconfig" --type=Opaque --namespace="kubemark" \
--from-file=kubelet.kubeconfig="${HOLLOWNODE_KUBECONFIG}" \
--from-file=kubeproxy.kubeconfig="${HOLLOWNODE_KUBECONFIG}" \
--from-file=npd.kubeconfig="${HOLLOWNODE_KUBECONFIG}" \
--from-file=heapster.kubeconfig="${HOLLOWNODE_KUBECONFIG}" \
--from-file=cluster_autoscaler.kubeconfig="${HOLLOWNODE_KUBECONFIG}" \
--from-file=dns.kubeconfig="${HOLLOWNODE_KUBECONFIG}"
# Create addon pods.
# Heapster.
mkdir -p "${RESOURCE_DIRECTORY}/addons"
sed "s@{{MASTER_IP}}@${MASTER_IP}@g" "${RESOURCE_DIRECTORY}/heapster_template.json" > "${RESOURCE_DIRECTORY}/addons/heapster.json"
metrics_mem_per_node=4
metrics_mem=$((200 + metrics_mem_per_node*NUM_NODES))
sed -i'' -e "s@{{METRICS_MEM}}@${metrics_mem}@g" "${RESOURCE_DIRECTORY}/addons/heapster.json"
metrics_cpu_per_node_numerator=${NUM_NODES}
metrics_cpu_per_node_denominator=2
metrics_cpu=$((80 + metrics_cpu_per_node_numerator / metrics_cpu_per_node_denominator))
sed -i'' -e "s@{{METRICS_CPU}}@${metrics_cpu}@g" "${RESOURCE_DIRECTORY}/addons/heapster.json"
eventer_mem_per_node=500
eventer_mem=$((200 * 1024 + eventer_mem_per_node*NUM_NODES))
sed -i'' -e "s@{{EVENTER_MEM}}@${eventer_mem}@g" "${RESOURCE_DIRECTORY}/addons/heapster.json"
# Cluster Autoscaler.
if [[ "${ENABLE_KUBEMARK_CLUSTER_AUTOSCALER:-}" == "true" ]]; then
echo "Setting up Cluster Autoscaler"
KUBEMARK_AUTOSCALER_MIG_NAME="${KUBEMARK_AUTOSCALER_MIG_NAME:-${NODE_INSTANCE_PREFIX}-group}"
KUBEMARK_AUTOSCALER_MIN_NODES="${KUBEMARK_AUTOSCALER_MIN_NODES:-0}"
KUBEMARK_AUTOSCALER_MAX_NODES="${KUBEMARK_AUTOSCALER_MAX_NODES:-10}"
NUM_NODES=${KUBEMARK_AUTOSCALER_MAX_NODES}
echo "Setting maximum cluster size to ${NUM_NODES}."
KUBEMARK_MIG_CONFIG="autoscaling.k8s.io/nodegroup: ${KUBEMARK_AUTOSCALER_MIG_NAME}"
sed "s/{{master_ip}}/${MASTER_IP}/g" "${RESOURCE_DIRECTORY}/cluster-autoscaler_template.json" > "${RESOURCE_DIRECTORY}/addons/cluster-autoscaler.json"
sed -i'' -e "s@{{kubemark_autoscaler_mig_name}}@${KUBEMARK_AUTOSCALER_MIG_NAME}@g" "${RESOURCE_DIRECTORY}/addons/cluster-autoscaler.json"
sed -i'' -e "s@{{kubemark_autoscaler_min_nodes}}@${KUBEMARK_AUTOSCALER_MIN_NODES}@g" "${RESOURCE_DIRECTORY}/addons/cluster-autoscaler.json"
sed -i'' -e "s@{{kubemark_autoscaler_max_nodes}}@${KUBEMARK_AUTOSCALER_MAX_NODES}@g" "${RESOURCE_DIRECTORY}/addons/cluster-autoscaler.json"
fi
# Kube DNS.
if [[ "${ENABLE_KUBEMARK_KUBE_DNS:-}" == "true" ]]; then
echo "Setting up kube-dns"
sed "s@{{dns_domain}}@${KUBE_DNS_DOMAIN}@g" "${RESOURCE_DIRECTORY}/kube_dns_template.yaml" > "${RESOURCE_DIRECTORY}/addons/kube_dns.yaml"
fi
"${KUBECTL}" create -f "${RESOURCE_DIRECTORY}/addons" --namespace="kubemark"
# Create the replication controller for hollow-nodes.
# We allow to override the NUM_REPLICAS when running Cluster Autoscaler.
NUM_REPLICAS=${NUM_REPLICAS:-${NUM_NODES}}
sed "s@{{numreplicas}}@${NUM_REPLICAS}@g" "${RESOURCE_DIRECTORY}/hollow-node_template.yaml" > "${RESOURCE_DIRECTORY}/hollow-node.yaml"
proxy_cpu=20
if [ "${NUM_NODES}" -gt 1000 ]; then
proxy_cpu=50
fi
proxy_cpu=${KUBEMARK_HOLLOW_PROXY_MILLICPU:-$proxy_cpu}
proxy_mem_per_node=${KUBEMARK_HOLLOW_PROXY_MEM_PER_NODE_KB:-50}
proxy_mem=$((100 * 1024 + proxy_mem_per_node*NUM_NODES))
hollow_node_labels=${HOLLOW_NODE_LABELS:-$(calculate-node-labels)}
hollow_kubelet_params=$(eval "for param in ${HOLLOW_KUBELET_TEST_ARGS:-}; do echo -n \\\"\$param\\\",; done")
hollow_kubelet_params=${hollow_kubelet_params%?}
hollow_proxy_params=$(eval "for param in ${HOLLOW_PROXY_TEST_ARGS:-}; do echo -n \\\"\$param\\\",; done")
hollow_proxy_params=${hollow_proxy_params%?}
sed -i'' -e "s@{{hollow_kubelet_millicpu}}@${KUBEMARK_HOLLOW_KUBELET_MILLICPU:-40}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_kubelet_mem_Ki}}@${KUBEMARK_HOLLOW_KUBELET_MEM_KB:-$((100*1024))}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_proxy_millicpu}}@${proxy_cpu}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_proxy_mem_Ki}}@${proxy_mem}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{npd_millicpu}}@${KUBEMARK_NPD_MILLICPU:-20}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{npd_mem_Ki}}@${KUBEMARK_NPD_MEM_KB:-$((20*1024))}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{kubemark_image_registry}}@${KUBEMARK_IMAGE_REGISTRY}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{kubemark_image_tag}}@${KUBEMARK_IMAGE_TAG}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{master_ip}}@${MASTER_IP}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_node_labels}}@${hollow_node_labels}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_kubelet_params}}@${hollow_kubelet_params}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{hollow_proxy_params}}@${hollow_proxy_params}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
sed -i'' -e "s@{{kubemark_mig_config}}@${KUBEMARK_MIG_CONFIG:-}@g" "${RESOURCE_DIRECTORY}/hollow-node.yaml"
"${KUBECTL}" create -f "${RESOURCE_DIRECTORY}/hollow-node.yaml" --namespace="kubemark"
echo "Created secrets, configMaps, replication-controllers required for hollow-nodes."
}
# Wait until all hollow-nodes are running or there is a timeout.
function wait-for-hollow-nodes-to-run-or-timeout {
echo -n "Waiting for all hollow-nodes to become Running"
start=$(date +%s)
nodes=$("${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" get node 2> /dev/null) || true
ready=$(($(echo "${nodes}" | grep -vc "NotReady") - 1))
until [[ "${ready}" -ge "${NUM_REPLICAS}" ]]; do
echo -n "."
sleep 1
now=$(date +%s)
# Fail it if it already took more than 30 minutes.
if [ $((now - start)) -gt 1800 ]; then
echo ""
"${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" describe node
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_red} Timeout waiting for all hollow-nodes to become Running. ${color_norm}"
# Try listing nodes again - if it fails it means that API server is not responding
if "${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" get node &> /dev/null; then
echo "Found only ${ready} ready hollow-nodes while waiting for ${NUM_NODES}."
else
echo "Got error while trying to list hollow-nodes. Probably API server is down."
fi
pods=$("${KUBECTL}" get pods -l name=hollow-node --namespace=kubemark) || true
running=$(($(echo "${pods}" | grep -c "Running")))
echo "${running} hollow-nodes are reported as 'Running'"
not_running=$(($(echo "${pods}" | grep -vc "Running") - 1))
echo "${not_running} hollow-nodes are reported as NOT 'Running'"
echo "${pods}" | grep -v Running
exit 1
fi
nodes=$("${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" get node 2> /dev/null) || true
ready=$(($(echo "${nodes}" | grep -vc "NotReady") - 1))
done
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_green} Done!${color_norm}"
}
############################### Main Function ########################################
# Setup for hollow-nodes.
function start-hollow-nodes {
# shellcheck disable=SC2154 # Color defined in sourced script
echo -e "${color_yellow}STARTING SETUP FOR HOLLOW-NODES${color_norm}"
create-and-upload-hollow-node-image
create-kube-hollow-node-resources
wait-for-hollow-nodes-to-run-or-timeout
}
# Annotates the node objects in the kubemark cluster to make their size
# similar to regular nodes.
# TODO(#90833): Replace this with image preloading from ClusterLoader to better
# reflect the reality in kubemark tests.
function resize-node-objects {
if [[ -z "$KUBEMARK_NODE_OBJECT_SIZE_BYTES" ]]; then
return 0
fi
annotation_size_bytes="${KUBEMARK_NODE_OBJECT_SIZE_BYTES}"
echo "Annotating node objects with ${annotation_size_bytes} byte label"
label=$( (LC_CTYPE=C < /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w "$annotation_size_bytes"; true) | head -n 1)
"${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" get nodes -o name \
| xargs -P50 -r -I% "${KUBECTL}" --kubeconfig="${LOCAL_KUBECONFIG}" annotate --overwrite % label="$label"
echo "Annotating node objects completed"
}
detect-project &> /dev/null
create-kubemark-master
if [ -f "${INTERNAL_KUBECONFIG}" ]; then
HOLLOWNODE_KUBECONFIG="${INTERNAL_KUBECONFIG}"
else
HOLLOWNODE_KUBECONFIG="${LOCAL_KUBECONFIG}"
fi
MASTER_IP=$(grep server "${HOLLOWNODE_KUBECONFIG}" | awk -F "/" '{print $3}')
start-hollow-nodes
resize-node-objects
echo ""
echo "Master IP: ${MASTER_IP}"
echo "Kubeconfig for kubemark master is written in ${LOCAL_KUBECONFIG}"
-46
View File
@@ -1,46 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 The Kubernetes Authors.
#
# 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.
# Script that destroys Kubemark cluster and deletes all master resources.
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
source "${KUBE_ROOT}/test/kubemark/skeleton/util.sh"
source "${KUBE_ROOT}/test/kubemark/cloud-provider-config.sh"
source "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/util.sh"
source "${KUBE_ROOT}/cluster/kubemark/${CLOUD_PROVIDER}/config-default.sh"
if [[ -f "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/shutdown.sh" ]] ; then
source "${KUBE_ROOT}/test/kubemark/${CLOUD_PROVIDER}/shutdown.sh"
fi
source "${KUBE_ROOT}/cluster/kubemark/util.sh"
KUBECTL="${KUBE_ROOT}/cluster/kubectl.sh"
KUBEMARK_DIRECTORY="${KUBE_ROOT}/test/kubemark"
RESOURCE_DIRECTORY="${KUBEMARK_DIRECTORY}/resources"
detect-project &> /dev/null
"${KUBECTL}" delete --timeout=5m -f "${RESOURCE_DIRECTORY}/addons" --namespace="kubemark" &> /dev/null || true
"${KUBECTL}" delete --timeout=5m -f "${RESOURCE_DIRECTORY}/hollow-node.yaml" --namespace="kubemark" &> /dev/null || true
"${KUBECTL}" delete --timeout=5m -f "${RESOURCE_DIRECTORY}/kubemark-ns.json" &> /dev/null || true
rm -rf "${RESOURCE_DIRECTORY}/addons" \
"${RESOURCE_DIRECTORY}/kubeconfig.kubemark" \
"${RESOURCE_DIRECTORY}/hollow-node.yaml" &> /dev/null || true
delete-kubemark-master