Kubernetesにいまさら入門した話

# ローカル環境構築

Minikubeとkubectlをダウンロードする。

- https://kubernetes.io/docs/tasks/tools/install-minikube/
- https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-windows

kubectlはPATHを通す。Minikubeはインストーラーを実行してインストール。

```
minikube.exe start
minikube.exe dashboard
```

ブラウザが立ち上がってKubernetes Dashboardが表示される。
とりあえずノードを作る。

```
kubectl create deployment hello-node --image=gcr.io/hello-minikube-zero-install/hello-node
```

Deploymentを確認。

```
kubectl get deployments
```

Podを確認する。

```
kubectl get pods
```

Kubernetes Dashboardで確認する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/e27a6335-3523-9ec5-5476-0a82b2baa17e.png)

イベントを確認する。

```
kubectl get events
```

設定を確認する。

```
kubectl config view
```

設定はこんなん出ます。

```yaml
apiVersion: v1
clusters:
- cluster:
    certificate-authority: C:\Users\xxxxxx\.minikube\ca.crt
    server: https://192.168.99.101:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: C:\Users\xxxxxx\.minikube\client.crt
    client-key: C:\Users\xxxxxx\.minikube\client.key
```

サービスを作る。--type=LoadBalancerフラグはServiceをクラスタ外部に公開するということ。

```
kubectl expose deployment hello-node --type=LoadBalancer --port=8080
```

サービスを確認する。

```
$ kubectl get service
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
hello-node   LoadBalancer   10.96.194.179   <pending>     8080:30610/TCP   3m21s
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP          25h
```

> ロードバランサーをサポートするクラウドプロバイダーでは、Serviceにアクセスするための外部IPアドレスが提供されます。 Minikube では、LoadBalancerタイプはminikube serviceコマンドを使用した接続可能なServiceを作成します。

ということらしい。以下でブラウザが立ち上がる。

```
minikube service hello-node
```

# 用語の確認

このチュートリアルにしたがってやるよ
https://thinkit.co.jp/series/7342

## Workloads…コンテナの実行に関するリソース

### Pod

- Workloads リソースの最小単位
- Pod は1つ以上のコンテナから構成
- ネットワークは隔離されておらず、Pod内のコンテナはお互いにlocalhost宛で通信することが可能
- 補助するサブコンテナのことを「サイドカー」と呼ぶ

### ReplicaSetとReplicationController

- Podのレプリカを生成し、指定した数のPodを維持し続ける
- ReplicationControllerは今後廃止される
- 特定のラベルがつけられたPodの数をカウントし、レプリカ数が不足している場合はtemplateからPodを生成する

### **Deployments ★推奨**

- 複数のReplicaSetを管理しローリングアップデートやロールバックなどを実現する
  1. 新しいReplicaSetを作成
  2. 新しいReplicaSet上のレプリカ数（Pod数）を徐々に増やす
  3. 古いReplicaSet上のレプリカ数（Pod数）を徐々に減らす
  4. 古いReplicaSetはレプリカ数0で保持する
- ReplicaSetが生成される条件は「生成されるPodの内容の変更」。
- 正確にはspec.templateに変更があるとReplicaSetを新規で作成し、ローリングアップデートが行われる。
- ロールバック機能の実体はReplicaSetの切り替えと同義で、ReplicaSetは基本的には履歴としてレプリカ数を0にして形だけは残っている。
- 実際にはこのロールバック機能を使っている利用者は少なく、古いYAMLファイルを再度kubectl applyして適用したほうが良い。

### StatefulSet

- データベースなどstatefulなワークロードに対応するためのリソース
- ReplicaSetとの違い
  - 生成されるPod名が数字でindexingされたものになる
  - PersistentVolumeを使っている場合は同じディスクを利用して再作成される
  - Pod名が変わらない
- 1つずつPodを作成し、Ready状態になってから次のPodを作成し始める。
- 常にindex:0がMasterとなるような構成を取ることが可能。

### DaemonSet

- 全nodeに1 podずつ配置する

### Jobs

- **停止＝正常終了**となるようなもので使う。
- ワークロード別パラメータの使い分け（Think ITより）

| ワークロード                | completions | parallelism | backoffLimit |
| :-------------------------- | :---------- | :---------- | :----------- |
| 1回だけ実行するタスク       | 1           | 1           | 1            |
| N並列で実行させるタスク     | M           | N           | P            |
| 1個ずつ実行するワークキュー | 未指定      | 1           | P            |
| N並列で実行するワークキュー | 未指定      | N           | P            |

### CronJobs

- Cronのようにスケジュールされた時間にJobを生成する

## Service,LB,Network

Kubernetesでクラスタを構築すると、Podのための内部用ネットワークが構成される。Pod内のコンテナはお互いにlocalhost宛で通信することが可能。

サービスディスカバリ（DNS的な仕組み）もサービスが提供する。以下の三種類ある。

- Aレコード（kube-dnsのAレコード）を利用したサービスディスカバリ。
  - IP単位で対応させるのがAレコード
  - 正式なFQDNは[Service名].[Namespace名].svc.[ClusterDomain名]
  - コンテナ内の/etc/resolv.confで、[Service名].[Namespace名]や[Service名]だけで名前解決できる
