mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Now it is still a high number, but one that has a more realistic chance to run effectively on small machines. PiperOrigin-RevId: 770887549
380 lines
11 KiB
Go
380 lines
11 KiB
Go
// Copyright 2024 The gVisor 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 wordpress
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gvisor.dev/gvisor/test/kubernetes/benchmarks/httpbench"
|
|
"gvisor.dev/gvisor/test/kubernetes/benchmarks/profiling"
|
|
"gvisor.dev/gvisor/test/kubernetes/k8sctx"
|
|
"gvisor.dev/gvisor/test/kubernetes/testcluster"
|
|
v13 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
)
|
|
|
|
const (
|
|
wordpressImage = "wordpress:6.2.0-php8.2-apache"
|
|
mariaDBImage = "mariadb:10.11.3-jammy"
|
|
wordpressPort = 80
|
|
mariaDBPort = 3306
|
|
wordpressBenchmarkDuration = 55 * time.Second
|
|
wordpressRequestTimeout = 10 * time.Second
|
|
wordpressLoginPage = "/wp-login.php"
|
|
mariaDBName = "wpbench"
|
|
mariaDBUser = "wpuser"
|
|
mariaDBPassword = "wppassword"
|
|
mariaDBRootPassword = "hunter2"
|
|
mariaDBVolumeName = "wpdata"
|
|
mariaDBVolumeDirectory = "/var/lib/mysql"
|
|
|
|
wordpressServerLabelKey = "app.kubernetes.io/name"
|
|
wordpressServerLabelValue = "wordpress"
|
|
mariaDBServerLabelKey = "app.kubernetes.io/name"
|
|
mariaDBServerLabelValue = "mariadb"
|
|
)
|
|
|
|
var (
|
|
threads = []int{1, 8, 256}
|
|
targetQPS = []int{1, 64, httpbench.InfiniteQPS}
|
|
wantPercentiles = []int{50, 95, 99}
|
|
)
|
|
|
|
// BenchmarkWordpress runs a benchmark of WordPress performance.
|
|
func BenchmarkWordpress(ctx context.Context, t *testing.T, k8sCtx k8sctx.KubernetesContext, cluster *testcluster.TestCluster) {
|
|
benchmarkNS := cluster.Namespace(testcluster.NamespaceBenchmark)
|
|
if err := benchmarkNS.Reset(ctx); err != nil {
|
|
t.Fatalf("cannot reset namespace: %v", err)
|
|
}
|
|
defer benchmarkNS.Cleanup(ctx)
|
|
endProfiling, err := profiling.MaybeSetup(ctx, t, k8sCtx, cluster, benchmarkNS)
|
|
if err != nil {
|
|
t.Fatalf("Failed to setup profiling: %v", err)
|
|
}
|
|
defer endProfiling()
|
|
|
|
// Create a persistent volume on which to store the database data.
|
|
dbVolume := benchmarkNS.GetPersistentVolume(mariaDBVolumeName, "30Gi")
|
|
dbVolume, err = cluster.CreatePersistentVolume(ctx, dbVolume)
|
|
if err != nil {
|
|
t.Fatalf("failed to create persistent volume: %v", err)
|
|
}
|
|
defer cluster.DeletePersistentVolume(ctx, dbVolume)
|
|
|
|
databaseName := "mariadb"
|
|
mariaDBImg, err := k8sCtx.ResolveImage(ctx, mariaDBImage)
|
|
if err != nil {
|
|
t.Fatalf("failed to resolve image: %v", err)
|
|
}
|
|
database := newMariaDBServer(benchmarkNS, databaseName, mariaDBImg, dbVolume)
|
|
database, err = cluster.ConfigurePodForTertiaryNodepool(ctx, database)
|
|
if err != nil {
|
|
t.Fatalf("Failed to configure pod for tertiary nodepool: %v", err)
|
|
}
|
|
database, err = cluster.CreatePod(ctx, database)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create pod: %v", err)
|
|
}
|
|
defer cluster.DeletePod(ctx, database)
|
|
if err := cluster.WaitForPodRunning(ctx, database); err != nil {
|
|
t.Fatalf("Failed to wait for pod: %v", err)
|
|
}
|
|
databaseService := newMariaDBService(benchmarkNS, databaseName)
|
|
databaseService, err = cluster.CreateService(ctx, databaseService)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create database service: %v", err)
|
|
}
|
|
defer cluster.DeleteService(ctx, databaseService)
|
|
mariaDBIP := testcluster.GetIPFromService(databaseService)
|
|
|
|
name := "wordpress"
|
|
wordpressImg, err := k8sCtx.ResolveImage(ctx, wordpressImage)
|
|
if err != nil {
|
|
t.Fatalf("Failed to resolve image: %v", err)
|
|
}
|
|
server := newWordpressServer(benchmarkNS, name, wordpressImg, mariaDBIP)
|
|
server, err = cluster.ConfigurePodForRuntimeTestNodepool(ctx, server)
|
|
if err != nil {
|
|
t.Fatalf("Failed to configure pod for runtime nodepool: %v", err)
|
|
}
|
|
server, err = testcluster.SetContainerResources(server, "", testcluster.ContainerResourcesRequest{})
|
|
if err != nil {
|
|
t.Fatalf("Failed to set container resources: %v", err)
|
|
}
|
|
server, err = cluster.CreatePod(ctx, server)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create pod: %v", err)
|
|
}
|
|
defer cluster.DeletePod(ctx, server)
|
|
|
|
if err := cluster.WaitForPodRunning(ctx, server); err != nil {
|
|
t.Fatalf("Failed to wait for pod: %v", err)
|
|
}
|
|
|
|
service := newWordpressService(benchmarkNS, name)
|
|
service, err = cluster.CreateService(ctx, service)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create service: %v", err)
|
|
}
|
|
defer cluster.DeleteService(ctx, service)
|
|
wordpressIP := testcluster.GetIPFromService(service)
|
|
|
|
// Install WordPress.
|
|
installWordpressPod := newWordpressInstall(benchmarkNS, "install-wordpress", wordpressIP)
|
|
installWordpressPod, err = cluster.ConfigurePodForClientNodepool(ctx, installWordpressPod)
|
|
if err != nil {
|
|
t.Fatalf("Failed to configure pod for client nodepool: %v", err)
|
|
}
|
|
installWordpressPod, err = cluster.CreatePod(ctx, installWordpressPod)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create pod: %v", err)
|
|
}
|
|
defer cluster.DeletePod(ctx, installWordpressPod)
|
|
if err := cluster.WaitForPodCompleted(ctx, installWordpressPod); err != nil {
|
|
t.Fatalf("Failed to wait for pod: %v", err)
|
|
}
|
|
cluster.DeletePod(ctx, installWordpressPod)
|
|
|
|
var rounds []httpbench.Round
|
|
for _, numThreads := range threads {
|
|
for _, qps := range targetQPS {
|
|
if qps < numThreads {
|
|
continue
|
|
}
|
|
onlyReport := []httpbench.MetricType{httpbench.RequestsPerSecond}
|
|
// If we're testing at max QPS, don't report latency,
|
|
// because all requests will hit the timeout.
|
|
// Otherwise, only report latency, because the throughput
|
|
// is exactly determined by the QPS target anyway.
|
|
if qps != httpbench.InfiniteQPS {
|
|
onlyReport = append(onlyReport, httpbench.Latency)
|
|
}
|
|
rounds = append(rounds, httpbench.Round{
|
|
NumThreads: numThreads,
|
|
TargetQPS: qps,
|
|
Duration: wordpressBenchmarkDuration,
|
|
OnlyReport: onlyReport,
|
|
})
|
|
}
|
|
}
|
|
benchmark := &httpbench.HTTPBenchmark{
|
|
Name: "wordpress",
|
|
Cluster: cluster,
|
|
Namespace: benchmarkNS,
|
|
Service: service,
|
|
Port: wordpressPort,
|
|
Path: wordpressLoginPage,
|
|
Rounds: rounds,
|
|
Timeout: wordpressRequestTimeout,
|
|
WantPercentiles: wantPercentiles,
|
|
}
|
|
benchmark.Run(ctx, t)
|
|
}
|
|
|
|
func newMariaDBServer(namespace *testcluster.Namespace, name, image string, volume *v13.PersistentVolumeClaim) *v13.Pod {
|
|
return &v13.Pod{
|
|
TypeMeta: v1.TypeMeta{
|
|
Kind: "Pod",
|
|
APIVersion: "v1",
|
|
},
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace.Namespace,
|
|
Labels: map[string]string{mariaDBServerLabelKey: mariaDBServerLabelValue},
|
|
},
|
|
Spec: v13.PodSpec{
|
|
Containers: []v13.Container{
|
|
{
|
|
Name: name,
|
|
Image: image,
|
|
Ports: []v13.ContainerPort{
|
|
{
|
|
Name: name,
|
|
ContainerPort: mariaDBPort,
|
|
},
|
|
},
|
|
Env: []v13.EnvVar{
|
|
{
|
|
Name: "MARIADB_ROOT_PASSWORD",
|
|
Value: mariaDBRootPassword,
|
|
},
|
|
{
|
|
Name: "MARIADB_DATABASE",
|
|
Value: mariaDBName,
|
|
},
|
|
{
|
|
Name: "MARIADB_USER",
|
|
Value: mariaDBUser,
|
|
},
|
|
{
|
|
Name: "MARIADB_PASSWORD",
|
|
Value: mariaDBPassword,
|
|
},
|
|
},
|
|
VolumeMounts: []v13.VolumeMount{{
|
|
Name: volume.GetName(),
|
|
MountPath: mariaDBVolumeDirectory,
|
|
}},
|
|
},
|
|
},
|
|
Volumes: []v13.Volume{{
|
|
Name: volume.GetName(),
|
|
VolumeSource: v13.VolumeSource{
|
|
PersistentVolumeClaim: &v13.PersistentVolumeClaimVolumeSource{
|
|
ClaimName: volume.GetName(),
|
|
},
|
|
},
|
|
}},
|
|
RestartPolicy: v13.RestartPolicyNever,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newMariaDBService(namespace *testcluster.Namespace, name string) *v13.Service {
|
|
return namespace.GetService(name, v13.ServiceSpec{
|
|
Selector: map[string]string{mariaDBServerLabelKey: mariaDBServerLabelValue},
|
|
Ports: []v13.ServicePort{
|
|
{
|
|
Name: name,
|
|
Protocol: v13.ProtocolTCP,
|
|
Port: mariaDBPort,
|
|
TargetPort: intstr.FromString(name),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func newWordpressServer(namespace *testcluster.Namespace, name, image, mariaDBHost string) *v13.Pod {
|
|
return &v13.Pod{
|
|
TypeMeta: v1.TypeMeta{
|
|
Kind: "Pod",
|
|
APIVersion: "v1",
|
|
},
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace.Namespace,
|
|
Labels: map[string]string{wordpressServerLabelKey: wordpressServerLabelValue},
|
|
},
|
|
Spec: v13.PodSpec{
|
|
Containers: []v13.Container{
|
|
{
|
|
Name: name,
|
|
Image: image,
|
|
Ports: []v13.ContainerPort{
|
|
{
|
|
Name: name,
|
|
ContainerPort: wordpressPort,
|
|
},
|
|
},
|
|
Env: []v13.EnvVar{
|
|
{
|
|
Name: "WORDPRESS_DB_HOST",
|
|
Value: mariaDBHost,
|
|
},
|
|
{
|
|
Name: "WORDPRESS_DB_USER",
|
|
Value: mariaDBUser,
|
|
},
|
|
{
|
|
Name: "WORDPRESS_DB_PASSWORD",
|
|
Value: mariaDBPassword,
|
|
},
|
|
{
|
|
Name: "WORDPRESS_DB_NAME",
|
|
Value: mariaDBName,
|
|
},
|
|
{
|
|
Name: "WORDPRESS_TABLE_PREFIX",
|
|
Value: "wp_",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
RestartPolicy: v13.RestartPolicyNever,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newWordpressService(namespace *testcluster.Namespace, name string) *v13.Service {
|
|
return namespace.GetService(name, v13.ServiceSpec{
|
|
Selector: map[string]string{wordpressServerLabelKey: wordpressServerLabelValue},
|
|
Ports: []v13.ServicePort{
|
|
{
|
|
Name: name,
|
|
Protocol: v13.ProtocolTCP,
|
|
Port: wordpressPort,
|
|
TargetPort: intstr.FromString(name),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func newWordpressInstall(namespace *testcluster.Namespace, name, wpHost string) *v13.Pod {
|
|
return &v13.Pod{
|
|
TypeMeta: v1.TypeMeta{
|
|
Kind: "Pod",
|
|
APIVersion: "v1",
|
|
},
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace.Namespace,
|
|
},
|
|
Spec: v13.PodSpec{
|
|
Containers: []v13.Container{
|
|
{
|
|
Name: "install-wordpress",
|
|
Image: "debian:latest",
|
|
// This command installs WordPress through the web UI.
|
|
// Source of the parameters:
|
|
// https://github.com/GoogleCloudPlatform/click-to-deploy/blob/master/k8s/wordpress/chart/wordpress/templates/wordpress-configmap.yaml
|
|
Command: []string{
|
|
"sh", "-c",
|
|
strings.Join([]string{
|
|
"apt-get update -y </dev/null",
|
|
"apt-get install -y curl </dev/null",
|
|
strings.Join([]string{
|
|
"curl",
|
|
"--fail",
|
|
"--retry", "20",
|
|
"--retry-delay", "5",
|
|
"--retry-connrefused",
|
|
"--data-urlencode", "'weblog_title=WPBench'",
|
|
"--data-urlencode", "'user_name=iamroot'",
|
|
"--data-urlencode", "'[email protected]'",
|
|
"--data-urlencode", fmt.Sprintf("'admin_password=%s'", mariaDBPassword),
|
|
"--data-urlencode", fmt.Sprintf("'admin_password2=%s'", mariaDBPassword),
|
|
"--data-urlencode", "'pw_weak=1'",
|
|
fmt.Sprintf("'http://%s/wp-admin/install.php?step=2'", wpHost),
|
|
}, " "),
|
|
}, " && "),
|
|
},
|
|
Env: []v13.EnvVar{
|
|
{
|
|
Name: "DEBIAN_FRONTEND",
|
|
Value: "noninteractive",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
RestartPolicy: v13.RestartPolicyNever,
|
|
},
|
|
}
|
|
}
|