├── .gitignore ├── Makefile ├── ansible ├── hosts.template ├── roles │ ├── k3s-server │ │ └── tasks │ │ │ └── main.yml │ ├── common │ │ └── tasks │ │ │ └── main.yml │ ├── k3s-common │ │ └── tasks │ │ │ └── main.yml │ ├── k3s-agent │ │ └── tasks │ │ │ └── main.yml │ └── k3s-config │ │ └── tasks │ │ └── main.yml ├── group_vars │ └── all └── site.yml ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /ansible/hosts 2 | /ansible/site.retry 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | ansible-playbook ./ansible/site.yml -i ./ansible/hosts 3 | -------------------------------------------------------------------------------- /ansible/hosts.template: -------------------------------------------------------------------------------- 1 | [k3s-server] 2 | kube1.example.com 3 | 4 | [k3s-agents] 5 | kube2.example.com 6 | kube3.example.com 7 | -------------------------------------------------------------------------------- /ansible/roles/k3s-server/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install k3s server service 3 | get_url: 4 | url: https://raw.githubusercontent.com/rancher/k3s/master/k3s.service 5 | dest: /etc/systemd/system/k3s-server.service 6 | mode: a+x 7 | force: yes 8 | 9 | - name: Enable and start the k3s server service 10 | service: 11 | name: k3s-server 12 | enabled: yes 13 | state: started 14 | -------------------------------------------------------------------------------- /ansible/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | # Disable All Updates 3 | # By default automatic updates are enabled, set this value to true to disable all automatic updates 4 | auto_up_disable: false 5 | 6 | #Define Core Update Level 7 | #true = Development, minor, and major updates are all enabled 8 | #false = Development, minor, and major updates are all disabled 9 | #minor = Minor updates are enabled, development, and major updates are disabled 10 | core_update_level: true 11 | 12 | ssh_user: pi 13 | ssh_identity_key: ~/.ssh/id_rsa.pub 14 | -------------------------------------------------------------------------------- /ansible/roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure US locale exists 3 | locale_gen: 4 | name: en_US.UTF-8 5 | state: present 6 | 7 | - name: Set hostname to inventory hostname 8 | hostname: name={{inventory_hostname}} 9 | 10 | - name: Update apt cache and upgrade 11 | apt: 12 | update_cache: yes 13 | upgrade: yes 14 | 15 | - name: Remove useless packages from the cache 16 | apt: 17 | autoclean: yes 18 | 19 | - name: Remove dependencies that are no longer required 20 | apt: 21 | autoremove: yes 22 | -------------------------------------------------------------------------------- /ansible/roles/k3s-common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set GPU memory split to 16 MB 3 | lineinfile: 4 | path: /boot/config.txt 5 | line: 'gpu_mem=16' 6 | create: yes 7 | 8 | - name: Add cgroup directives to boot commandline config 9 | lineinfile: 10 | path: /boot/cmdline.txt 11 | regexp: '((.)+?)(\scgroup_\w+=\w+)*$' 12 | line: '\1 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory' 13 | backrefs: yes 14 | 15 | - name: Reboot the node 16 | reboot: 17 | 18 | - name: Download k3s binary 19 | get_url: url=https://github.com/rancher/k3s/releases/download/v0.2.0/k3s-armhf dest=/usr/local/bin/k3s mode=a+x 20 | 21 | - name: Point hostname to localhost (k3s requirement) 22 | lineinfile: 23 | path: /etc/hosts 24 | line: "127.0.0.1 {{inventory_hostname}}" 25 | -------------------------------------------------------------------------------- /ansible/roles/k3s-agent/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install k3s agent service 3 | get_url: 4 | url: https://raw.githubusercontent.com/rancher/k3s/master/k3s.service 5 | dest: /etc/systemd/system/k3s-agent.service 6 | mode: a+x 7 | force: yes 8 | 9 | - name: Replace server command in k3s agent service with agent command 10 | replace: 11 | path: /etc/systemd/system/k3s-agent.service 12 | regexp: '^ExecStart=/usr/local/bin/k3s server$' 13 | replace: 'ExecStart=/usr/local/bin/k3s agent -s "{{ k3s_server_address}}" -t "{{ k3s_cluster_token }}"' 14 | 15 | - name: Reload systemd daemon to ensure latest service config 16 | systemd: 17 | daemon_reload: yes 18 | 19 | - name: Enable and start the k3s agent service 20 | service: 21 | name: k3s-agent 22 | enabled: yes 23 | state: started 24 | -------------------------------------------------------------------------------- /ansible/site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Provision k3s nodes 3 | hosts: k3s-server:k3s-agents 4 | remote_user: pi 5 | become: yes 6 | become_user: root 7 | 8 | roles: 9 | - common 10 | - { role: k3s-common, tags: common } 11 | 12 | - name: Provision k3s server node 13 | hosts: k3s-server 14 | remote_user: pi 15 | become: yes 16 | become_user: root 17 | 18 | roles: 19 | - { role: k3s-server, tags: server } 20 | 21 | - name: Get k3s server config for all nodes 22 | hosts: all 23 | remote_user: pi 24 | become: yes 25 | become_user: root 26 | 27 | roles: 28 | - { role: k3s-config, tags: config } 29 | 30 | - name: Provision k3s agent nodes 31 | hosts: k3s-agents 32 | remote_user: pi 33 | become: yes 34 | become_user: root 35 | 36 | roles: 37 | - { role: k3s-agent, tags: agent } 38 | -------------------------------------------------------------------------------- /ansible/roles/k3s-config/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Wait until node token is generated 3 | wait_for: 4 | path: /var/lib/rancher/k3s/server/node-token 5 | run_once: true 6 | 7 | - name: Get node token 8 | slurp: 9 | src: /var/lib/rancher/k3s/server/node-token 10 | register: k3s_cluster_token 11 | run_once: true 12 | 13 | - name: Clean up node token contents 14 | set_fact: 15 | k3s_cluster_token: "{{ k3s_cluster_token['content'] | b64decode | replace('\n', '')}}" 16 | run_once: yes 17 | 18 | - name: Print cluster node token 19 | debug: 20 | msg: "{{ k3s_cluster_token }}" 21 | 22 | - name: Set server address 23 | set_fact: 24 | k3s_server_address: "https://{{ inventory_hostname }}:6443" 25 | run_once: yes 26 | 27 | - name: Print server address 28 | debug: 29 | msg: "{{ k3s_server_address }}" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 David Spreekmeester 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This Ansible playbook turns your fleet of Raspberry Pi into Kubernetes cattle with k3s, the streamlined version of Kubernetes by @rancher that runs silky smooth on the ARM processor powering your Pi. 2 | 3 | # Manually prepare your Raspberries 4 | - Burn Raspian Stretch Lite on an SD card with EtcherBalena, or something alike 5 | - Create an empty `ssh` file in the root of the SD card (volume is called `boot`) 6 | 7 | # Secure your Raspberries 8 | Optional but advisable: use SSH key auth and disable password login. 9 | The default ssh credentials for a Raspberry Pi are username `pi` and password `raspberry`. 10 | - Copy your pubkey to the Pi with `ssh-copy-id pi@kube1.example.com` 11 | - In `/etc/ssh/sshd_config` on the Pi, set `PasswordAuthentication` to `no` 12 | 13 | # Configure ansible setup 14 | - Copy `ansible/hosts.template` to `ansible/hosts` for your configuration 15 | - Choose one of the Raspberries to lead / orchestrate your cluster; we'll call this the _server_ 16 | - In `ansible/hosts`, fill out the ip or hostname for the leading Raspberry under `[k3s-server]` 17 | - Fill out the ip's or hostnames for the rest of your cattle under `[k3s-agents]` 18 | 19 | I personally prefer using the Pi's hardware mac address to assign a hostname and ip address within the LAN by DHCP, but you could also set a static ip address on the Pi. 20 | 21 | # Provision the nodes 22 | When you're all set up and configured, run the Ansible playbook: 23 | ```bash 24 | $ make 25 | ``` 26 | 27 | This will: 28 | - Install the k3s binary on the 'server' Pi (the leading node) 29 | - Install a `k3s-server` service on the server and start it 30 | - Fetch the node token from the server 31 | - Install and start a `k3s-agent` service on the agents, joining the cluster 32 | - Enable autostart on boot for k3s on all nodes 33 | 34 | # See if it worked 35 | Log into your server node and run: 36 | ```bash 37 | $ sudo k3s kubectl get node -o wide 38 | ``` 39 | You should see all of your nodes broadcasting a _Ready_ status. 40 | 41 | Happy cattle herding! 42 | --------------------------------------------------------------------------------