├── .gitignore ├── provider.tf ├── keys.tf ├── terraform.tfvars.example ├── outputs.tf ├── variables.tf ├── Makefile ├── README.md └── swarm.tf /.gitignore: -------------------------------------------------------------------------------- 1 | terraform.tfvars 2 | *.tfstate* 3 | tmp/ 4 | keys/* 5 | .terraform 6 | -------------------------------------------------------------------------------- /provider.tf: -------------------------------------------------------------------------------- 1 | provider "digitalocean" { 2 | token = "${var.do_token}" 3 | } 4 | -------------------------------------------------------------------------------- /keys.tf: -------------------------------------------------------------------------------- 1 | # Create a new SSH key 2 | resource "digitalocean_ssh_key" "default" { 3 | name = "Docker Swarm Demo SSH Key" 4 | public_key = "${file("${var.ssh_key_file}.pub")}" 5 | } 6 | -------------------------------------------------------------------------------- /terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | do_token = "123456" 2 | ssh_key_file = "~/.ssh/somekey" 3 | do_region = "ams3" 4 | do_droplet_size = "512mb" 5 | swarm_nodes = 2 6 | swarm_manager_nodes = 1 7 | do_image = "fedora-23-x64" 8 | swarm_token = "123456789" 9 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "Docker Swarm Manager(s) Public IPs" { 2 | value = "${join("\n ", formatlist("%s", split(",", digitalocean_droplet.swarm_manager.*.ipv4_address)))}" 3 | } 4 | 5 | output "Docker Swarm Node(s) Public IPs" { 6 | value = "${join("\n ", formatlist("%s", split(",", digitalocean_droplet.swarm_node.*.ipv4_address)))}" 7 | } 8 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "do_token" { 2 | description = "Digital Ocean Token" 3 | } 4 | 5 | variable "ssh_key_file" { 6 | description = "Default SSH Key file" 7 | } 8 | 9 | variable "do_region" { 10 | default = "ams3" 11 | description = "Digital Ocean Region" 12 | } 13 | 14 | variable "do_droplet_size" { 15 | default = "512mb" 16 | description = "Droplet Size" 17 | } 18 | 19 | variable "do_image" { 20 | default = "fedora-23-x64" 21 | description = "Image Name" 22 | } 23 | 24 | variable "swarm_manager_nodes" { 25 | default = 1 26 | description = "Number of manager nodes in the cluster" 27 | } 28 | 29 | variable "swarm_nodes" { 30 | default = 1 31 | description = "Number of nodes in the cluster" 32 | } 33 | 34 | variable "swarm_token" { 35 | default = "12345789" 36 | description = "A 26 chars Docker Swarm Token" 37 | } 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := help 2 | TERRAFORM_VERSION = 0.6.15 3 | TERRAFORM_BIN = docker run -it --rm -v `pwd`:/data sjourdan/terraform:$(TERRAFORM_VERSION) 4 | 5 | validate: terraform-fmt terraform-validate ## Validate syntax 6 | 7 | plan: terraform-validate terraform-get terraform-plan ## Plan changes 8 | 9 | apply: terraform-validate terraform-get terraform-apply ## Apply Changes 10 | 11 | destroy: terraform-destroy ## Destroy infrastructure 12 | 13 | output: terraform-output ## Display State Output 14 | 15 | terraform-validate: 16 | $(TERRAFORM_BIN) validate 17 | 18 | terraform-get: 19 | $(TERRAFORM_BIN) get 20 | 21 | terraform-plan: 22 | $(TERRAFORM_BIN) plan 23 | 24 | terraform-apply: 25 | $(TERRAFORM_BIN) apply 26 | 27 | terraform-fmt: 28 | $(TERRAFORM_BIN) fmt -list 29 | 30 | terraform-destroy: 31 | $(TERRAFORM_BIN) destroy 32 | 33 | terraform-output: 34 | $(TERRAFORM_BIN) output 35 | 36 | help: 37 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Swarm Mode (>= Docker 1.12) 2 | 3 | This docker cluster is running on Docker Swarm (new 1.12 mode). Warning: this was written with a pre-release version of Docker 1.12 - things work differently in the final release. 4 | 5 | ## Requirements 6 | 7 | You'll need: 8 | 9 | - terraform >= v0.6.15 10 | - the `./keys/docker-demo` private key 11 | - a populated `terraform.tfvars` file 12 | 13 | ## Setup 14 | 15 | make apply 16 | 17 | ### Manual Swarm Configuration 18 | 19 | Initialize the swarm on the first manager: 20 | 21 | docker swarm init --secret 22 | 23 | Leave the Swarm: 24 | docker swarm leave --force 25 | 26 | Join a member to the Swarm: 27 | 28 | docker swarm join --secret (--ca-hash sha256:) :2377 29 | 30 | ## Troubleshooting 31 | 32 | ## Known Bugs 33 | * the `--secret` option to `docker swarm join` has been pulled from 1.12 final. A related discussion includes [this issue](https://github.com/docker/docker/issues/24430). Workaround may include playing around (didn't test yet) `MANAGER_JOIN_TOKEN="$(docker swarm join-token -q manager)"` and `MANAGER_JOIN_TOKEN="$(docker swarm join-token -q worker)"`. 34 | -------------------------------------------------------------------------------- /swarm.tf: -------------------------------------------------------------------------------- 1 | /* A Docker Swarm Manager */ 2 | resource "digitalocean_droplet" "swarm_manager" { 3 | image = "${var.do_image}" 4 | count = "${var.swarm_manager_nodes}" 5 | name = "swarm-manager-${count.index+1}" 6 | region = "${var.do_region}" 7 | size = "${var.do_droplet_size}" 8 | ssh_keys = ["${digitalocean_ssh_key.default.id}"] 9 | private_networking = true 10 | 11 | connection { 12 | user = "root" 13 | key_file = "${var.ssh_key_file}" 14 | } 15 | 16 | provisioner "remote-exec" { 17 | inline = [ 18 | "apt update", 19 | "apt upgrade -y", 20 | "curl -fsSL https://test.docker.com/ | sh", 21 | "docker swarm init --secret ${var.swarm_token}", 22 | ] 23 | } 24 | } 25 | 26 | /* As Many Docker Swarm Nodes As Needed */ 27 | resource "digitalocean_droplet" "swarm_node" { 28 | depends_on = ["digitalocean_droplet.swarm_manager"] 29 | image = "${var.do_image}" 30 | count = "${var.swarm_nodes}" 31 | name = "swarm-node-${count.index+1}" 32 | region = "${var.do_region}" 33 | size = "${var.do_droplet_size}" 34 | ssh_keys = ["${digitalocean_ssh_key.default.id}"] 35 | private_networking = true 36 | 37 | connection { 38 | user = "root" 39 | key_file = "${var.ssh_key_file}" 40 | } 41 | 42 | provisioner "remote-exec" { 43 | inline = [ 44 | "apt update", 45 | "apt upgrade -y", 46 | "curl -fsSL https://test.docker.com/ | sh", 47 | "docker swarm join --secret ${var.swarm_token} ${digitalocean_droplet.swarm_manager.ipv4_address_private}:2377", 48 | ] 49 | } 50 | } 51 | --------------------------------------------------------------------------------