{"id":16945365,"url":"https://github.com/felipecruz91/spinner","last_synced_at":"2025-07-16T05:34:27.972Z","repository":{"id":115785346,"uuid":"325014223","full_name":"felipecruz91/spinner","owner":"felipecruz91","description":"Serverless functions built with OpenFaaS to spin new servers on Hetzner Cloud and shut them down automatically when they are unutilized.","archived":false,"fork":false,"pushed_at":"2020-12-31T14:34:30.000Z","size":150,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-18T11:53:38.285Z","etag":null,"topics":["faasd","hetzner","hetzner-cloud","openfaas","serverless"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felipecruz91.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-28T13:01:33.000Z","updated_at":"2024-09-11T20:19:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"61ffc8bf-3237-4c92-8fa8-3a9c4faa1868","html_url":"https://github.com/felipecruz91/spinner","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecruz91%2Fspinner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecruz91%2Fspinner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecruz91%2Fspinner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecruz91%2Fspinner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felipecruz91","download_url":"https://codeload.github.com/felipecruz91/spinner/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235665658,"owners_count":19026236,"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":["faasd","hetzner","hetzner-cloud","openfaas","serverless"],"created_at":"2024-10-13T21:22:11.918Z","updated_at":"2025-01-26T05:12:24.176Z","avatar_url":"https://github.com/felipecruz91.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spinner ⚡🔄\r\n\r\n![ci](https://github.com/felipecruz91/spinner/workflows/ci/badge.svg)\r\n\r\n## Introduction\r\n\r\nServerless functions built with [OpenFaaS](https://www.openfaas.com/) to spin new servers on Hetzner Cloud and shut them down automatically when they are unutilized.\r\n\r\n## Use-cases\r\n\r\n- Scaling nodes horizontally for video-encoding based on incoming HTTP requests.\r\n\r\n## Benefits\r\n\r\n- Saving costs for large and expensive servers in Hetzner Cloud provider.\r\n\r\n## Prerequisites\r\n\r\n- Docker\r\n- [faas-cli](https://github.com/openfaas/faas-cli)\r\n- Terraform\r\n\r\n## Provision infrastructure\r\n\r\nAs of today, the cheapest server type on Hetzner Cloud is `cx11` (1vCPU, 2GB RAM for 3EUR/month). Learn more about the wide range of server types [here](https://www.hetzner.com/cloud).\r\n\r\nLet's provision a `cx11` server with `faasd` installed. We'll be using [cloud-init](https://cloudinit.readthedocs.io/en/latest/) to initialize the server with `faasd`, as per the [cloud-config.tpl](cloud-config.tpl) file.\r\n\r\n## Overview\r\n\r\nTo make it easier to provide all prerequisites like the OpenFaaS and Terraform command line utilities, we provide a container image and use it for bootstrapping now.\r\n\r\n```cli\r\ndocker run --rm -it \\\r\n  -e TF_VAR_hcloud_token=\u003cHCLOUD_TOKEN\u003e \\\r\n  -v ~/.ssh:/root/.ssh \\\r\n  felipecruz/spinner-infra-boostrap\r\n```\r\n\r\n- The `-e TF_VAR_hcloud_token=\u003cHCLOUD_TOKEN\u003e` env. var is required to authenticate to Hetzner Cloud and provision the infrastructure.\r\n- The `-v ~/.ssh:/root/.ssh` parameter is required to configure the Hetzner server with your SSH key so that you can SSH into it if needed.\r\n\r\nOr you could build and run it yourself:\r\n\r\n```cli\r\n# Clone the repository\r\ngit clone https://github.com/felipecruz91/spinner.git\r\ncd spinner\r\n\r\n# Build the bootstrap container\r\ndocker build -t spinner-infra-boostrap .\r\n\r\n# Exec into the bootstrap container\r\ndocker run --rm -it \\\r\n  -e TF_VAR_hcloud_token=\u003cHCLOUD_TOKEN\u003e \\\r\n  -v ~/.ssh:/root/.ssh \\\r\n  spinner-infra-boostrap\r\n```\r\n\r\n## Bootstrap the infrastructure\r\n\r\n```cli\r\n# Initialize Terraform\r\n/work # terraform init\r\n# Create the infrastructure in Hetzner Cloud\r\n/work # terraform apply -auto-approve\r\n```\r\n\r\nIf everything went well, you should see the following output:\r\n\r\n```\r\ngateway_url = http://\u003cfaasd-node-ip\u003e:8080\r\nlogin_cmd = faas-cli login -g http://\u003cfaasd-node-ip\u003e:8080 -p \u003crandom-password\u003e\r\npassword = \u003crandom-password\u003e\r\n```\r\n\r\n![faasd-node](docs/images/faasd-node.PNG)\r\n\r\nThen, access the OpenFaaS UI at http://$FAASD_NODE_IP:8080/ using the username `admin` and the random password generated previously.\r\n\r\n![openfaas-ui](docs/images/openfaas-ui.PNG)\r\n\r\nAs you can see in the picture above, there are two functions already deployed:\r\n\r\n- The [spinner](spinner) function serves an endpoint to create a new server to process HTTP requests. It will serve the request by creating a new server of type `cx21` with image `Ubuntu 20.04` located on `nbg1` (Nuremberg) on Hetzner Cloud and will perform a `301 Redirect` to the caller. Replace the `X-Api-Key` value with your own.\r\n\r\n```cli\r\ncurl -v \\\r\n --header \"X-Api-Key: \u003cHCLOUD_TOKEN\u003e\" \\\r\n http://$FAASD_NODE_IP:8080/function/spinner?server_type=cx21\u0026image_name=ubuntu-20.04\u0026location=nbg1\r\n```\r\n\r\n- The [spinner-controller](spinner-controller) function is triggered based on the cron expression defined in [spinner-controller.yml](spinner-controller.yml#L12) and is responsible for deleting any running servers that are not doing any work based on the [provided criteria](spinner-controller.yml#L18-L20).\r\n\r\nFor instance, if we want to delete any servers whose CPU load is below under 50% in the last 5 minutes, set the following values:\r\n\r\n```yaml\r\nmetric_name: \"cpu\"\r\nmetric_threshold: \"50\"\r\nlast_minutes: 5\r\n```\r\n\r\nand deploy the spinner-controller function again:\r\n\r\n```cli\r\nfaas-cli login -g http://\u003cfaasd-node-ip\u003e:8080 -p \u003cpassword\u003e\r\nfaas-cli deploy -g http://\u003cfaasd-node-ip\u003e:8080 -f spinner-controller.yml\r\n```\r\n\r\nOnce deployed, it will be automatically called based on the cron schedule.\r\n\r\n## Clean up\r\n\r\n```cli\r\n# Destroy the infrastructure in Hetzner Cloud\r\n/work # terraform destroy -auto-approve\r\nexit\r\n```\r\n\r\n## Troubleshooting\r\n\r\nThe server should have initialized with the cloud-init configuration right after it has booted. If needed, you could SSH into the server and check the status of the `faasd` service. It should say `active (running)`.\r\n\r\n```cli\r\nssh root@$FAASD_NODE_IP 'systemctl status faasd'\r\n\r\nsystemctl status faasd\r\n● faasd.service - faasd\r\n     Loaded: loaded (/lib/systemd/system/faasd.service; enabled; vendor preset: enabled)\r\n     Active: active (running) since Mon 2020-12-28 15:14:15 CET; 12min ago\r\n...\r\n(ommited lines)\r\n...\r\n```\r\n\r\nThe cloud-init output log file (/var/log/cloud-init-output.log) captures console output so it is easy to debug your scripts following a launch if the instance does not behave the way you intended.\r\n\r\n```\r\nssh root@\u003cfaasd-node-ip\u003e\r\ncat /var/log/cloud-init-output.log\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipecruz91%2Fspinner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelipecruz91%2Fspinner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipecruz91%2Fspinner/lists"}