Kubernetes 勉強会&ハンズオン@CDSL

# 第1回 Pod + Service

## はじめに

Kuberneteの仕組みを以下の動画で大まかに理解してください．

[![k8s-movie-1](http://img.youtube.com/vi/yrCaCBUceL4/0.jpg)](http://www.youtube.com/watch?v=yrCaCBUceL4)

## 参考資料

基本的に書き方や使い方は公式リファレンスを読んでください．

[Kubernetesドキュメント | Kubernetes](https://kubernetes.io/ja/docs/home/)

日本語で網羅的に書かれている資料として以下がオススメです．

[kubernetes-dojo - Toku's Blog](https://cstoku.dev/tags/kubernetes-dojo/)

## 環境構築

簡単に構築できるKubernetes環境の例には以下があります．

- インストール型
    - [Minikube](https://kubernetes.io/ja/docs/setup/learning-environment/minikube/)
    - [Microk8s](https://microk8s.io/)
    - [Docker for Desktop](https://www.docker.com/products/docker-desktop)
- パブリッククラウド(有料)
    - [Amazon EKS](https://aws.amazon.com/jp/eks/)
    - [Google GKE](https://cloud.google.com/kubernetes-engine)
    - [Microsoft AKS](https://azure.microsoft.com/ja-jp/services/kubernetes-service/)

Webで簡単に試すだけなら katacoda も使えます．何らかの方法でKubernetes環境を構築してください．

以下のコマンドを実行して結果が得られるか確認してください．以下ではDocker Desktopを使っています．

```bash
$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```

## Dockerコマンドでコンテナを起動

まずは，準備運動として以下のコンテナをdockerコマンドで立ち上げてみてください．このコンテナは80/tcpでリクエストを待ち受けます．

[nginxdemos/hello - Docker Hub](https://hub.docker.com/r/nginxdemos/hello/)

### 練習

```bash
docker run --rm -p <略>
```

Webブラウザからコンテナにアクセスすると，以下が表示されます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/c86ab6ac-8db6-1bc2-e613-86a2cc5d4e9e.png)

## Kubernetesの基本操作

Kubernetes上で動作するコンポーネント(要素や機能郡)を操作する基本的な方法は以下です．

1. YAMLファイル `example.yml` を作成する．
    - コマンド例: `vi example.yml`
2. kubectlコマンドでデプロイする．
    - コマンド例: `kubectl apply -f example.yml`
3. kubectlコマンドでデプロイしたコンポーネントを確認する．
    - コマンド例: `kubectl get pod`
    - コマンド例: `kubectl get deployment`
    - コマンド例: `kubectl get service`

## Podをデプロイ

### Podとは

最初に貼った動画では「さや」という例えで説明されています．

https://youtu.be/yrCaCBUceL4?t=282

Kubernetes公式のサイトでのPodの説明を引用します．

> Pod は、Kubernetesアプリケーションの基本的な実行単位です。これは、作成またはデプロイするKubernetesオブジェクトモデルの中で最小かつ最も単純な単位です。Podは、クラスターで実行されているプロセスを表します。
出典: [Podについて理解する](https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-overview/#understanding-pods)

Podとコンテナの関係は次の2パターンがあります．Podに1つのコンテナを配置するパターン(図:パターン1)と，Podに複数のコンテナを配置するパターン(図:パターン2)です．

![Pod説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/88d28350-8365-bc72-70fe-324ff84fe343.png)

Podの詳細は[公式ドキュメント](https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-overview/)を確認してください．

### Podのデプロイ

まずは，簡単なパターン1でコンテナをデプロイ(配置)していきます．操作は前述の「Kubernetesの基本操作」をもとに行います．

#### [手順1] YAMLファイルを作成

テキストエディタで作成するコンポーネント(要素や機能郡)の情報をYAMLファイルに記述します．YAMLはインデントでデータ階層を表現する記述形式です．ファイルの拡張子には `yml` や `yaml` が使われます．

ここでは `pod.yaml` にPodの設定を記述します．

```
$ vi pod.yaml
```

pod.yamlの中身は以下です．

```yaml:pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
    - name: demo-container
      image: nginxdemos/hello
      ports:
        - containerPort: 80
```

pod.yamlの中身に説明を入れてみました．

```yaml:pod.yamlの説明
# Podを記述する時のきまり
apiVersion: v1
kind: Pod
# Podの名前やラベルをはじめとする細かい情報
metadata:
  name: myapp-pod  # Podに名前をつける
  labels:
    app: myapp  # ラベル app -> myapp をつける
# Podに配置するコンテナ本体の情報
spec:
  containers:
    - name: demo-container  # コンテナに名前をつける
      image: nginxdemos/hello  # コンテナ名(Docker Hubの名前と一致)
      ports:
        - containerPort: 80  # 80番ポートを使う
```

詳細な解説は以下の記事を参照してください．

[Kubernetes道場 3日目 - Podについてとkubectlの簡単な使い方](https://cstoku.dev/posts/2018/k8sdojo-03/)

作業ディレクトリには，pod.yamlだけが存在する状況です．

```bash
$ ls 
pod.yaml
```

#### [手順2] kubectlコマンドでデプロイ

次にpod.yamlに記述した設定をKubernetesへ適用させます．正常に実行できると以下のメッセージが出力されます．

```bash
$ kubectl apply -f pod.yaml
pod/myapp-pod created
```

#### [手順3] kubectlコマンドでデプロイされたか確認

Podが作成されているかkubectlコマンドで確認します．

```bash
$ kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          3m23s
```

Podが作成されたことが確認できました．

<補足> オプション `-o wide` をつけると，さらに細かい情報が確認できます．

```bash
kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP           NODE             NOMINATED NODE   READINESS GATES
myapp-pod   1/1     Running   0          3m47s   10.1.0.160   docker-desktop   <none>           <none>
```

デプロイしたPodを以下の図に表しました．Pod <myapp-pod>の中にコンテナ <demo-container>が配置されています．コンテナのイメージには nginxdemos/hello を使っています．

![Pod説明2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/fc1bfb6f-70f9-aaa8-74c2-90ffa27fd771.png)

Podの情報を細かく見るには `kubectl describe` を使います．

```bash
$ kubectl describe pod myapp-pod
Name:         myapp-pod
Namespace:    default
Priority:     0
Node:         docker-desktop/192.168.65.3
Start Time:   Sat, 05 Sep 2020 20:58:29 +0900
Labels:       app=myapp
Annotations:  Status:  Running
IP:           10.1.0.160
IPs:
  IP:  10.1.0.160
Containers:
  demo-container:
    Container ID:   docker://cc834c6900185dbc14a201a0b47b4548c627daf40ab6aace5c6919fe2ac5bdb2
    Image:          nginxdemos/hello
    Image ID:       docker-pullable://nginxdemos/hello@sha256:f5a0b2a5fe9af497c4a7c186ef6412bb91ff19d39d6ac24a4997eaed2b0bb334
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 05 Sep 2020 20:58:32 +0900
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-wf42w (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-wf42w:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-wf42w
    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:          <none>
```

## Serviceをデプロイ

### Serviceとは

最初に紹介した動画ではサービスを店として例えています．

https://youtu.be/yrCaCBUceL4?t=753

PodはKubernetesクラスタ内のIPアドレスからしかアクセスできません．また，IPアドレスは頻繁に変更されます．こうした状況下で，外部にPodを公開したりPod同士がやり取りしたりする場合は，Serviceを使います．

![Svc説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/3537d381-2af0-7de3-b8ac-e2253e4e4121.png)

ServiceにはTypeとよばれるパラメータでServiceの種類が選べます．TypeにはCluster IP(初期値), NodePort, ExternalName, LoadBalancerがあります．詳細は[公式ドキュメント](https://kubernetes.io/ja/docs/concepts/services-networking/service/#publishing-services-service-types)を参照してください．

参考: [Next 東京：Kubernetes のコンテナ技術ですべてをシンプルに（Brian Dorsey）](https://youtu.be/aMcLGD20kTY?t=1177)

### Serviceのデプロイ

それでは，Serviceを作ってみます．操作は前述の「Kubernetesの基本操作」に従います．

#### [手順1] YAMLファイルを作成

ここでは `service.yaml` にServiceの設定を記述します．

```yaml:service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  type: NodePort
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
      nodePort: 31080
  selector:
    app: myapp
```

`service.yaml`の中身を説明します．

```yaml:service.yamlの説明
# Serviceを記述する時のきまり
apiVersion: v1
kind: Service
# Serviceの名前やラベルをはじめとする細かい情報
metadata:
  name: myapp-svc
# Service本体の情報
spec:
  # Serviceの種類. 未指定ではClusterIPになる．NodePortの詳細は割愛．
  type: NodePort
  # ポートの対応付け
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080  # ClusterIPで受け付けるポート
      targetPort: 80  # Pod側のポート
      nodePort: 31080  # 外部からのアクセスを受けるポート(全ノードで使用)
  selector:
    app: myapp
```

ServiceのTypeごとの細かな説明は以下の記事がオススメです．

- Cluster IP, External IP: [KubernetesのDiscovery＆LBリソース（その1） | Think IT（シンクイット）](https://thinkit.co.jp/article/13738)
- NodePort, LoadBalancer: [KubernetesのDiscovery＆LBリソース（その1） | Think IT（シンクイット）](https://thinkit.co.jp/article/13738?page=0%2C1)

#### [手順2] kubectlコマンドでデプロイ

設定を記述したServiceをデプロイします．

```bash
$ kubectl apply -f service.yaml
service/myapp-svc created
```

#### [手順3] kubectlコマンドでデプロイされたか確認

kubectlコマンドで確認してみます．

```bash
$ kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP          93d
myapp-svc    NodePort    10.107.57.76   <none>        8080:31080/TCP   47m
```

実行結果にあるPORT(S)の `8080:31080/TCP` はYAMLファイルで指定した設定パラメータ `port:nodePort/protocol` に対応しています．

## Pod + Serviceでデプロイしたコンテナへアクセス

Webブラウザから `http://localhost:31080/` へアクセスして以下のWebページが表示されるか確認します．localhostは，Kubernetesクラスタのアドレスに置き換えてください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/b3b327b3-5243-1761-28cb-2cb6d957140e.png)

ここで表示されている Server address と Server name が `kubectl get pod -o wide` の情報と一致するか確認してみます．

```bash
$ kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP           NODE             NOMINATED NODE   READINESS GATES
myapp-pod   1/1     Running   0          14h   10.1.0.160   docker-desktop   <none>           <none>
```

<!-- 図 -->

## 片付け

以下のコマンドで作成したコンポーネントを削除します．

```bash
$ kubectl delete pod myapp-pod
pod "myapp-pod" deleted

$ kubectl delete service myapp-svc
service "myapp-svc" deleted
```

コンポーネントが削除されているか確認します．

```bash
$ kubectl get pod
No resources found in default namespace.

$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   93d
```

## 練習

以下のイメージをKubernetesを使ってデプロイしてください．

[pmorjan/demo - Docker Hub](https://registry.hub.docker.com/r/pmorjan/demo)

起動すると以下のWebページが確認できます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/a39a2938-7832-7877-2557-284e133c5d01.png)

## まとめ

- Dockerコンテナの実行
- Kubernetesの使い方
    - Pod
    - Service
    - kubectlコマンド
        - kubectl get xxx
        - kubectl apply -f xxx
        - kubectl describe xxx

# 第2回 YAMLの書き方 + kubectlコマンド

## YAMLの書き方

Kubernetesで自由自在にコンテナをはじめとするコンポーネントを操るには，事前に定義された形式に従って設定ファイルを記述する必要があります．

ここでは基本的なYAMLの書き方をPodを例に説明します．

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
    - name: demo-container
      image: nginxdemos/hello
      ports:
        - containerPort: 80
```

### apiVersion, kind

apiVersionは使用するコンポーネントに対応するKubernetesのAPIバージョンを記述します．
kindは使用するコンポーネントの種類を指定します．
以下にkindと対応するapiVersionの例をあげています．

- Pod: v1
- Service: v1

以下は以降の回で説明するコンポーネントです．

- Deployment: apps/v1
- DaemonSet: apps/v1
- CronJob: batch/v1beta1
- Job: batch/v1
- Ingress: networking.k8s.io/v1beta1

### metadata

metadataには，作成するコンポーネントの名前やラベル，アノテーション(Annotation)を記述します．
作成後のコンポーネントを操作したり識別したりするにはこれらが使われます．
以下はmetadataの記述例です．

```yaml
metadata:
  name: annotations-demo
  annotations:
    imageregistry: "https://hub.docker.com/"
  labels:
    app: sample-app
    app-arch: x86_64
    app-version: v1.3.5
```

次の命名規則に従って名前付けを行う必要があります．

> ラベルは、キーとバリューのベアです。正しいラベルキーは2つのセグメントを持ちます。それは/によって分割されたオプショナルなプレフィックスと名前です。名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z])で、文字列の間ではこれに加えてダッシュ(-)、アンダースコア(_)、ドット(.)を使うことができます。プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/)が続きます。
出典: [ラベル(Labels)とセレクター(Selectors) | Kubernetes](https://kubernetes.io/ja/docs/concepts/overview/working-with-objects/labels/)

> 名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z])と、文字列の間にダッシュ(-)、アンダースコア(_)、ドット(.)を使うことができます。 プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/)が続きます。
出典: [アノテーション(Annotations) | Kubernetes](https://kubernetes.io/ja/docs/concepts/overview/working-with-objects/annotations/)

### spec

作成するコンポーネントの詳細を記述します．
Podの場合は，その中に配置するコンテナごとの名前やイメージ，ポートや環境変数を指定します．
以下はPodにFluentdとデモNginxのコンテナを記述した例です．

```yaml
spec:
  containers:
    - name: demo-container
      image: nginxdemos/hello
      ports:
        - containerPort: 80
    - name: fluentd-container
      image: fluent/fluentd:v1.11-2
      env:
        - name:  FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch-logging"
        - name:  FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        - name:  FLUENT_ELASTICSEARCH_SSL_VERIFY
          value: "true"
        - name:  FLUENT_ELASTICSEARCH_SSL_VERSION
          value: "TLSv1_2"
```

## kubectlコマンド

Kubernetesクラスタへ新たにコンポーネントを追加や既存のコンポーネントを変更や削除には `kubectl` コマンドを使います．kubectlコマンドを実行すると，Kubernetesクラスタのマスターノードへリクエストを送信します．マスターノードではRESTful APIサーバ(下図: kube-adi-server)が動作しており，受け取ったリクエストに応じてコンテナをはじめとするコンポーネントの制御を他のシステムと連携して行います．

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/b66b436f-763f-ddba-6820-a4a47d0e528f.png)
> 出典: [Kubernetesのコンポーネント | Kubernetes](https://kubernetes.io/ja/docs/concepts/overview/components/)

### kubectlで一覧と構成の取得

コマンドの基本的な形式は以下です．オプションをつけることで

```
kubectl get <取得したい対象>
```

|コマンド|説明|
|---|---|
|kubectl get node|ノードの一覧を取得|
|kubectl get pod|Podの一覧を取得|
|kubectl get svc|Serviceの一覧を取得|
|kubectl get all -o wide|Pod, Service, Deployment, ReplicaSetの一覧を取得|
|kubectl get ns|Namespaceの一覧を取得|
|kubectl get pod -o json|Podの構成をJSON形式で取得|
|kubectl get svc -o yaml|Serviceの構成をYAML形式で取得|
|kubectl get all -A|全てのNamespaceの一覧を取得|
|kubectl get -f pod.yaml|pod.yamlに記述されたコンポーネントの一覧を取得|

#### 練習

1. pod.yamlに記述された内容をデプロイして，JSON形式で表示してください．
2. kubectl get allの結果でコンポーネント名(例: pod/xxx, service/yyy)だけを表示してください．

### kubectlでログを見る

kubectlコマンドのサブコマンド `logs` を使うと，PodやServiceをはじめとするコンポーネントのログを見れます．コマンドの基本形式は以下です．

```
kubectl logs <ログを見る対象>
```

ここではPodのログを見てみます．

```bash
$ kubectl get all
NAME            READY   STATUS    RESTARTS   AGE
pod/myapp-pod   1/1     Running   0          9m57s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   18m

$ kubectl logs pod/myapp-pod
2020/09/11 03:48:45 listening on :8080
```

#### 練習

1. コンテナイメージ[chentex/random-logger](https://hub.docker.com/r/chentex/random-logger/)をKubernetesへデプロイしてください．
2. デプロイしたコンテナのログから `WARN` を含むログのみをコマンドを使って表示してください．
3. `WARN` を含むログの件数をコマンドを使って取得してください．

コンテナの出力するログの例

```
2020-09-11T12:50:58+0000 WARN A warning that should be ignored is usually at this level and should be actionable.
2020-09-11T12:50:59+0000 ERROR An error is usually an exception that has been caught and not handled.
2020-09-11T12:50:59+0000 INFO This is less important than debug log and is often used to provide context in the current task.
2020-09-11T12:50:59+0000 DEBUG This is a debug log that shows a log that can be ignored.
2020-09-11T12:50:59+0000 INFO This is less important than debug log and is often used to provide context in the current task.
2020-09-11T12:51:00+0000 INFO This is less important than debug log and is often used to provide context in the current task.
```

### kubectlでコンテナに入る

デプロイしたPod内のコンテナに入ってみます．

```bash
kubectl exec <オプション> <対象>
```

Podを構成するコンテナが複数ある場合は以下のコマンドを実行します．

```bash
kubectl exec <pod_name> --container <container_name> -- <command>
```

Podを構成するコンテナが1つの場合は以下のコマンドを実行します．

```bash
kubectl exec <pod_name> -- <command> 
```

試しにコンテナを作成して，その中に入ってみます．
YAMLファイルからPodを作成してもよいのですが，ここではkubectl runコマンドを使ってみます．
以下では，Ubuntu 18.04のPodを起動して `tail -f /dev/null` を実行しておきます．

```bash
kubectl run ubuntu --image=ubuntu:18.04 --command -- tail -f /dev/null
```

Podが作成されているか確認します．

```bash
$ kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          2d5h
ubuntu      1/1     Running   0          4m23s
```

Podで動くコンテナの中に `kubectl exec` で入ってみます．
コンテナから出るにはexitコマンドを使います．

```bash
$ kubectl exec -it pod/ubuntu -- /bin/bash
root@ubuntu:/#
root@ubuntu:/# hostname -I
10.1.0.13
root@ubuntu:/# exit
exit
$ 
```

#### 練習

- Ubuntu 20.04のコンテナを含むPodを作成してください．方法は問いません．
- kubectl execコマンドを使ってコンテナに入ってください．
- コンテナの中に `htop` コマンドをインストールして，実行してください．
    - ヒント: apt-getコマンド OR aptコマンド

実行結果の例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/6d6a5703-4876-769f-e9c6-6f41300bdd60.png)

### kubectlでトラブルシューティング

kubectlコマンドはトラブルシュート(障害の診断や対応)に役立ちます．以下はkubectlコマンドの役立つTipsです．

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/7b756a7b-3527-47ba-88a6-37cd9cd72114.png)
> 出典: [40 topic of Kubernetes in 40 minutes (Yoshio Terada) - Japan Container Day 2018](https://www.slideshare.net/tyoshio2002/japan-container-day-2018/35)

最後のUbuntuコンテナのデプロイには以下のコマンドが使えます．

```bash
kubectl run -it --rm shooting --image=ubuntu:18.04 -- /bin/bash
``` 

# 第3回 コントローラ, Deployment

コントローラ(Controller)はPodを制御するためのコンポーネントです．
可用性やスケール，無停止入れ替えを実現しています．

https://youtu.be/yrCaCBUceL4?t=535

例えば，ノードが故障してPod数が減少すると，コントローラは動作する他のノードでPodを作成して全体のPod数を一定に保ちます．

また，アクセス状況にあわせて柔軟にコンポーネントを制御できます．アクセスが増加したときにPod数を増やしたり，アクセスが減少したときにPod数を減らしたりできます．

## コントローラの種類

コントローラには複数の種類があり，それぞれに役割や特徴があります．デプロイするPodの性質に適したコントローラを選択する必要があります．

- ReplicaSet
- Deployment
- StatefulSet
- DaemonSet
- Job
- CronJob
- ガベージコレクション
- (TTL Controller for Finished Resources)

## Deploymentとは

Deploymentはコントローラの1つです．コンテナをデプロイする場面で頻繁に使われます．
Deploymentの役割が下図で紹介されています．Deploymentコントローラは，Pod数が増減した場合に増減前の数を維持したり，新たなリリースを徐々に適用や復元したり，需要に応じて柔軟にPod数を増減させたりします．

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/ed9ae25a-5a17-7487-6e09-4edd17c2c956.png)
> 出典: [Kubernetesハンズオン(高良 真穂) - Internet Week 2018](https://www.nic.ad.jp/ja/materials/iw/2018/proceedings/h2/h2-takara-4.pdf)

## Deploymentをデプロイ

### [手順1] YAMLファイルを作成

DeploymentをKubernetesの上にデプロイしていきます．

```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
        - name: hello-k8s
          image: paulbouwer/hello-kubernetes:1.8
          ports:
            - containerPort: 8080
```

### [手順2] kubectlコマンドでデプロイ

設定を記述したDeploymentをデプロイします．

```bash
$ kubectl apply -f deployment.yaml
deployment.apps/sample-deploy created
```

### [手順3] kubectlコマンドでデプロイされたか確認

デプロイしたコンテナを確認してみます．

```bash
$ kubectl get deploy
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
sample-deploy   3/3     3            3           38s
```

Pod, Deployment, ReplicaSetが作られていることが確認できます．

```bash
$ kubectl get all
NAME                                 READY   STATUS    RESTARTS   AGE
pod/sample-deploy-795b599766-fvhv9   1/1     Running   0          3m14s
pod/sample-deploy-795b599766-qmj66   1/1     Running   0          3m14s
pod/sample-deploy-795b599766-vlr8d   1/1     Running   0          3m14s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   5d6h

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/sample-deploy   3/3     3            3           3m14s

NAME                                       DESIRED   CURRENT   READY   AGE
replicaset.apps/sample-deploy-795b599766   3         3         3       3m14s
```

## Serviceのデプロイ

Podを作成した時と同様にServiceを作成します．

### [手順1] YAMLファイルを作成

```hello-k8s-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-svc
spec:
  type: NodePort
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 2080
      targetPort: 8080
      nodePort: 32080
  selector:
    app: sample
```

### [手順2] kubectlコマンドでデプロイ

```bash
$ kubectl apply -f hello-k8s-svc.yaml
service/sample-svc created
```

### [手順3] kubectlコマンドでデプロイされたか確認

sample-svcが作成されていることが分かります．

```bash
$ kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          5d7h
sample-svc   NodePort    10.102.60.209   <none>        2080:32080/TCP   105s
```

ブラウザから実際に http://localhost:32080/ へアクセスしてみます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/ff5f3a7e-f9fe-669e-8026-0171c1239c28.png)

Ctrl + Shift + Rで強制リロードをしてみます．Webサイトのpodの部分が変化するかを確かめてください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/c668972f-cb71-c87d-96b1-d9d79f4dff7d.png)

Deployment, ReplicaSet, Podの関係を以下の図に表しました．

![Dep説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/7af01bbf-c516-caab-c9f4-7028bd295699.png)

## Self-healing

TBD
## Rolling Update

TBD

## 練習

TBD

### Deployment + Serviceでアプリをデプロイ

TBD

# 第4回 ConfigMap, Secret

## コンテナにおける設定管理

コンテナを使ってアプリケーションを公開する場合，開発環境と本番環境でアプリケーションの動作を変更したいことがあります．例えば開発環境で動作するアプリケーションではURLを `dev.example.com` に，本番環境で動作するアプリケーションではURLを `www.example.com` にする場合です．

### 環境ごとにイメージを作成

こうした場面で考えられる最も単純な方法は，開発環境と本番環境に対応するコンテナイメージをそれぞれ準備することです．この方法では，環境が増えるにつれ次にあげる2つの問題が存在します．

1. コンテナイメージの種類が増え，管理する手間が増加
2. コンテナレジストリの容量を消費

### 単一イメージを環境変数や設定ファイルで制御

単一のコンテナイメージを設定パラメータにより制御する方法があります．ここでの設定パラメータとは，環境変数や設定ファイルを指します．例えば開発環境では，それ用の設定ファイルをコンテナへ起動時にコピーしたり，環境変数として設定を渡したりすることで開発環境用の設定を適用させます．同様に本番環境でも，対応した設定ファイルや環境変数に割り当てることでコンテナの動作を制御します．

この手法は，単一のコンテナイメージを設定パラメータ(設定ファイルや環境変数)で制御することにより，複数の環境への対応を柔軟に行えます．コンテナでアプリケーションの動作を制御する場合，この手法を使うことが一般的です．

### 環境変数と設定ファイル

環境変数と設定ファイルをKubernetesで指定する方法はいくつかあります．以降ではその1つであるConfigMapとSecretを説明します．

## ConfigMap

## Secret

# 第5回 PersistentVolume, PersistentVolumeClaim, Volume

# 第6回 StatefulSet, DaemonSet