├── .gitattributes ├── .gitignore ├── .machine ├── .gitignore └── env ├── apps ├── .editorconfig ├── .gitignore ├── src │ ├── Consumer │ │ ├── Job.cs │ │ ├── consumer.nomad │ │ ├── Consumer.csproj │ │ ├── Configuration.cs │ │ └── Program.cs │ └── Producer │ │ ├── Job.cs │ │ ├── Producer.csproj │ │ ├── Program.cs │ │ └── Configuration.cs └── Apps.sln ├── rabbit ├── build.sh ├── rabbitmq.conf ├── Dockerfile └── rabbit.nomad ├── scripts ├── build.sh └── host.sh ├── vagrantfile ├── LICENSE ├── readme.md └── box └── common.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh eol=lf 2 | *.conf eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | .artifacts/ 3 | .vscode/ -------------------------------------------------------------------------------- /.machine/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !env -------------------------------------------------------------------------------- /apps/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | indent_size = 4 3 | indent_style = tab 4 | -------------------------------------------------------------------------------- /rabbit/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker build -t rabbitmq:consul . 4 | 5 | -------------------------------------------------------------------------------- /apps/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .idea/ 4 | .build/ 5 | 6 | *.user 7 | *.zip 8 | -------------------------------------------------------------------------------- /apps/src/Consumer/Job.cs: -------------------------------------------------------------------------------- 1 | namespace Jobs 2 | { 3 | public class Job 4 | { 5 | public int Sequence { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /.machine/env: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NOMAD_ADDR=http://one.karhu.xyz:4646 4 | export VAULT_ADDR=http://one.karhu.xyz:8200 5 | -------------------------------------------------------------------------------- /apps/src/Producer/Job.cs: -------------------------------------------------------------------------------- 1 | namespace Jobs 2 | { 3 | public class Job 4 | { 5 | public int Sequence { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rabbit/rabbitmq.conf: -------------------------------------------------------------------------------- 1 | cluster_formation.peer_discovery_backend = rabbit_peer_discovery_consul 2 | cluster_formation.consul.svc_addr_auto = true 3 | -------------------------------------------------------------------------------- /rabbit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rabbitmq:management-alpine 2 | COPY rabbitmq.conf /etc/rabbitmq 3 | RUN rabbitmq-plugins enable --offline rabbitmq_peer_discovery_consul 4 | -------------------------------------------------------------------------------- /apps/src/Producer/Producer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/src/Consumer/consumer.nomad: -------------------------------------------------------------------------------- 1 | job "consumer" { 2 | datacenters = ["dc1"] 3 | type = "service" 4 | 5 | group "consumers" { 6 | count = 1 7 | 8 | task "consumer" { 9 | driver = "exec" 10 | 11 | config { 12 | command = "/usr/bin/dotnet" 13 | args = [ 14 | "local/Consumer.dll" 15 | ] 16 | } 17 | 18 | artifact { 19 | source = "http://artifacts.service.consul:3000/Consumer.zip" 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | output_dir=".artifacts" 4 | 5 | mkdir -p "$output_dir" 6 | rm -rf $output_dir/*.zip 7 | 8 | pushd apps 9 | 10 | find ./src -iname "*.csproj" | while read project_path; do 11 | 12 | project_name=$(basename "$project_path" .csproj) 13 | 14 | dotnet publish "$project_path" --output "bin/$project_name" 15 | 16 | publish_path="./bin/$project_name" 17 | output_zip="../$output_dir/$project_name.zip" 18 | 19 | 7z a "$output_zip" "$publish_path/*" > /dev/null 20 | 21 | done 22 | 23 | popd 24 | -------------------------------------------------------------------------------- /vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure(2) do |config| 2 | config.vm.box = "local/hashibox" 3 | 4 | config.vm.provider "hyperv" do |h, override| 5 | h.memory = "1024" 6 | h.linked_clone = true 7 | 8 | override.vm.network "public_network", bridge: "Default Switch" 9 | end 10 | 11 | config.vm.provider "libvirt" do |lv, override| 12 | lv.memory = 1024 13 | override.vm.synced_folder "./", "/vagrant", type: 'nfs' 14 | end 15 | 16 | config.vm.define "one" do |n1| 17 | n1.vm.hostname = "one" 18 | end 19 | 20 | config.vm.define "two" do |n2| 21 | n2.vm.hostname = "two" 22 | end 23 | 24 | config.vm.define "three" do |n3| 25 | n3.vm.hostname = "three" 26 | end 27 | 28 | config.vm.provision "shell", privileged: true, path: './box/common.sh' 29 | 30 | end 31 | -------------------------------------------------------------------------------- /apps/src/Consumer/Consumer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /apps/src/Consumer/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Consul; 4 | 5 | namespace Consumer 6 | { 7 | public class Configuration : IDisposable 8 | { 9 | private static readonly Random Random = new Random(); 10 | private readonly ConsulClient _consul; 11 | 12 | public Configuration() 13 | { 14 | _consul = new ConsulClient(); 15 | } 16 | 17 | public async Task GetRabbitBroker() 18 | { 19 | var service = await GetService("rabbitmq", "amqp"); 20 | 21 | var builder = new UriBuilder 22 | { 23 | Scheme = "rabbitmq", 24 | Host = service.Address, 25 | Port = service.ServicePort 26 | }; 27 | 28 | return builder.Uri; 29 | } 30 | 31 | private async Task GetService(string serviceName, string tag = null) 32 | { 33 | var service = await _consul.Catalog.Service(serviceName, tag); 34 | var index = Random.Next(0, service.Response.Length - 1); 35 | 36 | return service.Response[index]; 37 | } 38 | 39 | public void Dispose() 40 | { 41 | _consul.Dispose(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /apps/src/Producer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Jobs; 5 | using MassTransit; 6 | 7 | namespace Producer 8 | { 9 | class Program 10 | { 11 | public static async Task Main(string[] args) 12 | { 13 | var config = new Configuration(); 14 | var broker = await config.GetRabbitBroker(); 15 | 16 | var bus = Bus.Factory.CreateUsingRabbitMq(c => 17 | { 18 | c.Host(broker, r => 19 | { 20 | r.Username("admin"); 21 | r.Password("admin"); 22 | }); 23 | }); 24 | 25 | await bus.StartAsync(); 26 | 27 | var total = args 28 | .Where(x => int.TryParse(x, out _)) 29 | .Select(int.Parse) 30 | .DefaultIfEmpty(1000) 31 | .First(); 32 | 33 | Console.WriteLine($"Publishing {total} jobs..."); 34 | 35 | for (var i = 0; i < total; i++) 36 | await bus.Publish( 37 | new Job { Sequence = i }, 38 | context => context.MessageId = Guid.NewGuid() 39 | ); 40 | 41 | await bus.StopAsync(); 42 | config.Dispose(); 43 | 44 | Console.WriteLine("Done"); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /apps/src/Producer/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Consul; 5 | 6 | namespace Producer 7 | { 8 | public class Configuration : IDisposable 9 | { 10 | private static readonly Random Random = new Random(); 11 | private readonly ConsulClient _consul; 12 | 13 | public Configuration() 14 | { 15 | _consul = new ConsulClient(); 16 | } 17 | 18 | public async Task GetRabbitBroker() 19 | { 20 | var service = await GetService("rabbitmq", "amqp"); 21 | 22 | var builder = new UriBuilder 23 | { 24 | Scheme = "rabbitmq", 25 | Host = service.Address, 26 | Port = service.ServicePort 27 | }; 28 | 29 | return builder.Uri; 30 | } 31 | 32 | private async Task GetService(string serviceName, string tag = null) 33 | { 34 | var service = await _consul.Catalog.Service(serviceName, tag); 35 | var instance = service.Response[Random.Next(0, service.Response.Length - 1)]; 36 | 37 | return instance; 38 | } 39 | 40 | public void Dispose() 41 | { 42 | _consul.Dispose(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Andy Davies 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Nomad Demo 2 | 3 | Repository to go with my talk on [Nomad: Kubernetes without the Complexity](https://andydote.co.uk/presentations/index.html?nomad). 4 | 5 | ## Tooling 6 | 7 | Required: 8 | * Hyper-v - You can adapt the `Vagrantfile`s to other virtualisation tools if you want 9 | * [Vagrant](https://www.vagrantup.com/) - for the VMs 10 | * [Nomad](https://www.nomadproject.io/) - to interact with the cluster 11 | * Bash - gitbash is fine 12 | 13 | Optionals: 14 | * [Consul](https://www.consul.io) - run a consul node on your local machine to host other services 15 | * Tmux - just makes running one of the scripts easier 16 | 17 | ## Setup 18 | 19 | 1. start the cluster 20 | ```shell 21 | ./scripts/init.sh # or make sure there is a host_ip file at repo root with your host machine ip in it 22 | vagrant up 23 | ``` 24 | 1. Run all the demo junk 25 | * if you have tmux: 26 | ```shell 27 | ./scripts/demo.sh 28 | ``` 29 | * if you don't, run a separate shell for each of these: 30 | * `./scripts/consul.sh` 31 | * `./scripts/host.sh` 32 | 1. in a shell (as admin on windows), run this: 33 | ```shell 34 | export NOMAD_ADDR="http://$(cat server_ip):4646" 35 | nomad status 36 | ``` 37 | You can now run jobs: 38 | ```shell 39 | nomad job run rabbit/rabbit.nomad 40 | ``` 41 | 42 | 43 | Good Luck! 44 | -------------------------------------------------------------------------------- /apps/src/Consumer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Jobs; 5 | using MassTransit; 6 | using Microsoft.Extensions.Configuration; 7 | 8 | namespace Consumer 9 | { 10 | class Program 11 | { 12 | private static Random Random = new Random(); 13 | 14 | public static async Task Main(string[] args) 15 | { 16 | var config = new Configuration(); 17 | var broker = await config.GetRabbitBroker(); 18 | 19 | var bus = Bus.Factory.CreateUsingRabbitMq(c => 20 | { 21 | var host = c.Host(broker, r => 22 | { 23 | r.Username("admin"); 24 | r.Password("admin"); 25 | }); 26 | 27 | c.ReceiveEndpoint(host, "Jobs", ep => ep.Handler(OnJob)); 28 | }); 29 | 30 | await bus.StartAsync(); 31 | 32 | WaitForCancel(); 33 | 34 | await bus.StopAsync(); 35 | config.Dispose(); 36 | } 37 | 38 | private static async Task OnJob(ConsumeContext context) 39 | { 40 | var duration = TimeSpan.FromSeconds(Random.Next(0, 5)); 41 | 42 | await Task.Delay(duration); 43 | 44 | Console.WriteLine($"Processing {context.Message.Sequence} took {duration.TotalSeconds} seconds"); 45 | } 46 | 47 | private static void WaitForCancel() 48 | { 49 | var pause = new ManualResetEvent(false); 50 | Console.WriteLine("Press Ctrl+C to exit"); 51 | 52 | Console.CancelKeyPress += (sender, e) => 53 | { 54 | Console.WriteLine("Shutting down..."); 55 | e.Cancel = true; 56 | pause.Set(); 57 | }; 58 | 59 | pause.WaitOne(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /rabbit/rabbit.nomad: -------------------------------------------------------------------------------- 1 | job "rabbit" { 2 | 3 | datacenters = ["dc1"] 4 | type = "service" 5 | 6 | group "cluster" { 7 | count = 1 8 | 9 | update { 10 | max_parallel = 1 11 | } 12 | 13 | migrate { 14 | max_parallel = 1 15 | health_check = "checks" 16 | min_healthy_time = "5s" 17 | healthy_deadline = "30s" 18 | } 19 | 20 | task "rabbit" { 21 | driver = "docker" 22 | 23 | config { 24 | image = "registry.service.consul:5000/pondidum/rabbitmq:consul" 25 | hostname = "${attr.unique.hostname}" 26 | port_map { 27 | amqp = 5672 28 | ui = 15672 29 | discovery = 4369 30 | clustering = 25672 31 | } 32 | } 33 | 34 | vault { 35 | policies = ["rabbit"] 36 | } 37 | 38 | env { 39 | CONSUL_HOST = "${attr.unique.network.ip-address}" 40 | CONSUL_SVC_PORT = "${NOMAD_HOST_PORT_amqp}" 41 | CONSUL_SVC_TAGS = "amqp" 42 | } 43 | 44 | template { 45 | data = < Configuring host containers" 6 | # machine_ip=$(ip route get 1 | awk '{print $(NF-2);exit}') 7 | machine_ip=$(ip addr show docker0 | awk '$1 == "inet" {gsub(/\/.*$/, "", $2); print $2}') 8 | echo " HostIP: $machine_ip" 9 | 10 | echo " Running Consul" 11 | docker run -d --rm \ 12 | --name nomad-consul \ 13 | --net=host \ 14 | -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' \ 15 | consul agent -bind="$machine_ip" -retry-join="one.karhu.xyz" 16 | 17 | echo " Running docker registry" 18 | docker run -d --rm \ 19 | --name nomad-registry \ 20 | -p 5000:5000 \ 21 | registry:latest 22 | 23 | echo " Running http artifacts server" 24 | docker run -d --rm \ 25 | --name nomad-artifacts \ 26 | -p 3000:3000 \ 27 | -e 'PORT=3000' \ 28 | -v "$PWD/.artifacts:/web" \ 29 | halverneus/static-file-server:latest 30 | 31 | echo "==> Pusing rabbitmq:consul to docker registry" 32 | docker tag rabbitmq:consul localhost:5000/pondidum/rabbitmq:consul 33 | docker push localhost:5000/pondidum/rabbitmq:consul 34 | 35 | echo "==> Registering services into Consul" 36 | 37 | echo " http artifacts host" 38 | curl --silent \ 39 | --request PUT \ 40 | --url http://localhost:8500/v1/agent/service/register \ 41 | --header 'content-type: application/json' \ 42 | --data '{ "ID": "artifacts", "Name": "artifacts", "Port": 3000 }' 43 | 44 | echo " docker registry" 45 | curl --silent \ 46 | --request PUT \ 47 | --url http://localhost:8500/v1/agent/service/register \ 48 | --header 'content-type: application/json' \ 49 | --data '{ "ID": "registry", "Name": "registry", "Port": 5000 }' 50 | 51 | echo "==> Consul Status" 52 | 53 | consul members 54 | 55 | source .machine/one 56 | 57 | echo "==> Writing into Vault" 58 | 59 | vault secrets enable -path=secret -version=2 kv 60 | 61 | echo 'path "secret/data/rabbit" { 62 | capabilities = ["read"] 63 | }' | vault policy write rabbit - 64 | 65 | vault kv put secret/rabbit \ 66 | cookie="$(cat /proc/sys/kernel/random/uuid)" \ 67 | admin_user="admin" \ 68 | admin_pass="admin" 69 | 70 | echo "==> Done." 71 | -------------------------------------------------------------------------------- /apps/Apps.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{615CF37F-0D4A-40AA-8BC2-BAC6B06461DA}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Consumer", "src\Consumer\Consumer.csproj", "{2076C05B-11FF-4B9D-9DB6-51942A51B3A4}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Producer", "src\Producer\Producer.csproj", "{81515672-2893-4F57-B362-D6F909174B10}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|x64.Build.0 = Debug|Any CPU 29 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Debug|x86.Build.0 = Debug|Any CPU 31 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|x64.ActiveCfg = Release|Any CPU 34 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|x64.Build.0 = Release|Any CPU 35 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|x86.ActiveCfg = Release|Any CPU 36 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4}.Release|x86.Build.0 = Release|Any CPU 37 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|x64.Build.0 = Debug|Any CPU 41 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {81515672-2893-4F57-B362-D6F909174B10}.Debug|x86.Build.0 = Debug|Any CPU 43 | {81515672-2893-4F57-B362-D6F909174B10}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {81515672-2893-4F57-B362-D6F909174B10}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {81515672-2893-4F57-B362-D6F909174B10}.Release|x64.ActiveCfg = Release|Any CPU 46 | {81515672-2893-4F57-B362-D6F909174B10}.Release|x64.Build.0 = Release|Any CPU 47 | {81515672-2893-4F57-B362-D6F909174B10}.Release|x86.ActiveCfg = Release|Any CPU 48 | {81515672-2893-4F57-B362-D6F909174B10}.Release|x86.Build.0 = Release|Any CPU 49 | EndGlobalSection 50 | GlobalSection(NestedProjects) = preSolution 51 | {2076C05B-11FF-4B9D-9DB6-51942A51B3A4} = {615CF37F-0D4A-40AA-8BC2-BAC6B06461DA} 52 | {81515672-2893-4F57-B362-D6F909174B10} = {615CF37F-0D4A-40AA-8BC2-BAC6B06461DA} 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /box/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo "==> Configuring Consul" 4 | ( 5 | cat <<-EOF 6 | { 7 | "data_dir": "/var/consul", 8 | "client_addr": "127.0.0.1 {{ GetInterfaceIP \"eth0\" }}", 9 | "bind_addr": "{{ GetInterfaceIP \"eth0\" }}", 10 | "ui": true, 11 | "server": true, 12 | "bootstrap_expect": 3, 13 | "retry_join": [ "one.karhu.xyz", "two.karhu.xyz", "three.karhu.xyz" ], 14 | "connect": { 15 | "enabled": true 16 | } 17 | } 18 | EOF 19 | ) | tee /etc/consul/consul.json 20 | 21 | rc-update add consul 22 | rc-service consul start 23 | 24 | sleep 2 # allow agent to start 25 | 26 | echo " waiting for cluster to form" 27 | while [ "$(consul operator raft list-peers | grep -c leader)" != "1" ]; do 28 | sleep 1 29 | done 30 | 31 | echo " Done" 32 | 33 | echo "==> Configuring Vault" 34 | 35 | ( 36 | cat < /tmp/vault_init 2>/dev/null"; 63 | then 64 | echo " Initialised Vault" 65 | init_json=$(cat /tmp/vault_init) 66 | consul kv put vagrant/init "$init_json" 67 | else 68 | echo " Already initialised" 69 | sleep 2s 70 | init_json=$(consul kv get vagrant/init) 71 | fi 72 | 73 | root_token=$(echo "$init_json" | jq -r .root_token) 74 | unseal_key=$(echo "$init_json" | jq -r .unseal_keys_b64[0]) 75 | 76 | echo " Root Token: $root_token" 77 | echo " Unseal Key: $unseal_key" 78 | 79 | vault operator unseal "$unseal_key" 80 | 81 | echo " Vault Unsealed" 82 | 83 | echo "==> Configuring Nomad" 84 | 85 | export VAULT_TOKEN="$root_token" 86 | escaped_token=$(echo "$root_token" | sed -e 's/[\/&]/\\&/g') 87 | 88 | ( 89 | cat <<-EOF 90 | data_dir = "/var/nomad" 91 | 92 | client { 93 | enabled = true 94 | } 95 | 96 | server { 97 | enabled = true 98 | bootstrap_expect = 3 99 | } 100 | 101 | vault { 102 | enabled = true 103 | address = "http://vault.service.consul:8200" 104 | token = "$escaped_token" 105 | } 106 | EOF 107 | ) | tee /etc/nomad/nomad.hcl 108 | 109 | rc-update add nomad 110 | rc-service nomad start 111 | 112 | echo " Nomad started" 113 | 114 | echo "==> Configuring Docker" 115 | 116 | echo ' 117 | { 118 | "insecure-registries": [ 119 | "registry.service.consul:5000" 120 | ], 121 | "dns": [ 122 | "192.168.121.1" 123 | ] 124 | }' | tee /etc/docker/daemon.json 125 | 126 | rc-service docker restart 127 | 128 | echo "==> Exporting machine info" 129 | 130 | rm -f "/vagrant/.machine/$HOSTNAME" 131 | echo "export VAULT_ADDR=http://$HOSTNAME.karhu.xyz:8200" >> "/vagrant/.machine/$HOSTNAME" 132 | echo "export VAULT_TOKEN=$root_token" >> "/vagrant/.machine/$HOSTNAME" 133 | echo "export VAULT_UNSEAL=$unseal_key" >> "/vagrant/.machine/$HOSTNAME" 134 | echo "export NOMAD_ADDR=http://$HOSTNAME.karhu.xyz:8200" >> "/vagrant/.machine/$HOSTNAME" 135 | --------------------------------------------------------------------------------