raspberry pi に k3s を入れてLチカアプリをデプロイしてみる

K3Sで電子工作とアプリをデプロイしていきたいと思います。
電子工作の初めはやっぱLチカですよねとラズパイのセットアップから記していきます。

Orangepiはやっぱ情報が少なく...

最新のraspibianを持ってきてSDカードに書き込みます。

```
$ wget https://downloads.raspberrypi.org/raspbian_lite_latest
$ unzip raspbian_lite_latest
$ dd bs=4M if=2018-11-13-raspbian-stretch-lite.img of=/dev/sdd
```

書いたら起動させます。
DHCPでラズパイに割り振られたIPにSSH接続をして、IPアドレスを固定します。

```:/etc/dhcpcd.conf
interface eth0
static ip_address=10.0.0.15
static routers=10.0.0.1
static domain_name_servers=8.8.8.
```

IPアドレスを固定してインターネットに接続できたら、WiringPiをインストールします。

http://wiringpi.com/

```
$ wget https://lion.drogon.net/wiringpi-2.50-1.deb
$ sudo dpkg -i wiringpi-2.50-1.deb
```

WiringPiをインストールしたら、gpioコマンドでLチカを試してみます。

```
pi@raspberrypi:~ $ gpio readall
pi@raspberrypi:~ $ gpio -g mode 17 out
pi@raspberrypi:~ $ gpio -g write 17 1
pi@raspberrypi:~ $ gpio -g write 17 0
```

gpioコマンドでLチカができたら、Lチカのプログラムを書いてみます。

```cpp:blink.c
#include <stdio.h>
#include <wiringPi.h>


#define LED 0

int main (void)
{
  wiringPiSetup () ;
  pinMode (LED, OUTPUT) ;

  for (;;)
  {
    digitalWrite (LED, HIGH) ;  // On
    delay (1000) ;       // mS
    digitalWrite (LED, LOW) ;   // Off
    delay (1000) ;
  }
  return 0 ;
}
```

コンパイルして実行してみます。

```
pi@raspberrypi:~ $ gcc blink.c -o blink -I/usr/include -L/usr/lib -lwiringPi
pi@raspberrypi:~ $ ./blink
```

作成したバイナリをコンテナから実行させることを試してみるため、ラズパイにdockerを入れます。

```yml:install_docker.yml
---

- hosts: raspi
  connection: ssh
  gather_facts: False
  become: true

  tasks:
  - name: install packages
    apt:
      name: "{{ packages }}"
      state: present
      update_cache: yes
    vars:
      packages:
        - apt-transport-https
        - ca-certificates
        - curl
        - software-properties-common

  - name: Add Docker’s official GPG key
    apt_key:
      url: https://download.docker.com/linux/debian/gpg
      state: present

  - name: add repo
    apt_repository:
      repo: deb [arch=armhf] https://download.docker.com/linux/debian stretch stable

  - name: install docker
    apt:
      name: "{{ packages }}"
      state: present
      update_cache: yes
    vars:
      packages:
        - docker-ce
        - docker-ce-cli
        - containerd.io
```

↑なPlaybookを書いてAnsibleで入れました。

```
$ ansible-playbook -i hosts install_docker.yml

PLAY [raspi] *******************************************************************************

TASK [install packages] ********************************************************************
ok: [10.0.0.15]

TASK [Add Docker’s official GPG key] *******************************************************
ok: [10.0.0.15]

TASK [add repo] ****************************************************************************
ok: [10.0.0.15]

TASK [install docker] **********************************************************************
changed: [10.0.0.15]

PLAY RECAP *********************************************************************************
10.0.0.15                  : ok=4    changed=1    unreachable=0    failed=0
```

dockerをインストールしたら、以下のようなDockerfileを書いてイメージをビルドします。
イメージにWiringPiのライブラリを入れないとLチカバイナリが動きません。

```:Dockerfile
FROM resin/rpi-raspbian
COPY blink /
COPY libwiringPi.so /lib
RUN ldconfig
ENTRYPOINT ["/blink"]
```

ビルドをして、

```
pi@raspberrypi:~/build $ docker build -t led:1 .
Sending build context to Docker daemon  82.94kB
Step 1/5 : FROM resin/rpi-raspbian
# Executing 1 build trigger
 ---> Running in 7cb905cb4d7d
$
 __      ___   ___ _  _ ___ _  _  ___ 
 \ \    / /_\ | _ \ \| |_ _| \| |/ __|
  \ \/\/ / _ \|   / .` || || .` | (_ |
   \_/\_/_/ \_\_|_\_|\_|___|_|\_|\___|
======================================
resin base images have been deprecated
in favour of the new balenalib images,
read more about it in our docs:
https://www.balena.io/docs/reference/base-images/base-images/
======================================
Removing intermediate container 7cb905cb4d7d
 ---> f6d968d89d9a
Step 2/5 : COPY blink /
 ---> e25eb6335289
Step 3/5 : COPY libwiringPi.so /lib
 ---> 893268fc2c33
Step 4/5 : RUN ldconfig
 ---> Running in f2b1af6a3b0a
Removing intermediate container f2b1af6a3b0a
 ---> 11c353cef56f
Step 5/5 : ENTRYPOINT ["/blink"]
 ---> Running in f8c46e818eb3
Removing intermediate container f8c46e818eb3
 ---> 1a09eb917eef
Successfully built 1a09eb917eef
Successfully tagged led:1
```

