K3Sに自作アプリをデプロイしてみる

先日作成したOrangePiのK3S環境、~~通称おっぱいK3S~~にアプリをデプロイしてみたいと思います。

こんなコードを書いてみました。

```.go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"
)

type Output struct {
	Time time.Time `json:"time"`
}

func handler(w http.ResponseWriter, r *http.Request) {
	rtn := Output{time.Now()}
	defer func() {
		outjson, e := json.Marshal(rtn)
		if e != nil {
			panic(e)
		}
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintf(w, string(outjson))
	}()
}

func main() {
	http.HandleFunc("/", handler)
	server := &http.Server{Addr: ":8080"}
	if err := server.ListenAndServe(); err != nil {
		log.Println(err)
	}
}
```

実行してcurlを打つと時間をJSONで返す単純なものです。
なんかAPIぽくしてみました。

```
$ curl http://localhost:8080
{"time":"2019-03-02T00:35:28.624239357+09:00"}
```

以下のようなDockerfileを書いてラズパイで multi stage build してみました。

```:Dockerfile
#Step1
FROM golang AS build-env
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build json_time.go

#Step2
From alpine
WORKDIR /app
COPY --from=build-env /src/json_time /app/
EXPOSE 8080
CMD /app/json_time
```

Imageを作成します。

```
pi@raspberrypi:myapp $ docker build -t sat0ken/mytestapp:latest .
Sending build context to Docker daemon  3.584kB
Step 1/9 : FROM golang AS build-env
 ---> d49e6b20f5ac
Step 2/9 : WORKDIR /src
 ---> Running in 59733800bce0
Removing intermediate container 59733800bce0
 ---> de9bb4c584ad
Step 3/9 : COPY . .
 ---> 6a27290b6c94
Step 4/9 : RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build json_time.go
 ---> Running in cbefd066087e
Removing intermediate container cbefd066087e
 ---> 58961d1d9ade
Step 5/9 : From alpine
 ---> c29735a66c89
Step 6/9 : WORKDIR /app
 ---> Running in 1d15d450d14b
Removing intermediate container 1d15d450d14b
 ---> 4024882ab15e
Step 7/9 : COPY --from=build-env /src/json_time /app/
 ---> f7deb81133c1
Step 8/9 : EXPOSE 8080
 ---> Running in 9c5d9d1ebca5
Removing intermediate container 9c5d9d1ebca5
 ---> 6c6165c57952
Step 9/9 : CMD /app/json_time
 ---> Running in a3a0b4773b11
Removing intermediate container a3a0b4773b11
 ---> d0e668da1288
Successfully built d0e668da1288
Successfully tagged sat0ken/mytestapp:latest
pi@raspberrypi:myapp $
```

buildが成功したらdockerhubにpushしてみます。

```
pi@raspberrypi:myapp $ docker push sat0ken/mytestapp
```

初めてdockerhubにpushしてみたのでちょっと感動です :heart_eyes:

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146663/40777b4a-5761-e517-6ec0-d78806ceb722.png)

できたのをK3Sにデプロイしてみます。
以下のようなyamlを書いてみてapplyします。

```
root@orangepizero:~# cat mypod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: myapp
      image: sat0ken/mytestapp
      ports:
        - containerPort: 8080
root@orangepizero:~# k3s kubectl apply -f mypod.yml 
pod/myapp created
root@orangepizero:~# k3s kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
myapp   1/1     Running   0          36s
root@orangepizero:~#
```

作成されたPodの情報を確認します。

```
root@orangepizero:~# k3s kubectl describe pods myapp
Name:               myapp
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               orangepione/192.168.0.201
Start Time:         Sat, 02 Mar 2019 18:34:48 +0000
Labels:             <none>
Annotations:        kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"containers":[{"image":"sat0ken...
Status:             Running
IP:                 10.42.1.7
Containers:
  myapp:
    Container ID:   containerd://70ab0f7b3628691ae70a455094d85f091960a368517bf9468ed6815f5b4f2d8b
    Image:          sat0ken/mytestapp
    Image ID:       docker.io/sat0ken/mytestapp@sha256:3cef9e387ebc0b6d7a6a3e50f2d24e7f72d0a7a7e26c27623ee0af789b263a66
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 02 Mar 2019 18:35:11 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-cpc9k (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-cpc9k:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-cpc9k
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                  Message
  ----    ------     ----  ----                  -------
  Normal  Scheduled  77s   default-scheduler     Successfully assigned default/myapp to orangepione
  Normal  Pulling    75s   kubelet, orangepione  pulling image "sat0ken/mytestapp"
  Normal  Pulled     56s   kubelet, orangepione  Successfully pulled image "sat0ken/mytestapp"
  Normal  Created    54s   kubelet, orangepione  Created container
  Normal  Started    54s   kubelet, orangepione  Started container
root@orangepizero:~#
```

orangepioneのほうに作成されたのでそっちでcurlを投げてみます。

```
root@orangepione:~# curl http://10.42.1.7:8080
{"time":"2019-03-02T18:39:03.165678763Z"}root@orangepione:~# 
root@orangepione:~# curl http://10.42.1.7:8080
{"time":"2019-03-02T18:39:07.161079872Z"}root@orangepione:~# 
root@orangepione:~# 
```

おー返ってきました〜
というわけで自分で作ってみた簡単なアプリをdockerhubにpushして、そいつをk3sで動かしてみました。