├── prep.sh └── README.md /prep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | main() { 4 | read -r -p "Is this a Master or Slave node? (slave) " node_choice Update: I previously recommended downloading Raspbian Jessie instead of Stretch. At time of writing (3 Jan 2018) Stretch is now fully compatible. 47 | 48 | https://www.raspberrypi.org/downloads/raspbian/ 49 | 50 | #### Change hostname 51 | 52 | Use the `raspi-config` utility to change the hostname to k8s-master-1 or similar and then reboot. 53 | 54 | #### Set a static IP address 55 | 56 | It's not fun when your cluste breaks because the IP of your master changed. Let's fix that problem ahead of time: 57 | 58 | ``` 59 | cat >> /etc/dhcpcd.conf 60 | ``` 61 | 62 | Paste this block: 63 | 64 | ``` 65 | profile static_eth0 66 | static ip_address=192.168.0.100/24 67 | static routers=192.168.0.1 68 | static domain_name_servers=8.8.8.8 69 | ``` 70 | 71 | Hit Control + D. 72 | 73 | Change 100 for 101, 102, 103 for each node in your cluster as you see fit. 74 | 75 | You may also need to make a reservation on your router's DHCP table so these addresses don't get given out to other devices on your network. 76 | 77 | #### Install Docker 78 | 79 | This installs the latest version of Docker. Using the script above, you can set a specific version of Docker. 80 | 81 | ``` 82 | $ curl -sSL get.docker.com | sh && \ 83 | sudo usermod pi -aG docker 84 | ``` 85 | 86 | #### Disable swap 87 | 88 | For Kubernetes 1.7 and newer you will get an error if swap space is enabled. 89 | 90 | Turn off swap: 91 | 92 | ``` 93 | $ sudo dphys-swapfile swapoff && \ 94 | sudo dphys-swapfile uninstall && \ 95 | sudo update-rc.d dphys-swapfile remove 96 | ``` 97 | 98 | This should now show no entries: 99 | 100 | ``` 101 | $ sudo swapon --summary 102 | ``` 103 | 104 | #### Edit `/boot/cmdline.txt` 105 | 106 | Add this text at the end of the line, but don't create any new lines: 107 | 108 | ``` 109 | cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory 110 | ``` 111 | 112 | Now reboot - do not skip this step. 113 | 114 | #### Add repo lists & install kubeadm 115 | 116 | ``` 117 | $ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - && \ 118 | echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list && \ 119 | sudo apt-get update -q && \ 120 | sudo apt-get install -qy kubeadm=1.10.2-00 kubectl=1.10.2-00 kubelet=1.10.2-00 121 | ``` 122 | > To install a later version, remove the version flag at the end (e.g. `sudo apt-get install -qy kubeadm`) 123 | > I realise this says 'xenial' in the apt listing, don't worry. It still works. 124 | 125 | 126 | #### You now have two new commands installed: 127 | * kubeadm - used to create new clusters or join an existing one 128 | * kubectl - the CLI administration tool for Kubernetes 129 | 130 | #### Modify 10-kubeadm.conf on the master node only 131 | ``` 132 | $ sudo sed -i '/KUBELET_NETWORK_ARGS=/d' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 133 | ``` 134 | 135 | #### Initialize your master node: 136 | 137 | ``` 138 | $ sudo kubeadm init --token-ttl=0 --pod-network-cidr=10.244.0.0/16 139 | ``` 140 | 141 | We pass in `--token-ttl=0` so that the token never expires - do not use this setting in production. The UX for `kubeadm` means it's currently very hard to get a join token later on after the initial token has expired. 142 | 143 | > Optionally also pass `--apiserver-advertise-address=192.168.0.27` with the IP of the Pi. 144 | 145 | Note: This step will take a long time, even up to 15 minutes. 146 | 147 | After the `init` is complete run the snippet given to you on the command-line: 148 | 149 | ``` 150 | mkdir -p $HOME/.kube 151 | sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 152 | sudo chown $(id -u):$(id -g) $HOME/.kube/config 153 | ``` 154 | 155 | This step takes the key generated for cluster administration and makes it available in a default location for use with `kubectl`. 156 | 157 | #### Now save your join-token 158 | 159 | Your join token is valid for 24 hours, so save it into a text file. Here's an example of mine: 160 | 161 | ``` 162 | $ kubeadm join --token 9e700f.7dc97f5e3a45c9e5 192.168.0.27:6443 --discovery-token-ca-cert-hash sha256:95cbb9ee5536aa61ec0239d6edd8598af68758308d0a0425848ae1af28859bea 163 | ``` 164 | 165 | #### Check everything worked: 166 | 167 | ``` 168 | $ kubectl get pods --namespace=kube-system 169 | NAME READY STATUS RESTARTS AGE 170 | etcd-of-2 1/1 Running 0 12m 171 | kube-apiserver-of-2 1/1 Running 2 12m 172 | kube-controller-manager-of-2 1/1 Running 1 11m 173 | kube-dns-66ffd5c588-d8292 3/3 Running 0 11m 174 | kube-proxy-xcj5h 1/1 Running 0 11m 175 | kube-scheduler-of-2 1/1 Running 0 11m 176 | weave-net-zz9rz 2/2 Running 0 5m 177 | ``` 178 | 179 | You should see the "READY" count showing as 1/1 for all services as above. DNS uses three pods, so you'll see 3/3 for that. 180 | 181 | #### Setup networking 182 | 183 | Install Flannel network driver 184 | 185 | ``` 186 | $ curl -sSL https://rawgit.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml | sed "s/amd64/arm/g" | kubectl create -f - 187 | ``` 188 | 189 | ## Join other nodes 190 | 191 | On the other RPis, repeat everything apart from `kubeadm init`. 192 | 193 | #### Change hostname 194 | 195 | Use the `raspi-config` utility to change the hostname to k8s-worker-1 or similar and then reboot. 196 | 197 | #### Join the cluster 198 | 199 | Copy and paste the command provided after Kubeadm init completes. It should look something like this: 200 | 201 | ``` 202 | $ sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash sha256:1c06faa186e7f85... 203 | ``` 204 | 205 | You can now run this on the master: 206 | 207 | ``` 208 | $ kubectl get nodes 209 | NAME STATUS AGE VERSION 210 | k8s-1 Ready 5m v1.7.4 211 | k8s-2 Ready 10m v1.7.4 212 | ``` 213 | 214 | ## Deploy a container 215 | 216 | This container will expose a HTTP port and convert Markdown to HTML. Just post a body to it via `curl` - follow the instructions below. 217 | 218 | *function.yml* 219 | 220 | ``` 221 | apiVersion: v1 222 | kind: Service 223 | metadata: 224 | name: markdownrender 225 | labels: 226 | app: markdownrender 227 | spec: 228 | type: NodePort 229 | ports: 230 | - port: 8080 231 | protocol: TCP 232 | targetPort: 8080 233 | nodePort: 31118 234 | selector: 235 | app: markdownrender 236 | --- 237 | apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1 238 | kind: Deployment 239 | metadata: 240 | name: markdownrender 241 | spec: 242 | replicas: 1 243 | template: 244 | metadata: 245 | labels: 246 | app: markdownrender 247 | spec: 248 | containers: 249 | - name: markdownrender 250 | image: functions/markdownrender:latest-armhf 251 | imagePullPolicy: Always 252 | ports: 253 | - containerPort: 8080 254 | protocol: TCP 255 | ``` 256 | 257 | Deploy and test: 258 | 259 | ``` 260 | $ kubectl create -f function.yml 261 | ``` 262 | 263 | Once the Docker image has been pulled from the hub and the Pod is running you can access it via `curl`: 264 | 265 | ``` 266 | $ curl -4 http://127.0.0.1:31118 -d "# test" 267 |

test

268 | ``` 269 | 270 | If you want to call the service from a remote machine such as your laptop then use the IP address of your Kubernetes master node and try the same again. 271 | 272 | ## Start up the dashboard 273 | 274 | The dashboard can be useful for visualising the state and health of your system but it does require the equivalent of "root" in the cluster. If you want to proceed you should first run in a [ClusterRole from the docs](https://github.com/kubernetes/dashboard/wiki/Access-control#admin-privileges). 275 | 276 | ``` 277 | echo -n 'apiVersion: rbac.authorization.k8s.io/v1beta1 278 | kind: ClusterRoleBinding 279 | metadata: 280 | name: kubernetes-dashboard 281 | labels: 282 | k8s-app: kubernetes-dashboard 283 | roleRef: 284 | apiGroup: rbac.authorization.k8s.io 285 | kind: ClusterRole 286 | name: cluster-admin 287 | subjects: 288 | - kind: ServiceAccount 289 | name: kubernetes-dashboard 290 | namespace: kube-system' | kubectl apply -f - 291 | ``` 292 | 293 | This is the development/alternative dashboard which has TLS disabled and is easier to use. 294 | 295 | ``` 296 | $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard-arm.yaml 297 | ``` 298 | 299 | You can then find the IP and port via `kubectl get svc -n kube-system`. To access this from your laptop you will need to use `kubectl proxy` and navigate to `http://localhost:8001/` on the master, or tunnel to this address with `ssh`. 300 | 301 | ## Remove the test deployment 302 | 303 | Now on the Kubernetes master remove the test deployment: 304 | 305 | ``` 306 | $ kubectl delete -f function.yml 307 | ``` 308 | --------------------------------------------------------------------------------