├── .gitignore ├── README.md ├── arm ├── README.md ├── arm-alpinehello │ ├── Dockerfile │ ├── index.js │ └── package.json ├── arm-pingcurl │ └── Dockerfile └── arm_redis_counter │ ├── app.js │ └── package.json ├── mkguid ├── Dockerfile ├── app.js └── package.json └── mkguid_tester ├── Dockerfile ├── app.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swarmmode-tests 2 | Series of test cases for Docker swarmmode 3 | 4 | 5 | Check out the *arm* folder for the first set of tests. 6 | 7 | ## Contributing: 8 | 9 | Help is welcome, but my time is limited so if you have a suggestion, enhancement or bug fix then please raise an issue to begin a conversation. 10 | 11 | Once an issue is open we can can talk about the proposed change in the open. Once we've figured out what needs to be done then you can go ahead and raise a PR and it's very likely to get merged. 12 | -------------------------------------------------------------------------------- /arm/README.md: -------------------------------------------------------------------------------- 1 | # Docker Swarmmode Test Scenarios 2 | 3 | These scenarios are designed to test the basic connectivity and features of swarmmode on the Raspberry Pi. 4 | 5 | * [Get Docker installed on your Pi](http://blog.alexellis.io/getting-started-with-docker-on-raspberry-pi/) 6 | 7 | ### Reporting feedback 8 | 9 | Please report feedback to Docker Captain [@alexellisuk](http://twitter.com/alexellisuk) by creating a Github Issue in this repository. 10 | 11 | Please include: 12 | 13 | * Hardware used 14 | * Installation method 15 | * Linux Distribution i.e. Raspbian/Raspbian Lite/HypriotOS/Arch Linux 16 | * Kernel version `uname -a` 17 | * `docker version` 18 | 19 | ## Scenario 1 - the scaled service 20 | 21 | This scenario tests basic scheduling and orchestration. 22 | 23 | With at least two nodes in the swarm: 24 | 25 | ``` 26 | # docker service create --name ping1 --replicas=2 alexellis2/arm-pingcurl ping google.com 27 | ``` 28 | 29 | * Testing: 30 | 31 | Check logs on both nodes for successful ping responses. 32 | 33 | * Cleanup: 34 | 35 | ``` 36 | docker service rm ping1 37 | ``` 38 | 39 | * Source: 40 | 41 | [arm-pingcurl](https://github.com/alexellis/swarmmode-tests/tree/master/arm/arm-pingcurl) 42 | 43 | ## Scenario 2 - the hello world webservice 44 | 45 | This scenario tests the built-in load balancing / mesh routing capabilities. 46 | 47 | With at least two nodes in the swarm: 48 | 49 | ``` 50 | # docker service create --name hello1 --publish 3000:3000 --replicas=2 alexellis2/arm-alpinehello 51 | ``` 52 | 53 | * Testing 54 | 55 | Perform this step 4 times while logged into the manager only. 56 | 57 | ``` 58 | # curl -4 localhost:3000 59 | hello 60 | # curl -4 localhost:3000 61 | hello 62 | # curl -4 localhost:3000 63 | hello 64 | # curl -4 localhost:3000 65 | hello 66 | ``` 67 | 68 | > `curl -4` forces IPv4 69 | 70 | * Cleanup: 71 | 72 | ``` 73 | docker service rm hello1 74 | ``` 75 | 76 | * Source 77 | 78 | [arm-alpinehello](https://github.com/alexellis/swarmmode-tests/tree/master/arm/arm-alpinehello) 79 | 80 | ## Scenario 3 - inter-container communication 81 | 82 | Thie scenario tests inter-container resolution and connectivity. A redis database runs on only one node and on both nodes we run a hit counter which will increment a number held in the redis database with each GET request. 83 | 84 | Make sure you have at least 2 nodes in your swarm. 85 | 86 | * Setting up: 87 | 88 | ``` 89 | # docker network create --driver overlay --subnet 20.0.14.0/24 armnet 90 | # docker service create --replicas=1 --network=armnet --name redis alexellis2/redis-arm:v6 91 | # docker service create --name counter --replicas=2 --network=armnet --publish 3000:3000 alexellis2/arm_redis_counter 92 | ``` 93 | 94 | * Testing / verification 95 | 96 | Perform this test logged into the manager. 97 | 98 | Use `docker service ps counter` and check that at there is one `counter` replica on either host. 99 | 100 | Check there are no error messages in the logs of `docker service ps counter` and if needed check the daemon logs on the node. 101 | 102 | ``` 103 | # curl localhost:3000/incr 104 | {"count":1} 105 | # curl localhost:3000/incr 106 | {"count":2} 107 | # curl localhost:3000/incr 108 | {"count":3} 109 | # curl localhost:3000/incr 110 | {"count":4} 111 | 112 | ``` 113 | 114 | The counter should now equal 4. 115 | 116 | * Clean-up 117 | 118 | ``` 119 | # docker service rm counter 120 | # docker service rm redis 121 | # docker network rm armnet 122 | ``` 123 | 124 | * Source 125 | 126 | [arm_redis_counter](https://github.com/alexellis/swarmmode-tests/tree/master/arm/arm_redis_counter) 127 | 128 | 129 | ### Heads-up 130 | 131 | Running the Docker daemon in debug mode `dockerd --daemon` appears to suggest that the kernel module VXLAN is not available. Please run `rpi-update` and if this command is not available it can be installed with `apt-get`. 132 | 133 | ``` 134 | $ sudo apt-get update && sudo apt-get install -qy rpi-update && sudo rpi-update && sudo reboot 135 | ``` 136 | -------------------------------------------------------------------------------- /arm/arm-alpinehello/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | RUN apk --update add nodejs 4 | 5 | WORKDIR /root/ 6 | ADD ./package.json ./package.json 7 | 8 | RUN npm i 9 | ADD ./index.js ./index.js 10 | 11 | EXPOSE 3000 12 | CMD ["npm", "start"] 13 | -------------------------------------------------------------------------------- /arm/arm-alpinehello/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const express = require('express'); 4 | let app = express(); 5 | 6 | app.get("/", (req, res) => 7 | { 8 | res.status(200).send("Hello"); 9 | }); 10 | 11 | app.listen(3000, () => { 12 | console.log("I'm listening.") 13 | }); 14 | 15 | -------------------------------------------------------------------------------- /arm/arm-alpinehello/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start" : "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.14.0", 14 | "merge-descriptors": "^1.0.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /arm/arm-pingcurl/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM armhf/alpine:latest 2 | 3 | RUN apk --update add curl iputils 4 | 5 | CMD ["ping"] 6 | 7 | -------------------------------------------------------------------------------- /arm/arm_redis_counter/app.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const redis = require('redis'); 4 | const express = require('express') 5 | let app = express(); 6 | 7 | let redisClient = redis.createClient({host: "redis"}); 8 | 9 | app.get("/incr", (req, res) => { 10 | redisClient.incr("counter", (err, val) => { 11 | res.status(200).send({"count": val}); 12 | }); 13 | 14 | }); 15 | 16 | app.listen(3000, () => 17 | { 18 | console.log("Listening"); 19 | }); 20 | -------------------------------------------------------------------------------- /arm/arm_redis_counter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "counter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.14.0", 14 | "redis": "^2.6.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mkguid/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:4.4 2 | ADD package.json 3 | RUN npm i 4 | ADD app.js 5 | 6 | EXPOSE 9000 7 | 8 | CMD ["npm", "start"] 9 | -------------------------------------------------------------------------------- /mkguid/app.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const express = require('express'); 4 | const uuid = require('uuid'); 5 | const os = require('os'); 6 | 7 | let app = express(); 8 | 9 | let hostname = os.hostname(); 10 | 11 | app.get("/guid", (req, res) => { 12 | res.json({ "guid": uuid.v4(), "container": hostname }); 13 | }); 14 | 15 | app.listen(9000, () => { 16 | console.log("listening on port 9000"); 17 | }); 18 | 19 | -------------------------------------------------------------------------------- /mkguid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guid_generator", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.14.0", 14 | "uuid": "^2.0.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mkguid_tester/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:4.4 2 | ADD ./package.json ./package.json 3 | RUN npm i 4 | ADD ./app.js ./app.js 5 | 6 | EXPOSE 9000 7 | 8 | RUN apk --update add curl 9 | 10 | HEALTHCHECK CMD curl --fail -s localhost:9000/guid || exit 1 11 | 12 | CMD ["npm", "start"] 13 | -------------------------------------------------------------------------------- /mkguid_tester/app.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const express = require('express'); 4 | const uuid = require('uuid'); 5 | const os = require('os'); 6 | 7 | let app = express(); 8 | let hostname = os.hostname(); 9 | 10 | let state = { 11 | generateFailure: false 12 | }; 13 | 14 | app.get("/guid", (req, res) => { 15 | if(state.generateFailure) { 16 | return res.status(500).end(); 17 | } 18 | res.json({ "guid": uuid.v4(), "container": hostname }); 19 | }); 20 | 21 | app.post("/toggle.failure", (req, res) => { 22 | state.generateFailure = !state.generateFailure; 23 | res.status(200).end(); 24 | }); 25 | 26 | app.listen(9000, () => { 27 | console.log("listening on port 9000"); 28 | }); 29 | 30 | -------------------------------------------------------------------------------- /mkguid_tester/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guid_generator", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.14.0", 15 | "uuid": "^2.0.2" 16 | } 17 | } 18 | --------------------------------------------------------------------------------