{"id":13582309,"url":"https://github.com/sfproductlabs/roo","last_synced_at":"2025-04-12T18:41:37.661Z","repository":{"id":142077351,"uuid":"254530567","full_name":"sfproductlabs/roo","owner":"sfproductlabs","description":"Setup and run your own clusters on your own infrastructure in minutes (Eg. ECS or EKS). Roo is a zero config distributed ingress, edge-router \u0026 reverse-proxy (supporting multiple letsencrypt/https hosts) using Docker Swarm. No dependencies.","archived":false,"fork":false,"pushed_at":"2023-04-19T22:29:59.000Z","size":1003,"stargazers_count":61,"open_issues_count":0,"forks_count":7,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-26T12:51:16.347Z","etag":null,"topics":["cluster","clustered","distributed","docker","docker-compose","docker-swarm","edge-router","haproxy","ingress","kubernetes","lets-encrypt","letsencrypt","load-balancer","nginx","reverse-proxy","swarm-service","traefik","traefik-v2","websocket-proxy","zero-config"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sfproductlabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-04-10T02:58:47.000Z","updated_at":"2024-11-20T06:10:31.000Z","dependencies_parsed_at":"2024-01-19T08:14:30.077Z","dependency_job_id":"f07f55eb-3326-4782-a5bf-acc385cf34bc","html_url":"https://github.com/sfproductlabs/roo","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfproductlabs%2Froo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfproductlabs%2Froo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfproductlabs%2Froo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfproductlabs%2Froo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sfproductlabs","download_url":"https://codeload.github.com/sfproductlabs/roo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248616668,"owners_count":21134119,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cluster","clustered","distributed","docker","docker-compose","docker-swarm","edge-router","haproxy","ingress","kubernetes","lets-encrypt","letsencrypt","load-balancer","nginx","reverse-proxy","swarm-service","traefik","traefik-v2","websocket-proxy","zero-config"],"created_at":"2024-08-01T15:02:35.303Z","updated_at":"2025-04-12T18:41:37.627Z","avatar_url":"https://github.com/sfproductlabs.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg width=\"75\" src=\"https://media.giphy.com/media/ekFkyOSUtzvn8nHYEl/giphy.gif\"/\u003e \n\t\u003cbr\u003e\n\u003c/div\u003e\n\n# Roo\n\n## TL;DR\n**Roo is the opposite of Kubernetes. It's designed for sub-1 minute cluster setup times.**\n\nThis basically lets you run your own encrypted and load balanced Amazon AWS clusters on your own hardware, and is a 5-minute replacement for Kubernetes, with no configuration (no additional setup for clustered kv stores, no janky config files, no defining providers, no dodgy second hand helm charts, no ssl setup, no manual ssl certification, no single point failures etc). You can setup a cluster, and publish a new domain in around 30 seconds (once you get the one time, 5 minute setup out of the way).\n\nAll you need to do is add a few lines to a docker-compose file and Roo does the rest [see a full configuration example](https://github.com/sfproductlabs/roo/blob/master/test-docker-compose.yml):\n```yaml\n      OriginHosts: example.com,www.example.com\n      OriginScheme: https\n      OriginPort: 443\n      DestinationHost: test_test\n      DestinationScheme: http\n      DestinationPort: 80\n```\n\n[See a 5 minute line-by-line run-through example setup (includes setting up physical infrastructure, virtual docker swarm infrastructure, and roo cluster that runs on top of the swarm, that handles requests and passes it to your underlying clustered services)](https://github.com/sfproductlabs/roo#getting-started-complete-run-through-example-on-hetzner-cloud)\n\n## Introduction\n\n![Roo functional diagram](misc/Roo.png)\n\nThis aims to be a free replacement of Amazon's ECS (Elastic Compute Service), EKS (Kubernetes), CertificateManager, Load-Balancer and CloudWatch using your own Docker Swarm. It IS a complete replacement for nginx, traefik, haproxy, and a lot of kubernetes. The idea is to give developers back the power and take it back from ridiculous self-complicating dev-ops tools that get more complicated and less useful (for example Traefik 2 just removed support for clustered Letsencrypt from their open source version to spruik their enterprise version. Nginx and HAProxy do the same). I wasted a lot of time on their software before writing this. I truly hope it benefits others too.\n\nIf you are unfamiliar with swarm/kubernetes and are a developer and want a quick intro into how powerful and easy swarm can be, [see how you can setup a thousand-machine cluster in just 20 lines](https://github.com/sfproductlabs/scrp#running-on-docker-swarm) (just copy + paste from there) or [check out my command notes](https://github.com/sfproductlabs/haswarm/blob/master/README.md). In a day I was scaling clusters up and down on my own infrastructure with single commands.\n\nThe power Roo gives you is to add HTTPS://example1.com and HTTPS://example2.com to your clustered services with zero configuration. Let's encrypt allocates your service's certificates. It works across every machine, docker node, service, in your cluster.\n\nRoo itself is clustered. Every machine it runs on shares the load to your services. It's distributed store shares certificates from Letsencrypt used across all your nodes. Now apple is denying certificates older than a year, I feel as a dev, that lets encrypt is almost mandatory as it creates a lot of admin.\n\n\n## Getting Started (on docker)\n\n* Want to just run it?\n```\ndocker run sfproductlabs/roo:latest\n```\n* Want to compile and run?\n```sh\ngit mod download\nmake\n# update the config if you need\nsudo rood ./config.json\n```\n* Run a cluster on docker swarm (trivial example)\n```sh\ndocker swarm init\ndocker network create -d overlay --attachable forenet --subnet 192.168.9.0/24\n#the following label notifies that we should put a single instnce of roo on machines/swarm-nodes with the label \"load_balancer\"\ndocker node ls -q | xargs docker node update --label-add load_balancer=true\ndocker stack deploy -c roo-docker-compose.yml --resolve-image never roo\n``` \n* Lets examine whats going on in docker swarm\n```sh\n# Diagnostic Functions:\ndocker stack ls\ndocker stack services roo\ndocker service inspect roo_roo\ndocker stats --no-stream\ndocker node ls\ndocker node inspect --pretty \u003cNODE_NAME\u003e \n# or for a single machine cluster\ndocker node ls -q | xargs docker node inspect --pretty\ndocker service ps roo_roo\ndocker service logs roo_roo -f\necho \"docker service rm roo_roo # WARNING WILL REMOVE CLUSTER\"\necho \"docker stack rm roo # WARNING WILL REMOVE CLUSTER\"\n```\n\n### Cluster API Endpoints\n* Write a record to the KV Store - PUT http://localhost:6299/roo/v1/kvs/hop Ex. ```curl -X POST -i http://localhost:6299/roo/v1/kv/hop --data 'scotch'```\n* Get a record from the KV Store - GET http://localhost:6299/roo/v1/kv/hopscotch\n* Search/Scan the KV Store - GET http://localhost:6299/roo/v1/kvs/hop\n* Get the Server Status - GET http://localhost:6299/roo/v1/status\n* Clear the Cluster/Servers - POST http://localhost:6299/roo/v1/rescue\n* Swarm Update - POST http://localhost:6299/roo/v1/swarm\n* Ping - GET http://localhost:6299/roo/v1/ping\n* Join a machine to the swarm - POST http://localhost:6299/roo/v1/join \n* Remove a machine from the swarm - POST http://localhost:6299/roo/v1/remove \n* Debug Cmdline - GET http://localhost:6299/debug/pprof/heap\n* Debug Profile - GET http://localhost:6299/debug/pprof/profile\n* Debug Symbols - GET http://localhost:6299/debug/pprof/symbol\n* Debug Trace - GET http://localhost:6299/debug/pprof/trace\n* Debug Indices - GET http://localhost:6299/debug/pprof/1\n* Delete a permission - DELETE http://localhost:6299/roo/v1/perm/user\n* Add a permission - PUT http://localhost:6299/roo/v1/perm\n* Check a permission - POST http://localhost:6299/roo/v1/perm\n\n\n## Getting Started With a Real Example (complete run-through example on Hetzner Cloud)\n\n### Setup the physical nodes\nThis will set you up with a cluster on Hetzner Cloud (change the first 20 lines to suit your own cloud provider). I use this on my own production servers. I don't love [Hetzner](https://hetzner.cloud/?ref=kVvYlAsUNbOF) - the service isn't as good as I'd like - but it is improving and is CHEAP (~$3 per server).\n\n```sh\n# mac\nbrew install hcloud \nbrew install jq\n#debian/ubuntu\n#sudo apt install hcloud-cli jq\n#create a project in hetzner called test (https://console.hetzner.cloud/projects)\n#create a api key in the project you setup on hetzner\n#hcloud context create test #connect the api key to the project\n#test the connection\nhcloud server-type list \n#start with an empty project (check this is empty)\nhcloud server list \nhcloud ssh-key create --name andy --public-key-from-file ~/.ssh/id_rsa.pub  \nhcloud network create --ip-range=10.1.0.0/16 --name=aftnet\nhcloud network add-subnet --ip-range=10.1.0.0/16 --type=server --network-zone=eu-central aftnet\n#If you want a lot more machines see the horizontal web scraper project commands (https://github.com/sfproductlabs/scrp)\n#for n in {1..30}; do (hcloud server create --name docker$RANDOM$RANDOM$RANDOM$RANDOM --type cx11 --image debian-9 --datacenter nbg1-dc3 --network aftnet --ssh-key andy 2\u003e\u00261 \u003e/dev/null \u0026) ; done\n#watch -n 5 \"echo \"Press Ctrl-c to exit when your server count meets the desired amount. You will need to copy and paste just the following instructions to proceed.\" \u0026\u0026 hcloud server list | grep 'running' | awk 'END {print NR}'\"\nhcloud server create --name docker1 --type cx11 --image debian-9 --datacenter nbg1-dc3 --network aftnet --ssh-key andy \nhcloud server create --name docker2 --type cx11 --image debian-9 --datacenter nbg1-dc3 --network aftnet --ssh-key andy \nhcloud server create --name docker3 --type cx11 --image debian-9 --datacenter nbg1-dc3 --network aftnet --ssh-key andy \nrm *.txt\nhcloud server list -o columns=name -o noheader \u003e worker-names.txt\nhcloud server list -o columns=ipv4 -o noheader \u003e worker-ips.txt\ncat worker-names.txt | xargs -I {} hcloud server describe -o json {} | jq -r '.private_net[0].ip' \u003e\u003e worker-vips.txt\nhcloud server create --name manager1 --type cx11 --image debian-9 --datacenter nbg1-dc3 --network aftnet --ssh-key andy\nhcloud server describe -o json manager1 | jq -r '.private_net[0].ip' \u003e manager-vip.txt\nscp -o StrictHostKeyChecking=no *.txt root@$(hcloud server list -o columns=ipv4,name -o noheader | grep manager1 | awk '{print $1}'):~/\nscp -o StrictHostKeyChecking=no ansible/* root@$(hcloud server list -o columns=ipv4,name -o noheader | grep manager1 | awk '{print $1}'):~/\nscp -o StrictHostKeyChecking=no *-docker-compose.yml root@$(hcloud server list -o columns=ipv4,name -o noheader | grep manager1 | awk '{print $1}'):~/\n```\nIf it stuffs up run **DANGEROUS** it will delete all your servers for the project:\n```sh\nhcloud server list -o columns=name -o noheader | xargs -P 8 -I {} hcloud server delete {}\n```\n\n### Setup the docker swarm\n\nGet on the manager1 node: \n\n```sh\n#only required on a mac\neval `ssh-agent` \u0026\u0026 ssh-add ~/.ssh/id_rsa \n#now login to manager1\nssh -l root -A $(hcloud server list -o columns=ipv4,name -o noheader | grep manager1 | awk '{print $1}')\n```\n\nThen run:\n\n```sh\napt-get update \u0026\u0026 \\\napt-get upgrade -y \u0026\u0026 \\\napt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y \u0026\u0026 \\\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - \u0026\u0026 \\\napt-key fingerprint 0EBFCD88 \u0026\u0026 \\\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\" \u0026\u0026 \\\napt-get update \u0026\u0026 \\\napt-get install docker-ce docker-ce-cli containerd.io ansible -y \u0026\u0026 \\\ndocker swarm init --advertise-addr=ens10 \u0026\u0026 \\\ndocker swarm join-token worker | xargs | sed -r 's/^.*(docker.*).*$/\\1/' \u003e join.sh \u0026\u0026 \\\nchmod +x join.sh \u0026\u0026 \\\nprintf \"\\n[defaults]\\nhost_key_checking = False\\n\" \u003e\u003e /etc/ansible/ansible.cfg \u0026\u0026 \\\nprintf \"\\n[managers]\\n\" \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\ncat manager-vip.txt \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\nprintf \"\\n[dockers]\\n\" \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\ncat manager-vip.txt \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\ncat worker-vips.txt \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\nprintf \"\\n[workers]\\n\" \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\ncat worker-vips.txt \u003e\u003e /etc/ansible/hosts \u0026\u0026 \\\nansible dockers -a \"uptime\" \u0026\u0026 \\\nprintf \"\\n            $(cat join.sh | awk '{print $0}')\" \u003e\u003e swarm-init.yml \u0026\u0026 \\\nansible-playbook swarm-init.yml \u0026\u0026 \\\nansible dockers -a \"docker stats --no-stream\" \u0026\u0026 \\\ndocker node ls  \n```\n\n### Setup roo\n\n```sh\n#It's required to run roo on a manager node to get the automatic updates from the docker-compose files. You don't need to serve content from it though.\ndocker node update --label-add load_balancer=true manager1 \u0026\u0026 \\\ndocker node update --label-add load_balancer=true docker1 \u0026\u0026 \\\ndocker node update --label-add load_balancer=true docker2 \u0026\u0026 \\\ndocker node update --label-add load_balancer=true docker3 \u0026\u0026 \\\ndocker network create -d overlay --attachable forenet --subnet 192.168.9.0/24 \u0026\u0026 \\\ndocker stack deploy -c roo-docker-compose.yml roo\n```\nYou can watch roo boot \u0026 status using ```docker service logs roo_roo -f``` otherwise **wait about a minute** for the services \u0026 raft-log to auto-start.\n\n#### Start a service (test)\n* Setup a test-domain and and IPs in your host-name record. \n* Edit [test-docker-compose.yml](https://github.com/sfproductlabs/roo/blob/master/test-docker-compose.yml) and replace ```test.sfpl.io``` with the test-domain,  (make sure to set it up in your host records and use a [load-balancer](https://github.com/sfproductlabs/floater)!). \n\nThen run:\n```sh\ndocker stack deploy -c test-docker-compose.yml test\n```\nSo long as you have your DNS setup, this will do:\n- IP \u0026 Service Failover\n- Get your HTTPS certificate for you automatically\n- Route \u0026 Load balance all the traffic through to your services.\n\nGo to your domain. **All Done** \n\n#### Debug\n\n##### Check roo's distributed keystore\n```sh\ndocker run -it --net=forenet alpine ash\napk add curl\ncurl -X GET http://tasks.roo_roo:6299/roo/v1/kvs\n```\n\n##### Check the service log\n```sh\ndocker service logs roo_roo -f\ndocker service ps roo_roo\n```\n\n##### Check using Ansible\n```sh\nansible workers -a \"ip addr\"\n```\n\n##### More Help\n\n[Check the FAQ](https://github.com/sfproductlabs/roo#help)\n\n## Getting Started (on swarm)\nRun this all in the docker swarm manager look [here](https://github.com/sfproductlabs/haswarm#getting-started) to get started.\n* Create the default network, for example:\n```\ndocker network create -d overlay --attachable forenet --subnet 192.168.9.0/24 \n```\n* Add label to the nodes you want to run it on (load_balancer describes the label for roo to attach to):\n```\ndocker node update --label-add load_balancer=true docker1-prod\n```\n* You'll need to run roo on at least one manager node if you want docker services to auto-sync with Let's Encrypt. Don't worry though as this is not a security issue like in other platforms (like Traefik) as the manager node need not be publicly accessible.\n* Run [the docker-compose file](https://github.com/sfproductlabs/roo/blob/master/roo-docker-compose.yml) on swarm (WARNING: LetsEncrypt hates load, so update the ```ROO_ACME_STAGING=true``` if you plan to muck about):\n```\n# docker stack deploy -c roo-docker-compose.yml roo\n```\n* It takes a minute to bootstrap\n* Notice the roo images are available at dockerhub [sfproductlabs/roo:latest](https://hub.docker.com/repository/docker/sfproductlabs/roo). I don't use the Github repository service as it requires a key to just get the image.\n* Then in your own docker-compose file do something like (note the label used in the zeroconfig, and the destination, its usually swarmstack_swarmservicename):\n```yaml\nversion: \"3.7\"\nservices:\n  test:\n    image: test\n    deploy:\n      replicas: 1\n    networks:\n      - forenet\n    labels:\n      OriginHosts: test.sfpl.io\n      DestinationHost: test_test\n      DestinationScheme: http\n      DestinationPort: 80\n    \nnetworks:\n  forenet:\n    external: true  \n```\n* NOTE: Give it a minute before you query your service, as the service blocks unknown traffic (the docker watcher updates every 30 seconds or so, and it will need a bit to find your new service).\nJOB DONE!\n### Zeroconfig of docker swarm services\nYou need to tell roo what the incoming hostname etc is and where to route it to in the docker-compose file (if you want to go fully automoatic)\n\n### Letsencrypt caveats\nPlease be extremely careful, letsencrypt/acme have weekly limits (which are super low) that will ban you from getting certificates for a week. Please use the staging setting in the roo-docker-compose-file. \n\nhttps://letsencrypt.org/docs/rate-limits/\n\n### Going Manual\nRoo comes with a clustered Distributed Key-Value (KV) Store (See the API below for access). You can use this to manually configure roo. To add the route and do the zeroconfig example above manually, do this instead:\n* You'll need to first deploy the test stack\n```\ndocker stack deploy -c test-docker-compose.yml test\n```\n* Then let roo know the route (do this inside any machine in the forenet network):\n```\ncurl -X PUT roo_roo:6299/roo/v1/kv/com.roo.host:test.sfpl.io:https -d 'http://test_test:80'\n```\n\n## Building from source\n* You need to get the dependencies. Check the roo-docker-compose.yml file for a current list.\n* Run ```make``` in the root directory (not the roo directory).\n\n## Schema Definitions\n\n### Adding a route to the routing table\n* Use the Put API below\n```\ncom.roo.host:\u003crequesting_host\u003c:port (optional)\u003e:scheme\u003e  \u003cdestination_url\u003e\n```\n[See an example](https://github.com/sfproductlabs/roo/blob/master/README.md#a-real-example-route)\n\n## API \n### Post a single key to the distributed store\n```\ncurl -X PUT -d'test data' http://localhost:6299/roo/v1/kv/test\n```\n* Returns a json object { \"ok\" : true} if succeded\n#### A Real Example Route\n**Put in a test route**. For our example we are serving goole.com at our public endpoint, and routing to a swarm service with an endpoint inside our network on port 9001. The swarm stack is _cool_, the swarm service name is _game_. In docker swarm world this equates to a mesh network load balanced DNS record of tasks.cool_game. (you'll need to find your stack, service, and replace that and port 9001 with your details to get it working). The overall result to add this to our routing tables is:\n\n```curl -X PUT -d'http://tasks.cool_game:9001' http://localhost:6299/roo/v1/kv/com.roo.host:google.com:https```\n\n * Note: as we don't specify a port in our requests we remove the optional port :443\n\nTo test you can run something like this (this just makes your localhost pretend like its responding to a request to google.com):\n```curl -H \"Host: google.com\" https://localhost/```\n\nSo to summarize, google.com:443 is the incoming route to roo from the internet, and tasks.cool_game:9001 is your service and port to your internal service (in this case its an internal intranet _docker swarm_ service).\n\n### Get a SINGLE key from the store\n```\ncurl -X GET http://localhost:6299/roo/v1/kv/test\n```\n* Returns the raw bytes (you'll see this as a string if you stored it like that)\n### List multiple keys from the store (Using a SCAN/Prefix filter query)\n```\ncurl -X GET http://localhost:6299/roo/v1/kvs/te #Searches the prefix _te_\ncurl -X GET http://localhost:6299/roo/v1/kvs/tes #Searches the prefix _tes_\ncurl -X GET http://localhost:6299/roo/v1/kvs/test #Searches the prefix _test_\ncurl -X GET http://localhost:6299/roo/v1/kvs #Gets everything in the _entire_ kv store (filter is on nothing)\n```\n* Returns the rows searched using the SCAN query (in KV land its a prefix filter) in JSON\n* The resulting values are encoded in base64, so you may need to convert them (unlike the GET single query above which returns raw bytes)\n* Use ```window.atob(\"dGVz......dCBkYXRh\")``` in javascript. Use json.Unmarshall or string([]byte) in Golang Go if you want a string... OR just use GET instead.\n\n### Setting a permission\n\n* Note : The rune is a single character (G,F,R etc.) KEEP LOWER CASE. Use 'G'.charCodeAt(0) to get int32 for javascript\n\n```sh\ncurl -X PUT -i http://localhost:6299/roo/v1/perm --data '[{ \n  \"Entity\" : { \"Val\" : \"dioptre\", \"Rune\" : 117},\n  \"Context\" : { \"Val\" : \"/folder1\", \"Rune\" : 102},  \n  \"Right\" : [4],\n  \"Delete\" : false\n},{ \n  \"Entity\" : { \"Val\" : \"marketing\", \"Rune\" : 103},\n  \"Context\" : { \"Val\" : \"/folder1/folder2\", \"Rune\" : 102},\n  \"Action\" : { \"Val\" : \"push_pr\", \"Rune\" : 114},\n  \"Delete\" : false\n},{ \n  \"Entity\" : { \"Val\" : \"admins\", \"Rune\" : 103},\n  \"Context\" : { \"Val\" : \"/folder1/folder2\", \"Rune\" : 102},\n  \"Right\" : [4],\n  \"Delete\" : false\n}]'\n```\n\n### Permission Request\n\n```sh\ncurl -X POST -i http://localhost:6299/roo/v1/perm --data '{ \n  \"User\" : { \"Val\" : \"dioptreX\", \"Rune\" : 117},\n  \"Entities\" : [ { \"Val\" : \"admins\", \"Rune\" : 103}, { \"Val\" : \"marketing\", \"Rune\" : 103}],\n  \"Resource\" : { \"Val\" : \"/folder1/folder2/wb1\", \"Rune\" : 102},  \n  \"Right\" : [4]\n}\n'\n```\nAnother using Action:\n```sh\ncurl -X POST -i http://localhost:6299/roo/v1/perm --data '{ \n  \"User\" : { \"Val\" : \"dioptreX\", \"Rune\" : 117},\n  \"Entities\" : [ { \"Val\" : \"marketing\", \"Rune\" : 103}],\n  \"Resource\" : { \"Val\" : \"/folder1/folder2/wb1\", \"Rune\" : 102},\n  \"Action\" : { \"Val\" : \"push_pr\", \"Rune\": 114 }\n}'\n```\n\n## Help!\n\n### FAQ\n\n#### It hangs\n* You've reached the maximum requests to LetsEncrypt probably. You can check this by running `curl -X GET http://localhost:6299/roo/v1/kvs/` and finding `com.roo.cache:your.domain.com`. If it exists it's not this.\n* Or your stack_service name isn't correct (the DestinationHost label in your docker-compose file).\n\n#### I don't see my site!\n* You may have tried to go to the site before the service updated the docker routing table (it updates every 60 seconds). If you went to your site before it updates, roo thinks that your domain is a dodgy request and puts similar requests in the bin for 4 minutes.\n\n#### Something might be up!\n\n* Get a status of your containers (you first need to get ansible, and add your docker nodes to the docker-hosts group [you may need to look into ssh-agent too]):\n\n```\nansible docker-hosts -a \"docker stats --no-stream\"\n```\n\n* Or go deeper:\n```\nansible docker -a \"bash -c 'ps waux'\" | grep -E \"(rood)\"\n```\n\nThis will get a realtime snapshot on all your machines in your swarm.\n\n#### Get some profiling info\nNOTE: This might be removed in a future release, but it's super useful now\n\nInstall golang on a computer in your network and get profiler insights (see more https://golang.org/pkg/runtime/pprof/):\n\nOn swarm run ```go tool pprof http://roo_roo_host_from_internal_forenet_network:6299/debug/pprof/heap``` then type ```svg``` (or output to something you may like better).\n\nOn my local development machine I do:\n```\ngo tool pprof http://localhost:6299/debug/pprof/heap?debug=1\n```\nthen type:\n```\n(pprof) svg\n```\n\n![Example of a roo heap profile](misc/profiler_example.png)\n\n_Or for intermittent results_\n\nRun from source directory (./roo):\n```\nmkdir pprof\ncd pprof\ncurl http://localhost:6299/debug/pprof/heap \u003e heap.0.pprof\nsleep 30\ncurl http://localhost:6299/debug/pprof/heap \u003e heap.1.pprof\nsleep 30\ncurl http://localhost:6299/debug/pprof/heap \u003e heap.2.pprof\nsleep 30\ncurl http://localhost:6299/debug/pprof/heap \u003e heap.3.pprof\n```\nThen:\n```\ngo tool pprof pprof/heap.3.pprof\n(pprof) top20\n(pprof) list NewWriterSize\n```\n_Or for manual results_ \n\nGo to http://roo_roo_host_from_internal_forenet_network:6299/debug/pprof/\n\n#### Get detailed memory info using Valgrind\n\nThe docker image contains ```apt install valgrind```\n\nRun:\n\n```\n#valgrind --tool=memcheck --vgdb=yes --leak-check=yes --track-origins=yes --progress-interval=600 /app/roo/rood /app/roo/roo/config.json\n```\nThen run gdb (you may need to ```apt install gdb``` on swarm node first):\n```\n#gdb /app/roo/rood\n(gdb) target remote | vgdb\n(gdb) set logging on\n(gdb) set logging redirect on\n(gdb) set logging overwrite on\n(gdb) set logging debugredirect on\n(gdb) show logging\n(gdb) monitor leak_check full reachable any\n```\nOr alternatively pipe it to a gdb.txt logfile: \n```\ngdb -c /app/roo/rood -ex \"target remote | vgdb\" -ex \"set logging on\" -ex \"set logging redirect on\" -ex \"set logging debugredirect on\" -ex \"set logging overwrite on\" -ex \"monitor leak_check full reachable any\" -ex detach -ex quit 0 2\u003e\u00261 \u003e/dev/null\n```\n\n### Inspecting the roo containers\n* Inspect the logs\n```\ndocker service logs roo_roo -f\n```\n* Inspect the containers\n```\ndocker run -it --net=forenet alpine ash\nnslookup tasks.roo_roo.\ncurl -X GET http://\u003cresult_of_nslookup\u003e:6299/roo/v1/kvs\n```\n\n## Andrew's DevOps Setup (Yuck! But we have to do it)\n* I use [floating IPs](https://github.com/sfproductlabs/floater) that transition from swarm worker to swarm worker upon failure. **(Highly Available)**\n* with round robin DNS (setup a few workers and share the IPs) **(Load Balanced, a bit dodgy but works)**\n* You need to make the swarm redundant with more than one node, the mesh network load balances internally. Make it more than 2 nodes so that the raft cluster doesn't fight over leadership. Odd numbers are great. **(HA \u0026 LB)**\n* It may not cost as much as an AWS ELB, but it probably won't saturate either. Yes, I've run into issues where you need to \"warm up\" the Amazon elastic load balancer before. I wouldn't be surprised if this handled as much traffic without the cost.\n* No need to say this is $$$$ cheap. I'm saving 10x as much as I would be if I used Amazon AWS using this setup. It's nice to give my startups the same tech my enterprise clients get, but they can actually afford. I don't want to share which cloud provider I used as it took 30 days to request 1 extra machine. But it was cheap. Let us all know if you find something better! You can get these benefits too if you look!\n* Add a loopback in macOS ```ifconfig lo0 alias 127.0.0.2```\n\n## TODO\n* [ ] Add jwt token inspection (optional) as replacement for client ssl auth\n* [ ] Add support for Elastic's APM Monitoring Service https://www.elastic.co/guide/en/apm/get-started/current/quick-start-overview.html\n* [x] ~~Add an option to whitelist hostnames only in the store (this will prevent dodgy requests)~~\n* [x] ~~Add a synchronized scheduler so that only one docker manager runs the auto-update script (it currently depends on 1 manager node notifying the slaves indirectly via the kv store)~~\n* [x] ~~Memory api checker needs to be cached in hourly, replace kvcache, docker update, add node to hosts during join so if it fails it can be deleted, cache host whitelist~~\n* [x] ~~Autoscaling raft~~\n* [ ] Could add rejoin once kicked out of raft https://github.com/lni/dragonboat/blob/master/config/config.go#L329\n* [ ] Autoscale Docker\n* [ ] Autoscale Physical Infratructure\n* [x] ~~Move flaoting IPs (Load balance, service down)~~ https://github.com/sfproductlabs/floater thanks @costela\n* [ ] SSL in API\n* [ ] HTTP for Proxying Origin (Only SSL Supported atm)\n* [ ] Add end to end encryption of kv-store and distributed raft api and api:6299\n* [ ] Investigate the possibilty of a race condition between the in memory certificate/proxy cache right when letsencrypt should be renewing (might be a 10 minute window of inoperability)? Interesting thought...\n* [ ] Use Kubernetes container management (I'd like help with this one esp.!)\n\n## Support\nRoo is in use commercially and in production. If you want support, email us at support@sfpl.io.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsfproductlabs%2Froo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsfproductlabs%2Froo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsfproductlabs%2Froo/lists"}