diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..906f80e
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,54 @@
+pipeline {
+ agent {
+ node {
+ label 'ubuntu-1604-aufs-stable'
+ }
+ }
+ stages {
+ stage('Build result') {
+ steps {
+ sh 'docker build -t dockersamples/result ./result'
+ }
+ }
+ stage('Build vote') {
+ steps {
+ sh 'docker build -t dockersamples/vote ./vote'
+ }
+ }
+ stage('Build worker') {
+ steps {
+ sh 'docker build -t dockersamples/worker ./worker'
+ }
+ }
+ stage('Push result image') {
+ when {
+ branch 'master'
+ }
+ steps {
+ withDockerRegistry(credentialsId: 'dockerbuildbot-index.docker.io', url:'') {
+ sh 'docker push dockersamples/result'
+ }
+ }
+ }
+ stage('Push vote image') {
+ when {
+ branch 'master'
+ }
+ steps {
+ withDockerRegistry(credentialsId: 'dockerbuildbot-index.docker.io', url:'') {
+ sh 'docker push dockersamples/vote'
+ }
+ }
+ }
+ stage('Push worker image') {
+ when {
+ branch 'master'
+ }
+ steps {
+ withDockerRegistry(credentialsId: 'dockerbuildbot-index.docker.io', url:'') {
+ sh 'docker push dockersamples/worker'
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index d49bf2f..b8ad8a9 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,27 @@ Once you have your swarm, in this directory run:
docker stack deploy --compose-file docker-stack.yml vote
```
+Run the app in Kubernetes
+-------------------------
+
+The folder k8s-specifications contains the yaml specifications of the Voting App's services.
+
+Run the following command to create the deployments and services objects:
+```
+$ kubectl create -f k8s-specifications/
+deployment "db" created
+service "db" created
+deployment "redis" created
+service "redis" created
+deployment "result" created
+service "result" created
+deployment "vote" created
+service "vote" created
+deployment "worker" created
+```
+
+The vote interface is then available on port 31000 on each host of the cluster, the result one is available on port 31001.
+
Architecture
-----
@@ -36,4 +57,4 @@ Architecture
Note
----
-The voting application only accepts one vote per client. It does not register votes if a vote has already been submitted from a client.
\ No newline at end of file
+The voting application only accepts one vote per client. It does not register votes if a vote has already been submitted from a client.
diff --git a/docker-compose-k8s.yml b/docker-compose-k8s.yml
new file mode 100644
index 0000000..5a65415
--- /dev/null
+++ b/docker-compose-k8s.yml
@@ -0,0 +1,27 @@
+version: ':8080'
+
+services:
+ redis:
+ image: redis:alpine
+ ports:
+ - "6379:6379"
+ db:
+ image: postgres:9.4
+ ports:
+ - "5432:5432"
+ vote:
+ image: dockersamples/examplevotingapp_vote:before
+ ports:
+ - "5000:80"
+ deploy:
+ replicas: 2
+ result:
+ image: dockersamples/examplevotingapp_result:before
+ ports:
+ - "5001:80"
+ worker:
+ image: dockersamples/examplevotingapp_worker
+ visualizer:
+ image: dockersamples/visualizer:stable
+ ports:
+ - "8080:8080"
diff --git a/docker-stack-simple.yml b/docker-stack-simple.yml
new file mode 100644
index 0000000..b941140
--- /dev/null
+++ b/docker-stack-simple.yml
@@ -0,0 +1,78 @@
+version: "3"
+services:
+
+ redis:
+ image: redis:alpine
+ ports:
+ - "6379"
+ networks:
+ - frontend
+ deploy:
+ replicas: 1
+ update_config:
+ parallelism: 2
+ delay: 10s
+ restart_policy:
+ condition: on-failure
+ db:
+ image: postgres:9.4
+ volumes:
+ - db-data:/var/lib/postgresql/data
+ networks:
+ - backend
+ deploy:
+ placement:
+ constraints: [node.role == manager]
+ vote:
+ image: dockersamples/examplevotingapp_vote:before
+ ports:
+ - 5000:80
+ networks:
+ - frontend
+ depends_on:
+ - redis
+ deploy:
+ replicas: 1
+ update_config:
+ parallelism: 2
+ restart_policy:
+ condition: on-failure
+ result:
+ image: dockersamples/examplevotingapp_result:before
+ ports:
+ - 5001:80
+ networks:
+ - backend
+ depends_on:
+ - db
+ deploy:
+ replicas: 1
+ update_config:
+ parallelism: 2
+ delay: 10s
+ restart_policy:
+ condition: on-failure
+
+ worker:
+ image: dockersamples/examplevotingapp_worker
+ networks:
+ - frontend
+ - backend
+ deploy:
+ mode: replicated
+ replicas: 1
+ labels: [APP=VOTING]
+ restart_policy:
+ condition: on-failure
+ delay: 10s
+ max_attempts: 3
+ window: 120s
+ placement:
+ constraints: [node.role == manager]
+
+networks:
+ frontend:
+ backend:
+
+volumes:
+ db-data:
\ No newline at end of file
diff --git a/k8s-specifications/db-deployment.yaml b/k8s-specifications/db-deployment.yaml
new file mode 100644
index 0000000..774c54a
--- /dev/null
+++ b/k8s-specifications/db-deployment.yaml
@@ -0,0 +1,20 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: db
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: db
+ spec:
+ containers:
+ - image: postgres:9.4
+ name: db
+ volumeMounts:
+ - mountPath: /var/lib/postgresql/data
+ name: db-data
+ volumes:
+ - name: db-data
+ emptyDir: {}
diff --git a/k8s-specifications/db-service.yaml b/k8s-specifications/db-service.yaml
new file mode 100644
index 0000000..81f59b4
--- /dev/null
+++ b/k8s-specifications/db-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: db
+spec:
+ type: ClusterIP
+ ports:
+ - port: 5432
+ targetPort: 5432
+ selector:
+ app: db
+
diff --git a/k8s-specifications/redis-deployment.yaml b/k8s-specifications/redis-deployment.yaml
new file mode 100644
index 0000000..a606e5c
--- /dev/null
+++ b/k8s-specifications/redis-deployment.yaml
@@ -0,0 +1,20 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: redis
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - image: redis:alpine
+ name: redis
+ volumeMounts:
+ - mountPath: /data
+ name: redis-data
+ volumes:
+ - name: redis-data
+ emptyDir: {}
diff --git a/k8s-specifications/redis-service.yaml b/k8s-specifications/redis-service.yaml
new file mode 100644
index 0000000..1c6cda4
--- /dev/null
+++ b/k8s-specifications/redis-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis
+spec:
+ type: ClusterIP
+ ports:
+ - port: 6379
+ targetPort: 6379
+ selector:
+ app: redis
+
diff --git a/k8s-specifications/result-deployment.yaml b/k8s-specifications/result-deployment.yaml
new file mode 100644
index 0000000..bd29380
--- /dev/null
+++ b/k8s-specifications/result-deployment.yaml
@@ -0,0 +1,14 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: result
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: result
+ spec:
+ containers:
+ - image: dockersamples/examplevotingapp_result:before
+ name: result
diff --git a/k8s-specifications/result-service.yaml b/k8s-specifications/result-service.yaml
new file mode 100644
index 0000000..7a9793c
--- /dev/null
+++ b/k8s-specifications/result-service.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: result
+spec:
+ type: NodePort
+ ports:
+ - name: "result-service"
+ port: 5001
+ targetPort: 80
+ nodePort: 31001
+ selector:
+ app: result
diff --git a/k8s-specifications/vote-deployment.yaml b/k8s-specifications/vote-deployment.yaml
new file mode 100644
index 0000000..ccd5b27
--- /dev/null
+++ b/k8s-specifications/vote-deployment.yaml
@@ -0,0 +1,14 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: vote
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: vote
+ spec:
+ containers:
+ - image: dockersamples/examplevotingapp_vote:before
+ name: vote
diff --git a/k8s-specifications/vote-service.yaml b/k8s-specifications/vote-service.yaml
new file mode 100644
index 0000000..45f20a8
--- /dev/null
+++ b/k8s-specifications/vote-service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: vote
+spec:
+ type: NodePort
+ ports:
+ - name: "vote-service"
+ port: 5000
+ targetPort: 80
+ nodePort: 31000
+ selector:
+ app: vote
+
diff --git a/k8s-specifications/worker-deployment.yaml b/k8s-specifications/worker-deployment.yaml
new file mode 100644
index 0000000..9d483de
--- /dev/null
+++ b/k8s-specifications/worker-deployment.yaml
@@ -0,0 +1,14 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: worker
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: worker
+ spec:
+ containers:
+ - image: dockersamples/examplevotingapp_worker
+ name: worker
diff --git a/kube-deployment.yml b/kube-deployment.yml
new file mode 100644
index 0000000..0b03da9
--- /dev/null
+++ b/kube-deployment.yml
@@ -0,0 +1,203 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: redis
+ name: redis
+spec:
+ clusterIP: None
+ ports:
+ - name: redis
+ port: 6379
+ targetPort: 6379
+ selector:
+ app: redis
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: redis
+ labels:
+ app: redis
+spec:
+ selector:
+ matchLabels:
+ app: redis
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - name: redis
+ image: redis:alpine
+ ports:
+ - containerPort: 6379
+ name: redis
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: db
+ name: db
+spec:
+ clusterIP: None
+ ports:
+ -
+ name: db
+ port: 5432
+ targetPort: 5432
+ selector:
+ app: db
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: db
+ # labels:
+ # app: db
+spec:
+ template:
+ metadata:
+ labels:
+ app: db
+ spec:
+ containers:
+ -
+ name: db
+ image: postgres:9.4
+ env:
+ - name: PGDATA
+ value: /var/lib/postgresql/data/pgdata
+ ports:
+ - containerPort: 5432
+ name: db
+ volumeMounts:
+ - name: db-data
+ mountPath: /var/lib/postgresql/data
+ volumes:
+ - name: db-data
+ persistentVolumeClaim:
+ claimName: postgres-pv-claim
+
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: postgres-pv-claim
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: result
+ labels:
+ app: result
+spec:
+ type: LoadBalancer
+ ports:
+ -
+ port: 5001
+ targetPort: 80
+ name: result
+ selector:
+ app: result
+ # clusterIP: None
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: result
+ labels:
+ app: result
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: result
+ spec:
+ containers:
+ - name: result
+ image: dockersamples/examplevotingapp_result:before
+ ports:
+ - containerPort: 80
+ name: result
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: vote
+ labels:
+ apps: vote
+spec:
+ type: LoadBalancer
+ ports:
+ - port: 5000
+ targetPort: 80
+ name: vote
+ selector:
+ app: vote
+ # clusterIP: None
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: vote
+ labels:
+ app: vote
+spec:
+ replicas: 2
+ template:
+ metadata:
+ labels:
+ app: vote
+ spec:
+ containers:
+ - name: vote
+ image: dockersamples/examplevotingapp_vote:before
+ ports:
+ -
+ containerPort: 80
+ name: vote
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ apps: worker
+ name: worker
+spec:
+ clusterIP: None
+ selector:
+ app: worker
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ labels:
+ app: worker
+ name: worker
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: worker
+ spec:
+ containers:
+ -
+ image: dockersamples/examplevotingapp_worker
+ name: worker
diff --git a/worker/.classpath b/worker/.classpath
new file mode 100644
index 0000000..71f5fef
--- /dev/null
+++ b/worker/.classpath
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/worker/.project b/worker/.project
new file mode 100644
index 0000000..49e0d9a
--- /dev/null
+++ b/worker/.project
@@ -0,0 +1,23 @@
+
+
+ worker
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/worker/.settings/org.eclipse.jdt.apt.core.prefs b/worker/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 0000000..d4313d4
--- /dev/null
+++ b/worker/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=false
diff --git a/worker/.settings/org.eclipse.jdt.core.prefs b/worker/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1eb325e
--- /dev/null
+++ b/worker/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.processAnnotations=disabled
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/worker/.settings/org.eclipse.m2e.core.prefs b/worker/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/worker/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/worker/src/Worker/Program.cs b/worker/src/Worker/Program.cs
index 0e375d7..e8ca4c1 100644
--- a/worker/src/Worker/Program.cs
+++ b/worker/src/Worker/Program.cs
@@ -104,7 +104,7 @@ namespace Worker
private static ConnectionMultiplexer OpenRedisConnection(string hostname)
{
- // Use IP address to workaround hhttps://github.com/StackExchange/StackExchange.Redis/issues/410
+ // Use IP address to workaround https://github.com/StackExchange/StackExchange.Redis/issues/410
var ipAddress = GetIp(hostname);
Console.WriteLine($"Found redis at {ipAddress}");
diff --git a/worker/target/classes/worker/Worker.class b/worker/target/classes/worker/Worker.class
new file mode 100644
index 0000000..0191c38
Binary files /dev/null and b/worker/target/classes/worker/Worker.class differ