- SRVレコード（kube-dnsのSRVレコード）を利用したサービスディスカバリ
  - IP＋Port単位で対応させるのがSRVレコード
  - 正式なFQDNは[**_**ServiceのPort名].[**_**Protocol].[Service名].[Namespace名].svc.[ClusterDomain名]
- 環境変数を利用したサービスディスカバリ
  - 環境変数でも同じNamespaceのサービスが確認できる

サービスのタイプ別の挙動の違い

- ClusterIP
  - クラスタ内からでないと疎通性のないInternal Networkに作り出されるVIPが割り当てられる
- ExternalIP
  - type自体はClusterIP
  - externalIPsにnodeのIPを指定することでKubernetesクラスタ外からそのIPでのアクセスができる
  - ExternalIPに利用するIPは全てのnodeのIPでなくて良い
  - Podへのリクエストは分散される
- NodePort
  - 全てのNodeで受けたトラフィックをコンテナに転送する。ExteralIPの全ノード版
  - ノード上のNodePortに到達したパケットは、さらにノードをまたいだPodへもロードバランシングされる
  - externalTrafficPolicyをデフォルトのClusterからLocalに設定すると同じノードのPodに転送される
- LoadBalancer
  - コンテナ内からの通信はClusterIPを利用するために、ClusterIPも自動的に確保される
  - 外部のLoadBalancerと連携できるのは、GCP、AWS、Azureを始めとしたCloudProviderのみ
  - 8080:30082/TCPみたいに表示されるのは、左側がVIPにアクセスした時のポートで、右側がノードのIPでアクセスしたときのポート
- Headless
  - 永続性の高いStatefulSetのみで利用できる。逆に言えばこれを使いたいとき以外は関係ない
  - PodのIP Addressが返ってくるService
  - DNS Round Robin（DNS RR）を使ったエンドポイントを提供
  - 転送先のPodのIPアドレスがクラスタ内DNSから返ってくる形で負荷分散
  - spec.typeはClusterIP
  - metadata.nameはStatefulSetのspec.serviceNameと同じ。
  - spec.clusterIPはNone
  - [Pod名].[Service名].[Namespace名].svc.[domain名]
- ExternalName
  - Service名の名前解決に対してCNAMEを返す
  - これ、使わない気がします
- Ingress
  - L7 LoadBalancerを提供する
  - 「Kind: Service」タイプのリソースではなく、「Kind: Ingress」タイプのリソース

## Config

環境変数を渡す際にはpodテンプレートに**env**または**envFrom**を指定する。下記の5つの情報源から環境変数を埋め込むことができる。

- 静的設定　値をそのまま書くだけ
- Podの情報　fieldRefを使う
- Containerの情報 resourceFieldRefを使う
- Secretリソースの機密情報　
- ConfigMapリソースからのKey-Value値。nginx.confやhttpd.confのような設定ファイル自体も保存可能

## Storage

### Volume

- 既存のボリューム（ホストの領域、NFS、Ceph、GCP Volume）などをYAML Manifestに直接指定する
- 利用者が新規でボリュームを作成したり、既存のボリュームを削除したりはできない
- YAML ManifestからVolumeリソースを作成するといった処理もない

### PersistentVolume

- 新規のボリュームの作成や、既存のボリュームの削除などを行うことが可能
- YAML ManifestなどからPersistent Volumeリソースを別途作成する形
- GCPやAWSのボリュームサービスでは、Persistent VolumeプラグインとVolumeプラグインの両方が用意されている
- Persistent Volumeはクラスタにボリュームを登録するだけ

### PersistentVolumeClaim

- 作成されたPersistentVolumeリソースの中からアサインするためのリソース

- Dynamic Provisioningを利用した場合は、Persistent Volume Claimが利用されたタイミングでPersistent Volumeを動的に作成することが可能

### Volumeプラグイン

- EmptyDir Pod用の一時的なディスク領域として利用可能です。PodがTerminateされると削除されます

- HostPath  Node上の領域をコンテナにマッピング。

- [その他]: https://kubernetes.io/docs/concepts/storage/volumes/



# よく使う？kubectlのコマンド

## Workload関連のコマンド

### 2つのコンテナを持つPodを作る。

まずはyamlファイルを作る。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-2pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.12
      ports:
      - containerPort: 80
    - name: redis-container
      image: redis:5.0.5
      ports:
      - containerPort: 6379
```

以下のコマンドでyamlファイルの内容を反映させる。

```bash
kubectl apply -f .\2pod_sample.yaml
```

### コンテナの中に入る

ReplicaSetで作ったPodのコンテナの中に入ることもできるよ。

```bash
# sample-podはPodの名前。
# 複数のコンテナがPodの中に存在する場合、何も指定しないとデフォルトのコンテナが選択される。
# 特定のコンテナを指定したい場合は-cでコンテナの名前を指定する。
$ kubectl exec -it sample-2pod -c nginx-container /bin/bash
```

### 存在しているPodを確認する

```bash
kubectl get pods
```

### Podを消す

```bash
kubectl delete pods sample-2pod
```

### ReplicaSetを作る

yamlファイルを作る。

ReplicaSetが生成するPodは、［ReplicaSet名］−［乱数］で命名される。

```yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sample-rs
spec:
  replicas: 3
  # selectorの下のラベルの追加Podを探しにいって維持しようとする
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
    # Podにつけられるラベルはここで指定して、これは上の指定と一致していないといけない
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.12
          ports:
            - containerPort: 80