実行するとLチカ出来ました :heart_eyes:

```
pi@raspberrypi:~/build $ docker run --privileged -d led:1
```

ではこいつをk3sでデプロイしてみましょう。
まずdockerhubにpushします。

```
pi@raspberrypi:~/build $ docker tag 1a09eb917eef sat0ken/blinkapp:latest
pi@raspberrypi:~/build $ docker push sat0ken/blinkapp
```

pushできました。

![Screenshot from 2019-03-30 18-30-30.png](https://qiita-image-store.s3.amazonaws.com/0/146663/5782238b-83bd-fa15-da1b-63f616f292d5.png)

K3Sを入れてデプロイしてみます。

```
pi@raspberrypi:~ $ wget https://github.com/rancher/k3s/releases/download/v0.3.0/k3s-armhf
pi@raspberrypi:~ $ mv k3s-armhf k3s
pi@raspberrypi:~ $ chmod +x k3s
pi@raspberrypi:~ $ sudo ./k3s server &
[1] 747
pi@raspberrypi:~ $ INFO[0000] Preparing data dir /var/lib/rancher/k3s/data/e737b8b70ac9d19bd61626eed5131ce159e2e04bb75af26df5235fafa4bed87e 
INFO[2019-03-30T09:40:30.794669865Z] Starting k3s v0.3.0 (9a1a1ec)                
INFO[2019-03-30T09:40:54.253064923Z] Running kube-apiserver --watch-cache=false --cert-dir /var/lib/rancher/k3s/server/tls/temporary-certs --allow-privileged=true --authorization-mode Node,RBAC --service-account-signing-key-file /var/lib/rancher/k3s/server/tls/service.key --service-cluster-ip-range 10.43.0.0/16 --advertise-port 6445 --advertise-address 127.0.0.1 --insecure-port 0 --secure-port 6444 --bind-address 127.0.0.1 --tls-cert-file /var/lib/rancher/k3s/server/tls/localhost.crt --tls-private-key-file /var/lib/rancher/k3s/server/tls/localhost.key --service-account-key-file /var/lib/rancher/k3s/server/tls/service.key --service-account-issuer k3s --api-audiences unknown --basic-auth-file /var/lib/rancher/k3s/server/cred/passwd --kubelet-client-certificate /var/lib/rancher/k3s/server/tls/token-node.crt --kubelet-client-key /var/lib/rancher/k3s/server/tls/token-node.key 
INFO[2019-03-30T09:41:14.850140213Z] Running kube-scheduler --kubeconfig /var/lib/rancher/k3s/server/cred/kubeconfig-system.yaml --port 10251 --address 127.0.0.1 --secure-port 0 --leader-elect=false 
INFO[2019-03-30T09:41:14.852846586Z] Running kube-controller-manager --kubeconfig /var/lib/rancher/k3s/server/cred/kubeconfig-system.yaml --service-account-private-key-file /var/lib/rancher/k3s/server/tls/service.key --allocate-node-cidrs --cluster-cidr 10.42.0.0/16 --root-ca-file /var/lib/rancher/k3s/server/tls/token-ca.crt --port 10252 --address 127.0.0.1 --secure-port 0 --leader-elect=false 
Flag --address has been deprecated, see --bind-address instead.
INFO[2019-03-30T09:41:15.884067730Z] Creating CRD listenerconfigs.k3s.cattle.io   
INFO[2019-03-30T09:41:15.941017587Z] Creating CRD addons.k3s.cattle.io            
INFO[2019-03-30T09:41:15.985705929Z] Creating CRD helmcharts.k3s.cattle.io        
INFO[2019-03-30T09:41:16.002797256Z] Waiting for CRD addons.k3s.cattle.io to become available 
INFO[2019-03-30T09:41:16.507213810Z] Done waiting for CRD addons.k3s.cattle.io to become available 
INFO[2019-03-30T09:41:16.507310115Z] Waiting for CRD helmcharts.k3s.cattle.io to become available 
INFO[2019-03-30T09:41:17.011560465Z] Done waiting for CRD helmcharts.k3s.cattle.io to become available 
INFO[2019-03-30T09:41:17.021883229Z] Listening on :6443                           
INFO[2019-03-30T09:41:28.436266003Z] Writing static file: /var/lib/rancher/k3s/server/static/charts/traefik-1.64.0.tgz 
INFO[2019-03-30T09:41:31.586828708Z] Node token is available at /var/lib/rancher/k3s/server/node-token 
INFO[2019-03-30T09:41:31.587053089Z] To join node to cluster: k3s agent -s https://10.0.0.15:6443 -t ${NODE_TOKEN} 
INFO[2019-03-30T09:41:31.588886675Z] Writing manifest: /var/lib/rancher/k3s/server/manifests/coredns.yaml 
INFO[2019-03-30T09:41:31.589825760Z] Writing manifest: /var/lib/rancher/k3s/server/manifests/traefik.yaml 
INFO[2019-03-30T09:41:34.587899023Z] Wrote kubeconfig /etc/rancher/k3s/k3s.yaml   
INFO[2019-03-30T09:41:34.587996526Z] Run: k3s kubectl                             
INFO[2019-03-30T09:41:34.588053923Z] k3s is up and running                        
INFO[2019-03-30T09:41:35.387105628Z] Logging containerd to /var/lib/rancher/k3s/agent/containerd/containerd.log 
INFO[2019-03-30T09:41:35.389304534Z] Running containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/k3s/agent/containerd 
INFO[2019-03-30T09:41:35.402832302Z] Waiting for containerd startup: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial unix /run/k3s/containerd/containerd.sock: connect: no such file or directory" 
INFO[2019-03-30T09:41:36.442551356Z] Connecting to wss://localhost:6443/v1-k3s/connect 
INFO[2019-03-30T09:41:36.442919750Z] Connecting to proxy                           url="wss://localhost:6443/v1-k3s/connect"
INFO[2019-03-30T09:41:36.555225108Z] Handling backend connection request [raspberrypi] 
WARN[2019-03-30T09:41:36.560068086Z] Disabling CPU quotas due to missing cpu.cfs_period_us 
INFO[2019-03-30T09:41:36.560269654Z] Running kubelet --healthz-bind-address 127.0.0.1 --read-only-port 0 --allow-privileged=true --cluster-domain cluster.local --kubeconfig /var/lib/rancher/k3s/agent/kubeconfig.yaml --eviction-hard imagefs.available<5%,nodefs.available<5% --eviction-minimum-reclaim imagefs.available=10%,nodefs.available=10% --fail-swap-on=false --cgroup-driver cgroupfs --root-dir /var/lib/rancher/k3s/agent/kubelet --cert-dir /var/lib/rancher/k3s/agent/kubelet/pki --seccomp-profile-root /var/lib/rancher/k3s/agent/kubelet/seccomp --cni-conf-dir /var/lib/rancher/k3s/agent/etc/cni/net.d --cni-bin-dir /var/lib/rancher/k3s/data/e737b8b70ac9d19bd61626eed5131ce159e2e04bb75af26df5235fafa4bed87e/bin --cluster-dns 10.43.0.10 --resolv-conf /etc/resolv.conf --container-runtime remote --container-runtime-endpoint unix:///run/k3s/containerd/containerd.sock --address 127.0.0.1 --anonymous-auth=false --client-ca-file /var/lib/rancher/k3s/agent/client-ca.pem --hostname-override raspberrypi --cpu-cfs-quota=false --runtime-cgroups /systemd/user.slice/user-1000.slice --kubelet-cgroups /systemd/user.slice/user-1000.slice 
Flag --allow-privileged has been deprecated, will be removed in a future version
INFO[2019-03-30T09:41:38.360287096Z] waiting for node raspberrypi: nodes "raspberrypi" not found 
INFO[2019-03-30T09:41:40.657116309Z] waiting for node raspberrypi: nodes "raspberrypi" not found 
INFO[2019-03-30T09:41:42.661866793Z] waiting for node raspberrypi: nodes "raspberrypi" not found 
INFO[2019-03-30T09:41:44.666385929Z] waiting for node raspberrypi: nodes "raspberrypi" not found 
INFO[2019-03-30T09:41:46.670340912Z] waiting for node raspberrypi: nodes "raspberrypi" not found 

pi@raspberrypi:~ $ sudo ./k3s kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
raspberrypi   Ready    <none>   82s   v1.13.5-k3s.1
pi@raspberrypi:~ $ 
```

ymlを書いてみてデプロイだー

```yml:mypod.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: myapp
      image: sat0ken/blinkapp
      securityContext:
        privileged: true
```

デプロイしてしばし待つこと数分、STATUSがRunningになったら

```
pi@raspberrypi:~ $ sudo ./k3s kubectl apply -f mypod.yml 
pod/myapp created
pi@raspberrypi:~ $ sudo ./k3s kubectl get pods
NAME    READY   STATUS              RESTARTS   AGE
myapp   0/1     ContainerCreating   0          2m45s
pi@raspberrypi:~ $ sudo ./k3s kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
myapp   1/1     Running   0          5m29s
pi@raspberrypi:~ $ 
```

光った！光ったよ〜 :v:

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146663/1a31edcf-992d-127d-9b25-f2ec9f714dc7.png)

というわけでk3sと電子工作を初めてみました。
温度計をつなげたりもできそうですね！