Time4VPSにk3dでhello-appを本番デプロイするまで

# k3dとは？
[Rancher](https://rancher.com/)が公開しているk3sという軽量版Kubernetesを
dockerを使ってクラスタ構築してくれる代物です。
VPSにdocker-composeで本番運用してしまっているなんていう人には
代替手段となり得るツールかと思います。

# 全体の流れ
- [はじめに](#はじめに)
- [Time4VPSサーバーを用意](#time4vpsサーバーを用意)
- [Time4VPSにk3dをインストール](#time4vpsにk3dをインストール)
- [k3dでクラスタを構築する](#k3dでクラスタを構築する)
- [クラスタにcert-managerをインストールする](#クラスタにcert-managerをインストールする)
- [freenomで無料ドメインを取得する](#freenomで無料ドメインを取得する)
- [マニフェストファイルを書いてデプロイ](#マニフェストファイルを書いてデプロイ)

# はじめに
今回は、テストということで出来る限り無料に近い構成で
k3dを使ってクラスタを構築していきます。
サーバーは海外の最強激安VPS Time4VPSを採用し、
ドメインは無料ドメイン取得ができる
freenomで取得していきます。
dockerコンテナイメージは[こいつ](https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/master/hello-app)を使っていきます。


# Time4VPSサーバーを用意
まずは[こちら](https://www.time4vps.com/)からvpsサーバーを用意しましょう。
ちなみに当記事で利用するOSの種類は`Ubuntu18.04`です。
vpsの契約が完了したら下記の記事あたりを参考にガリガリとUbuntuの初期設定をしていきます。
[Ubuntu 最低限抑えておきたい初期設定](https://qiita.com/kotarella1110/items/f638822d64a43824dfa4)



# Time4VPSにk3dをインストール
k3dにはもちろんdockerが必要なので、まずはdockerをインストールします。
Ubuntuにdockerをインストールする場合はこちらの記事を参考にするのがオススメです。
[Ubuntu 18.04にDockerをインストールする(+docker-composeも)](https://qiita.com/iganari/items/fe4889943f22fd63692a)

dockerがインストールできたら[k3dをインストール](https://k3d.io/#installation)します。

```shell
curl -s https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash
```


# k3dでクラスタを構築する
それではいよいよk3dでクラスタを立てます。
`<your vps global ip>`の箇所は自分の用意したvpsのipを適用してください。

```shell
k3d cluster create hoge-cluster --agents 2 --api-port <your vps global ip>:6550 -p 80:80@agent[0] -p 443:443@agent[0]
```

# ローカルのkubectlと繋ぐ
まずサーバー側で下記を実行し`certificate-authority-data`とユーザーのpasswordをひかえておく

```shell
vi ~/.kube/config
```

ローカルの`~/.kube/config`に今回作成したclusterの情報、context、userを追加する
これで、ローカルのkubectlとTime4VPS上のクラスタが繋がる

```yaml:~/.kube/config(ローカル)
apiVersion: v1
kind: Config
current-context: hoge-cluster
preferences: {}

clusters:
  - name: hoge-cluster
    cluster:
      certificate-authority-data: <your certificate-authority-data in vps ~/.kube/config>
      server: https://<your vps global ip>:6550

users:
  - name: admin@hoge-cluster
    user:
      password: <your password in vps ~/.kube/config>
      username: admin

contexts:
  - name: hoge-cluster
    context:
      cluster: hoge-cluster
      user: admin@hoge-cluster
```

***クラスタに接続できたか確認***

```shell
kubectl get node

NAME                        STATUS   ROLES    AGE   VERSION
k3d-hoge-cluster-agent-0    Ready    <none>   39m   v1.18.8+k3s1
k3d-hoge-cluster-agent-1    Ready    <none>   39m   v1.18.8+k3s1
k3d-hoge-cluster-server-0   Ready    master   39m   v1.18.8+k3s1
```


# クラスタにcert-managerをインストールする
続いてサービスをSSLで配信するためクラスタにcert-managerをインストールします。
cert-managerはマニフェスト一発でインストール完了するので導入自体は超簡単です。
[cert-managerのインストール](https://cert-manager.io/docs/installation/kubernetes/)

# freenomで無料ドメインを取得する
テストで試しに動かしてみる程度でわざわざ有料のドメインを取得するなど勿体ないと思います。
なので[freenom](https://my.freenom.com/clientarea.php)という無料ドメイン取得に便利な
サービスを利用します。
取得するドメイン名は今回は`k3d-hello-app.tk`とでもしておきます。

# マニフェストファイルを書いてデプロイ
最後にマニフェストファイルを書いてデプロイします。
今回、コンテナイメージはgoogleがGKE用のサンプルとして公開しているレジストリを利用するため
イメージのビルド作業もリモートレジストリへのpush作業もないので寂しい作業になりますが
k8sというマニフェストを管理するディレクトリを用意し
2種類のマニフェストファイルを用意していきましょう。

```shell
# ディレクトリ構成はこんな感じ
.
└── k8s
    ├── hello-app.yaml
    └── ingress.yaml
```


```yaml:k8s/hello-app.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-app-service
spec:
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
  selector:
    app: hello-app

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app-deployment
spec:
  replicas: 6
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
        env: stage
    spec:
      containers:
        - image: gcr.io/google-samples/hello-app:1.0
          name: hello-app
          ports:
            - containerPort: 8080

```

ちなみにServiceのタイプがLoadBalancerになっていますが
k3dは`type: LoadBalancer`を使うことができます。

続いて、ingress用のマニフェストファイルを書きます。
`<your mail address>`の箇所にはご自身のメールアドレスを置き換えてください。

```yaml:k8s/ingress.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt-issuer
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration, update to your own.
    email: <your mail address>
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-issuer
    solvers:
      - http01:
          ingress:
            class: traefik
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: letsencrypt-cert
spec:
  dnsNames:
    - k3d-hello-app.tk

  secretName: letsencrypt-cert-tls
  issuerRef:
    name: letsencrypt-issuer


---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hoge-cluster-ingress
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
    kubernetes.io/ingress.class: "traefik"
    certmanager.k8s.io/issuer: "letsencrypt-issuer"
    certmanager.k8s.io/acme-challenge-type: http01
spec:
  tls:
    - secretName: letsencrypt-cert-tls
      hosts:
        - k3d-hello-app.tk

  rules:
    - host: k3d-hello-app.tk
      http:
        paths:
          - path: /
            backend:
              serviceName: hello-app-service
              servicePort: 8080
```

それではマニフェストを適用します。

```shell
kubectl apply -f k8s -R
```

ちなみに`-R`フラグは今回必要ないのですが
もしも、マニフェストファイルの内容が膨大になった。とかになったら
マニフェストファイルをパッケージ分割する必要も出てくるかと思います。
そういった時に`-R`フラグをつけるとパッケージ分割したマニフェストも
再起的に適用してくれると、そういう事です。

```shell

# 例えばこんな感じにパッケージ分割
.
└── k8s
    ├── hello-app.yaml
    └── ingress
        ├── certificate.yaml
        ├── ingress.yaml
        └── issuer.yaml
```

マニフェストが適用できたらブラウザで確認してみましょう。
下記のように表示されSSL化もできていれば完了です！

|![スクリーンショット 2020-10-02 19.26.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224153/2dad6650-eb17-12e4-e1ae-00e869091a97.png)|
|:-:|






# まとめ
k3dは一つの物理サーバーの中に仮想でNodeを立て
クラスタを構築するので、物理サーバー層での可用性は全くありません。
1台のサーバーが一時停止すればドカン！と丸ごと
そのクラスタで運用しているサービスは一時停止します。
いわゆる、Blast Radiusはデカイどころの騒ぎじゃありません。
もはや一撃必殺ですww
なのでビジネス規模によっては全く要件に合わないでしょうが
個人規模などランニングコストの節約の方を重視する場合などは
k3dのような仮想クラスタというものもありなのではないでしょうか？
特にこれまで個人でdocker-composeで本番運用してました！
というような方には超オススメです。

# 参考
- [k3d](https://k3d.io/)
- [cert-manager](https://cert-manager.io/docs/installation/kubernetes/)
- [Time4VPS](https://www.time4vps.com/)
- [freenom](https://my.freenom.com/clientarea.php)
- [hello-appコンテナイメージ](https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/master/hello-app)
- [Ubuntu 18.04にDockerをインストールする(+docker-composeも)](https://qiita.com/iganari/items/fe4889943f22fd63692a)
- [Ubuntu 最低限抑えておきたい初期設定](https://qiita.com/kotarella1110/items/f638822d64a43824dfa4)