Compare commits

..

1 Commits

Author SHA1 Message Date
Craig Sterrett 4ed6f3fca2 Fixed code for no_proxy in setup_system.sh
The sed command for updating no-proxy settings in the proxy.sh file was
not working. I made it match the above command which was working for
/etc/environment.

Signed-off-by: Craig Sterrett <craig.sterrett@intel.com>
2019-11-11 08:52:39 -08:00
55 changed files with 108 additions and 1056 deletions
Vendored
-56
View File
@@ -1,56 +0,0 @@
pipeline {
agent {
label 'clearlinux'
}
options {
timeout(time: 1, unit: "HOURS")
}
triggers {
cron('H */12 * * *')
}
environment {
CLR_K8S_PATH="${env.WORKSPACE}/clr-k8s-examples"
}
stages {
stage('Setup system') {
steps {
dir(path: "$CLR_K8S_PATH") {
sh './setup_system.sh'
}
}
}
stage('Init') {
steps {
dir(path: "$CLR_K8S_PATH") {
sh './create_stack.sh init'
sh 'mkdir -p $HOME/.kube'
sh 'sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config'
sh 'sudo chown $(id -u):$(id -g) $HOME/.kube/config'
sh 'kubectl version'
}
}
}
stage('CNI') {
steps {
dir(path: "$CLR_K8S_PATH") {
sh './create_stack.sh cni'
sh 'kubectl rollout status deployment/coredns -n kube-system --timeout=5m'
sh 'kubectl get pods -n kube-system'
}
}
}
stage('Reset Stack') {
steps {
dir(path: "$CLR_K8S_PATH") {
sh './reset_stack.sh'
}
}
}
}
post {
always {
sh 'uname -a'
sh 'swupd info'
}
}
}
@@ -1,2 +0,0 @@
resources:
cilium/cilium.yaml
@@ -1,2 +0,0 @@
resources:
- flannel/Documentation/kube-flannel.yml
@@ -1,8 +0,0 @@
resources:
- metrics-server/deploy/1.8+/aggregated-metrics-reader.yaml
- metrics-server/deploy/1.8+/auth-delegator.yaml
- metrics-server/deploy/1.8+/auth-reader.yaml
- metrics-server/deploy/1.8+/metrics-apiservice.yaml
- metrics-server/deploy/1.8+/metrics-server-deployment.yaml
- metrics-server/deploy/1.8+/metrics-server-service.yaml
- metrics-server/deploy/1.8+/resource-reader.yaml
@@ -1,3 +0,0 @@
resources:
- ingress-nginx/deploy/static/mandatory.yaml
- ingress-nginx/deploy/static/provider/baremetal/service-nodeport.yaml
@@ -1,6 +0,0 @@
resources:
- metallb/manifests/example-layer2-config.yaml
- metallb/manifests/metallb.yaml
patchesStrategicMerge:
- patch_configmap.yaml
@@ -1,11 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data:
config: |
address-pools:
- name: my-ip-space
protocol: layer2
addresses:
- 10.0.0.240/28
@@ -1,11 +1,7 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/storageclass.yaml
patchesStrategicMerge:
- patch_operator.yaml
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
- patch_operator.yaml
@@ -1,10 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
storage:
directories:
- path: /var/lib/rook
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,22 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
mon:
allowMultiplePerNode: true
storage:
directories:
- path: /var/lib/rook
---
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
replicated:
requireSafeReplicaSize: false
size: 1
@@ -1,10 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
storage:
directories:
- path: /var/lib/rook
@@ -1,4 +1,3 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
@@ -7,4 +6,4 @@ metadata:
spec:
storage:
directories:
- path: /var/lib/rook
- path: /var/lib/rook
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,22 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
mon:
allowMultiplePerNode: true
storage:
directories:
- path: /var/lib/rook
---
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
replicated:
requireSafeReplicaSize: false
size: 1
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,10 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
storage:
directories:
- path: /var/lib/rook
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,22 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
mon:
allowMultiplePerNode: true
storage:
directories:
- path: /var/lib/rook
---
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
replicated:
requireSafeReplicaSize: false
size: 1
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,10 +0,0 @@
resources:
- rook/cluster/examples/kubernetes/ceph/common.yaml
- rook/cluster/examples/kubernetes/ceph/operator.yaml
- rook/cluster/examples/kubernetes/ceph/cluster.yaml
- rook/cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml
patchesStrategicMerge:
# patches rook to use 'directories' instead of partitions.
# comment out to use partitions
- patch_cephcluster.yaml
@@ -1,22 +0,0 @@
---
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
mon:
allowMultiplePerNode: true
storage:
directories:
- path: /var/lib/rook
---
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
replicated:
requireSafeReplicaSize: false
size: 1
@@ -1,11 +0,0 @@
resources:
- packaging/kata-deploy/kata-deploy.yaml
- packaging/kata-deploy/kata-rbac.yaml
- packaging/kata-deploy/k8s-1.14/kata-fc-runtimeClass.yaml
- packaging/kata-deploy/k8s-1.14/kata-qemu-runtimeClass.yaml
images:
# change 'latest' to specified version
- name: katadocker/kata-deploy
newName: katadocker/kata-deploy
newTag: 1.9.1
@@ -38,7 +38,7 @@ add_pair_ns() {
ln -sfT $CNI_NETNS /var/run/netns/$CNI_CONTAINERID
ip netns exec $CNI_CONTAINERID ip link add $CNI_IFNAME type veth peer name $peer
ip netns exec $CNI_CONTAINERID ip link set $CNI_IFNAME addr $mac up alias $vfpci
ip netns exec $CNI_CONTAINERID ip link set $CNI_IFNAME addr $mac up
ip netns exec $CNI_CONTAINERID ip link set $peer up
ip netns exec $CNI_CONTAINERID ip addr add $ip dev $CNI_IFNAME
}
-18
View File
@@ -38,9 +38,6 @@ This script ensures the following
script uses the runtime specified in the `RUNNER` environment variable and defaults to `crio`. To use the
`containerd` runtime, set the `RUNNER` environment variable to `containerd`.
In case of vagrant, if you want to spin up VM's using different environment variable than declared in [`setup_system.sh`],
specify when performing vagrant up. E.g., `RUNNER=containerd vagrant up`
### Specify a version of Clear Linux
To specify a particular version of Clear Linux to use, set the CLRK8S_CLR_VER environment variable to the desired
@@ -162,18 +159,3 @@ Grafana is available at this URL http://localhost:3000 . Default credentials are
## Cleaning up the cluster (Hard reset to a clean state)
Run `reset_stack.sh` on all the nodes
## Additional Components
### Rook
The default Rook configuration provided is intended for testing purposes only
and is not suitable for a production environment. By default Rook is configured
to provide local storage (/var/lib/rook) and will be provisioned differently
depending on whether or not you startup a single node Kubernetes cluster, or
a multiple node Kubernetes cluster.
- When starting up a single node Kubernetes cluster, Rook will be configured
to start up a single replica, and will allow multiple monitors on the same node.
- When multiple Kubernetes worker nodes are detected, Rook will be configured
to startup a replica on each available node and will schedule monitor processes
on separate nodes providing greater reliability.
@@ -44,21 +44,18 @@ sudo systemctl enable --now containerd-devmapper
# no. of feature arguments
# Skip zeroing blocks for new volumes.
sudo dmsetup create contd-thin-pool \
--table "0 20971520 thin-pool /dev/loop21 /dev/loop20 512 32768 1 skip_block_zeroing"
--table "0 2097152 thin-pool /dev/loop21 /dev/loop20 512 32768 1 skip_block_zeroing"
sudo mkdir -p /etc/containerd/
if [ -f /etc/containerd/config.toml ]
then
sudo sed -i 's|^\(\[plugins\]\).*|\1\n \[plugins.devmapper\]\n pool_name = \"contd-thin-pool\"\n base_image_size = \"4096MB\"|' /etc/containerd/config.toml
sudo sed -i 's|^\(\[plugins\]\).*|\1\n \[plugins.devmapper\]\n pool_name = \"contd-thin-pool\"\n base_image_size = \"512MB\"|' /etc/containerd/config.toml
else
cat<<EOT | sudo tee /etc/containerd/config.toml
[plugins]
[plugins.devmapper]
pool_name = "contd-thin-pool"
base_image_size = "4096MB"
[plugins.cri]
[plugins.cri.containerd]
snapshotter = "devmapper"
base_image_size = "512MB"
EOT
fi
+15 -18
View File
@@ -17,23 +17,21 @@ HIGH_POD_COUNT=${HIGH_POD_COUNT:-""}
# versions
CANAL_VER="${CLRK8S_CANAL_VER:-v3.10}"
CILIUM_VER="${CLRK8S_CILIUM_VER:-v1.6.4}"
FLANNEL_VER="${CLRK8S_FLANNEL_VER:-960b3243b9a7faccdfe7b3c09097105e68030ea7}"
CILIUM_VER="${CLRK8S_CILIUM_VER:-v1.6}"
FLANNEL_VER="${CLRK8S_FLANNEL_VER:-16b0fe66285d1ad1f42b154ab852682f6fafb1a7}"
K8S_VER="${CLRK8S_K8S_VER:-}"
KATA_VER="${CLRK8S_KATA_VER:-1.9.1-kernel-config}"
ROOK_VER="${CLRK8S_ROOK_VER:-v1.2.6}"
METRICS_VER="${CLRK8S_METRICS_VER:-v0.3.6}"
KATA_VER="${CLRK8S_KATA_VER:-1.8.2-kernel-config}"
ROOK_VER="${CLRK8S_ROOK_VER:-v1.1.1}"
METRICS_VER="${CLRK8S_METRICS_VER:-v0.3.5}"
DASHBOARD_VER="${CLRK8S_DASHBOARD_VER:-v2.0.0-beta2}"
INGRES_VER="${CLRK8S_INGRES_VER:-nginx-0.26.1}"
INGRES_VER="${CLRK8S_INGRES_VER:-nginx-0.25.1}"
EFK_VER="${CLRK8S_EFK_VER:-v1.15.1}"
METALLB_VER="${CLRK8S_METALLB_VER:-v0.8.3}"
METALLB_VER="${CLRK8S_METALLB_VER:-v0.8.1}"
NPD_VER="${CLRK8S_NPD_VER:-v0.6.6}"
PROMETHEUS_VER="${CLRK8S_PROMETHEUS_VER:-f458e85e5d7675f7bc253072e1b4c8892b51af0f}"
CNI=${CLRK8S_CNI:-"canal"}
if [[ -z "${RUNNER+x}" ]]; then RUNNER="${CLRK8S_RUNNER:-"crio"}"; fi
RUNNER=${CLRK8S_RUNNER:-"crio"}
NFD_VER="${CLRK8S_NFD_VER:-v0.4.0}"
mode="multinode"
function print_usage_exit() {
exit_code=${1:-0}
@@ -109,7 +107,6 @@ function cluster_init() {
#Ensure single node k8s works
if [ "$(kubectl get nodes | wc -l)" -eq 2 ]; then
kubectl taint nodes --all node-role.kubernetes.io/master-
mode="standalone"
fi
}
@@ -147,10 +144,10 @@ function cni() {
FLANNEL_VER=${1:-$FLANNEL_VER}
FLANNEL_URL="https://github.com/coreos/flannel"
FLANNEL_DIR="0-flannel"
get_repo "${FLANNEL_URL}" "${FLANNEL_DIR}/overlays/${FLANNEL_VER}"
set_repo_version "${FLANNEL_VER}" "${FLANNEL_DIR}/overlays/${FLANNEL_VER}/flannel"
kubectl apply -k "${FLANNEL_DIR}/overlays/${FLANNEL_VER}"
set_repo_version "${FLANNEL_VER}" "${FLANNEL_DIR}/overlays/${FLANNEL_VER}/flannel"
kubectl apply -k "${FLANNEL_DIR}/overlays/${FLANNEL_VER}"
;;
cilium)
CILIUM_VER=${1:-$CILIUM_VER}
@@ -170,7 +167,7 @@ function cni() {
function metrics() {
METRICS_VER="${1:-$METRICS_VER}"
METRICS_URL="https://github.com/kubernetes-sigs/metrics-server.git"
METRICS_URL="https://github.com/kubernetes-incubator/metrics-server.git"
METRICS_DIR="1-core-metrics"
get_repo "${METRICS_URL}" "${METRICS_DIR}/overlays/${METRICS_VER}"
set_repo_version "${METRICS_VER}" "${METRICS_DIR}/overlays/${METRICS_VER}/metrics-server"
@@ -210,9 +207,9 @@ function storage() {
ROOK_DIR=7-rook
# get and apply rook
get_repo "${ROOK_URL}" "${ROOK_DIR}/overlays/${ROOK_VER}/${mode}"
set_repo_version "${ROOK_VER}" "${ROOK_DIR}/overlays/${ROOK_VER}/${mode}/rook"
kubectl apply -k "${ROOK_DIR}/overlays/${ROOK_VER}/${mode}"
get_repo "${ROOK_URL}" "${ROOK_DIR}/overlays/${ROOK_VER}"
set_repo_version "${ROOK_VER}" "${ROOK_DIR}/overlays/${ROOK_VER}/rook"
kubectl apply -k "${ROOK_DIR}/overlays/${ROOK_VER}"
# wait for the rook OSDs to run which means rooks should be ready
while [[ $(kubectl get po --all-namespaces | grep -e 'osd.*Running.*' -c) -lt 1 ]]; do
echo "Waiting for Rook OSD"
+2 -3
View File
@@ -1,4 +1,4 @@
apiVersion: kubeadm.k8s.io/v1beta2
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
---
apiVersion: kubelet.config.k8s.io/v1beta1
@@ -13,10 +13,9 @@ kubeReserved:
cpu: 500m
memory: 256M
---
apiVersion: kubeadm.k8s.io/v1beta2
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
+19 -23
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
@@ -8,15 +9,15 @@ CLR_VER=${CLRK8S_CLR_VER:-""}
HIGH_POD_COUNT=${HIGH_POD_COUNT:-""}
# set no proxy
NO_PROXY_ARRAY=(.svc 10.0.0.0/8 )
NO_PROXY_ARRAY+=( $(hostname -I | awk -F. '{print $1"."$2"."$3".0/24"}'))
if [[ -z "${RUNNER+x}" ]]; then RUNNER="${CLRK8S_RUNNER:-crio}"; fi
ADD_NO_PROXY=".svc,10.244.0.0/16,10.96.0.0/12"
ADD_NO_PROXY+=",$(hostname -I | sed 's/[[:space:]]/,/g')"
: "${RUNNER:=crio}"
# update os version
function upate_os_version() {
if [[ -n "${CLR_VER}" ]]; then
sudo swupd repair -m "${CLR_VER}" --picky --force
if [[ -n "${CLR_VER}" ]];
then
sudo swupd repair -m "${CLR_VER}" --picky
return
fi
sudo swupd update
@@ -144,15 +145,9 @@ function ensure_system_ready() {
# add proxy if found
function setup_proxy() {
set +o nounset
set +o errexit
if [[ ${http_proxy} ]] || [[ ${HTTP_PROXY} ]]; then
echo "Setting up proxy stuff...."
# Setup IP for users too
for ip in "${NO_PROXY_ARRAY[@]}"
do
result=`grep no_proxy /etc/profile.d/proxy.sh | grep $ip`
[ -z "$result" ] && ADD_NO_PROXY+="$ip,"
done
sed_val=${ADD_NO_PROXY//\//\\/}
[ -f /etc/environment ] && sudo sed -i "/no_proxy/I s/$/,${sed_val}/g" /etc/environment
if [ -f /etc/profile.d/proxy.sh ]; then
@@ -161,18 +156,19 @@ function setup_proxy() {
echo "Warning, failed to find /etc/profile.d/proxy.sh to edit no_proxy line"
fi
cat <<EOF | sudo bash -c "cat > /usr/lib/systemd/system.conf.d/proxy.conf"
[Manager]
DefaultEnvironment="HTTP_PROXY=${http_proxy}"
DefaultEnvironment="HTTPS_PROXY=${https_proxy}"
DefaultEnvironment="SOCKS_PROXY=${socks_proxy}"
DefaultEnvironment="NO_PROXY=${no_proxy},${ADD_NO_PROXY}"
services=("${RUNNER}" 'kubelet')
for s in "${services[@]}"; do
sudo mkdir -p "/etc/systemd/system/${s}.service.d/"
cat <<EOF | sudo bash -c "cat > /etc/systemd/system/${s}.service.d/proxy.conf"
[Service]
Environment="HTTP_PROXY=${http_proxy}"
Environment="HTTPS_PROXY=${https_proxy}"
Environment="SOCKS_PROXY=${socks_proxy}"
Environment="NO_PROXY=${no_proxy},${ADD_NO_PROXY}"
EOF
sudo systemctl daemon-reexec
fi
set -o nounset
set -o errexit
done
fi
set -o nounset
}
# init for performing any pre tasks
+2 -30
View File
@@ -13,11 +13,10 @@ is below:
| Tool | Description |
| ---- | ----------- |
| collectd | `collectd` based statistics/metrics gathering daemonset code |
| lib | General library helper functions for forming and launching workloads, and storing results in a uniform manner to aid later analysis |
| lib/cpu-load* | Routines to enable CPU load generation on a cluster |
| report | Rmarkdown based report generator, used to produce a PDF comparison report of 1 or more sets of results |
| scaling | Tests to measure scaling, such as linear or parallel launching of pods |
| report | Rmarkdown based report generator, used to produce a PDF comparison report of 1 or more sets of results |
## Results storage and analysis
@@ -131,30 +130,3 @@ If k8s_parallel.sh was run, the results file is named `k8s-parallel.json` rather
└── scaling-4.png
```
More details about result reporting can be reviewed at [`report`](./report) directory.
# Developers
This section provides some details of how the code is structured and configured. This may be of use whilst modifying
existing or creating new tests.
## Metrics gathering
Metrics can be gathered using either a daemonset deployment of privileged pods used to gather statistics directly from the nodes using a combination of `mpstat`, `free` and `df`, or a daemonset deployment based around `collectd`.
### `collectd` statistics
The `collected` based code can be found in the `collectd` subdirectory. It uses the `collected` configuration found in the `collectd.conf` file to gather statistics, and store the results on the nodes themselves whilst tests are running. At the end of the test, the results are copied from the nodes and stored in the results directory for later processing.
The `collectd` statistics are only configured and gathered if the environment variable `SMF_USE_COLLECTD` is set to non-empty by the test code (that is, only enabled upon request).
### privileged statistics pods
The privileged statistics pods `YAML` can be found in the `scaling/stats.yaml` file. An example of how to invoke and use this daemonset to extract statistics can be found in the `scaling/k8s_scale.sh` file.
## Configuring constant 'loads'
The framework includes some tooling to assist in setting up constant pre-defined 'loads' across the cluster to aid evaluation of their impacts on the scaling metrics.
### CPU load generator
Details of how to configure a constant CPU load are detailed in the [cpu-load documentation](lib/cpu-load.md).
+2
View File
@@ -25,6 +25,8 @@ init_stats() {
}
cleanup_stats() {
local delete_wait_time=$1
# attempting to provide buffer for collectd CPU collection to record adequate history
sleep 6
-3
View File
@@ -9,8 +9,6 @@ LoadPlugin memory
LoadPlugin cpufreq
LoadPlugin df
Hostname localhost
<Plugin "cpu">
ReportByCpu true
ReportByState true
@@ -25,7 +23,6 @@ Hostname localhost
Interface "/^ens/"
Interface "/^enp/"
Interface "/^em/"
Interface "/^eth/"
IgnoreSelected false
</Plugin>
<Plugin "aggregation">
-62
View File
@@ -10,7 +10,6 @@ RESULT_DIR="${LIB_DIR}/../results"
source ${LIB_DIR}/json.bash
source ${LIB_DIR}/k8s-api.bash
source ${LIB_DIR}/cpu-load.bash
source /etc/os-release || source /usr/lib/os-release
die() {
@@ -68,48 +67,6 @@ init_env()
# been deliberately injected into the cluster under test.
}
framework_init() {
info "Initialising"
check_cmds "${cmds[@]}"
info "Checking k8s accessible"
local worked=$( kubectl get nodes > /dev/null 2>&1 && echo $? || echo $? )
if [ "$worked" != 0 ]; then
die "kubectl failed to get nodes"
fi
info $(get_num_nodes) "k8s nodes in 'Ready' state found"
k8s_api_init
# Launch our stats gathering pod
if [ -n "$SMF_USE_COLLECTD" ]; then
info "Setting up collectd"
init_stats $wait_time
fi
# And now we can set up our results storage then...
metrics_json_init "k8s"
save_config
# Initialise the cpu load generators now - after json init, as they may
# produce some json results (config) data.
cpu_load_init
}
framework_shutdown() {
metrics_json_save
k8s_api_shutdown
cpu_load_shutdown
if [ -n "$SMF_USE_COLLECTD" ]; then
cleanup_stats
fi
}
# finds elements in $1 that are not in $2
find_unique_pods() {
local list_a=$1
@@ -129,22 +86,3 @@ find_unique_pods() {
fi
done
}
# waits for process to complete within a given time range
waitForProcess(){
wait_time="$1"
sleep_time="$2"
cmd="$3"
proc_info_msg="$4"
while [ "$wait_time" -gt 0 ]; do
if eval "$cmd"; then
return 0
else
info "$proc_info_msg"
sleep "$sleep_time"
wait_time=$((wait_time-sleep_time))
fi
done
return 1
}
-104
View File
@@ -1,104 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
# Helper routines for setting up a constant CPU load on the cluster/nodes
CPULOAD_DIR=${THIS_FILE%/*}
# Default to testing all cores
SMF_CPU_LOAD_NODES_NCPU=${SMF_CPU_LOAD_NODES_NCPU:-0}
# Default to 100% load (yes, this might kill your node)
SMF_CPU_LOAD_NODES_PERCENT=${SMF_CPU_LOAD_NODES_PERCENT:-}
# Default to not setting any limits or requests, so no cpuset limiting and
# no cpu core pinning
SMF_CPU_LOAD_NODES_LIMIT=${SMF_CPU_LOAD_NODES_LIMIT:-}
SMF_CPU_LOAD_NODES_REQUEST=${SMF_CPU_LOAD_NODES_REQUEST:-}
cpu_load_post_deploy_sleep=${cpu_load_post_deploy_sleep:-30}
cpu_per_node_daemonset=cpu-load
clean_up_cpu_per_node=false
# Use a DaemonSet to place one cpu stressor on each node.
cpu_per_node_init() {
info "Generating per-node CPU load daemonset"
local ds_template=${CPULOAD_DIR}/cpu_load_daemonset.yaml.in
local ds_yaml=${ds_template%\.in}
# Grab a copy of the template
cp -f ${ds_template} ${ds_yaml}
# If a setting is not used (defined), then delete its relevant
# lines from the YAML. Note, the YAML is constructed when necessary
# with comments on the correct lines to ensure all necessary lines are
# deleted
if [ -z "$SMF_CPU_LOAD_NODES_NCPU" ]; then
sed -i '/CPU_NCPU/d' ${ds_yaml}
fi
if [ -z "${SMF_CPU_LOAD_NODES_PERCENT}" ]; then
sed -i '/CPU_PERCENT/d' ${ds_yaml}
fi
if [ -z "${SMF_CPU_LOAD_NODES_LIMIT}" ]; then
sed -i '/CPU_LIMIT/d' ${ds_yaml}
fi
if [ -z "${SMF_CPU_LOAD_NODES_REQUEST}" ]; then
sed -i '/CPU_REQUEST/d' ${ds_yaml}
fi
# And then finally replace all the remaining defined parts with the
# real values.
sed -i \
-e "s|@CPU_NCPU@|${SMF_CPU_LOAD_NODES_NCPU}|g" \
-e "s|@CPU_PERCENT@|${SMF_CPU_LOAD_NODES_PERCENT}|g" \
-e "s|@CPU_LIMIT@|${SMF_CPU_LOAD_NODES_LIMIT}|g" \
-e "s|@CPU_REQUEST@|${SMF_CPU_LOAD_NODES_REQUEST}|g" \
${ds_yaml}
# Launch the daemonset...
info "Deploying cpu-load-per-node daemonset"
kubectl apply -f ${ds_yaml}
kubectl rollout status --timeout=${wait_time}s daemonset/${cpu_per_node_daemonset}
clean_up_cpu_per_node=yes
info "cpu-load-per-node daemonset Deployed"
if [ -n "$cpu_load_post_deploy_sleep" ]; then
info "Sleeping ${cpu_load_post_deploy_sleep}s for cpu-load to settle"
sleep ${cpu_load_post_deploy_sleep}
fi
# And store off our config into the JSON results
metrics_json_start_array
local json="$(cat << EOF
{
"LOAD_NODES_NCPU": "${SMF_CPU_LOAD_NODES_NCPU}",
"LOAD_NODES_PERCENT": "${SMF_CPU_LOAD_NODES_PERCENT}",
"LOAD_NODES_LIMIT": "${SMF_CPU_LOAD_NODES_LIMIT}",
"LOAD_NODES_REQUEST": "${SMF_CPU_LOAD_NODES_REQUEST}"
}
EOF
)"
metrics_json_add_array_element "$json"
metrics_json_end_array "cpu-load"
}
cpu_load_init() {
info "Check if we need CPU load generators..."
# This is defaulted of off (not defined), unless the high level test requests it.
if [ -n "$SMF_CPU_LOAD_NODES" ]; then
info "Initialising per-node CPU load"
cpu_per_node_init
fi
}
cpu_load_shutdown() {
if [ "$clean_up_cpu_per_node" = "yes" ]; then
info "Cleaning up cpu per node load daemonset"
kubectl delete daemonset --wait=true --timeout=${delete_wait_time}s "${cpu_per_node_daemonset}" || true
fi
}
-81
View File
@@ -1,81 +0,0 @@
# `cpu-load` stack stresser
The `cpu-load` stress functionality of the scaling framework allows you to optionally add a constant CPU stress
load to cluster under test whilst the tests are running. This aids impact analysis of CPU load.
The `cpu-load` functionality utilises the [`stress-ng`](https://kernel.ubuntu.com/git/cking/stress-ng.git/) tool
to generate the CPU load. Some of the configuration parameters are taken directoy from the `stress-ng` command line.
## Configuration
`cpu-load` is configured via a number of environment variables:
| Tool | Description |
| ---- | ----------- |
| collectd | `collectd` based statistics/metrics gathering daemonset code |
| lib | General library helper functions for forming and launching workloads, and storing results in a uniform manner to aid later analysis |
| report | Rmarkdown based report generator, used to produce a PDF comparison report of 1 or more sets of results |
| scaling | Tests to measure scaling, such as linear or parallel launching of pods |
| Variable | Description | Default |
| -------- | ----------- | ------- |
| `SMF_CPU_LOAD_NODES` | Set to non-empty to deploy `cpu-load` stressor | unset (off) |
| `SMF_CPU_LOAD_NODES_NCPU` | Number of stressor threads to launch per node | 0 (one per cpu) |
| `SMF_CPU_LOAD_NODES_PERCENT` | Percentage of CPU to load | unset (100%) |
| `SMF_CPU_LOAD_NODES_LIMIT` | k8s cpu resource limit to set | unset (none) |
| `SMF_CPU_LOAD_NODES_REQUEST` | k8s cpu resource request to set | unset (none) |
| `cpu_load_post_deploy_sleep` | Seconds to sleep for `cpu-load` deployment to settle | 30 |
`SMF_CPU_LOAD_NODES` must be set to a non-empty string to enable the `cpu-load` functionality. `cpu-load` uses
a daemonSet to deploy one `stress-ng` single container pod to each active node in the cluster.
Any of the `SMF_CPU_LOAD_NODES_*` variables can be set, or unset, and the daemonSet pods will be configured
appropriately.
## Examples
The combinations of settings available allow a lot of flexibility. Below are some common example setups:
### 50% CPU load on all cores of all nodes (`stress-ng`)
Here we allow `stress-ng` to spawn workers to cover all the CPUs on each node, but ask it to restrict its
bandwidth use to 50% of the CPU. We do not use the k8s limits.
```bash
export SMF_CPU_LOAD_NODES=true
#export SMF_CPU_LOAD_NODES_NCPU=
export SMF_CPU_LOAD_NODES_PERCENT=50
#export SMF_CPU_LOAD_NODES_LIMIT=999m
#export SMF_CPU_LOAD_NODES_REQUEST=999m
```
### 50% CPU load on 1 un-pinned core of all nodes (k8s `limits`)
Here we set `stress-ng` to run a single worker thread at 100% CPU, but use the k8s resource limits to restrict
actual CPU usage to 50%. Because the k8s limit and request are not whole interger units, if the static policy is
in place on the k8s cluster, the pods will be classified as Guaranteed QoS, but will *not* get pinned to a specific
cpuset.
```bash
export SMF_CPU_LOAD_NODES=true
export SMF_CPU_LOAD_NODES_NCPU=1
export SMF_CPU_LOAD_NODES_PERCENT=100
export SMF_CPU_LOAD_NODES_LIMIT=500m
export SMF_CPU_LOAD_NODES_REQUEST=500m
```
### 50% CPU load pinned to 1 core, on all nodes
Here we set `stress-ng` to run a single worker thread at 50% CPU, and use the k8s resource limits to classify the
pod as Guaranteed, and as we are using whole integer units of CPU resource requests, if the static policy manager is
in play, the thread will be pinned to a single cpu cpuset.
```bash
export SMF_CPU_LOAD_NODES=true
export SMF_CPU_LOAD_NODES_NCPU=1
export SMF_CPU_LOAD_NODES_PERCENT=50
export SMF_CPU_LOAD_NODES_LIMIT=1
export SMF_CPU_LOAD_NODES_REQUEST=1
```
-30
View File
@@ -1,30 +0,0 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: cpu-load
spec:
selector:
matchLabels:
name: cpu-load-pods
template:
metadata:
labels:
name: cpu-load-pods
spec:
hostNetwork: true
terminationGracePeriodSeconds: 0
containers:
- name: cpu-load
imagePullPolicy: IfNotPresent
image: polinux/stress-ng
command: ["stress-ng"]
args: # comment fields here so we can *delete* sections on demand
- "--cpu"
- "@CPU_NCPU@"
- "-l" #CPU_PERCENT
- "@CPU_PERCENT@" #CPU_PERCENT
resources:
limits:
cpu: @CPU_LIMIT@
requests:
cpu: @CPU_REQUEST@
+1 -2
View File
@@ -100,7 +100,7 @@ setup() {
}
run() {
docker run ${extra_opts} --rm -v ${HOSTINPUTDIR}:${GUESTINPUTDIR} -v ${HOSTOUTPUTDIR}:${GUESTOUTPUTDIR} ${extra_volumes} ${IMAGE} ${extra_command}
docker run -ti --rm -v ${HOSTINPUTDIR}:${GUESTINPUTDIR} -v ${HOSTOUTPUTDIR}:${GUESTOUTPUTDIR} ${extra_volumes} ${IMAGE} ${extra_command}
ls -la ${HOSTOUTPUTDIR}/*
}
@@ -113,7 +113,6 @@ main() {
# In debug mode, run a shell instead of the default report generation
extra_command="bash"
extra_volumes="-v ${HOSTSCRIPTDIR}:${GUESTSCRIPTDIR}"
extra_opts="-ti"
;;
esac
done
@@ -435,7 +435,6 @@ mem_line_plot <- ggplot() +
ylab("System Avail (Gb)") +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./mem_scale, name="pods")) +
ggtitle("System Memory free") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page1 = grid.arrange(
@@ -474,7 +473,6 @@ cpu_line_plot <- ggplot() +
xlab("seconds") +
ylab("System CPU Idle (%)") +
ggtitle("System CPU usage") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page2 = grid.arrange(
@@ -499,7 +497,6 @@ boot_line_plot <- ggplot() +
xlab("pods") +
ylab("Boot time (s)") +
ggtitle("Pod boot time") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page3 = grid.arrange(
@@ -538,7 +535,6 @@ inode_line_plot <- ggplot() +
ylab("inodes free") +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./inode_scale, name="pods")) +
ggtitle("inodes free") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page4 = grid.arrange(
@@ -581,7 +577,6 @@ interface_packet_line_plot <- ggplot() +
ylab("packets") +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./ip_scale, name="pods")) +
ggtitle("interface packets") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
oct_scale = max(c(max(ifoctetdata$tx, na.rm=TRUE),
@@ -614,7 +609,6 @@ interface_octet_line_plot <- ggplot() +
ylab("octets") +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./oct_scale, name="pods")) +
ggtitle("interface octets") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page5 = grid.arrange(
@@ -657,9 +651,8 @@ interface_drop_line_plot <- ggplot() +
labs(colour="") +
xlab("seconds") +
ylab("drops") +
scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./drop_scale, name="pods", labels=comma)) +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./drop_scale, name="pods")) +
ggtitle("interface drops") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
# errors are often 0, so providing 1 so we won't scale by infinity
@@ -692,9 +685,8 @@ interface_error_line_plot <- ggplot() +
labs(colour="") +
xlab("seconds") +
ylab("errors") +
scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./error_scale, name="pods", labels=comma)) +
scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./error_scale, name="pods")) +
ggtitle("interface errors") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page6 = grid.arrange(
-4
View File
@@ -8,10 +8,6 @@ author: "Auto generated"
date: "`r format(Sys.time(), '%d %B, %Y')`"
output:
pdf_document:
# Shrink the page margins so we get bigger/better resolution on the graphs
# Keep the top and bottom margins reasonable, as we are really interested in
# gaining 'width', and if we trim the bottom too much, we lose the page numbers.
geometry: "left=1cm, right=1cm, top=2cm, bottom=2cm"
urlcolor: blue
---
@@ -190,13 +190,13 @@ for (currentdir in resultdirs) {
"avg_inode"=round(inodetotal/num_pods, 4)
)
inodestats=rbind(inodestats, local_inodes)
# And collect up our rows into our global table of all results
# These two tables *should* be the source of all the data we need to
# process and plot (apart from the stats....)
bootdata=rbind(bootdata, local_bootdata, make.row.names=FALSE)
nodedata=rbind(nodedata, local_nodedata, make.row.names=FALSE)
}
# And collect up our rows into our global table of all results
# These two tables *should* be the source of all the data we need to
# process and plot (apart from the stats....)
bootdata=rbind(bootdata, local_bootdata, make.row.names=FALSE)
nodedata=rbind(nodedata, local_nodedata, make.row.names=FALSE)
}
}
@@ -229,7 +229,6 @@ mem_line_plot <- ggplot(data=nodedata, aes(n_pods,
ylab("System Avail (Gb)") +
scale_y_continuous(labels=comma) +
ggtitle("System Memory free") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page1 = grid.arrange(
@@ -257,7 +256,6 @@ cpu_line_plot <- ggplot(data=nodedata, aes(n_pods,
xlab("pods") +
ylab("System CPU Idle (%)") +
ggtitle("System CPU usage") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page2 = grid.arrange(
@@ -281,7 +279,6 @@ boot_line_plot <- ggplot() +
xlab("pods") +
ylab("Boot time (s)") +
ggtitle("Pod boot time") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page3 = grid.arrange(
@@ -310,7 +307,6 @@ inode_line_plot <- ggplot(data=nodedata, aes(n_pods,
ylab("inodes free") +
scale_y_continuous(labels=comma) +
ggtitle("inodes free") +
theme(legend.position="bottom") +
theme(axis.text.x=element_text(angle=90))
page4 = grid.arrange(
-3
View File
@@ -13,7 +13,6 @@ deployment="busybox"
stats_pod="stats"
NUM_PODS=${NUM_PODS:-20}
NUM_DEPLOYMENTS=${NUM_DEPLOYMENTS:-20}
STEP=${STEP:-1}
LABEL=${LABEL:-magiclabel}
@@ -25,8 +24,6 @@ delete_wait_time=${delete_wait_time:-600}
settle_time=${settle_time:-5}
use_api=${use_api:-yes}
grace=${grace:-30}
proc_wait_time=${proc_wait_time:-20}
proc_sleep_time=2
declare -a new_pods
declare -A node_basemem
+9 -2
View File
@@ -126,10 +126,14 @@ init() {
# a nice way to do it (unless you want to parse 'descibe nodes')
# Have a read of https://github.com/kubernetes/kubernetes/issues/25353
framework_init
k8s_api_init
# Ensure we pre-cache the container image etc.
warmup
# And now we can set up our results storage then...
metrics_json_init "k8s"
save_config
}
save_config(){
@@ -214,8 +218,11 @@ cleanup() {
# First try to save any results we got
metrics_json_end_array "BootResults"
metrics_json_save
kill_deployment "${deployment}" "${LABEL}" "${LABELVALUE}" ${delete_wait_time}
framework_shutdown
k8s_api_shutdown
}
show_vars()
+9 -3
View File
@@ -169,7 +169,7 @@ EOF
if [ $n_pods -eq 0 ]; then
local pods_per_gb=0
else
local pods_per_gb=$(printf "%0f" $(bc -l <<< "scale=2; ($total_mem_used/1024) / $n_pods"))
local pods_per_gb=$(bc -l <<< "scale=2; ($total_mem_used/1024) / $n_pods")
fi
local mem_json="$(cat << EOF
"memory": {
@@ -209,7 +209,7 @@ init() {
# FIXME - check the node(s) can run enough pods - check 'max-pods' in the
# kubelet config - from 'kubectl describe node -o json' ?
framework_init
k8s_api_init
# Launch our stats gathering pod
kubectl apply -f ${SCRIPT_PATH}/${stats_pod}.yaml
@@ -218,6 +218,10 @@ init() {
# FIXME - we should probably 'warm up' the cluster with the container image(s) we will
# use for testing, otherwise the download time will likely be included in the first pod
# boot time.
# And now we can set up our results storage then...
metrics_json_init "k8s"
save_config
}
save_config(){
@@ -343,7 +347,9 @@ EOF
)"
metrics_json_add_fragment "$json"
framework_shutdown
metrics_json_save
k8s_api_shutdown
}
show_vars()
+9 -3
View File
@@ -195,7 +195,7 @@ EOF
if [ $n_pods -eq 0 ]; then
local pods_per_gb=0
else
local pods_per_gb=$(printf "%0f" $(bc -l <<< "scale=2; ($total_mem_used/1024) / $n_pods"))
local pods_per_gb=$(bc -l <<< "scale=2; ($total_mem_used/1024) / $n_pods")
fi
local mem_json="$(cat << EOF
"memory": {
@@ -235,7 +235,7 @@ init() {
# FIXME - check the node(s) can run enough pods - check 'max-pods' in the
# kubelet config - from 'kubectl describe node -o json' ?
framework_init
k8s_api_init
# Launch our stats gathering pod
kubectl apply -f ${SCRIPT_PATH}/${stats_pod}.yaml
@@ -244,6 +244,10 @@ init() {
# FIXME - we should probably 'warm up' the cluster with the container image(s) we will
# use for testing, otherwise the download time will likely be included in the first pod
# boot time.
# And now we can set up our results storage then...
metrics_json_init "k8s"
save_config
}
save_config(){
@@ -406,7 +410,9 @@ EOF
)"
metrics_json_add_fragment "$json"
framework_shutdown
metrics_json_save
k8s_api_shutdown
}
show_vars()
-285
View File
@@ -1,285 +0,0 @@
#!/bin/bash
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
set -e
# Pull in some common, useful, items
SCRIPT_PATH=$(dirname "$(readlink -f "$0")")
source "${SCRIPT_PATH}/../lib/common.bash"
source "${SCRIPT_PATH}/common.bash"
LABELVALUE=${LABELVALUE:-scale_net}
# Set some default metrics env vars
TEST_ARGS="runtime=${RUNTIME}"
TEST_NAME="k8s scaling net"
input_yaml="${SCRIPT_PATH}/net-serve.yaml.in"
input_json="${SCRIPT_PATH}/net-serve.json.in"
name_base_depl="net-serve"
# $1 is the launch time in seconds this pod/container took to start up.
# $2 is the number of pod/containers under test
# $3 is the time to pod network measure
grab_stats(){
local launch_time_ms=$1
local n_pods=$2
local net_time=$3
info "And grab some stats"
local date_json="$(cat << EOF
"date": {
"ns": $(date +%s%N),
"Date": "$(date -u +"%Y-%m-%dT%T.%3N")"
}
EOF
)"
metrics_json_add_array_fragment "$date_json"
local pods_json="$(cat << EOF
"n_pods": {
"Result": ${n_pods},
"Units" : "int"
}
EOF
)"
metrics_json_add_array_fragment "$pods_json"
local time_to_pod_net_json="$(cat << EOF
"time_to_pod_net": {
"Result": ${net_time},
"Units" : "ms"
}
EOF
)"
metrics_json_add_array_fragment "$time_to_pod_net_json"
local launch_json="$(cat << EOF
"launch_time": {
"Result": $launch_time_ms,
"Units" : "ms"
}
EOF
)"
metrics_json_add_array_fragment "$launch_json"
info "launch [$launch_time_ms]"
metrics_json_close_array_element
}
init() {
info "Initialising"
local cmds=("bc" "jq")
check_cmds "${cmds[@]}"
info "Checking Kubernetes accessible"
local worked=$( kubectl get nodes > /dev/null 2>&1 && echo $? || echo $? )
if [ "$worked" != 0 ]; then
die "kubectl failed to get nodes"
fi
info $(get_num_nodes) "Kubernetes nodes in 'Ready' state found"
framework_init
}
save_config() {
metrics_json_start_array
local json="$(cat << EOF
{
"testname": "${TEST_NAME}",
"NUM_DEPLOYMENTS": ${NUM_DEPLOYMENTS},
"STEP": ${STEP},
"wait_time": ${wait_time},
"delete_wait_time": ${delete_wait_time},
"settle_time": ${settle_time}
}
EOF
)"
metrics_json_add_array_element "$json"
metrics_json_end_array "Config"
}
run() {
info "Running test"
local header_post="Content-Type: application/json"
local base_curl=${API_ADDRESS}:${API_PORT}/apis/apps/v1/namespaces/default/deployments
trap cleanup EXIT QUIT KILL
metrics_json_start_array
for reqs in $(seq ${STEP} ${STEP} ${NUM_DEPLOYMENTS}); do
local deployment="${name_base_depl}${reqs}"
info "Testing replicas ${reqs} of ${NUM_DEPLOYMENTS}"
# Generate the next yaml file
local runtime_command
if [ -n "$RUNTIME" ]; then
runtime_command="s|@RUNTIMECLASS@|${RUNTIME}|g"
else
runtime_command="/@RUNTIMECLASS@/d"
fi
local input_template
local generated_file
if [ "$use_api" != "no" ]; then
input_template=$input_json
generated_file=$generated_json
else
input_template=$input_yaml
generated_file=$generated_yaml
fi
sed -e $runtime_command \
-e "s|@DEPLOYMENT@|${deployment}|g" \
-e "s|@LABEL@|${LABEL}|g" \
-e "s|@LABELVALUE@|${LABELVALUE}|g" \
-e "s|@GRACE@|${grace}|g" \
< ${input_template} > ${generated_file}
info "Applying changes"
local start_time=$(date +%s%N)
if [ "$use_api" != "no" ]; then
curl -s ${base_curl} -XPOST -H "${header_post}" -d@${generated_file} > /dev/null
else
kubectl apply -f ${generated_file}
fi
kubectl rollout status --timeout=${wait_time}s deployment/${deployment}
kubectl expose --port=8080 deployment $deployment
# Check service exposed
cmd="kubectl get services $deployment -n default --no-headers=true"
waitForProcess "$proc_wait_time" "$proc_sleep_time" "$cmd" "Waiting for service"
IP=$(kubectl get services $deployment -n default --no-headers=true | awk '{printf $3}')
end_net=$(date +%s%N)
info "IP: $IP"
# service health check
cmd="curl --noproxy \"*\" http://$IP:8080/healthz"
waitForProcess "$proc_wait_time" "$proc_sleep_time" "$cmd" "http server is not ready yet!!"
RESP=$(curl -s --noproxy "*" http://$IP:8080/echo?msg=curl%20request%20to%20$deployment)
local end_time=$(date +%s%N)
info "http reply: $RESP"
local total_milliseconds=$(( (end_time - start_time) / 1000000 ))
local net_diff=$(( (end_net - start_time) / 1000000 ))
info "Took $total_milliseconds ms ($end_time - $start_time)"
info "Net took $net_diff ms"
kubectl delete service $deployment
if [ $? -ne 0 ]; then
echo "kubectl delete service failed"
exit
fi
sleep ${settle_time}
grab_stats $total_milliseconds $reqs $net_diff
done
}
cleanup() {
info "Cleaning up"
# First try to save any results we got
metrics_json_end_array "BootResults"
local start_time=$(date +%s%N)
for reqs in $(seq ${STEP} ${STEP} ${NUM_DEPLOYMENTS}); do
local deployment="${name_base_depl}${reqs}"
kubectl delete deployment --wait=true --timeout=${delete_wait_time}s ${deployment} || true
done
for x in $(seq 1 ${delete_wait_time}); do
local npods=$(kubectl get pods -l=${LABEL}=${LABELVALUE} -o=name | wc -l)
if [ $npods -eq 0 ]; then
echo "All pods have terminated at cycle $x"
local alldied=true
break;
fi
sleep 1
done
if [ -z "$alldied" ]; then
echo "ERROR: Not all pods died!"
fi
local end_time=$(date +%s%N)
local total_milliseconds=$(( (end_time - start_time) / 1000000 ))
info "Delete Took $total_milliseconds ms ($end_time - $start_time)"
local json="$(cat << EOF
"Delete": {
"Result": ${total_milliseconds},
"Units" : "ms"
}
EOF
)"
metrics_json_add_fragment "$json"
framework_shutdown
}
show_vars() {
echo -e "\nEnvironment variables:"
echo -e "\tName (default)"
echo -e "\t\tDescription"
echo -e "\tNUM_DEPLOYMENTS (${NUM_DEPLOYMENTS})"
echo -e "\t\tNumber of deployments to launch"
echo -e "\tSTEP (${STEP})"
echo -e "\t\tNumber of pods to launch per cycle"
echo -e "\twait_time (${wait_time})"
echo -e "\t\tSeconds to wait for pods to become ready"
echo -e "\tproc_wait_time (${proc_wait_time})"
echo -e "\t\tSeconds to wait for net server process to become ready"
echo -e "\tdelete_wait_time (${delete_wait_time})"
echo -e "\t\tSeconds to wait for all pods to be deleted"
echo -e "\tsettle_time (${settle_time})"
echo -e "\t\tSeconds to wait after pods ready before taking measurements"
echo -e "\tuse_api (${use_api})"
echo -e "\t\tspecify yes or no to use the API to launch pods"
echo -e "\tgrace (${grace})"
echo -e "\t\tspecify the grace period in seconds for workload pod termination"
}
help() {
usage=$(cat << EOF
Usage: $0 [-h] [options]
Description:
Launch a series of workloads and take time to pod network metric measurements after
each launch.
Options:
-h, Help page.
EOF
)
echo "$usage"
show_vars
}
main() {
local OPTIND
while getopts "h" opt;do
case ${opt} in
h)
help
exit 0;
;;
esac
done
shift $((OPTIND-1))
init
run
}
main "$@"
+26 -4
View File
@@ -15,8 +15,6 @@ source "${SCRIPT_PATH}/../collectd/collectd.bash"
NUM_PODS=${NUM_PODS:-20}
STEP=${STEP:-1}
SMF_USE_COLLECTD=true
LABELVALUE=${LABELVALUE:-gandalf}
pod_command="[\"tail\", \"-f\", \"/dev/null\"]"
@@ -66,7 +64,27 @@ EOF
}
init() {
framework_init
info "Initialising"
local cmds=("bc" "jq")
check_cmds "${cmds[@]}"
info "Checking k8s accessible"
local worked=$( kubectl get nodes > /dev/null 2>&1 && echo $? || echo $? )
if [ "$worked" != 0 ]; then
die "kubectl failed to get nodes"
fi
info $(get_num_nodes) "k8s nodes in 'Ready' state found"
k8s_api_init
# Launch our stats gathering pod
init_stats $wait_time
# And now we can set up our results storage then...
metrics_json_init "k8s"
save_config
}
save_config(){
@@ -180,7 +198,11 @@ EOF
)"
metrics_json_add_fragment "$json"
framework_shutdown
metrics_json_save
cleanup_stats $delete_wait_time
k8s_api_shutdown
}
show_vars()
-40
View File
@@ -1,40 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"run": "net-serve"
},
"name": "@DEPLOYMENT@"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"run": "net-serve"
}
},
"template": {
"metadata": {
"labels": {
"run": "net-serve",
"@LABEL@": "@LABELVALUE@"
}
},
"spec": {
"terminationGracePeriodSeconds": @GRACE@,
"runtimeClassName": "@RUNTIMECLASS@",
"automountServiceAccountToken": false,
"containers": [{
"name": "net-serve",
"image": "gcr.io/kubernetes-e2e-test-images/agnhost:2.8",
"imagePullPolicy": "IfNotPresent",
"args": [
"netexec"
]
}],
"restartPolicy": "Always"
}
}
}
}
-27
View File
@@ -1,27 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: net-serve
name: @DEPLOYMENT@
spec:
replicas: 1
selector:
matchLabels:
run: net-serve
template:
metadata:
labels:
run: net-serve
@LABEL@: @LABELVALUE@
spec:
terminationGracePeriodSeconds: @GRACE@
runtimeClassName: @RUNTIMECLASS@
automountServiceAccountToken: false
containers:
- name: net-serve
image: gcr.io/kubernetes-e2e-test-images/agnhost:2.8
imagePullPolicy: IfNotPresent
args:
- netexec
restartPolicy: Always