Merge pull request #9586 from caesarxuchao/k8petstore-examples-v1

Update examples/k8petstore to v1
pull/6/head
Fabio Yeon 2015-06-15 10:03:03 -07:00
commit 157d152d0c
3 changed files with 340 additions and 27 deletions

View File

@ -8,17 +8,17 @@ This is a follow up to the [Guestbook Example](../guestbook/README.md)'s [Go imp
- It generates massive load using a semantically rich, realistic transaction simulator for petstores
This application will run a web server which returns REDIS records for a petstore application.
It is meant to simulate and test high load on kubernetes or any other docker based system.
It is meant to simulate and test high load on Kubernetes or any other docker based system.
If you are new to kubernetes, and you haven't run guestbook yet,
If you are new to Kubernetes, and you haven't run guestbook yet,
you might want to stop here and go back and run guestbook app first.
The guestbook tutorial will teach you a lot about the basics of kubernetes, and we've tried not to be redundant here.
The guestbook tutorial will teach you a lot about the basics of Kubernetes, and we've tried not to be redundant here.
## Architecture of this SOA
A diagram of the overall architecture of this application can be seen in [arch.dot](arch.dot) (you can paste the contents in any graphviz viewer, including online ones such as http://sandbox.kidstrythisathome.com/erdos/.
A diagram of the overall architecture of this application can be seen in [k8petstore.dot](k8petstore.dot) (you can paste the contents in any graphviz viewer, including online ones such as http://sandbox.kidstrythisathome.com/erdos/.
## Docker image dependencies
@ -48,7 +48,7 @@ To work on the app, just cd to the `dev` directory, and follow the instructions.
redis and go. Then you can use the `Vagrantfile` in this top level directory to launch a minimal version of the app in pure docker containers.
If that is all working, you can finally run `k8petstore.sh` in any kubernetes cluster, and run the app at scale.
If that is all working, you can finally run `k8petstore.sh` in any Kubernetes cluster, and run the app at scale.
## Set up the data generator (optional)
@ -70,33 +70,31 @@ You will likely want to checkout the branch 2b2392bf135e9f1256bd0b930f05ae5aef8b
## Now what?
Once you have done the above 3 steps, you have a working, from source, locally runnable version of the k8petstore app, now, we can try to run it in kubernetes.
Once you have done the above 3 steps, you have a working, from source, locally runnable version of the k8petstore app, now, we can try to run it in Kubernetes.
## Hacking, testing, benchmarking
Once the app is running, you can go to the location of publicIP:3000 (the first parameter in the script). In your browser, you should see a chart
Once the app is running, you can access the app in your browser, you should see a chart
and the k8petstore title page, as well as an indicator of transaction throughput, and so on. You should be able to modify
and the k8petstore title page, as well as an indicator of transaction throughput, and so on.
You can modify the HTML pages, add new REST paths to the Go app, and so on.
## Running in kubernetes
## Running in Kubernetes
Now that you are done hacking around on the app, you can run it in kubernetes. To do this, you will want to rebuild the docker images (most likely, for the Go web-server app), but less likely for the other images which you are less likely to need to change. Then you will push those images to dockerhub.
Now that you are done hacking around on the app, you can run it in Kubernetes. To do this, you will want to rebuild the docker images (most likely, for the Go web-server app), but less likely for the other images which you are less likely to need to change. Then you will push those images to dockerhub.
Now, how to run the entire application in kubernetes?
Now, how to run the entire application in Kubernetes?
To simplify running this application, we have a single file, k8petstore.sh, which writes out json files on to disk. This allows us to have dynamic parameters, without needing to worry about managing multiplejson files.
To simplify running this application, we have a single file, k8petstore.sh, which writes out json files on to disk. This allows us to have dynamic parameters, without needing to worry about managing multiple json files.
You might want to change it to point to your customized Go image, if you chose to modify things.
You might want to change it to point to your customized Go image, if you chose to modify things, like the number of data generators (more generators will create more load on the redis master).
like the number of data generators (more generators will create more load on the redis master).
So, to run this app in Kubernetes, simply run [The all in one k8petstore.sh shell script](k8petstore.sh).
So, to run this app in kubernetes, simply run [The all in one k8petstore.sh shell script](k8petstore.sh).
Note that at the top of the script there are a few self explanatory parameters to set, among which the Public IPs parameter is where you can checkout the web ui (at $PUBLIC_IP:3000), which will show a plot and read outs of transaction throughput.
Note that there are a few , self explanatory parameters to set at the top of it.
Most importantly, the Public IPs parameter, so that you can checkout the web ui (at $PUBLIC_IP:3000), which will show a plot and read outs of transaction throughput.
In the mean time, because the public IP will be deprecated in Kubernetes v1, we provide another script k8petstore-loadbalancer.sh, which requests the cloud provider (e.g., GCE, AWS) to assign a public IP. You can find the assigned IP address in the output of the script. If your cloud provider does not support load balancer or you are not running Kubernetes on a cloud, you may want to use [NodePort](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/services.md#external-services) instead.
## Future

View File

@ -0,0 +1,305 @@
#!/bin/bash
# Copyright 2015 The Kubernetes Authors All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
echo "WRITING KUBE FILES , will overwrite the jsons, then testing pods. is kube clean ready to go?"
#Args below can be overriden when calling from cmd line.
#Just send all the args in order.
#for dev/test you can use:
#kubectl=$GOPATH/src/github.com/GoogleCloudPlatform/kubernetes/cluster/kubectl.sh"
kubectl="kubectl"
VERSION="r.2.8.19"
_SECONDS=1000 # number of seconds to measure throughput.
FE="1" # amount of Web server
LG="1" # amount of load generators
SLAVE="1" # amount of redis slaves
TEST="1" # 0 = Dont run tests, 1 = Do run tests.
NS="default" # namespace
kubectl="${1:-$kubectl}"
VERSION="${2:-$VERSION}"
_SECONDS="${3:-$_SECONDS}" # number of seconds to measure throughput.
FE="${4:-$FE}" # amount of Web server
LG="${5:-$LG}" # amount of load generators
SLAVE="${6:-$SLAVE}" # amount of redis slaves
TEST="${7:-$TEST}" # 0 = Dont run tests, 1 = Do run tests.
NS="${8:-$NS}" # namespace
echo "Running w/ args: kubectl $kubectl version $VERSION sec $_SECONDS fe $FE lg $LG slave $SLAVE test $TEST NAMESPACE $NS"
function create {
cat << EOF > fe-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1",
"metadata": {
"name": "fectrl",
"labels": {"name": "frontend"}
},
"spec": {
"replicas": $FE,
"selector": {"name": "frontend"},
"template": {
"metadata": {
"labels": {
"name": "frontend",
"uses": "redis-master"
}
},
"spec": {
"containers": [{
"name": "frontend-go-restapi",
"image": "jayunit100/k8-petstore-web-server:$VERSION"
}]
}
}
}
}
EOF
cat << EOF > bps-load-gen-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1",
"metadata": {
"name": "bpsloadgenrc",
"labels": {"name": "bpsLoadGenController"}
},
"spec": {
"replicas": $LG,
"selector": {"name": "bps"},
"template": {
"metadata": {
"labels": {
"name": "bps",
"uses": "frontend"
}
},
"spec": {
"containers": [{
"name": "bps",
"image": "jayunit100/bigpetstore-load-generator",
"command": ["sh","-c","/opt/PetStoreLoadGenerator-1.0/bin/PetStoreLoadGenerator http://\$FRONTEND_SERVICE_HOST:3000/rpush/k8petstore/ 4 4 1000 123"]
}]
}
}
}
}
EOF
cat << EOF > fe-s.json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "frontend",
"labels": {
"name": "frontend"
}
},
"spec": {
"ports": [{
"port": 3000
}],
"selector": {
"name": "frontend"
},
"type": "LoadBalancer"
}
}
EOF
cat << EOF > rm.json
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "redismaster",
"labels": {
"name": "redis-master"
}
},
"spec": {
"containers": [{
"name": "master",
"image": "jayunit100/k8-petstore-redis-master:$VERSION",
"ports": [{
"containerPort": 6379
}]
}]
}
}
EOF
cat << EOF > rm-s.json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "redismaster",
"labels": {
"name": "redis-master"
}
},
"spec": {
"ports": [{
"port": 6379
}],
"selector": {
"name": "redis-master"
}
}
}
EOF
cat << EOF > rs-s.json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "redisslave",
"labels": {
"name": "redisslave"
}
},
"spec": {
"ports": [{
"port": 6379
}],
"selector": {
"name": "redisslave"
}
}
}
EOF
cat << EOF > slave-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1",
"metadata": {
"name": "redissc",
"labels": {"name": "redisslave"}
},
"spec": {
"replicas": $SLAVE,
"selector": {"name": "redisslave"},
"template": {
"metadata": {
"labels": {
"name": "redisslave",
"uses": "redis-master"
}
},
"spec": {
"containers": [{
"name": "slave",
"image": "jayunit100/k8-petstore-redis-slave:$VERSION",
"ports": [{"containerPort": 6379}]
}]
}
}
}
}
EOF
$kubectl create -f rm.json --namespace=$NS
$kubectl create -f rm-s.json --namespace=$NS
sleep 3 # precaution to prevent fe from spinning up too soon.
$kubectl create -f slave-rc.json --namespace=$NS
$kubectl create -f rs-s.json --namespace=$NS
sleep 3 # see above comment.
$kubectl create -f fe-rc.json --namespace=$NS
$kubectl create -f fe-s.json --namespace=$NS
$kubectl create -f bps-load-gen-rc.json --namespace=$NS
}
#This script assumes the cloud provider is able to create a load balancer. If this not the case, you may want to check out other ways to make the frontend service accessible from outside (https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/services.md#external-services)
function getIP {
echo "Waiting up to 1 min for a public IP to be assigned by the cloud provider..."
for i in `seq 1 20`;
do
PUBLIC_IP=$($kubectl get services/frontend --namespace=$NS -o template --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")
if [ -n "$PUBLIC_IP" ]; then
printf '\n\n\n%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' =
echo "public IP=$PUBLIC_IP"
printf '%*s\n\n\n\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' =
return
fi
sleep 3
done
echo "Failed to detect the public IP after 1 min, exit!"
exit 1
}
function pollfor {
pass_http=0
### Test HTTP Server comes up.
for i in `seq 1 150`;
do
### Just testing that the front end comes up. Not sure how to test total entries etc... (yet)
echo "Trying curl ... $PUBLIC_IP:3000 , attempt $i . expect a few failures while pulling images... "
curl "$PUBLIC_IP:3000" > result
cat result
cat result | grep -q "k8-bps"
if [ $? -eq 0 ]; then
echo "TEST PASSED after $i tries !"
i=1000
break
else
echo "the above RESULT didn't contain target string for trial $i"
fi
sleep 3
done
if [ $i -eq 1000 ]; then
pass_http=1
fi
}
function tests {
pass_load=0
### Print statistics of db size, every second, until $SECONDS are up.
for i in `seq 1 $_SECONDS`;
do
echo "curl : $PUBLIC_IP:3000 , $i of $_SECONDS"
curr_cnt="`curl "$PUBLIC_IP:3000/llen"`"
### Write CSV File of # of trials / total transcations.
echo "$i $curr_cnt" >> result
echo "total transactions so far : $curr_cnt"
sleep 1
done
}
create
getIP
pollfor
if [[ $pass_http -eq 1 ]]; then
echo "Passed..."
else
exit 1
fi
if [[ $TEST -eq 1 ]]; then
echo "running polling tests now"
tests
fi

View File

@ -29,7 +29,7 @@ FE="1" # amount of Web server
LG="1" # amount of load generators
SLAVE="1" # amount of redis slaves
TEST="1" # 0 = Dont run tests, 1 = Do run tests.
NS="k8petstore" # namespace
NS="default" # namespace
kubectl="${1:-$kubectl}"
VERSION="${2:-$VERSION}"
@ -47,7 +47,7 @@ function create {
cat << EOF > fe-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "fectrl",
"labels": {"name": "frontend"}
@ -76,7 +76,7 @@ EOF
cat << EOF > bps-load-gen-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "bpsloadgenrc",
"labels": {"name": "bpsLoadGenController"}
@ -106,7 +106,7 @@ EOF
cat << EOF > fe-s.json
{
"kind": "Service",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "frontend",
"labels": {
@ -117,7 +117,7 @@ cat << EOF > fe-s.json
"ports": [{
"port": 3000
}],
"publicIPs":["$PUBLIC_IP","10.1.4.89"],
"deprecatedPublicIPs":["$PUBLIC_IP","10.1.4.89"],
"selector": {
"name": "frontend"
}
@ -128,7 +128,7 @@ EOF
cat << EOF > rm.json
{
"kind": "Pod",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "redismaster",
"labels": {
@ -150,7 +150,7 @@ EOF
cat << EOF > rm-s.json
{
"kind": "Service",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "redismaster",
"labels": {
@ -171,7 +171,7 @@ EOF
cat << EOF > rs-s.json
{
"kind": "Service",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "redisslave",
"labels": {
@ -192,7 +192,7 @@ EOF
cat << EOF > slave-rc.json
{
"kind": "ReplicationController",
"apiVersion": "v1beta3",
"apiVersion": "v1",
"metadata": {
"name": "redissc",
"labels": {"name": "redisslave"}
@ -271,6 +271,16 @@ function tests {
done
}
function warning {
echo ""
echo "THIS SCRIPT IS FOR KUBERNETES < v1."
echo "For LATER VERSIONS, use k8petstore-nodeport.sh or k8petstore-loadbalacer.sh!!!!"
echo "In particular PublicIP is DEPRECATED in post-v1 releases!!!"
echo ""
}
warning
create
pollfor