Setup a Docker Swarm cluster
This commit is contained in:
commit
ccd9ff3064
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.log
|
||||||
|
nodes.rb
|
||||||
|
.settings.yml
|
||||||
|
.swarm
|
||||||
|
.vagrant
|
12
LICENSE
Normal file
12
LICENSE
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Copyright (C) 2023 by Kris Lamoureux <kris@lamoureux.io>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
10
Makefile
Normal file
10
Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.PHONY: all vagrant clean
|
||||||
|
|
||||||
|
all: vagrant
|
||||||
|
|
||||||
|
vagrant:
|
||||||
|
vagrant up --no-destroy-on-error --no-color | tee ./vagrantup.log
|
||||||
|
|
||||||
|
clean:
|
||||||
|
vagrant destroy -f --no-color
|
||||||
|
rm -rf .vagrant vagrantup.log .swarm
|
120
README.md
Normal file
120
README.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Vagrant Docker Swarm Environment
|
||||||
|
|
||||||
|
**Warning: For development only, do not use for production**
|
||||||
|
|
||||||
|
This repository contains a Vagrantfile and the necessary configuration files
|
||||||
|
for automating the setup of a Docker Swarm cluster using Vagrant’s shell
|
||||||
|
provisioning. You can easily override the default settings for the Vagrant
|
||||||
|
environment and the Swarm cluster to suit your needs. Customize global
|
||||||
|
settings via the `.settings.yml` file, and specify per-node overrides using the
|
||||||
|
`NODES` Ruby hash in `nodes.rb`.
|
||||||
|
|
||||||
|
By default, `make` will create three Debian Stable x86_64 Docker Swarm nodes.
|
||||||
|
Each node will consume:
|
||||||
|
- 2 threads/cores (depending on architecture)
|
||||||
|
- 2 GB of RAM
|
||||||
|
- ~1 GB of storage (base install only)
|
||||||
|
|
||||||
|
**Warning: Make sure your machine has enough resources or adjust override settings.**
|
||||||
|
|
||||||
|
# Quick Start
|
||||||
|
Get your Vagrant Docker Swarm cluster up and running with these simple steps:
|
||||||
|
|
||||||
|
- Setup the Cluster
|
||||||
|
|
||||||
|
Run the following command to clean any previous setup and start fresh:
|
||||||
|
```bash
|
||||||
|
make clean && make
|
||||||
|
```
|
||||||
|
|
||||||
|
- SSH into a Node
|
||||||
|
|
||||||
|
Access the first node (`node1`) in your cluster:
|
||||||
|
```bash
|
||||||
|
vagrant ssh node1
|
||||||
|
```
|
||||||
|
|
||||||
|
- Verify Cluster Setup
|
||||||
|
|
||||||
|
List all the nodes to ensure they've joined the cluster successfully:
|
||||||
|
```bash
|
||||||
|
docker node ls
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Global Overrides
|
||||||
|
If you wish to override the default settings on a global level,
|
||||||
|
you can do so by creating a `.settings.yml` file based on the provided
|
||||||
|
`example-.settings.yml` file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp example-.settings.yml .settings.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have copied the `example-.settings.yml` to `.settings.yml`, you can
|
||||||
|
edit it to override the default settings. Below are the available settings:
|
||||||
|
|
||||||
|
## Vagrant Settings Overrides
|
||||||
|
- `VAGRANT_BOX`
|
||||||
|
- Default: `debian/bookworm64`
|
||||||
|
- Tested most around Debian Stable x86_64 (currently Bookworm)
|
||||||
|
- `VAGRANT_CPU`
|
||||||
|
- Default: `2`
|
||||||
|
- Two threads or cores per node, depending on CPU architecture
|
||||||
|
- `VAGRANT_MEM`
|
||||||
|
- Default: `2048`
|
||||||
|
- Two GB of RAM per node
|
||||||
|
- `SSH_FORWARD`
|
||||||
|
- Default: `false`
|
||||||
|
- Enable this if you need to forward SSH agents to the Vagrant machines
|
||||||
|
|
||||||
|
## Docker Swarm Settings Overrides
|
||||||
|
- `SWARM_NODES`
|
||||||
|
- Default: `3`
|
||||||
|
- The total number of nodes in your Docker Swarm cluster
|
||||||
|
- `JOIN_TIMEOUT`
|
||||||
|
- Default: `60`
|
||||||
|
- Timeout in seconds for nodes to obtain a swarm join token
|
||||||
|
|
||||||
|
# Per-Node Overrides
|
||||||
|
The naming convention for nodes follows a specific pattern: `nodeX`, where `X`
|
||||||
|
is a number corresponding to the node's position within the cluster. This
|
||||||
|
convention is strictly adhered to due to the iteration logic within the
|
||||||
|
`Vagrantfile`, which utilizes a loop iterating over an array range defined by
|
||||||
|
the number of swarm nodes (`Array(1..SWARM_NODES)`). Each iteration of the loop
|
||||||
|
corresponds to a node, and the loop counter is in the node name (`nodeX`).
|
||||||
|
|
||||||
|
The overrides, if specified in `nodes.rb`, take the highest precedence,
|
||||||
|
followed by the overrides in `.settings.yml`, and lastly, the defaults hard
|
||||||
|
coded in the `Vagrantfile` itself. This hierarchy allows for a flexible
|
||||||
|
configuration where global overrides can be specified in `.settings.yml`, and
|
||||||
|
more granular, per-node overrides can be defined in `nodes.rb`. If a particular
|
||||||
|
setting is not overridden in either `.settings.yml` or `nodes.rb`, the default
|
||||||
|
value from the `Vagrantfile` is used.
|
||||||
|
|
||||||
|
If you wish to override the default settings on a per-node level, you can do so
|
||||||
|
by creating a `nodes.rb` file based on the provided `example-nodes.rb` file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp example-nodes.rb nodes.rb
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have copied the `example-nodes.rb` to `nodes.rb`, you can edit it to
|
||||||
|
override the default settings. Below are the available settings available
|
||||||
|
per-node:
|
||||||
|
|
||||||
|
- `BOX`
|
||||||
|
- Default: `debian/bookworm64` (or as overridden in `.settings.yml`)
|
||||||
|
- Vagrant box or image to be used for the node.
|
||||||
|
- `CPU`
|
||||||
|
- Default: `2` (or as overridden in `.settings.yml`)
|
||||||
|
- Defines the number of CPU cores or threads (depending on architecture).
|
||||||
|
- `MEM`
|
||||||
|
- Default: `2048` (2 GB) (or as overridden in `.settings.yml`)
|
||||||
|
- Specifies the amount of memory (in MB) allocated to the node.
|
||||||
|
- `SSH`
|
||||||
|
- Default: `false` (or as overridden in `.settings.yml`)
|
||||||
|
- Enable this if you need to forward SSH agents to the Vagrant machine
|
||||||
|
|
||||||
|
All settings are optional, and as many or as few options can be overridden on
|
||||||
|
any arbitrary node.
|
59
Vagrantfile
vendored
Normal file
59
Vagrantfile
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# -*- mode: ruby -*-
|
||||||
|
# vi: set ft=ruby :
|
||||||
|
|
||||||
|
# Load override settings
|
||||||
|
require 'yaml'
|
||||||
|
settings_path = '.settings.yml'
|
||||||
|
settings = {}
|
||||||
|
|
||||||
|
if File.exist?(settings_path)
|
||||||
|
settings = YAML.load_file(settings_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default Vagrant settings
|
||||||
|
VAGRANT_BOX = settings['VAGRANT_BOX'] || 'debian/bookworm64'
|
||||||
|
VAGRANT_CPU = settings['VAGRANT_CPU'] || 2
|
||||||
|
VAGRANT_MEM = settings['VAGRANT_MEM'] || 2048
|
||||||
|
SSH_FORWARD = settings['SSH_FORWARD'] || false
|
||||||
|
|
||||||
|
# Default Swarm settings
|
||||||
|
SWARM_NODES = settings['SWARM_NODES'] || 3
|
||||||
|
JOIN_TIMEOUT = settings['JOIN_TIMEOUT'] || 60
|
||||||
|
|
||||||
|
# Node settings overrides
|
||||||
|
if File.exist?('nodes.rb')
|
||||||
|
require_relative 'nodes.rb'
|
||||||
|
else
|
||||||
|
# Using all defaults
|
||||||
|
NODES = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
HOSTS = Array(1..SWARM_NODES)
|
||||||
|
Vagrant.configure(2) do |vm_config|
|
||||||
|
HOSTS.each do |count|
|
||||||
|
vm_config.vm.define "node#{count}" do |config|
|
||||||
|
config.vm.hostname = "node#{count}"
|
||||||
|
config.vm.box = NODES.dig("node#{count}", 'BOX') || VAGRANT_BOX
|
||||||
|
config.ssh.forward_agent =
|
||||||
|
NODES.dig("node#{count}", 'SSH') || SSH_FORWARD
|
||||||
|
|
||||||
|
# Libvirt
|
||||||
|
config.vm.provider :libvirt do |virt|
|
||||||
|
virt.memory = NODES.dig("node#{count}", 'MEM') || VAGRANT_MEM
|
||||||
|
virt.cpus = NODES.dig("node#{count}", 'CPU') || VAGRANT_CPU
|
||||||
|
end
|
||||||
|
|
||||||
|
# VirtualBox
|
||||||
|
config.vm.provider :virtualbox do |vbox|
|
||||||
|
vbox.memory = NODES.dig("node#{count}", 'MEM') || VAGRANT_MEM
|
||||||
|
vbox.cpus = NODES.dig("node#{count}", 'CPU') || VAGRANT_CPU
|
||||||
|
end
|
||||||
|
|
||||||
|
# Install and Setup Docker Swarm
|
||||||
|
config.vm.provision "shell", inline: <<-SHELL
|
||||||
|
export JOIN_TIMEOUT=#{JOIN_TIMEOUT}
|
||||||
|
/bin/bash /vagrant/provision.sh
|
||||||
|
SHELL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
example-.settings.yml
Normal file
18
example-.settings.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
########################
|
||||||
|
### Example settings ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
# This configuration as-is will take 12 threads/cores and 12 GB of RAM
|
||||||
|
# Make sure you have enough resources before running something like this.
|
||||||
|
|
||||||
|
# Set per-node overrides in nodes.rb if your setup requires it
|
||||||
|
|
||||||
|
# Vagrant default global overrides
|
||||||
|
VAGRANT_BOX: debian/bookworm64
|
||||||
|
VAGRANT_CPUS: 4
|
||||||
|
VAGRANT_MEM: 4096
|
||||||
|
SSH_FORWARD: true
|
||||||
|
|
||||||
|
# Swarm default overrides
|
||||||
|
SWARM_NODES: 3
|
||||||
|
JOIN_TIMEOUT: 60
|
34
example-nodes.rb
Normal file
34
example-nodes.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#########################
|
||||||
|
### Example overrides ###
|
||||||
|
#########################
|
||||||
|
|
||||||
|
# This configuration as-is will take 10 threads/cores and 10 GB of RAM assuming
|
||||||
|
# that .settings.yml isn't overriding the defaults. Make sure you have enough
|
||||||
|
# resources before running something like this.
|
||||||
|
|
||||||
|
# Don't forget to set SWARM_NODES in .settings
|
||||||
|
# if you run more/less than 3 nodes
|
||||||
|
|
||||||
|
NODES = {
|
||||||
|
# CPU/MEM heavy node
|
||||||
|
'node1' => {
|
||||||
|
#'BOX' => 'debian/bookworm64',
|
||||||
|
'CPU' => 4,
|
||||||
|
'MEM' => 4096,
|
||||||
|
'SSH' => true
|
||||||
|
},
|
||||||
|
# Memory heavy node
|
||||||
|
'node2' => {
|
||||||
|
'BOX' => 'debian/bookworm64',
|
||||||
|
#'CPU' => 4,
|
||||||
|
'MEM' => 4096,
|
||||||
|
#'SSH' => true
|
||||||
|
},
|
||||||
|
# CPU heavy node
|
||||||
|
'node3' => {
|
||||||
|
'BOX' => 'debian/bookworm64',
|
||||||
|
'CPU' => 4,
|
||||||
|
#'MEM' => 4096,
|
||||||
|
#'SSH' => true
|
||||||
|
}
|
||||||
|
}
|
44
provision.sh
Executable file
44
provision.sh
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
######################################
|
||||||
|
### Install and setup Docker Swarm ###
|
||||||
|
######################################
|
||||||
|
|
||||||
|
# Print commands and exit on error
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
# Install Docker
|
||||||
|
which curl &>/dev/null || (apt-get update && apt-get install -y curl)
|
||||||
|
which docker &>/dev/null || curl -fsSL https://get.docker.com | sh
|
||||||
|
[ ! "$(id -nG vagrant | grep -c docker)" -eq 1 ] && usermod -aG docker vagrant
|
||||||
|
|
||||||
|
# Setup Docker Swarm
|
||||||
|
if [ ! "$(docker info | grep -c 'Swarm: active')" -eq 1 ]; then
|
||||||
|
# Make hostname: node1 the leader who gives the join token to others
|
||||||
|
if [ "$(hostname)" == "node1" ]; then
|
||||||
|
docker swarm init | grep -Eo 'docker swarm join .+:[0-9]+' > /vagrant/.swarm
|
||||||
|
else
|
||||||
|
# Initial delay
|
||||||
|
sleep 5
|
||||||
|
# Waits JOIN_TIMEOUT of seconds to find the swarm join token before giving up
|
||||||
|
START_TIME="$(date +%s)"
|
||||||
|
# Wait until .swarm can be found via Vagrant provider file sharing /vagrant
|
||||||
|
while [ ! -f /vagrant/.swarm ]; do
|
||||||
|
CURRENT_TIME="$(date +%s)"
|
||||||
|
DIFF_TIME="$((CURRENT_TIME - START_TIME))"
|
||||||
|
|
||||||
|
# Timeout
|
||||||
|
if [ "$DIFF_TIME" -ge "$JOIN_TIMEOUT" ]; then
|
||||||
|
echo "[ERROR]: $(hostname) waited $DIFF_TIME/$JOIN_TIMEOUT seconds"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Waiting
|
||||||
|
echo "Waiting ($DIFF_TIME/$JOIN_TIMEOUT seconds) for /vagrant/.swarm file"
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
# /vagrant/.swarm file found, so join the swarm
|
||||||
|
/bin/bash /vagrant/.swarm
|
||||||
|
fi
|
||||||
|
fi
|
2
scratch/.gitignore
vendored
Normal file
2
scratch/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
Loading…
Reference in New Issue
Block a user