```

反映させる。これはPodのときと同じコマンド。ファイルが違うだけ

```yaml
kubectl apply -f .\rs_sample.yaml
```

### 存在しているReplicaSetを確認する。

```bash
$ kubectl get replicaset
NAME        DESIRED   CURRENT   READY   AGE
sample-rs   3         3         3       19m
$ kubectl get replicaset -o wide
NAME        DESIRED   CURRENT   READY   AGE   CONTAINERS        IMAGES       SELECTOR
sample-rs   3         3         3       38m   nginx-container   nginx:1.12   app=sample-app
```

### オートヒーリングの確認。Podを消してみて、再作成されるのを確認する。

```bash
$ kubectl get pods -o wide
NAME              READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
sample-2pod       2/2     Running   2          16h     172.17.0.6   minikube   <none>           <none>
sample-rs-776l8   1/1     Running   0          3h53m   172.17.0.8   minikube   <none>           <none>
sample-rs-dhjdr   1/1     Running   0          3h53m   172.17.0.9   minikube   <none>           <none>
sample-rs-kcbn2   1/1     Running   0          3h53m   172.17.0.7   minikube   <none>           <none>
$ kubectl delete pod sample-rs-dhjdr
pod "sample-rs-dhjdr" deleted
$ kubectl get pods -o wide
NAME              READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
sample-2pod       2/2     Running   2          16h     172.17.0.6   minikube   <none>           <none>
sample-rs-776l8   1/1     Running   0          3h54m   172.17.0.8   minikube   <none>           <none>
sample-rs-kcbn2   1/1     Running   0          3h54m   172.17.0.7   minikube   <none>           <none>
sample-rs-w9h4r   1/1     Running   0          4s      172.17.0.9   minikube   <none>           <none>
```

### ReplicaSetの詳細を確認する。

```bash
$ kubectl describe replicaset sample-rs
Name:         sample-rs
Namespace:    default
Selector:     app=sample-app
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"sample-rs","namespace":"default"},"spec":{"replicas":3,"s...
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=sample-app
  Containers:
   nginx-container:
    Image:        nginx:1.12
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age    From                   Message
  ----    ------            ----   ----                   -------
  Normal  SuccessfulCreate  5m24s  replicaset-controller  Created pod: sample-rs-w9h4r
```

### Podのスケーリング

yamlを書き換える以外の方法だと以下のコマンドを使う

```
$ kubectl scale replicaset sample-rs --replicas 5
```

### Deployment（でPod）を作る

まずyamlファイルを作る

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.12
          ports:
            - containerPort: 80
```

読み込ませる

```bash
$ kubectl apply -f .\deployment_sample.yaml
```

### 存在するDeploymentを確認する

```bash
$ kubectl get deployment
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
sample-deployment   3/3     3            3           3m30s
```

```bash
$ kubectl describe deployment sample-deployment
Name:                   sample-deployment
Namespace:              default
CreationTimestamp:      Sat, 28 Dec 2019 15:58:26 +0900
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"sample-deployment","namespace":"default"},"spec":{"replic...
Selector:               app=sample-app
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=sample-app
  Containers:
   nginx-container:
    Image:        nginx:1.12
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   sample-deployment-c6c6778b4 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  5m55s  deployment-controller  Scaled up replica set sample-deployment-c6c6778b4 to 3
```

### Deploymentのイメージは以下で更新できる。

```bash
$ kubectl set image deployment sample-deployment nginx-container=nginx:1.13
```

### Jobを作成する。

yamlファイルを作る。

```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: sample-job
spec:
  # 実行の回数を指定する
  completions: 1
  # 並列度を指定する
  parallelism: 1
  # 失敗を許容する回数
  backoffLimit: 10
  template:
    spec:
      containers:
      - name: sleep-container
        image: centos:latest
        command: ["sleep"]
        args: ["60"]
      # spec.template.spec.restartPolicyにはOnFailureまたはNeverが指定可能
      # NeverはPodが障害時には新規のPodが作成される
      # OnFailureの場合には、再度同一のPodを利用してJobを再開する
      restartPolicy: Never
```

反映させる。

```yaml
$ kubectl apply -f job_sample.yml
```

### Jobの実行状況を確認する。

```bash
$ kubectl get jobs
NAME         COMPLETIONS   DURATION   AGE
sample-job   0/1           40s        40s
```

### CronJobを作る。

yamlファイルを作る。

```
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: sample-cronjob
spec:
  schedule: "*/1 * * * *"
  # spec.concurrencyPolicyで指定する同時実行に関するポリシー
  # - Allow（default）：同時実行に対して制限を行わない
  # - Forbid：前のJobが終了していない場合は次のJobは実行しない
  # - Replace：前のJobをキャンセルし、新たにJobを開始する
  concurrencyPolicy: Forbid
  # 開始時刻が遅れた場合に許容できる秒数
  startingDeadlineSeconds: 30
  # 保存する成功Jobの数
  successfulJobsHistoryLimit: 5
  # 保存する失敗Jobの数
  failedJobsHistoryLimit: 5
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: sleep-container
            image: centos:latest
            command: ["sleep"]
            args: ["30"]
          restartPolicy: Never
```

## ネットワーク関連のコマンド

### サービスを作成する

```
apiVersion: v1
kind: Service
metadata:
  name: sample-clusterip
spec:
  type: ClusterIP
  # 複数のPortを指定できる
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
  selector:
    app: sample-app
```

ClusterIPを静的にIPを指定する場合

```
apiVersion: v1
kind: Service
metadata:
  name: sample-static-clusterip
spec:
  type: ClusterIP
  clusterIP: 10.96.253.80
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
  selector:
    app: sample-app
```

External IPを指定する

```
apiVersion: v1
kind: Service
metadata:
  name: sample-static-clusterip
spec:
  type: ClusterIP
  clusterIP: 10.96.253.80
  externalIPs:
    - 192.168.99.101
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
  selector:
    app: sample-app
```

LoadBalancerを指定した場合

```
apiVersion: v1
kind: Service
metadata:
  name: sample-lb
spec:
  type: LoadBalancer
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
      nodePort: 30082
  selector:
    app: sample-app
```



設定を適用する。

```
kubectl apply -f clusterip_sample.yml
```

### 作成したサービスを確認する

```
kubectl get services
NAME               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes         ClusterIP   10.96.0.1     <none>        443/TCP    6d13h
sample-clusterip   ClusterIP   10.96.64.65   <none>        8080/TCP   23s
```

### サービスの詳細を確認する

```
kubectl describe services sample-clusterip
Name:              sample-clusterip
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"sample-clusterip","namespace":"default"},"spec":{"ports":[{"name"...      Selector:          app=sample-app
Type:              ClusterIP
IP:                10.96.64.65
Port:              http-port  8080/TCP
TargetPort:        80/TCP
Endpoints:         172.17.0.11:80,172.17.0.14:80,172.17.0.16:80 + 5 more...
Session Affinity:  None
Events:            <none>
```

### clusteripの動作を確認する。内部から出ないと呼べないので内部から

IPを使ってアクセスする。使えるIPはkubectl get servicesで確認したもの。

```
kubectl run --image=centos:7 --restart=Never --rm  -ti testpod -- curl -s http://10.96.64.65:8080
```

Aレコードを使ってアクセスする。[Service名].[Namespace名].svc.[ClusterDomain名]

```
 kubectl run --image=centos:7 --restart=Never --rm  -ti testpod -- curl -s http://sample-clusterip.default.svc.cluster.local:8080
```

/etc/resolv.confの[Service名]を使ってアクセスする。

```
kubectl run --image=centos:7 --restart=Never --rm  -ti testpod -- curl -s http://sample-clusterip:8080
```

SRVレコードを使ってアクセスする。[**_**ServiceのPort名].[**_**Protocol].[Service名].[Namespace名].svc.[ClusterDomain名]

```
kubectl run --image=centos:7 --restart=Never --rm  -ti testpod -- curl -s http://_http-port._tcp.sample-clusterip.default.svc.cluster.local:8080
```

環境変数にもレコードと同じ内容が設定される。

```
$ kubectl run --image=centos:7 --restart=Never --rm  -ti testpod -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=testpod
TERM=xterm
KUBERNETES_SERVICE_PORT_HTTPS=443
SAMPLE_CLUSTERIP_SERVICE_HOST=10.96.64.65
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
SAMPLE_CLUSTERIP_SERVICE_PORT=8080
SAMPLE_CLUSTERIP_PORT_8080_TCP_ADDR=10.96.64.65
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
SAMPLE_CLUSTERIP_PORT_8080_TCP=tcp://10.96.64.65:8080
SAMPLE_CLUSTERIP_PORT_8080_TCP_PROTO=tcp
SAMPLE_CLUSTERIP_PORT_8080_TCP_PORT=8080
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
SAMPLE_CLUSTERIP_SERVICE_PORT_HTTP_PORT=8080
SAMPLE_CLUSTERIP_PORT=tcp://10.96.64.65:8080
```

### External IPで指定できるノードのIPは以下で取得できる

```
$ kubectl get node -o custom-columns="NAME:{metadata.name},IP:{status.addresses[].address}"
NAME       IP
minikube   192.168.99.101
```

### External IPの指定した結果を確認する

```
kubectl get services
NAME                      TYPE        CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
kubernetes                ClusterIP   10.96.0.1      <none>           443/TCP    6d16h
sample-clusterip          ClusterIP   10.96.64.65    <none>           8080/TCP   3h48m
sample-static-clusterip   ClusterIP   10.96.253.80   192.168.99.101   8080/TCP   16m
```

## Secretを利用する

### ファイルからSecretを登録する

改行が入らないように注意

```
echo -n "root" > ./username
echo -n "rootpassword" > ./password
kubectl create secret generic sample-db-auth --from-file=./username --from-file=./password
```

### yamlファイルから作成する

値はbase64でエンコード済みのものでないといけない

```
apiVersion: v1
kind: Secret
metadata:
  name: sample-yaml-auth
type: Opaque
data:
  username: cm9vdA==
  password: cm9vdHBhc3N3b3Jk
```

```
kubectl apply -f ./secret_sample.yml
```

### kubectlから直接作成する (--from-literal)

```
kubectl create secret generic sample-cli-auth --from-literal=username=root --from-literal=password=rootpassword
```

### envfile（dockerの --env-fileオプションと同じ）から作成する

```
username=root
password=rootpassword
```

```
kubectl create secret generic sample-env-file --from-env-file ./env_secret
```

### 登録内容を確認する

```
kubectl describe secrets sample-db-auth
Name:         sample-db-auth
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  8 bytes
username:  9 bytes
```

### 中身まで確認する

base64でエンコードされているので、デコードする必要がある

```
kubectl get secret sample-db-auth -o json
{
    "apiVersion": "v1",
    "data": {
        "password": "UEBzc3cwcmQ=",
        "username": "dXNlci1uYW1l"
    },
    "kind": "Secret",
    "metadata": {
        "creationTimestamp": "2019-12-31T08:01:36Z",
        "name": "sample-db-auth",
        "namespace": "default",
        "resourceVersion": "123932",
        "selfLink": "/api/v1/namespaces/default/secrets/sample-db-auth",
        "uid": "d5e6188d-bbb3-496f-8b95-bb3dfc7fa4ec"
    },
    "type": "Opaque"
}
```

### 環境変数として利用する

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-secret-env
spec:
  containers:
    - name: secret-container
      image: nginx:1.12
      envFrom:
      - secretRef:
          name: sample-db-auth
```

```
kubectl apply -f .\secret_env_sample.yml
pod/sample-secret-env created
```

```
kubectl exec -it sample-secret-env env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=sample-secret-env
TERM=xterm
password=P@ssw0rd
username=user-name
```

### ファイルとして利用する

環境変数として設定する場合との違いは以下。

> Volumeマウントを利用したSecretに限り一定期間ごと（kubeletのSync Loopのタイミング）にkube-apiserverに変更を確認し、変更がある場合は入れ替えを行います。

> デフォルトではSyncLoopの間隔は60秒に設定されています。この頻度を上げる場合には、kubeletのオプションとして--sync-frequencyを設定して下さい。また、環境変数を利用したSecretの場合、動的な更新はできません。

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-secret-single-volume
spec:
  containers:
    - name: secret-container
      image: nginx:1.12
      volumeMounts:
      - name: config-volume
        mountPath: /config
  volumes:
    - name: config-volume
      secret:
        secretName: sample-db-auth
        items:
        - key: username
          path: username.txt
```

## ConfigMapを利用する

### ファイルから登録する

改行が入らないように注意

```
echo "config=true" > ./sample.conf
kubectl create configmap sample-config --from-file=./sample.conf
```

### yamlファイルから作成する

値はbase64でどうのこうのする必要はない

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
data:
  thread: "16"
  connection.max: "100"
  connection.min: "10"
  sample.properties: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
  nginx.conf: |
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;
```

```
kubectl apply -f ./sample-config-map.conf
```

### kubectlから直接作成する (--from-literal)

```
kubectl create configmap web-config --from-literal=connection.max=100 --from-literal=connection.min=10
```

### 環境変数として利用する

環境変数として利用する場合、以下の制限がある。

> 環境変数で下記の2パターンを表現することができない読み込まれない
>
> **.**が含まれる場合
>
> 改行が含まれる場合（**Key: |**で定義されているもの）

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-single-env
spec:
  containers:
    - name: configmap-container
      image: nginx:1.12
      env:
        - name: CONNECTION_MAX
          valueFrom:
            configMapKeyRef:
              name: sample-configmap
              key: connection.max
```

```
kubectl apply -f configmap_single_env_sample.yml
pod/sample-configmap-single-env created
```

### ファイルとして利用する

環境変数として設定する場合との違いはSecretの時と同じ。

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-multi-volume
spec:
  containers:
    - name: configmap-container
      image: nginx:1.12
      volumeMounts:
      - name: config-volume
        mountPath: /config
  volumes:
    - name: config-volume
      configMap:
        name: sample-configmap
```

## Volumeを利用する

### emptyDirを使う

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-emptydir
spec:
  containers:
  - image: nginx:1.12
    name: nginx-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
```

```
kubectl apply -f .\emptydir-sample.yml
```

```
kubectl exec -it sample-emptydir /bin/bash
root@sample-emptydir:/# ls -l
total 72
drwxrwxrwx   2 root root 4096 Jan  1 03:41 cache
```

### HostPathを使う

```
apiVersion: v1
kind: Pod
metadata:
  name: sample-hostpath
spec:
  containers:
  - image: nginx:1.12
    name: nginx-container
    volumeMounts:
    - mountPath: /srv
      name: hostpath-sample
  volumes:
  - name: hostpath-sample
    hostPath:
      path: /data
      type: DirectoryOrCreate
```

```
kubectl apply -f .\hostpath-sample.yml
```

```
kubectl exec -it sample-hostpath /bin/bash
touch /srv/test
```

```
$ minikube.exe ssh
                         _             _
            _         _ ( )           ( )
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

$ ls /data
test
```



# Kubernetesを構成しているコンポーネント

主に以下の引用です。

- https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613

- https://www.slideshare.net/ToruMakabe/kubernetes-120907020

### コンポーネント一覧

[コンポーネント一覧]: https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613

| コンポーネント                                               | 種別   | 説明                                                         |
| :----------------------------------------------------------- | :----- | :----------------------------------------------------------- |
| [etcd](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#etcd-link) | master | Kubernetesのリソースの永続化に使われる高信頼分散KVS          |
| [kube-apiserver](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-apiserver) | master | Kubernetesのリソースを管理するAPIサーバー                    |
| [kube-scheduler](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-scheduler) | master | Podのノードへの割り当てを行うスケジューラー                  |
| [kube-controller-manager](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-controller-manager) | master | Replication Controllerなどの各種コントローラーを起動し管理するマネージャー |
| [kubelet](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kubelet) | node   | Podを起動し管理するエージェント(Nodeのメイン処理)            |
| [kube-proxy](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-proxy) | node   | KubernetesのServiceが持つ仮想的なIPアドレス(cluster IP)へのアクセスをルーティングする |
| kubectl                                                      | client | KubernetesのCLIクライアント                                  |
| [hyperkube](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#hyperkube-all-in-oneバイナリ) | misc   | Kubernetes関連のバイナリを1つにまとめたall-in-oneバイナリ    |
| [pause](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#Pauseコンテナ) | misc   | pod内のネットワークnamespaceを保持するコンテナ               |
| [pod-master](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#pod-master) | add-on | High-Availability構成時にscheduler, controllerがどのMasterで動くかを調整するコンテナ |
| [kube-dns](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-dns) | add-on | クラスタ内DNSのPod                                           |
| [SkyDNS](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#skydns-link) | add-on | クラスタ内DNSのDNSサーバー                                   |
| [kube2sky](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube2sky) | add-on | SkyDNSにKubernetesの情報を反映させるブリッジ                 |
| [heapster](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#heapster) | add-on | Kuernetesのパフォーマンス情報を集約する仕組み                |
| [helm(Deployment Manager)](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#helm-deployment-manager) | add-on | Kubernetesの設定をテンプレート化しデプロイを管理しやすくする仕組み |
| [dashboard](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#dashboard) | UI     | 新しいKubernetesのダッシュボード                             |
| [kube-ui](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kube-ui) | UI     | 古いKubernetesのダッシュボード                               |
| [kubedash](https://qiita.com/tkusumi/items/c2a92cd52bfdb9edd613#kubedash) | UI     | パフォーマンス分析のダッシュボード                           |

![architecture](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F100377%2F8302c8a6-83a2-3631-a6b4-7bd555d3a18b.png?ixlib=rb-1.2.2&auto=compress%2Cformat&gif-q=60&s=0eb05fa2cae78b86f8c69b55c5ffb75e)

### コンポーネント同士がどうやって連携しあっているのかの基本的な考え方

https://www.slideshare.net/ToruMakabe/kubernetes-120907020　から抜粋。

各コンポーネントの中でReconciliation Loopというのが動いている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/0f05bf93-6f23-a868-c200-d4e91b4f73be.png)

#### Kubernetesの設計原則

> API Serverのみがクラスター状態を管理するデータストア(etcd)を扱う 部分的なサーバー障害がクラスター全体のダウンにつながらないよう にする 各コンポーネントへの指示が失われても、直近の指示にもとづいて処 理を継続できるようにする

> 各コンポーネントは関連する設定や状態をメモリに持つが、永続化は API Serverを通じてデータストア(etcd)へ行う ユーザーや他のコンポーネントがオブジェクトを変化させたことを検 知できるよう、コンポーネントはAPI Serverをウォッチする

#### イベントチェーンの流れ Deployment作成の例 

> 1. クライアントがDeployment APIを呼ぶ 
> 2. Deployment Controllerが検知し、ReplicaSet APIを呼ぶ 
> 3. ReplicaSet Controllerが検知し、Pod APIを呼ぶ 
> 4. Schedulerが検知し、配置先Nodeを決定し、Pod APIを呼ぶ 
> 5. Kubeletが検知し、Pod(Container)を作成 

## 冗長構成を組む

### 基本的な考え方

またこちらを見ました。https://www.slideshare.net/ToruMakabe/kubernetes-120907020

Controller ManagerとSchedulerはActive/Standby

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/4bd57b6e-1d80-7e0b-6f75-11ecafafdb75.png)

台数

> Master、Nodeともに3台以上がおすすめ Masterサーバーにetcdを同居させる場合、おすすめは3台以上で奇数 etcdの障害時、処理継続ノードの決定基準が過半数であるため Nodeサーバーは2台以上、必要なリソース量に応じて増やす Nodeサーバーが2台構成だと障害時に使えるリソースが一気に半減す るため、3台以上とするケースが多い

少なくともリージョンをまたがるようなクラスタを組まない方がいいらしい

> 複数のデータセンターに分散配置する場合、制約条件は遅延 etcdの死活確認、性能の観点から2～3msに抑えるのが一般的 Azureのバックボーンでも東阪は10ms程度かかる 1つのクラスターは1つの都市圏で構成するのが現実的 広域災害対策は1つのクラスターではなく、複数のクラスターで

HPA（Horizontal Pod Autoscaler）の定義

HPAはPodごとに定義できるRequestsを割り当てられるかどうかを判断基準にしていて、実際の使用量をもとにPodの配置を決めるわけではない。

Nodeに空きがないとPodがPendingになる。これを監視しているのがCluster AutoscalerでインフラのAPIを呼んでノードを追加する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16609/8b085637-21fd-4fa8-13b9-b9b5b9ee2ed1.png)

# Helmを導入する

Helmはk8sのパッケージマネージャ的なものらしい。

~~試してみたけど、公式通りにやってもちゃんと動かないことがあるというか…残念~~

Goで書かれていて、以下からダウンロードしてパスを通せば導入できる。

https://github.com/helm/helm/releases/tag/v3.0.2

```bash
$ helm
The Kubernetes package manager

Common actions for Helm:

- helm search:    search for charts
- helm pull:      download a chart to your local directory to view
- helm install:   upload the chart to Kubernetes
- helm list:      list releases of charts

Environment variables:

+------------------+-----------------------------------------------------------------------------+
| Name             | Description                                                                 |
+------------------+-----------------------------------------------------------------------------+
| $XDG_CACHE_HOME  | set an alternative location for storing cached files.                       |
| $XDG_CONFIG_HOME | set an alternative location for storing Helm configuration.                 |
| $XDG_DATA_HOME   | set an alternative location for storing Helm data.                          |
| $HELM_DRIVER     | set the backend storage driver. Values are: configmap, secret, memory       |
| $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins.                  |
| $KUBECONFIG      | set an alternative Kubernetes configuration file (default "~/.kube/config") |
+------------------+-----------------------------------------------------------------------------+

Helm stores configuration based on the XDG base directory specification, so

- cached files are stored in $XDG_CACHE_HOME/helm
- configuration is stored in $XDG_CONFIG_HOME/helm
- data is stored in $XDG_DATA_HOME/helm
```

## Helmでできること

https://qiita.com/thinksphere/items/5f3e918015cf4e63a0bc

> - 自分のKubernetesクラスター環境へのデプロイ(インストール)・削除(アンインストール)
> - パッケージを共有する仕組み(リポジトリ)
> - 新規のパッケージを開発する支援機能

## Helmの構成要素

> | 構成要素          | 説明                                                         | 補足                                                         |
> | :---------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
> | helm(CLI)         | go言語で開発されたコマンドラインツール。                     | ローカルOS環境の$HELM_HOMEでポイントする場所に、設定ファイル群や、「ローカルリポジトリ」を作り出し、その上でtillerと通信してKubernetesクラスタとのやりとりを行います。 |
> | tiller(サーバー)  | Kubernetesクラスタ内にリソースとして定義され、動作するサーバーアプリ。 | helmコマンドからの要求に基づき、apiserverを介してKubernetesクラスタ内のリソース作成・削除・情報取得などの操作を行います。 |
> | chart(チャート)   | Helmにおける管理対象としての「パッケージ」                   | 実体は.tgz形式の圧縮ファイル。様々なファイル群で構成され、Kubernetesのリソースを生成するためのテンプレートファイルやデフォルト値の設定ファイルなどが含まれる。 |
> | release(リリース) | chartを使って実際にデプロイ(インストール)されたクラスタ上のオブジェクトをまとめて表したもの。 | リリースは、暗黙にせよ明示的にせよ、「リリース名」が必ず与えられ、識別されます。 |
> | chartリポジトリ   | チャートをhelmクライアントに提供するWebサーバー              | 仕様として定められたindex.yamlおよびchartファイル(.tgz)群をサービスすれば、それはchartリポジトリとなりえます。 |

## Helmのクイックスタート

https://helm.sh/docs/intro/quickstart/

### MySQLの環境を立ち上げる。

```bash
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
$ helm repo update
$ helm install stable/mysql --generate-name
NAME: mysql-1577664762
LAST DEPLOYED: Mon Dec 30 09:12:44 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql-1577664762.default.svc.cluster.local

To get your root password run:

    MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default mysql-1577664762 -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)  
To connect to your database:

1. Run an Ubuntu pod that you can use as a client:

    kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il

2. Install the mysql client:

    $ apt-get update && apt-get install mysql-client -y

3. Connect using the mysql cli, then provide your password:
    $ mysql -h mysql-1577664762 -p

To connect to your database directly from outside the K8s cluster:
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306

    # Execute the following command to route the connection:
    kubectl port-forward svc/mysql-1577664762 3306

    mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
```

### MySQLの環境を調べてみる。

```bash
$ kubectl get deployments -o wide
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS              IMAGES         SELECTOR
mysql-1577664762        1/1     1            1           5m46s   mysql-1577664762        mysql:5.7.28   app=mysql-1577664762,release=mysql-1577664762 
```

```bash
$ kubectl describe deployments mysql-1577664762
Name:               mysql-1577664762
Namespace:          default
CreationTimestamp:  Mon, 30 Dec 2019 09:12:10 +0900
Labels:             app=mysql-1577664762
                    chart=mysql-1.6.2
                    heritage=Helm
                    release=mysql-1577664762
Annotations:        deployment.kubernetes.io/revision: 1
Selector:           app=mysql-1577664762,release=mysql-1577664762
Replicas:           1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:           app=mysql-1577664762
                    release=mysql-1577664762
  Service Account:  default
  Init Containers:
   remove-lost-found:
    Image:      busybox:1.29.3
    Port:       <none>
    Host Port:  <none>
    Command:
      rm
      -fr
      /var/lib/mysql/lost+found
    Requests:
      cpu:        10m
      memory:     10Mi
    Environment:  <none>
    Mounts:
      /var/lib/mysql from data (rw)
  Containers:
   mysql-1577664762:
    Image:      mysql:5.7.28
    Port:       3306/TCP
    Host Port:  0/TCP
    Requests:
      cpu:      100m
      memory:   256Mi
    Liveness:   exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=30s timeout=5s period=10s #success=1 #failure=3
    Readiness:  exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=5s timeout=1s period=10s #success=1 #failure=3
    Environment:
      MYSQL_ROOT_PASSWORD:  <set to the key 'mysql-root-password' in secret 'mysql-1577664762'>  Optional: false
      MYSQL_PASSWORD:       <set to the key 'mysql-password' in secret 'mysql-1577664762'>       Optional: true
      MYSQL_USER:
      MYSQL_DATABASE:
    Mounts:
      /var/lib/mysql from data (rw)
  Volumes:
   data:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  mysql-1577664762
    ReadOnly:   false
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   mysql-1577664762-d75956dbc (1/1 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  6m59s  deployment-controller  Scaled up replica set mysql-1577664762-d75956dbc to 1
```

```bash
$ kubectl get pods
NAME                                     READY   STATUS      RESTARTS   AGE
mysql-1577664762-d75956dbc-bz2fm         1/1     Running     0          4m28s
```

```bash
$ kubectl describe pods mysql-1577664762-d75956dbc-bz2fm
Name:         mysql-1577664762-d75956dbc-bz2fm
Namespace:    default
Priority:     0
Node:         minikube/192.168.99.101
Start Time:   Mon, 30 Dec 2019 09:12:11 +0900
Labels:       app=mysql-1577664762
              pod-template-hash=d75956dbc
              release=mysql-1577664762
Annotations:  <none>
Status:       Running
IP:           172.17.0.13
IPs:
  IP:           172.17.0.13
Controlled By:  ReplicaSet/mysql-1577664762-d75956dbc
Init Containers:
  remove-lost-found:
    Container ID:  docker://2ef1950b5844614c38122e32fa069e03490d8d0a077d0feb94d6b79a740f97da
    Image:         busybox:1.29.3
    Image ID:      docker-pullable://busybox@sha256:8ccbac733d19c0dd4d70b4f0c1e12245b5fa3ad24758a11035ee505c629c0796
    Port:          <none>
    Host Port:     <none>
    Command:
      rm
      -fr
      /var/lib/mysql/lost+found
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Mon, 30 Dec 2019 09:12:18 +0900
      Finished:     Mon, 30 Dec 2019 09:12:18 +0900
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        10m
      memory:     10Mi
    Environment:  <none>
    Mounts:
      /var/lib/mysql from data (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-jn5v7 (ro)
Containers:
  mysql-1577664762:
    Container ID:   docker://41735ace19ebb2f949d70d40b8b5d7f4a397369a9116230ee53dbe14f51de990
    Image:          mysql:5.7.28
    Image ID:       docker-pullable://mysql@sha256:b38555e593300df225daea22aeb104eed79fc80d2f064fde1e16e1804d00d0fc
    Port:           3306/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 30 Dec 2019 09:12:57 +0900
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:      100m
      memory:   256Mi
    Liveness:   exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=30s timeout=5s period=10s #success=1 #failure=3
    Readiness:  exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=5s timeout=1s period=10s #success=1 #failure=3
    Environment:
      MYSQL_ROOT_PASSWORD:  <set to the key 'mysql-root-password' in secret 'mysql-1577664762'>  Optional: false
      MYSQL_PASSWORD:       <set to the key 'mysql-password' in secret 'mysql-1577664762'>       Optional: true
      MYSQL_USER:
      MYSQL_DATABASE:
    Mounts:
      /var/lib/mysql from data (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-jn5v7 (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  data:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  mysql-1577664762
    ReadOnly:   false
  default-token-jn5v7:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-jn5v7
    Optional:    false
QoS Class:       Burstable
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
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  error while running "VolumeBinding" filter plugin for pod "mysql-1577664762-d75956dbc-bz2fm": pod has unbound immediate PersistentVolumeClaims
  Normal   Scheduled         <unknown>  default-scheduler  Successfully assigned default/mysql-1577664762-d75956dbc-bz2fm to minikube
  Normal   Pulling           11m        kubelet, minikube  Pulling image "busybox:1.29.3"
  Normal   Pulled            10m        kubelet, minikube  Successfully pulled image "busybox:1.29.3"
  Normal   Created           10m        kubelet, minikube  Created container remove-lost-found
  Normal   Started           10m        kubelet, minikube  Started container remove-lost-found
  Normal   Pulling           10m        kubelet, minikube  Pulling image "mysql:5.7.28"
  Normal   Pulled            10m        kubelet, minikube  Successfully pulled image "mysql:5.7.28"
  Normal   Created           10m        kubelet, minikube  Created container mysql-1577664762
  Normal   Started           10m        kubelet, minikube  Started container mysql-1577664762
  Warning  Unhealthy         10m        kubelet, minikube  Readiness probe failed: mysqladmin: [Warning] Using a password on the command line interface can be insecure.
mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)'
Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists!
```

### MySQLのrootパスワードを取得する。

```bash
$ kubectl get secret --namespace default mysql-1577664762 -o jsonpath="{.data.mysql-root-password}"
```

これであっているはずだけど、ここで取得できるパスワードを使っても繋がらない…