「おじいちゃん kubernetesってなに？」「...それはコスモスじゃよ」(2) -構築編-

おはこんばんにちは
zerobillbank株式会社のインフラエンジニアtomatoことtomatoです。

前回に引き続き、kubernetesの第2回目になります。
前回はkubernetesとはなんぞやという概要の部分をお伝えしたので、
今回はより具体的に、kubernetesの環境をどう構築していくのかについてお話ししていきマウス:confounded:

ちなみに前回の記事はこちらです:kissing:
<a href="https://qiita.com/Veritas666777/items/408f405028699d1b5cdd">「おじいちゃん kubernetesってなに？」「...それはコスモスじゃよ」(1) -概要編-</a>

## すごい図
まずいきなりですがこの図をご覧ください..ﾃﾞﾝ!
![kubernetes_resources.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274405/055d521a-7cea-cde2-c951-ead5c2ced879.png)

kubernetesの構築を理解する上で、大事であろうポイントをあえて3つに絞ってみました。

- Deployment
    - Podを定義するもの
- Service
    - 内部IP
- Ingress
    - 外部IP

まずはこの3つを基本の軸に考えることで、kubernetesの沼に
引きずり込まれることを防げるのではと思います！:relaxed::smirk::wink:

### 不死身のDeployment
「や、やつは不死身なのかッ..!?」「いや、コアを狙うんだ！！」
倒しても復活しちゃう系のボスっているじゃないですか:smiling_imp:
あれの身体が`Pod`で、コア部分が`Deployment`...まあそんな感じです。

`Deployment`には`Pod`の定義を記載します。
`Pod`には実際に動くアプリケーションが入ります（例えばnginxとか自分で作ったアプリとか）
`Pod`の自己増減や自己修復などの機能については、第一回でお伝えしていますが
それを実現するのがこの`Deployment`です。

例として、`Deployment`側で「Aというイメージの`Pod`を常に2つ起動しておく」
という定義を記載しておくと、常にAの`Pod`が2つ起動されるようになります。
そのため、Aの`Pod`を手動で1つ削除しても、Aの`Pod`が新しく作られ
常に2つが`Pod`が起動している状態を保つようになります。

補足ですが、似たようなものに`ReplicaSet`や`DaemonSet`などがあります。
ただ、可能な限りシンプルに説明したいため、あえて今回は触れません。
`Pod`を作成できるのは必ずしも`Deployment`だけではありませんが、
やはり`Deployment`が最もよく使用する基本のリソースになります。

### 引きこもりのService
`Service`で内部IPを定義します。
逆を言えば、`Deployment`によって`Pod`が作成されても
`Service`が定義されていなければ、どこからもアクセスできないわけです。
つまり最強の引きこもりです。

内部IPは`Private IP`とも呼ばれ、
同じkubernetesクラスタ内でのアクセスを可能にするものです。
ただしインターネットからのアクセスはできません。
例えるなら、マンションの部屋番号とか内線番号とかが近いですかね。

### パリぴのIngress
`Ingress`は外部IPを定義します。

上記の`Service`を定義した段階では、同じkubernetesクラスタ内でのみアクセスが可能で
外部（インターネット）からのアクセスはできない状態です。
外部からのアクセスを可能にするには`Ingress`が必要です。

`Ingress`はパブリックIPとkubernetes側の入り口の紐付けを行い
kubernetesを外界へと解き放ちます。
インターネット越しのアクセスは`Ingress`->`Service`->`Pod`という風に伝わっていきます。

外部IPはまさに住所みたいなもので、その外部IP（普通はそれに紐づくドメイン）を知っていれば
誰でもインターネットでアクセスすることができます。
エブリワンカムオン、ミンナトモダチ。まさにパリピです（偏見）


## 構築しちゃうzoy
超最小ですが、上記の3つのリソースを使用していよいよ`Kubernetes`を使用した構築をしちゃいたいと思います！！！
..が、その前にちょっとした下準備が必要になります。


### クラスタの作成
`Kubernetes`での構築を行う際にはまず`クラスタ`を作成する必要があります。
`クラスタ`とは第一回で説明した`node`の定義などを行います。
復習がてら説明しますと`node`は物理的なコンピュータの単位であり、
この`Kubernetes`でどのコンピュータをいくつ使いますねんっていう定義です

