GolangアプリをKubernetesにDeployしてIngressで公開までしてみる【minikube＆docker hubを利用】

以前に、[DockerでサクッとGolangの環境作ってみた](https://qiita.com/takuya911/items/b13b03429204eb95289c)という記事を書いたGoのアプリをkubernetesで動かして、webブラウザで確認するところまでやってみる。

##必要なもの
minikube v1.9.0
docker 19.03.8
dockerhubのアカウント

##成果物
https://github.com/atsugitakuya/golang_kubernetes

## Docker Hubにリポジトリを作成する
[docker hub](https://hub.docker.com/)のアカウントを作成し、リポジトリを作成する。
今回は以下のものがリポジトリの情報です。（publicなので、誰でも利用可です）
・アカウント名：takuya911
・リポジトリ名：go-kubernetes-sample

<img width="1437" alt="スクリーンショット 2020-05-16 14.30.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631619/8cbe85ce-7a9c-30e5-03ba-ab45809b7199.png">



## Dockerfileをビルドし、ImageをDocker Hubに登録する
前回の記事と同じ内容だが、念のためmain,goとDockerfileを載せておく

```ruby:/Dockerfile
FROM golang:alpine
# フォルダ作成
RUN mkdir /app/
# 作成したフォルダ内にmain.goを配置
COPY . /app/
# 作業場所を/appに設定（main.goがある場所）
WORKDIR /app/
# main.goをbuild
RUN go build -o main . 
CMD ["/app/main"]
```
```ruby:/main.go
package main

import (
	"fmt"
	"net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "golang api access")
}

func main() {
	http.HandleFunc("/", index)
	http.ListenAndServe(":80", nil)
}
```

Dockerfileをビルドして、imageを作成する。
docker hubのリポジトリ名と同じ名前のimage名になるようにする。

```ruby:zsh
$docker build -t takuya911/go-kubernetes-sample:1 .
....
Successfully built 74ed57aa2c28
Successfully tagged takuya911/go-kubernetes-sample:1
```
ビルドに成功したら、次はImageをDocker Hubにpushする。
Docker HubはDocker Imageを管理するためのモノ。

```ruby:zsh
$docker push takuya911/go-kubernetes-sample:1
....
1: digest: sha256:76487a1e6dc32faf94cb845ee9894c024340885e22432090304c870ce29b1d79 size: 1992
```
今回はbuild時にtagとして1を設定しているので、Docker Hubのtagが1になっていることを確認する。
<img width="1440" alt="スクリーンショット 2020-05-16 14.36.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631619/c027f75b-843b-0243-c2dd-78634d1cea15.png">

## Kunernetesでアプリを動かす
Docker Hubに登録したImageを取得し、Kubernetesにdeployする。
まずはminikubeを起動する。

```ruby:zsh
$minikube start
....
Done! kubectl is now configured to use "minikube"
```

インフラをコードで管理するのが今時（カッコいい）ので、deployしたい内容が記載されたyamlファイルを生成する。

```ruby:zsh
$cd manifest
$kubectl create deploy go-sample --image takuya911/go-kubernetes-sample:1 -o yaml --dry-run=client > deployment.yaml
```
すると、deployment.yamlが生成されている。

```ruby:/manifest/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: go-sample
  name: go-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-sample
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: go-sample
    spec:
      containers:
      - image: takuya911/go-kubernetes-sample:1
        name: go-kubernetes-sample
        resources: {}
status: {}

```

yamlファイルをapplyする

```ruby:zsh
$kubectl apply -f deployment.yaml
deployment.apps/go-sample created
```
ちゃんと動いていることを確認する。

```ruby:zsh
$kubectl get deploy,rs,po
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/go-sample   1/1     1            1           25s

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/go-sample-66b5fb64f6   1         1         1       25s

NAME                             READY   STATUS    RESTARTS   AGE
pod/go-sample-66b5fb64f6-p6sn8   1/1     Running   0          25s
```


##Ingressを使って、Goアプリを公開する
Kubernetes上で動かすことはできたけれど、やっぱりwebブラウザからgoが動いていることを確認したい。クラスタ外からクラスタ内のアプリにアクセスするための方法としては、以下の3つがある。

 - Node Portを使う
 - 外部ロードバランサーを使う
 - Ingressを使う

Ingressがよく使われている＆yamlで管理できるので、今回はIngressを使う。
ingressでサービスを公開する際にはserviceも必要になる。以下参考記事。
https://qiita.com/Esfahan/items/f7d13d7e80848e9b6963

なのでserviceとingressを作成していく。

まず、minikubeのIngressのaddonを有効にする。

```ruby:zsh
$minikube addons enable ingress
🌟  The 'ingress' addon is enabled
```
次にserviceを作成していく。

```ruby:/manifest/service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: go-sample
  name: go-sample
spec:
  type: NodePort
  ports:
  - protocol: TCP
    port: 7000
    targetPort: 80
  selector:
    app: go-sample
status:
  loadBalancer: {}
```


```ruby:/manifest/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: go-sample
spec:
  rules:
  - host: 
    http:
      paths:
      - path: 
        backend:
          serviceName: go-sample
          servicePort: 7000
```
service.yamlとingress.yamlをdeployする。

```ruby:zsh
$kubectl apply -f .                                                                           
deployment.apps/go-sample configured
ingress.extensions/go-sample created
service/go-sample created
```
しばらく待ってからingressの情報を表示するコマンドを実行すると、ipが振られているのでそのipを確認する。

```ruby:zsh
$kubectl get ing   
NAME        CLASS    HOSTS   ADDRESS        PORTS   AGE
go-sample   <none>   *       192.168.64.3   80      4m39s
```
実際にingressで割り振られたipアドレスにアクセスすると、main.goのindexメソッドの実行結果が帰ってくる
<img width="1370" alt="スクリーンショット 2020-05-16 16.52.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631619/39573e4e-a209-a9d4-aa9b-2775aa67b3af.png">

ここまでで、GolangのアプリのImageをDocker Hubに登録し、そのImageを使ってアプリをkubernetesにデプロイ＆外部公開までが完了です。