Merge branch 'master' into pull/28
# Conflicts: # .gitignore # kubernetes-manifests/frontend.yaml # kubernetes-manifests/loadgenerator.yaml # release/kubernetes-manifests.yaml # src/loadgenerator/Dockerfile # src/loadgenerator/loadgen.sh
This commit is contained in:
commit
a4148a51c8
29 changed files with 462 additions and 44 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,5 +9,7 @@ pkg/
|
||||||
.idea
|
.idea
|
||||||
.skaffold-*.yaml
|
.skaffold-*.yaml
|
||||||
.kubernetes-manifests-*/
|
.kubernetes-manifests-*/
|
||||||
|
env/
|
||||||
|
|
||||||
.project
|
.project
|
||||||
.eclipse.buildship.core.prefs
|
.eclipse.buildship.core.prefs
|
1
build.out
Normal file
1
build.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"builds":[{"imageName":"gcr.io/lesser-weevil/emailservice","tag":"gcr.io/lesser-weevil/emailservice:v0.1.0-74-g468e8dc@sha256:7256c7e27888c37e06c19036032b594c5240d9a80bbe54963fda437346239742"},{"imageName":"gcr.io/lesser-weevil/productcatalogservice","tag":"gcr.io/lesser-weevil/productcatalogservice:v0.1.0-74-g468e8dc@sha256:19b199f0a976a3cebd5cf00d99d040a82c9824506de988d9485fffa828428898"},{"imageName":"gcr.io/lesser-weevil/recommendationservice","tag":"gcr.io/lesser-weevil/recommendationservice:v0.1.0-74-g468e8dc@sha256:3300a437de46c8d2e2144540ce0fe51ec2ea7b728c724021182337fd051bacad"},{"imageName":"gcr.io/lesser-weevil/shippingservice","tag":"gcr.io/lesser-weevil/shippingservice:v0.1.0-74-g468e8dc@sha256:dd8c49052601f9e3873d0c8034e6010645d83768df3526ee99cb43a71ce8344d"},{"imageName":"gcr.io/lesser-weevil/checkoutservice","tag":"gcr.io/lesser-weevil/checkoutservice:v0.1.0-74-g468e8dc@sha256:0955d209db61815892477b6f06b0f7a4c3c3d96e714c8c472faa5a442a2af875"},{"imageName":"gcr.io/lesser-weevil/paymentservice","tag":"gcr.io/lesser-weevil/paymentservice:v0.1.0-74-g468e8dc@sha256:07903a2bddf38920a940a2ab9aaddfbc7c06b0aa27dc07aaf8b9694722b44d92"},{"imageName":"gcr.io/lesser-weevil/currencyservice","tag":"gcr.io/lesser-weevil/currencyservice:v0.1.0-74-g468e8dc@sha256:df6b933e6b42a27035419119f93b471e4f9973b2934c0124da399c64dfc779a9"},{"imageName":"gcr.io/lesser-weevil/cartservice","tag":"gcr.io/lesser-weevil/cartservice:v0.1.0-74-g468e8dc@sha256:538f48876ad2f13603b4992bb3b75cde587333920f0a9f7e4d6d54924d349d3b"},{"imageName":"gcr.io/lesser-weevil/frontend","tag":"gcr.io/lesser-weevil/frontend:v0.1.0-74-g468e8dc@sha256:8b552b7de8dd9c45439d4a334f9d8dfeec0b989075a85e11cb17a81f2e47bab5"},{"imageName":"gcr.io/lesser-weevil/loadgenerator","tag":"gcr.io/lesser-weevil/loadgenerator:v0.1.0-74-g468e8dc@sha256:e874a37782981f587238a8b5ce807f7ce65d4c2f97c6bb847462de5a1aeb74c0"},{"imageName":"gcr.io/lesser-weevil/adservice","tag":"gcr.io/lesser-weevil/adservice:v0.1.0-74-g468e8dc@sha256:446a5743ebf2b7f27758c9d7588742223a42328838e7de222363f170d30e6231"},{"imageName":"gcr.io/lesser-weevil/pingjob","tag":"gcr.io/lesser-weevil/pingjob:v0.1.0-74-g468e8dc@sha256:0ade87236d2d837ca1d9b468497b7d05d729b6420120da35b8a9e64b20ce10a8"}]}
|
|
@ -17,6 +17,8 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: adservice
|
name: adservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
|
replicas: 5
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: adservice
|
app: adservice
|
||||||
|
|
|
@ -17,6 +17,8 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: cartservice
|
name: cartservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
|
replicas: 10
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: cartservice
|
app: cartservice
|
||||||
|
@ -41,10 +43,10 @@ spec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
memory: 64Mi
|
memory: 128Mi
|
||||||
limits:
|
limits:
|
||||||
cpu: 300m
|
cpu: 300m
|
||||||
memory: 128Mi
|
memory: 256Mi
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
initialDelaySeconds: 15
|
initialDelaySeconds: 15
|
||||||
exec:
|
exec:
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: checkoutservice
|
name: checkoutservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: checkoutservice
|
app: checkoutservice
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: currencyservice
|
name: currencyservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: currencyservice
|
app: currencyservice
|
||||||
|
@ -67,3 +68,22 @@ spec:
|
||||||
- name: grpc
|
- name: grpc
|
||||||
port: 7000
|
port: 7000
|
||||||
targetPort: 7000
|
targetPort: 7000
|
||||||
|
---
|
||||||
|
apiVersion: autoscaling/v2beta1
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: currencyservice
|
||||||
|
labels:
|
||||||
|
app: currencyservice
|
||||||
|
spec:
|
||||||
|
maxReplicas: 7
|
||||||
|
minReplicas: 1
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: currencyservice
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
targetAverageUtilization: 19
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: emailservice
|
name: emailservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: emailservice
|
app: emailservice
|
||||||
|
|
|
@ -15,15 +15,82 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: frontend
|
name: frontend-a
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: frontend
|
app: frontend
|
||||||
|
env: a
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: frontend
|
app: frontend
|
||||||
|
env: a
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: server
|
||||||
|
image: frontend
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
readinessProbe:
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
httpGet:
|
||||||
|
path: "/_healthz"
|
||||||
|
port: 8080
|
||||||
|
httpHeaders:
|
||||||
|
- name: "Cookie"
|
||||||
|
value: "shop_session-id=x-readiness-probe"
|
||||||
|
livenessProbe:
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
httpGet:
|
||||||
|
path: "/_healthz"
|
||||||
|
port: 8080
|
||||||
|
httpHeaders:
|
||||||
|
- name: "Cookie"
|
||||||
|
value: "shop_session-id=x-liveness-probe"
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: "8080"
|
||||||
|
- name: PRODUCT_CATALOG_SERVICE_ADDR
|
||||||
|
value: "productcatalogservice:3550"
|
||||||
|
- name: CURRENCY_SERVICE_ADDR
|
||||||
|
value: "currencyservice:7000"
|
||||||
|
- name: CART_SERVICE_ADDR
|
||||||
|
value: "cartservice:7070"
|
||||||
|
- name: RECOMMENDATION_SERVICE_ADDR
|
||||||
|
value: "recommendationservice:8080"
|
||||||
|
- name: SHIPPING_SERVICE_ADDR
|
||||||
|
value: "shippingservice:50051"
|
||||||
|
- name: CHECKOUT_SERVICE_ADDR
|
||||||
|
value: "checkoutservice:5050"
|
||||||
|
- name: AD_SERVICE_ADDR
|
||||||
|
value: "adservice:9555"
|
||||||
|
# - name: JAEGER_SERVICE_ADDR
|
||||||
|
# value: "jaeger-collector:14268"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 128Mi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: frontend-b
|
||||||
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: frontend
|
||||||
|
env: b
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: frontend
|
||||||
|
env: b
|
||||||
annotations:
|
annotations:
|
||||||
sidecar.istio.io/rewriteAppHTTPProbers: "true"
|
sidecar.istio.io/rewriteAppHTTPProbers: "true"
|
||||||
spec:
|
spec:
|
||||||
|
@ -100,6 +167,7 @@ spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
selector:
|
selector:
|
||||||
app: frontend
|
app: frontend
|
||||||
|
env: b
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 80
|
port: 80
|
||||||
|
|
|
@ -16,6 +16,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: loadgenerator
|
name: loadgenerator
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: loadgenerator
|
app: loadgenerator
|
||||||
|
@ -29,6 +30,17 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
terminationGracePeriodSeconds: 5
|
terminationGracePeriodSeconds: 5
|
||||||
restartPolicy: Always
|
restartPolicy: Always
|
||||||
|
initContainers:
|
||||||
|
- name: wait-frontend
|
||||||
|
image: alpine:3.6
|
||||||
|
command: ['sh', '-c', 'set -x; apk add --no-cache curl &&
|
||||||
|
until timeout -t 2 curl -f "http://${FRONTEND_ADDR}"; do
|
||||||
|
echo "waiting for http://${FRONTEND_ADDR}";
|
||||||
|
sleep 2;
|
||||||
|
done;']
|
||||||
|
env:
|
||||||
|
- name: FRONTEND_ADDR
|
||||||
|
value: "frontend:80"
|
||||||
containers:
|
containers:
|
||||||
- name: main
|
- name: main
|
||||||
image: loadgenerator
|
image: loadgenerator
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: paymentservice
|
name: paymentservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: paymentservice
|
app: paymentservice
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: productcatalogservice
|
name: productcatalogservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: productcatalogservice
|
app: productcatalogservice
|
||||||
|
|
|
@ -15,15 +15,18 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: recommendationservice
|
name: recommendationservice-v1
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: recommendationservice
|
app: recommendationservice
|
||||||
|
version: v1
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: recommendationservice
|
app: recommendationservice
|
||||||
|
version: v1
|
||||||
spec:
|
spec:
|
||||||
terminationGracePeriodSeconds: 5
|
terminationGracePeriodSeconds: 5
|
||||||
containers:
|
containers:
|
||||||
|
@ -58,6 +61,53 @@ spec:
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
memory: 450Mi
|
memory: 450Mi
|
||||||
---
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: recommendationservice-v2
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: recommendationservice
|
||||||
|
version: v2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: recommendationservice
|
||||||
|
version: v2
|
||||||
|
spec:
|
||||||
|
terminationGracePeriodSeconds: 5
|
||||||
|
containers:
|
||||||
|
- name: server
|
||||||
|
image: recommendationservice
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
readinessProbe:
|
||||||
|
periodSeconds: 5
|
||||||
|
exec:
|
||||||
|
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||||
|
livenessProbe:
|
||||||
|
periodSeconds: 5
|
||||||
|
exec:
|
||||||
|
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: "8080"
|
||||||
|
- name: PRODUCT_CATALOG_SERVICE_ADDR
|
||||||
|
value: "productcatalogservice:3550"
|
||||||
|
- name: ENABLE_PROFILER
|
||||||
|
value: "0"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 220Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 450Mi
|
||||||
|
revisionHistoryLimit: 1
|
||||||
|
---
|
||||||
|
#In order for istio to route traffic correctly, it needs a kubernetes service to route traffic to
|
||||||
|
#the workloads in question.
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -67,6 +117,38 @@ spec:
|
||||||
selector:
|
selector:
|
||||||
app: recommendationservice
|
app: recommendationservice
|
||||||
ports:
|
ports:
|
||||||
- name: grpc
|
- name: grpc
|
||||||
port: 8080
|
port: 8080
|
||||||
targetPort: 8080
|
targetPort: 8080
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: recommendationservice
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- recommendationservice
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: recommendationservice
|
||||||
|
subset: v1
|
||||||
|
weight: 90
|
||||||
|
- destination:
|
||||||
|
host: recommendationservice
|
||||||
|
subset: v2
|
||||||
|
weight: 10
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: recommendationservice
|
||||||
|
spec:
|
||||||
|
host: recommendationservice
|
||||||
|
subsets:
|
||||||
|
- name: v1
|
||||||
|
labels:
|
||||||
|
version: v1
|
||||||
|
- name: v2
|
||||||
|
labels:
|
||||||
|
version: v2
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: redis-cart
|
name: redis-cart
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: redis-cart
|
app: redis-cart
|
||||||
|
|
|
@ -17,6 +17,7 @@ kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: shippingservice
|
name: shippingservice
|
||||||
spec:
|
spec:
|
||||||
|
revisionHistoryLimit: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: shippingservice
|
app: shippingservice
|
||||||
|
@ -24,6 +25,7 @@ spec:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: shippingservice
|
app: shippingservice
|
||||||
|
version: deployment
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: server
|
- name: server
|
||||||
|
@ -56,6 +58,47 @@ spec:
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
---
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: ReplicaSet
|
||||||
|
metadata:
|
||||||
|
name: shippingservice-rs
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: shippingservice
|
||||||
|
owner: rs
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: shippingservice
|
||||||
|
owner: rs
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: server
|
||||||
|
image: shippingservice
|
||||||
|
ports:
|
||||||
|
- containerPort: 50051
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: "50051"
|
||||||
|
readinessProbe:
|
||||||
|
periodSeconds: 5
|
||||||
|
exec:
|
||||||
|
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||||
|
# env:
|
||||||
|
# - name: JAEGER_SERVICE_ADDR
|
||||||
|
# value: "jaeger-collector:14268"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
|
|
|
@ -46,7 +46,7 @@ const request = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function _moneyToString (m) {
|
function _moneyToString (m) {
|
||||||
return `${m.units}.${m.nanos.toString().padStart(9,'0')} ${m.currency_code}`;
|
return `${m.units}.${m.nanos.toString().padStart(9, '0')} ${m.currency_code}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.getSupportedCurrencies({}, (err, response) => {
|
client.getSupportedCurrencies({}, (err, response) => {
|
||||||
|
|
|
@ -92,7 +92,13 @@ function _loadProto (path) {
|
||||||
*/
|
*/
|
||||||
function _getCurrencyData (callback) {
|
function _getCurrencyData (callback) {
|
||||||
const data = require('./data/currency_conversion.json');
|
const data = require('./data/currency_conversion.json');
|
||||||
callback(data);
|
// Currency conversion API slows down during peak hours.
|
||||||
|
let delay = 0;
|
||||||
|
const hour = new Date().getHours();
|
||||||
|
if (hour > 8 && hour < 17) {
|
||||||
|
delay = 100; // add 100ms slowdown
|
||||||
|
}
|
||||||
|
setTimeout(() => callback(data), delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
<p>
|
<p>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
This website is hosted for demo purposes only. It is not an
|
This website is hosted for demo purposes only. It is not an
|
||||||
actual shop. This is not an official Google project.
|
actual shop. This is not an official Google project. Demo
|
||||||
|
deployment for Google Cloud & Signals Monitoring
|
||||||
|
Topology.
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
you catch up with the hipster trend and express your
|
you catch up with the hipster trend and express your
|
||||||
personal style. Start shopping hip and vintage items now!
|
personal style. Start shopping hip and vintage items now!
|
||||||
</p>
|
</p>
|
||||||
|
<p class="lead text-muted">
|
||||||
|
Cloud Topology
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,5 @@ FROM base
|
||||||
COPY --from=builder /install /usr/local
|
COPY --from=builder /install /usr/local
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN chmod +x ./loadgen.sh
|
ENTRYPOINT ["./loadgen.sh"]
|
||||||
RUN apt-get -qq update \
|
|
||||||
&& apt-get install -y --no-install-recommends \
|
|
||||||
curl
|
|
||||||
ENTRYPOINT ./loadgen.sh
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/sh -eu
|
||||||
#
|
#
|
||||||
# Copyright 2018 Google LLC
|
# Copyright 2018 Google LLC
|
||||||
#
|
#
|
||||||
|
@ -14,22 +14,19 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
trap "exit" TERM
|
trap "exit" TERM
|
||||||
|
|
||||||
if [[ -z "${FRONTEND_ADDR}" ]]; then
|
if [ -z "${FRONTEND_ADDR}" ]; then
|
||||||
echo >&2 "FRONTEND_ADDR not specified"
|
echo >&2 "FRONTEND_ADDR not specified"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
|
locust \
|
||||||
# if one request to the frontend fails, then exit
|
-f locustfile.py \
|
||||||
STATUSCODE=$(curl --silent --output /dev/stderr --write-out "%{http_code}" http://${FRONTEND_ADDR})
|
--host="http://${FRONTEND_ADDR}" \
|
||||||
if test $STATUSCODE -ne 200; then
|
--no-web \
|
||||||
echo "Error: Could not reach frontend - Status code: ${STATUSCODE}"
|
-c "${USERS:-10}" \
|
||||||
exit 1
|
-r 1
|
||||||
fi
|
|
||||||
|
|
||||||
# else, run loadgen
|
|
||||||
locust --host="http://${FRONTEND_ADDR}" --no-web -c "${USERS:-10}" 2>&1
|
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
|
import time
|
||||||
from locust import HttpLocust, TaskSet
|
from locust import HttpLocust, TaskSet
|
||||||
|
|
||||||
products = [
|
products = [
|
||||||
|
@ -28,29 +30,39 @@ products = [
|
||||||
'LS4PSXUNUM',
|
'LS4PSXUNUM',
|
||||||
'OLJCESPC7Z']
|
'OLJCESPC7Z']
|
||||||
|
|
||||||
|
|
||||||
def index(l):
|
def index(l):
|
||||||
l.client.get("/")
|
l.client.get("/")
|
||||||
|
|
||||||
|
|
||||||
def setCurrency(l):
|
def setCurrency(l):
|
||||||
currencies = ['EUR', 'USD', 'JPY', 'CAD']
|
currencies = ['EUR', 'USD', 'JPY', 'CAD']
|
||||||
l.client.post("/setCurrency",
|
l.client.post("/setCurrency",
|
||||||
{'currency_code': random.choice(currencies)})
|
{'currency_code': random.choice(currencies)})
|
||||||
|
|
||||||
|
|
||||||
def browseProduct(l):
|
def browseProduct(l):
|
||||||
l.client.get("/product/" + random.choice(products))
|
l.client.get("/product/" + random.choice(products))
|
||||||
|
|
||||||
|
|
||||||
def viewCart(l):
|
def viewCart(l):
|
||||||
l.client.get("/cart")
|
l.client.get("/cart")
|
||||||
|
|
||||||
|
|
||||||
def addToCart(l):
|
def addToCart(l):
|
||||||
product = random.choice(products)
|
product = random.choice(products)
|
||||||
l.client.get("/product/" + product)
|
l.client.get("/product/" + product)
|
||||||
l.client.post("/cart", {
|
l.client.post("/cart", {
|
||||||
'product_id': product,
|
'product_id': product,
|
||||||
'quantity': random.choice([1,2,3,4,5,10])})
|
'quantity': random.choice([1, 2, 3, 4, 5, 10])})
|
||||||
|
|
||||||
|
|
||||||
def checkout(l):
|
def checkout(l):
|
||||||
addToCart(l)
|
addToCart(l)
|
||||||
|
# For five minutes every other hour, credit cards passed by the user will be
|
||||||
|
# invalid and the paymentservice will fail.
|
||||||
|
now = time.localtime()
|
||||||
|
expiration_year = '2015' if (now.tm_hour % 2) & (now.tm_min < 5) else '2060'
|
||||||
l.client.post("/cart/checkout", {
|
l.client.post("/cart/checkout", {
|
||||||
'email': 'someone@example.com',
|
'email': 'someone@example.com',
|
||||||
'street_address': '1600 Amphitheatre Parkway',
|
'street_address': '1600 Amphitheatre Parkway',
|
||||||
|
@ -60,23 +72,41 @@ def checkout(l):
|
||||||
'country': 'United States',
|
'country': 'United States',
|
||||||
'credit_card_number': '4432-8015-6152-0454',
|
'credit_card_number': '4432-8015-6152-0454',
|
||||||
'credit_card_expiration_month': '1',
|
'credit_card_expiration_month': '1',
|
||||||
'credit_card_expiration_year': '2039',
|
'credit_card_expiration_year': expiration_year,
|
||||||
'credit_card_cvv': '672',
|
'credit_card_cvv': '672',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class UserBehavior(TaskSet):
|
class UserBehavior(TaskSet):
|
||||||
|
min_wait = 500
|
||||||
|
max_wait = 15000
|
||||||
|
|
||||||
|
tasks = {index: 1,
|
||||||
|
setCurrency: 2,
|
||||||
|
browseProduct: 10,
|
||||||
|
addToCart: 2,
|
||||||
|
viewCart: 3,
|
||||||
|
checkout: 1}
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
index(self)
|
index(self)
|
||||||
|
|
||||||
tasks = {index: 1,
|
def wait_function(self):
|
||||||
setCurrency: 2,
|
"""Wait time between user activity is diurnal.
|
||||||
browseProduct: 10,
|
|
||||||
addToCart: 2,
|
Compute user's activity rate (wait time between actions) so traffic is
|
||||||
viewCart: 3,
|
minimum at hrs=0.0|24.0 and maximum at hrs=12.0.
|
||||||
checkout: 1}
|
"""
|
||||||
|
now = time.localtime()
|
||||||
|
hrs = now.tm_hour + now.tm_min/60.0
|
||||||
|
# Compute scale factor is between 0 and 1.
|
||||||
|
traffic_scaler = -1.0 * math.cos(2.0 * math.pi * hrs / 24)
|
||||||
|
traffic_scaler = (traffic_scaler + 1) / 2.0
|
||||||
|
|
||||||
|
# Scale traffic between minimum and maximum wait times.
|
||||||
|
wait = self.max_wait + (self.min_wait - self.max_wait) * traffic_scaler
|
||||||
|
return round(wait)
|
||||||
|
|
||||||
|
|
||||||
class WebsiteUser(HttpLocust):
|
class WebsiteUser(HttpLocust):
|
||||||
task_set = UserBehavior
|
task_set = UserBehavior
|
||||||
min_wait = 1000
|
|
||||||
max_wait = 10000
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
locustio==0.8.1
|
locustio==0.9.0
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# This file is autogenerated by pip-compile
|
# This file is autogenerated by pip-compile
|
||||||
# To update, run:
|
# To update, run:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file requirements.txt requirements.in
|
# pip-compile --output-file=requirements.txt requirements.in
|
||||||
#
|
#
|
||||||
certifi==2018.11.29 # via requests
|
certifi==2018.11.29 # via requests
|
||||||
chardet==3.0.4 # via requests
|
chardet==3.0.4 # via requests
|
||||||
|
@ -13,9 +13,9 @@ greenlet==0.4.15 # via gevent
|
||||||
idna==2.8 # via requests
|
idna==2.8 # via requests
|
||||||
itsdangerous==1.1.0 # via flask
|
itsdangerous==1.1.0 # via flask
|
||||||
jinja2==2.10 # via flask
|
jinja2==2.10 # via flask
|
||||||
locustio==0.8.1
|
locustio==0.9.0
|
||||||
markupsafe==1.1.0 # via jinja2
|
markupsafe==1.1.0 # via jinja2
|
||||||
msgpack-python==0.5.6 # via locustio
|
msgpack==0.6.1 # via locustio
|
||||||
pyzmq==17.0.0 # via locustio
|
pyzmq==17.0.0 # via locustio
|
||||||
requests==2.21.0 # via locustio
|
requests==2.21.0 # via locustio
|
||||||
six==1.12.0 # via locustio
|
six==1.12.0 # via locustio
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
const cardValidator = require('simple-card-validator');
|
const cardValidator = require('simple-card-validator');
|
||||||
const uuid = require('uuid/v4');
|
const uuid = require('uuid/v4');
|
||||||
const pino = require('pino');
|
const pino = require('pino');
|
||||||
|
const grpc = require('grpc');
|
||||||
|
|
||||||
const logger = pino({
|
const logger = pino({
|
||||||
name: 'paymentservice-charge',
|
name: 'paymentservice-charge',
|
||||||
|
@ -28,6 +29,7 @@ class CreditCardError extends Error {
|
||||||
constructor (message) {
|
constructor (message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.code = 400; // Invalid argument error
|
this.code = 400; // Invalid argument error
|
||||||
|
this.status = grpc.status.INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
src/pingjob/Dockerfile
Normal file
18
src/pingjob/Dockerfile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3-slim as base
|
||||||
|
|
||||||
|
FROM base as builder
|
||||||
|
|
||||||
|
RUN apt-get -qq update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
g++
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
RUN pip install --install-option="--prefix=/install" -r requirements.txt
|
||||||
|
|
||||||
|
FROM base
|
||||||
|
COPY --from=builder /install /usr/local
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
ENTRYPOINT ["./pinger.sh"]
|
||||||
|
|
87
src/pingjob/pinger.py
Normal file
87
src/pingjob/pinger.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2018 Google LLC
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
BASE = sys.argv[1]
|
||||||
|
|
||||||
|
products = [
|
||||||
|
'0PUK6V6EV0',
|
||||||
|
'1YMWWN1N4O',
|
||||||
|
'2ZYFJ3GM2N',
|
||||||
|
'66VCHSJNUP',
|
||||||
|
'6E92ZMYYFZ',
|
||||||
|
'9SIQT8TOJO',
|
||||||
|
'L9ECAV7KIM',
|
||||||
|
'LS4PSXUNUM',
|
||||||
|
'OLJCESPC7Z']
|
||||||
|
|
||||||
|
|
||||||
|
def index():
|
||||||
|
requests.get(BASE + "/")
|
||||||
|
|
||||||
|
|
||||||
|
def setCurrency():
|
||||||
|
currencies = ['EUR', 'USD', 'JPY', 'CAD']
|
||||||
|
requests.post(BASE + "/setCurrency",
|
||||||
|
{'currency_code': random.choice(currencies)})
|
||||||
|
|
||||||
|
|
||||||
|
def browseProduct():
|
||||||
|
requests.get(BASE + "/product/" + random.choice(products))
|
||||||
|
|
||||||
|
|
||||||
|
def viewCart():
|
||||||
|
requests.get(BASE + "/cart")
|
||||||
|
|
||||||
|
|
||||||
|
def addToCart():
|
||||||
|
product = random.choice(products)
|
||||||
|
requests.get(BASE + "/product/" + product)
|
||||||
|
requests.post(BASE + "/cart", {
|
||||||
|
'product_id': product,
|
||||||
|
'quantity': random.choice([1, 2, 3, 4, 5, 10])})
|
||||||
|
|
||||||
|
|
||||||
|
def checkout():
|
||||||
|
addToCart()
|
||||||
|
requests.post(BASE + "/cart/checkout", {
|
||||||
|
'email': 'someone@example.com',
|
||||||
|
'street_address': '1600 Amphitheatre Parkway',
|
||||||
|
'zip_code': '94043',
|
||||||
|
'city': 'Mountain View',
|
||||||
|
'state': 'CA',
|
||||||
|
'country': 'United States',
|
||||||
|
'credit_card_number': '4432-8015-6152-0454',
|
||||||
|
'credit_card_expiration_month': '1',
|
||||||
|
'credit_card_expiration_year': '2039',
|
||||||
|
'credit_card_cvv': '672',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if not BASE:
|
||||||
|
print("ERROR: no frontend address")
|
||||||
|
else:
|
||||||
|
print("pinging" + BASE)
|
||||||
|
index()
|
||||||
|
browseProduct()
|
||||||
|
addToCart()
|
||||||
|
viewCart()
|
||||||
|
checkout()
|
||||||
|
print("pinging complete")
|
27
src/pingjob/pinger.sh
Executable file
27
src/pingjob/pinger.sh
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/sh -eu
|
||||||
|
#
|
||||||
|
# Copyright 2018 Google LLC
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
trap "exit" TERM
|
||||||
|
|
||||||
|
if [ -z "${FRONTEND_ADDR}" ]; then
|
||||||
|
echo >&2 "FRONTEND_ADDR not specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -x
|
||||||
|
python pinger.py "${FRONTEND_ADDR}"
|
1
src/pingjob/requirements.in
Normal file
1
src/pingjob/requirements.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
requests
|
11
src/pingjob/requirements.txt
Normal file
11
src/pingjob/requirements.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#
|
||||||
|
# This file is autogenerated by pip-compile
|
||||||
|
# To update, run:
|
||||||
|
#
|
||||||
|
# pip-compile --output-file=requirements.txt requirements.in
|
||||||
|
#
|
||||||
|
certifi==2018.11.29 # via requests
|
||||||
|
chardet==3.0.4 # via requests
|
||||||
|
idna==2.8 # via requests
|
||||||
|
requests==2.21.0
|
||||||
|
urllib3==1.24.1 # via requests
|
Loading…
Add table
Add a link
Reference in a new issue