├── .gitignore ├── web-vote-app ├── requirements.txt ├── utils │ └── __init__.py ├── Dockerfile ├── templates │ ├── env.html │ └── index.html ├── app.py └── static │ └── stylesheets │ └── style.css ├── cluster.png ├── cluster-detailed.png ├── results-app ├── Dockerfile ├── rebuild-redploy-single-node-vagrant.sh ├── package.json ├── views │ ├── app.js │ ├── index.html │ └── stylesheets │ │ └── style.css └── server.js ├── docker-compose.override.yml ├── vote-worker ├── Dockerfile ├── pom.xml └── src │ └── main │ └── java │ └── worker │ └── Worker.java ├── Vagrant ├── first-time.sh ├── kill-all.sh ├── after-reboot.sh ├── Vagrantfile └── HOWTO.TXT ├── docker-compose.yml ├── AWS ├── HOWTO_CREATE_AMI.txt ├── HOWTO.txt └── cloudformation.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | -------------------------------------------------------------------------------- /web-vote-app/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Redis -------------------------------------------------------------------------------- /cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-archive/swarm-microservice-demo-v1/HEAD/cluster.png -------------------------------------------------------------------------------- /cluster-detailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-archive/swarm-microservice-demo-v1/HEAD/cluster-detailed.png -------------------------------------------------------------------------------- /results-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:0.10 2 | 3 | RUN mkdir /app 4 | WORKDIR /app 5 | 6 | ADD package.json /app/package.json 7 | RUN npm install && npm ls 8 | RUN mv /app/node_modules /node_modules 9 | 10 | ADD . /app 11 | 12 | ENV PORT 80 13 | EXPOSE 80 14 | 15 | CMD ["node", "server.js"] 16 | -------------------------------------------------------------------------------- /docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | # 2 | # docker-compose.override.yml provides settings for local development 3 | # 4 | 5 | version: '2' 6 | 7 | services: 8 | web-vote-app: 9 | ports: ['8081:80'] 10 | 11 | results-app: 12 | ports: ['8082:80'] 13 | 14 | redis01: 15 | ports: ["6379:6379"] 16 | 17 | -------------------------------------------------------------------------------- /results-app/rebuild-redploy-single-node-vagrant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker stop results-app ; docker rm results-app ; docker rmi results-app ; docker -H tcp://192.168.33.251:2375 build -t results-app . ; docker run --restart=unless-stopped --env="constraint:node==store" -p 80:80 -d --name results-app --net mynet results-app 4 | -------------------------------------------------------------------------------- /vote-worker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM java:7 2 | 3 | RUN apt-get update -qq && apt-get install -y maven && apt-get clean 4 | 5 | WORKDIR /code 6 | 7 | ADD pom.xml /code/pom.xml 8 | RUN ["mvn", "dependency:resolve"] 9 | RUN ["mvn", "verify"] 10 | 11 | # Adding source, compile and package into a fat jar 12 | ADD src /code/src 13 | RUN ["mvn", "package"] 14 | 15 | CMD ["/usr/lib/jvm/java-7-openjdk-amd64/bin/java", "-jar", "target/worker-jar-with-dependencies.jar"] 16 | -------------------------------------------------------------------------------- /web-vote-app/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import time 2 | from redis import Redis, ConnectionError 3 | 4 | 5 | def connect_to_redis(host): 6 | time.sleep(2) 7 | print "Connecting to redis" 8 | 9 | while True: 10 | try: 11 | redis = Redis(host=host, db=0) 12 | redis.ping() 13 | print "Connected to redis" 14 | return redis 15 | except ConnectionError: 16 | print "Failed to connect to redis - retrying" 17 | time.sleep(1) 18 | -------------------------------------------------------------------------------- /results-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "result-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "body-parser": "^1.14.1", 13 | "cookie-parser": "^1.4.0", 14 | "express": "^4.13.3", 15 | "method-override": "^2.3.5", 16 | "async": "^1.5.0", 17 | "pg": "^4.4.3", 18 | "socket.io": "^1.3.7" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web-vote-app/Dockerfile: -------------------------------------------------------------------------------- 1 | # Using official python runtime base image 2 | FROM python:2.7 3 | 4 | # Set the application directory 5 | WORKDIR /app 6 | 7 | # Install our requirements.txt 8 | ADD requirements.txt /app/requirements.txt 9 | RUN pip install -r requirements.txt 10 | 11 | # Copy our code from the current folder to /app inside the container 12 | ADD . /app 13 | 14 | # Make port 80 available for links and/or publish 15 | EXPOSE 80 16 | 17 | # Define our command to be run when launching the container 18 | CMD ["python", "app.py"] 19 | -------------------------------------------------------------------------------- /Vagrant/first-time.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | vagrant up 4 | 5 | vagrant ssh -c "sudo apt-get install -y linux-image-generic-lts-utopic && sudo reboot" master 6 | vagrant ssh -c "sudo apt-get install -y linux-image-generic-lts-utopic && sudo reboot" interlock 7 | vagrant ssh -c "sudo apt-get install -y linux-image-generic-lts-utopic && sudo reboot" frontend01 8 | vagrant ssh -c "sudo apt-get install -y linux-image-generic-lts-utopic && sudo reboot" worker01 9 | vagrant ssh -c "sudo apt-get install -y linux-image-generic-lts-utopic && sudo reboot" store 10 | 11 | -------------------------------------------------------------------------------- /web-vote-app/templates/env.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |{{s}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Vagrant/kill-all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Examples:
4 | # IP="192.168.33.11" sh -c 'docker -H tcp://$IP:2375 ps'
5 | # CID=ca476182988c IP="192.168.33.11" sh -c 'docker -$ tcp://$IP:2375 stop $CID ; docker rm $CID'
6 |
7 | arr=("192.168.33.11" "192.168.33.20" "192.168.33.200" "192.168.33.250")
8 |
9 | for IP in "${arr[@]}"; do
10 | echo "Clearing $IP"
11 | cids=( $(docker -H tcp://$IP:2375 ps -q -a) )
12 | for CID in ${cids[@]}; do
13 | echo " - Removing $CID [on $IP]"
14 | docker -H tcp://$IP:2375 stop $CID
15 | docker -H tcp://$IP:2375 rm $CID
16 | done
17 | done
18 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Compose file to run the voting app and dependent services
3 | #
4 |
5 | version: '2'
6 |
7 | services:
8 | web-vote-app:
9 | build: web-vote-app
10 | environment:
11 | WEB_VOTE_NUMBER: "01"
12 | constraint:node: "=frontend01"
13 |
14 | vote-worker:
15 | build: vote-worker
16 | environment:
17 | FROM_REDIS_HOST: 1
18 | TO_REDIS_HOST: 1
19 |
20 | results-app:
21 | build: results-app
22 |
23 | redis01:
24 | image: redis:3
25 |
26 | store:
27 | image: postgres:9.5
28 | environment:
29 | - POSTGRES_USER=postgres
30 | - POSTGRES_PASSWORD=pg8675309
31 |
--------------------------------------------------------------------------------
/AWS/HOWTO_CREATE_AMI.txt:
--------------------------------------------------------------------------------
1 | How I Created AMI "ami-bb90e5db" (Swarm-ready Ubuntu trusty):
2 |
3 | - Started with Ubuntu 14.04 box (ami-56f59e36)
4 | - Run these commands:
5 |
6 | sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
7 | sudo sh -c 'echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" > /etc/apt/sources.list.d/docker.list'
8 | sudo apt-get update
9 | sudo apt-get -y install linux-image-extra-$(uname -r) docker-engine linux-image-generic-lts-utopic
10 | sudo reboot
11 | sudo usermod -a -G docker ubuntu ## add ubuntu user to docker group
12 | sudo service docker restart
13 |
14 | - Removed the ``/etc/docker/key.json` file
15 |
16 | - Now in AWS console do: Instances and select your instance -> Actions -> Image -> Create Image
17 |
18 | - My customized Ubuntu AMI: ami-bb90e5db
19 |
20 | - The CloudFormation template will now rely on this new "ami-bb90e5db" that already has docker and kernel 3.16 installed installed.
21 |
22 | * Note that with ami-bb90e5db you must reset the Engine ID on each instance using a user-data bash script like this:
23 | sudo service docker stop
24 | sudo rm -f /etc/docker/key.json
25 | sudo service docker start
26 |
27 | This is done for each machine automatically in the CloudFormation template accompanying this repo.
28 |
--------------------------------------------------------------------------------
/Vagrant/after-reboot.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ##
4 | ## Commands to create the Swarm layer containers
5 | ##
6 |
7 | docker -H=tcp://192.168.33.11:2375 run --restart=unless-stopped -d -p 8500:8500 -h consul progrium/consul -server -bootstrap
8 |
9 | docker -H=tcp://192.168.33.20:2375 run --restart=unless-stopped -d swarm join --advertise=192.168.33.20:2375 consul://192.168.33.11:8500/
10 | docker -H=tcp://192.168.33.21:2375 run --restart=unless-stopped -d swarm join --advertise=192.168.33.21:2375 consul://192.168.33.11:8500/
11 | [et cetera]
12 |
13 | docker -H=tcp://192.168.33.200:2375 run --restart=unless-stopped -d swarm join --advertise=192.168.33.200:2375 consul://192.168.33.11:8500/
14 | docker -H=tcp://192.168.33.201:2375 run --restart=unless-stopped -d swarm join --advertise=192.168.33.201:2375 consul://192.168.33.11:8500/
15 | [et cetera]
16 |
17 | docker -H=tcp://192.168.33.250:2375 run --restart=unless-stopped -d swarm join --advertise=192.168.33.250:2375 consul://192.168.33.11:8500/
18 |
19 | docker -H=tcp://192.168.33.11:2375 run --restart=unless-stopped -d -p 3375:2375 swarm manage consul://192.168.33.11:8500/
20 |
21 | export DOCKER_HOST="tcp://192.168.33.11:3375"
22 | docker network create --driver overlay mynet
23 |
24 | ##
25 | ## OPTIONAL: Commands to test the cluster
26 | ##
27 | docker info
28 | docker run -d --name web --net mynet nginx
29 | docker run -itd --name shell1 --net mynet alpine /bin/sh
30 | docker attach shell1
31 | $ ping web
32 | docker stop web shell1 ; docker rm web shell1
33 |
--------------------------------------------------------------------------------
/results-app/views/app.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('catsvsdogs', []);
2 | var socket = io.connect({transports:['polling']});
3 |
4 | var bg1 = document.getElementById('background-stats-1');
5 | var bg2 = document.getElementById('background-stats-2');
6 |
7 | app.controller('statsCtrl', function($scope){
8 | var animateStats = function(a,b){
9 | if(a+b>0){
10 | var percentA = a/(a+b)*100;
11 | var percentB = 100-percentA;
12 | bg1.style.width= percentA+"%";
13 | bg2.style.width = percentB+"%";
14 | }
15 | };
16 |
17 | $scope.aPercent = 50;
18 | $scope.bPercent = 50;
19 | $scope.allVotes = [];
20 |
21 | var updateScores = function(){
22 | socket.on('scores', function (json) {
23 | data = JSON.parse(json);
24 | var a = parseInt(data.a || 0);
25 | var b = parseInt(data.b || 0);
26 | var allVotesArr = data.allVotesArr;
27 |
28 | $scope.allVotes = [];
29 | for(var i = 0; i