From 0fd383ce27ee517e2cd7e6c7221c31010500c2ed Mon Sep 17 00:00:00 2001 From: Luc Juggery Date: Mon, 5 Mar 2018 12:57:48 +0100 Subject: [PATCH 1/6] Add k8s specfications --- README.md | 23 ++++++++++++++++++++++- k8s-specifications/db-deployment.yaml | 20 ++++++++++++++++++++ k8s-specifications/db-service.yaml | 12 ++++++++++++ k8s-specifications/redis-deployment.yaml | 20 ++++++++++++++++++++ k8s-specifications/redis-service.yaml | 12 ++++++++++++ k8s-specifications/result-deployment.yaml | 14 ++++++++++++++ k8s-specifications/result-service.yaml | 13 +++++++++++++ k8s-specifications/vote-deployment.yaml | 14 ++++++++++++++ k8s-specifications/vote-service.yaml | 14 ++++++++++++++ k8s-specifications/worker-deployment.yaml | 14 ++++++++++++++ 10 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 k8s-specifications/db-deployment.yaml create mode 100644 k8s-specifications/db-service.yaml create mode 100644 k8s-specifications/redis-deployment.yaml create mode 100644 k8s-specifications/redis-service.yaml create mode 100644 k8s-specifications/result-deployment.yaml create mode 100644 k8s-specifications/result-service.yaml create mode 100644 k8s-specifications/vote-deployment.yaml create mode 100644 k8s-specifications/vote-service.yaml create mode 100644 k8s-specifications/worker-deployment.yaml 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/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 From 0e4a0796911a40b30925cd8e18d1ac4fce55c9bc Mon Sep 17 00:00:00 2001 From: Rodion Fedorov Date: Tue, 17 Jul 2018 20:49:40 +0300 Subject: [PATCH 2/6] Fix typo in the comment --- worker/src/Worker/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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}"); From a56b748832ef7fc6e66065394dd693c0a9bfa657 Mon Sep 17 00:00:00 2001 From: spara Date: Mon, 30 Jul 2018 11:20:25 -0500 Subject: [PATCH 3/6] updated .gitignore --- docker-compose-k8s.yml | 27 +++ kube-deployment.yml | 203 ++++++++++++++++++ worker/.classpath | 44 ++++ worker/.project | 23 ++ .../.settings/org.eclipse.jdt.apt.core.prefs | 2 + worker/.settings/org.eclipse.jdt.core.prefs | 7 + worker/.settings/org.eclipse.m2e.core.prefs | 4 + worker/target/classes/worker/Worker.class | Bin 0 -> 4102 bytes 8 files changed, 310 insertions(+) create mode 100644 docker-compose-k8s.yml create mode 100644 kube-deployment.yml create mode 100644 worker/.classpath create mode 100644 worker/.project create mode 100644 worker/.settings/org.eclipse.jdt.apt.core.prefs create mode 100644 worker/.settings/org.eclipse.jdt.core.prefs create mode 100644 worker/.settings/org.eclipse.m2e.core.prefs create mode 100644 worker/target/classes/worker/Worker.class 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/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/target/classes/worker/Worker.class b/worker/target/classes/worker/Worker.class new file mode 100644 index 0000000000000000000000000000000000000000..0191c3845dc96c15824785c4a2ca9f5e95d2ad18 GIT binary patch literal 4102 zcma)9340UQ6+I(M9$5?ognbV-};ZMwHk_mHN>geFb5v`zan`hD$>XzHH#Mo2amZ86`>o0+?wd+vQtZ~gn# z*8x0?zp3yk*!XnGxnw!?KXXb>_h=!fmrC>wd=dQXT`Kms;Xd52 zV$T}*GS@1uwV**q2cfeZN5M8PM7tCpV|Ffcw2TEtvX6O98*ct0Q`WDPTuZ-PwWm! zEQkb&D2xShMnT7zQ_5SFO1&PlB}YHdSvjERuE~2y)F!E61n1ZwvIMgVjyG|(n$)$F zYbdNOXTKogsD?DoD+pD~rr}ysjHhAs4$`epV*Q)gR0!k9sF)!9b>?QqQ;Dm2tL&1y z8nUv7WeOSB$Y07jMxNBW4^tYZae=T{S8bNh&+>`(H=H@P+t$^2)j(9R>%TM{aWZqF zY3hA&M?$q~idu^iBEyw~sBT_Xd)ROdVWJ5+$Qe}eX3eJ+9^>VJ0(%_=X zHmEe(V0+U(o)YGs)^HWqh=_I7%2!=$Qc_P&`(zOBVGB);4G(4$wM;XKtT&>slf-TdA?TStnO)3XlfO{POwfs}`)Uz5sg->&&RSK5Hk>-z%h+XBgcjQ=`2X!~NRB3dOcX@0C}H~b%lnAev`aWed1nFi+^ zi)=VJ?ATWAMt)i)*_kTEDW1fjFlBn_9 zwuQwXY4|aI!eQW+JXr zu%{74vdC@Psg_-<5d*7dRvkm^LL31jjCz&JW(ph~p-idjS5 zzHIweUU@L(v&vPRcQONkt{Vtm=fX#pKz;^-*ub^s3Glv=Pi@$Qdpu?32<3#4h4AKO zZb{+o%eZ&+W$X^`UBUz1E#a;u^!RV$kPmO*X!;iVW_oYnc%MJw51&}VqkRD`hQ*>) zD4hfZaCW*U5{R@eBel5lN~(JaWBz4KUYFtIk>}RkB7^N?NMNX~ z3{m5{9b0((2s5{>ILfC%Y{v!cz`L-SS`nB$&R)bW6u66v1Sgm%lfVof+imaatnF`J>LB$t|*vZM6A!> z6@IrAB8maO_c;;>c=C~eCn&Iru=e}zz)G;8gWhzOb1$>qN2&dMI>1b$T*Y{eGS@C< z+0FcVki`i3>yJ2~S`k7&Ia=@X_KR-i!CqdM6%`X!vPqC*IF@0f|clz7@Lk z6BZRm<^RhPmrer1pD#2gSoI=J2+GE9p?8M#d?wW${=gDG#PqjGmVJyYYsV*+@yW%N ze+UMBM$qmhs<*MyTk#y#1)2Br8LV3y4)gsZ{BneDj$${CG5d!Z=K%ND6EZ*DbBWJ0 zD?#@CcwTa$oxIB93#^%_>_)Ww3vH}yQpIyy7&U(%tt;mMP5CK2tE9qTT*jBDZ{dZR z@V9Q@JM4?^hJVP*5?&l##Gan;Ps2Z7#!IP1gwrCCrFv%FZ?62kJG@+@!|n2GqdiM_ z)z5Aa(yw`G`&iO0CNj=Q#*pE(^U@z-D}YCTA5JsUGuXpocHkUkQ!MHz0ZHRH-#yAk z7^L11?@69}$1ue!&$#@1f*_c@igxiRFk6Gj$M?^(NjT4N2)`k0K3WxEne?AzCEt)_ z$kKNnzvWi}UId;UR751o4Qejq5;Z~61JeSm{kfWNQ!p1$z_}wCcqat;0 z5cuigkF`w05^vF*Iq6NKFA*_K3uXKXf95^N?|J;C772gppP>cOg>Uhr4}bj+ekt)W literal 0 HcmV?d00001 From b832e3786496c65d9ba505706864f78067911d7a Mon Sep 17 00:00:00 2001 From: spara Date: Mon, 30 Jul 2018 11:23:50 -0500 Subject: [PATCH 4/6] added Jenkinsfile --- Jenkinsfile | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..387fdf2 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,31 @@ +node { + def resultImage + def voteImage + def workerImage + docker.withRegistry("https://index.docker.io/v1/", "dockersamples" ) { + stage('Clone repo') { + checkout scm + } + stage('Build result') { + resultImage = docker.build("dockersamples/result", "./result") + } + stage('Build vote') { + voteImage = docker.build("dockersamples/vote", "./vote") + } + stage('Build worker dotnet') { + workerImage = docker.build("dockersamples/worker", "./worker") + } + stage('Push result image') { + resultImage.push("${env.BUILD_NUMBER}") + resultImage.push() + } + stage('Push vote image') { + voteImage.push("${env.BUILD_NUMBER}") + voteImage.push() + } + stage('Push worker image') { + workerImage.push("${env.BUILD_NUMBER}") + workerImage.push() + } + } +} From 0355778d6e803b03bcca8174e7a12913450de369 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Thu, 16 Aug 2018 23:27:20 +0100 Subject: [PATCH 5/6] Update Jenkinsfile - Rewrite as declarative - Add credentials - Gate images pushes to master branch only Signed-off-by: Dave Tucker --- Jenkinsfile | 79 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 387fdf2..906f80e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,31 +1,54 @@ -node { - def resultImage - def voteImage - def workerImage - docker.withRegistry("https://index.docker.io/v1/", "dockersamples" ) { - stage('Clone repo') { - checkout scm +pipeline { + agent { + node { + label 'ubuntu-1604-aufs-stable' + } + } + stages { + stage('Build result') { + steps { + sh 'docker build -t dockersamples/result ./result' } - stage('Build result') { - resultImage = docker.build("dockersamples/result", "./result") - } - stage('Build vote') { - voteImage = docker.build("dockersamples/vote", "./vote") - } - stage('Build worker dotnet') { - workerImage = docker.build("dockersamples/worker", "./worker") - } - stage('Push result image') { - resultImage.push("${env.BUILD_NUMBER}") - resultImage.push() - } - stage('Push vote image') { - voteImage.push("${env.BUILD_NUMBER}") - voteImage.push() - } - stage('Push worker image') { - workerImage.push("${env.BUILD_NUMBER}") - workerImage.push() + } + 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 From d80c43b8f4e1827361981121aa7fb6400f589228 Mon Sep 17 00:00:00 2001 From: Mano Marks Date: Thu, 20 Sep 2018 15:42:35 -0700 Subject: [PATCH 6/6] adding simple stack file for getting started --- docker-stack-simple.yml | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docker-stack-simple.yml 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