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