実際の作成方法はここでつらつら説明するより、使用するクラウド側の
リファレンスを参照してもらった方がすんなりすんすんできると思います。
そんなに難しいものでなく、今のご時世ポータルからホイホイできちゃいます。

例えばAzureだと下記になります。

https://docs.microsoft.com/ja-jp/azure/aks/kubernetes-walkthrough-portal#create-an-aks-cluster

### yamlってなんやねん
で、もう一つ用意するのが`yaml`と呼ばれるファイルになります。
これに上記の`Deployment`やら`Service`やらの定義を書き込むわけです。

`yaml`とは...

- ファイル形式の一種だよ
- データ構造を表現できるよ

まあそんな感じものですが、難しいものではなく
実際に具体例を見れば理解しやすいものかと思います。

### Deploymentのyaml例
下記の`yaml`は、Webサーバの代名詞でもある`nginx`のリソースを定義したものです。
予備知識がなくても、なんとなく何を書いてあるのかがわかるんじゃないかなーと思います。

ポイントは`image: nginx`の部分で、ここで何のDockerイメージを読み込むかを記載します。
[Dockerのオフィシャルイメージ](https://hub.docker.com/search?image_filter=official&type=image)にあるものなら、イメージ名を書くだけで呼び出してくれます。

オリジナルのDockerイメージを使用したい場合は、
`Dockerファイルの作成` -> `Dockerファイルをコンテナレジストリに登録`という手順を踏み
そのコンテナレジストリのURLを`image`タグに記載します。


```yaml:nginx/deplyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: sample
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 80
```

### Serviceのyaml例

```yaml:nginx/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: sample
  labels:
    app: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80 # Default port for image
      targetPort: 80
```

### Ingressのyaml例
ドメインについてはレジストラから事前に取得しておく必要があります。
クラウドサービスからも割り当てることができますが、例えばAzureの場合`xxx.japaneast.cloudapp.azure.com`みたいなアドレスになります。

https://docs.microsoft.com/ja-jp/azure/virtual-network/public-ip-addresses

`xxx.com`やら`xxx.jp`やらが良いという場合は、レジストラから希望のドメインを購入する必要があります。



```yaml:nginx/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  namespace: sample
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'

spec:
  tls:
  - hosts:
    - xxx.com
    secretName: tls-secret
  rules:
  - host: xxx.com
    http:
      paths:
        - backend:
            serviceName: nginx
            servicePort: 80
          path: /
```

## yamlの適用

ではいよいよ`yaml`を適用して`kubernetes`を構築していきます！！

### kubectl
`kubernetes`の操作は`kubectl`というコマンドで行います。
インストールについてはOSごとに異なりますので、下記を参照してください。

https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/

### 適用コマンド
`kubectl`のインストールが成功したら`yaml`の適用を行います。

今回は`sample`という`namespace`を作成し、そこに適用したいと思います。
`namespace`というのは`kubernetes`における論理的な境界になります。

ターミナルを起動し、下記のコマンドを打ち込みます。

```bash
$ kubectl create namespace sample
```

上記で作成した`yaml`を適用します。

```bash
$ kubectl apply -f nginx/deplyment.yaml
$ kubectl apply -f nginx/service.yaml
$ kubectl apply -f nginx/ingress.yaml
```

`apply`した各リソースの確認は下記のコマンドで行います。
今回は`nginx`というリソースができていることを確認します。

```bash
$ kubectl -n sample get deplyment
$ kubectl -n sample get service
$ kubectl -n sample get ingress
```

そして`Deployment`から`Pod`が作成されていることを確認します。

```
$ kubectl -n sample get pod
NAME                      READY   STATUS        RESTARTS   AGE
nginx-546d5b6b48-r64gr    1/1     Running       0          10s
```

問題なければ`Ingress`で設定したドメインに
`nginx`の初期設定ページが表示されているはずです。


## おわり

今回はこんな感じです。
駆け足で構築までしましたが、次回はうまく構築できなかった時のトラブルシューティングや
実際の運用とか監視とかについてお話できればと思います。

ではまた🙋‍♂️

## さいごに
ZEROBILLBANKでは一緒に働く仲間を募集中です。
なんとかjsとか、ブロックチェーンとか、kubernetesとかでいろんなAPIを作るお仕事。
今のところエンジニアは5人くらい。スタートアップだけど、結構ホワイトで働きやすいです。

[ZEROBILLBANK JAPAN Inc.](https://zerobillbank.com)