Kubernetes（k8s）とは

# はじめに
この記事は[Certified Kubernetes Administrator](https://www.cncf.io/certification/cka/)資格取るために復習の目的書いています。
この記事はクラスターのアーキテクチャの部分のみとなります。

<font color="darkblue"><ins>内容追加していったら、いつの間にかアーキテクチャを大きく超える内容になってしまいました（涙）</ins></font>
<sub>2021/2/26 - この記事を投稿</sub>
<sub>2021/3/13 - CKA受験し、 合格しました (約2週間かかりました！！)</sub>

><sub>2021/3/13（土） 20:00　- 自宅で受験（子供の風呂終わってから受験しました）</sub>
<sub>2021/3/15（月） 08:02　- 合格メール受信  :congratulations: </sub>

試験のアウトラインが以下のようになっています。

|Sn  |Domain  |Weight  |
|---|---|---|
|1  |Cluster Architecture, Installation & Configuration  |25%  |
|2  |Workloads & Scheduling  |15%  |
|3  |Services & Networking  |20%  |
|4  |Storage  |10%  |
|5  |Troubleshooting  |30  |
[出題範囲](https://github.com/cncf/curriculum/blob/master/CKA_Curriculum_v1.20.pdf)


# Kubernetesとは
Kubernetesとはコンテナー化したアプリケーションをオーケストレーションするためのプラットフォーム。<font color="blue">飛行機操縦士を意味するギリシャ語から由来した名称だそうです。</font>

[公式サイト](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/)の説明
> Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available.
<font color="blue">The name Kubernetes originates from Greek, meaning helmsman or pilot. </font>


# デプロイメントの種類
<img src="https://d33wubrfki0l68.cloudfront.net/26a177ede4d7b032362289c6fccd448fc4a91174/eb693/images/docs/container_evolution.svg">
この図だけで十分伝わるであろうという事で説明を省く（笑）

# Kubernetesの構成
k8sクラスターは下記2種類のもので構成されている。
- Node (以前はworker node)
- Control plane(以前はmaster node)

## Node(以前はworker node)
Nodeは単純にコンピューターの事です。物理または仮想、どちらでもあり得る。僕らが作ったコンテナーアプリケーションが、

- *pod*という箱に梱包され、
- *node*の中にデプロイされます

<sub>☞1つのnodeに複数のpodが存在します</sub>
<sub>☞1つのpodに1以上のコンテナーが存在します</sub>

ノードが以下のコンポネントを持つ

- **kubelet**
- **kube-proxy**
- **container runtime**
- Addons
- DNS
- Web UI (Dashboard)
- Container Resource Monitoring
- Cluster Level Logging


## Control Plane(以前はmaster node)
K8s全体の管理（コントロール）するのが「control plane」です。ノードと同じく物理又は仮想コンピュータです。
以下の要素で構成されている
- **Kube API Server**
- **etcd**
- **Kube Scheduler**
- **Kube Controller Manager**
- **Cloud Control Manager**

<img src="https://d33wubrfki0l68.cloudfront.net/2475489eaf20163ec0f54ddc1d92aa8d4c87c96b/e7c81/images/docs/components-of-kubernetes.svg">

<hr >

# Control Planeの構成
## Kube API Server
クラスターを管理するために「Control Plane」と「node」の様々なコンポーネントとやり取りするためにAPIを公開する。
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
<details><summary>Podの定義の例</summary><div>

```/etc/kubernetes/manifests/kube-apiserver.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=172.17.0.21
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    - --etcd-servers=https://127.0.0.1:2379
    - --insecure-port=0
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --requestheader-allowed-names=front-proxy-client
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-group-headers=X-Remote-Group
    - --requestheader-username-headers=X-Remote-User
    - --secure-port=6443
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-cluster-ip-range=10.96.0.0/12
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    image: k8s.gcr.io/kube-apiserver:v1.19.0
    name: kube-apiserver
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: ca-certs
      readOnly: true
    - mountPath: /etc/ca-certificates
      name: etc-ca-certificates
      readOnly: true
    - mountPath: /etc/kubernetes/pki
      name: k8s-certs
      readOnly: true
    - mountPath: /usr/local/share/ca-certificates
      name: usr-local-share-ca-certificates
      readOnly: true
    - mountPath: /usr/share/ca-certificates
      name: usr-share-ca-certificates
      readOnly: true
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/ssl/certs
      type: DirectoryOrCreate
    name: ca-certs
  - hostPath:
      path: /etc/ca-certificates
      type: DirectoryOrCreate
    name: etc-ca-certificates
  - hostPath:
      path: /etc/kubernetes/pki
      type: DirectoryOrCreate
    name: k8s-certs
  - hostPath:
      path: /usr/local/share/ca-certificates
      type: DirectoryOrCreate
    name: usr-local-share-ca-certificates
  - hostPath:
      path: /usr/share/ca-certificates
      type: DirectoryOrCreate
    name: usr-share-ca-certificates
```
</div></details>

## etcd
Key-Value系の分散型データベースです。クラスターのすべてのデータがここに保管されます。
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
<details><summary>podの定義の例</summary><div>

```/etc/kubernetes/manifests/etcd.yaml  
apiVersion: v1
kind: Pod
metadata:
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://172.17.0.21:2379 # これがetcdがListenする情報。KubeApiServerに設定する必要がある。
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://172.17.0.21:2380
    - --initial-cluster=controlplane=https://172.17.0.21:2380
    - --key-file=/etc/kubernetes/pki/etcd/server.key
    - --listen-client-urls=https://127.0.0.1:2379,https://172.17.0.21:2379
    - --listen-metrics-urls=http://127.0.0.1:2381
    - --listen-peer-urls=https://172.17.0.21:2380
    - --name=controlplane
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    image: k8s.gcr.io/etcd:3.4.9-1
    name: etcd
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
```
</div></details>

etcdを操作するためにetcdctlを使います。バージョン２と３でコマンドが少し違うのでバージョンしてコマンドを実行するのがポイント！
以下はetcdに保存しているデータのKeyのみ取得するコマンドです。

```bash
kubectl exec etcd-controlplane -n kube-system -- sh -c "ETCDCTL_API=3 etcdctl get / --prefix --keys-only --limit=10 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt  --key /etc/kubernetes/pki/etcd/server.key" 
```
[詳細は公式サイトにて](https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#starting-etcd-clusters)


## Kube Scheduler
「pod」が作成されたけど、配置するノードがまだ決まっていないものを監視し、適切なノードを選ぶ。<font color="red">
※「kube scheduler」はどのノードに配置すべきか教えてくれるのみです。ノードの能力、Taint・Tolerationの設定等みて最適なノードを教えてくれます。実際にノードに配置するのが、「**kubelet**」の役割です。</font>

<font color="darkblue">逆に「kube scheduler」がないとpodが自動的にノードに配置されないため、明示的にノードを指定する必要がある。</font>

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  nodeName: node01 # このようにノードを指定する
  containers:
  -  image: nginx
     name: mycontainer
```


kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
<details><summary>Podの定義の例</summary><div>

```/etc/kubernetes/manifests/kube-scheduler.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: kube-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
    - --port=0
    image: k8s.gcr.io/kube-scheduler:v1.19.0
    name: kube-scheduler
    volumeMounts:
    - mountPath: /etc/kubernetes/scheduler.conf
      name: kubeconfig
      readOnly: true
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/scheduler.conf
      type: FileOrCreate
    name: kubeconfig
```
</div></details>


## Kube Controller Manager
以下の４種類のコントローラーで構成されている。

 - Node Controller：「node」が停止した時に知らせる役割
 - Replication Controller：常に設定した「pod」の数を保持する
 - Endpoints Controller：「service」と「pod」の紐づけのためのエンドポイントの注入
 - Service Account & Token Controllers：新しいnamespaceを作った時に必要となるアカウントとAPIアクセストークンの作成

<sub>※ 複雑さをなくすために上記の**4つの独立したプロセスを１つのバイナリ**にまとめられました。</sub>
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
<details><summary>Podの定義の例</summary><div>

```/etc/kubernetes/manifests/kube-controller-manager.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: kube-controller-manager
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
    - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --bind-address=127.0.0.1
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --cluster-cidr=10.244.0.0/16
    - --cluster-name=kubernetes
    - --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
    - --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
    - --controllers=*,bootstrapsigner,tokencleaner
    - --kubeconfig=/etc/kubernetes/controller-manager.conf
    - --leader-elect=true
    - --node-cidr-mask-size=24
    - --port=0
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --root-ca-file=/etc/kubernetes/pki/ca.crt
    - --service-account-private-key-file=/etc/kubernetes/pki/sa.key
    - --service-cluster-ip-range=10.96.0.0/12
    - --use-service-account-credentials=true
    image: k8s.gcr.io/kube-controller-manager:v1.19.0
    name: kube-controller-manager
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: ca-certs
      readOnly: true
    - mountPath: /etc/ca-certificates
      name: etc-ca-certificates
      readOnly: true
    - mountPath: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
      name: flexvolume-dir
    - mountPath: /etc/kubernetes/pki
      name: k8s-certs
      readOnly: true
    - mountPath: /etc/kubernetes/controller-manager.conf
      name: kubeconfig
      readOnly: true
    - mountPath: /usr/local/share/ca-certificates
      name: usr-local-share-ca-certificates
      readOnly: true
    - mountPath: /usr/share/ca-certificates
      name: usr-share-ca-certificates
      readOnly: true
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/ssl/certs
      type: DirectoryOrCreate
    name: ca-certs
  - hostPath:
      path: /etc/ca-certificates
      type: DirectoryOrCreate
    name: etc-ca-certificates
  - hostPath:
      path: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
      type: DirectoryOrCreate
    name: flexvolume-dir
  - hostPath:
      path: /etc/kubernetes/pki
      type: DirectoryOrCreate
    name: k8s-certs
  - hostPath:
      path: /etc/kubernetes/controller-manager.conf
      type: FileOrCreate
    name: kubeconfig
  - hostPath:
      path: /usr/local/share/ca-certificates
      type: DirectoryOrCreate
    name: usr-local-share-ca-certificates
  - hostPath:
      path: /usr/share/ca-certificates
      type: DirectoryOrCreate
    name: usr-share-ca-certificates
```
</div></details>

## Cloud Control Manager
クラウトプロバイダーとリンクするためのもの。オンプレミスで使う場合は不要。

## 補足
<font color="black">上でkubeadmを使った場合と記載しましたが、それ以外に、**サービス**として使う場合はもあります。**各コンポーネントのバイナリが用意されてある**ので、**ダウンロードしてサービスとして実行するだけ**です。</font>

<hr>

# nodeの構成

## Kubelet
k8sクラスターの各ノードに配置されるエージェントです。podのスペックで定義してあるようにコンテナーが動いている事を保証してくれる。

```bash
/usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
                 --kubeconfig=/etc/kubernetes/kubelet.conf \
                 --config=/var/lib/kubelet/config.yaml \
                 --network-plugin=cni \
                 --pod-infra-container-image=k8s.gcr.io/pause:3.2 \
                 --cni-bin-dir=/opt/cni/bin \
                 --cni-conf-dir=/etc/cni/net.d 
```

<details><summary>パラメーターで渡した設定ファイルの中身</summary><div>
kubeletがkube-api-serverと通信するためのユーザー情報（TLS証明書含む）が書かれています。

```yaml
$ cat /etc/kubernetes/kubelet.conf
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: LS0tL....<base64 encoded data>LS0tCg==
    server: https://172.17.0.14:6443 #kube-api-serverの情報
  name: default-cluster
contexts:
- context:
    cluster: default-cluster
    namespace: default
    user: default-auth
  name: default-context
current-context: default-context
preferences: {}
users:
- name: default-auth
  user:
    client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
    client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
```

```/var/lib/kubelet/config.yaml 
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 0s
    enabled: true
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 0s
    cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
resolvConf: /run/systemd/resolve/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 0s
staticPodPath: /etc/kubernetes/manifests # ここにstatic podの定義ファイルが置いてある
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
```
</div></details>

※ **「--cni-conf-dir」のデフォルト値が「/etc/cni/net.d」です**。なので、このパラメーターを指定しなかった場合はが自動的に「--cni-conf-dir=/etc/cni/net.d」とセットされる。

```bash
controlplane $ ls -al /etc/cni/net.d
total 12
drwxr-xr-x 2 root root 4096 Mar  7 04:22 .
drwxr-xr-x 3 root root 4096 Mar  7 04:21 ..
-rw-r--r-- 1 root root  318 Mar  7 04:22 10-weave.conflist

# ここを見るとたくさんのプラグインの中に「weave」を使っている事がわかる。
controlplane $ cat /etc/cni/net.d/10-weave.conflist 
{
    "cniVersion": "0.3.0",
    "name": "weave",
    "plugins": [
        {
            "name": "weave",
            "type": "weave-net",
            "hairpinMode": true
        },
        {
            "type": "portmap",
            "capabilities": {"portMappings": true},
            "snat": true
        }
    ]
}
```

## Kube Proxy
各ノードに配置してあるネットワークプロクシである。
Podとクラスターの各コンポーネントの間に通信できるように各ノードにネットワークルールを作る。
サービスを作成した時に他のノードから通信できるようにVIPを割り当ててくれる。

```bash
/usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf \
                          --hostname-override=node01
```
kube-api-serverに指定した「-service-cluster-ip-range=10.96.0.0/12」の範囲でIPが設定されます。


<details><summary>パラメーターで渡した設定ファイルの中身</summary><div>


```yaml
# controlplane$ kubectl exec kube-proxy-55bw8 -n kube-system -- cat /var/lib/kube-proxy/config.conf
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
  acceptContentTypes: ""
  burst: 0
  contentType: ""
  kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
  qps: 0
clusterCIDR: 10.244.0.0/16 # kube-api-serverに指定した「-service-cluster-ip-range=10.96.0.0/12」の範囲
configSyncPeriod: 0s
conntrack:
  maxPerCore: null
  min: null
  tcpCloseWaitTimeout: null
  tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
  masqueradeAll: false
  masqueradeBit: null
  minSyncPeriod: 0s
  syncPeriod: 0s
ipvs:
  excludeCIDRs: null
  minSyncPeriod: 0s
  scheduler: ""
  strictARP: false
  syncPeriod: 0s
  tcpFinTimeout: 0s
  tcpTimeout: 0s
  udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
  enableDSR: false
  networkName: ""
  sourceVip: ""
```
</div></details>

<details><summary>※実は、「kube-proxy」podの中身を見ると、ConfigMapをマウントしていることが分かる。</summary><div>

```bash
controlplane $ kubectl get pods -A |grep proxy
kube-system   kube-proxy-dgdbc                       1/1     Running   0          106m
kube-system   kube-proxy-tj6bm                       1/1     Running   2          106m


controlplane $ kubectl describe pod kube-proxy-dgdbc -n kube-system
Name:                 kube-proxy-dgdbc
Namespace:            kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Node:                 controlplane/172.17.0.11
Start Time:           Sun, 07 Mar 2021 02:17:54 +0000
Labels:               controller-revision-hash=ff45b7d7d
                      k8s-app=kube-proxy
                      pod-template-generation=1
Annotations:          <none>
Status:               Running
IP:                   172.17.0.11
IPs:
  IP:           172.17.0.11
Controlled By:  DaemonSet/kube-proxy
Containers:
  kube-proxy:
    Container ID:  docker://222569a30d2a14c6e2c132a649420bd14131407f046757a08bfe9aa22b70bd73
    Image:         k8s.gcr.io/kube-proxy:v1.19.0
    Image ID:      docker-pullable://k8s.gcr.io/kube-proxy@sha256:c752ecbd04bc4517168a19323bb60fb45324eee1e480b2b97d3fd6ea0a54f42d
    Port:          <none>
    Host Port:     <none>
    Command:
      /usr/local/bin/kube-proxy
      --config=/var/lib/kube-proxy/config.conf
      --hostname-override=$(NODE_NAME)
    State:          Running
      Started:      Sun, 07 Mar 2021 02:17:55 +0000
    Ready:          True
    Restart Count:  0
    Environment:
      NODE_NAME:   (v1:spec.nodeName)
    Mounts:
      /lib/modules from lib-modules (ro)
      /run/xtables.lock from xtables-lock (rw)
      /var/lib/kube-proxy from kube-proxy (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-proxy-token-dszlh (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-proxy:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      kube-proxy
    Optional:  false
  xtables-lock:
    Type:          HostPath (bare host directory volume)
    Path:          /run/xtables.lock
    HostPathType:  FileOrCreate
  lib-modules:
    Type:          HostPath (bare host directory volume)
    Path:          /lib/modules
    HostPathType:  
  kube-proxy-token-dszlh:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  kube-proxy-token-dszlh
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  kubernetes.io/os=linux
Tolerations:     op=Exists
                 CriticalAddonsOnly op=Exists
                 node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                 node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                 node.kubernetes.io/network-unavailable:NoSchedule op=Exists
                 node.kubernetes.io/not-ready:NoExecute op=Exists
                 node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                 node.kubernetes.io/unreachable:NoExecute op=Exists
                 node.kubernetes.io/unschedulable:NoSchedule op=Exists
Events:          <none>



controlplane $ kubectl describe configmap kube-proxy -n kube-system
Name:         kube-proxy
Namespace:    kube-system
Labels:       app=kube-proxy
Annotations:  kubeadm.kubernetes.io/component-config.hash: sha256:03c1a617b659fb4ef8617f375a89eef168bcd3a0d86f662f1bf20849fce238a9

Data
====
config.conf:
----
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
  acceptContentTypes: ""
  burst: 0
  contentType: ""
  kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
  qps: 0
clusterCIDR: 10.244.0.0/16
configSyncPeriod: 0s
conntrack:
  maxPerCore: null
  min: null
  tcpCloseWaitTimeout: null
  tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
  masqueradeAll: false
  masqueradeBit: null
  minSyncPeriod: 0s
  syncPeriod: 0s
ipvs:
  excludeCIDRs: null
  minSyncPeriod: 0s
  scheduler: ""
  strictARP: false
  syncPeriod: 0s
  tcpFinTimeout: 0s
  tcpTimeout: 0s
  udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
  enableDSR: false
  networkName: ""
  sourceVip: ""
kubeconfig.conf:
----
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    server: https://172.17.0.11:6443
  name: default
contexts:
- context:
    cluster: default
    namespace: default
    user: default
  name: default
current-context: default
users:
- name: default
  user:
    tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
Events:  <none>
```
</div></details>

## Container Runtime
コンテナーを動かすためのランタイムである。Docker以外にcontainered,CRI-O,などサポートしている。

## Addons
クラスターレベルの機能を実装するためのもの。例えば、DaemonSet, Deployement.「kube-system」というnamespaceに所属する。

## DNS
DNSサーバーの事です。


<details><summary>中身チェック</summary><div>

```bash
controlplane $ kubectl get pods -A -o wide -n kube-system
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
default       nginx                                  1/1     Running   0          16m   10.32.0.3     node01         <none>           <none>
kube-system   coredns-f9fd979d6-gt9h2                1/1     Running   2          32m   10.32.0.2     node01         <none>           <none>
kube-system   coredns-f9fd979d6-n5bkk                1/1     Running   0          32m   10.44.0.1     controlplane   <none>           <none>
kube-system   etcd-controlplane                      1/1     Running   0          87m   172.17.0.11   controlplane   <none>           <none>
kube-system   kube-apiserver-controlplane            1/1     Running   0          87m   172.17.0.11   controlplane   <none>           <none>
kube-system   kube-controller-manager-controlplane   1/1     Running   0          87m   172.17.0.11   controlplane   <none>           <none>
kube-system   kube-proxy-dgdbc                       1/1     Running   0          87m   172.17.0.11   controlplane   <none>           <none>
kube-system   kube-proxy-tj6bm                       1/1     Running   2          86m   172.17.0.15   node01         <none>           <none>
kube-system   kube-scheduler-controlplane            1/1     Running   0          87m   172.17.0.11   controlplane   <none>           <none>
kube-system   weave-net-wcsh5                        2/2     Running   3          33m   172.17.0.15   node01         <none>           <none>
kube-system   weave-net-x5zh2                        2/2     Running   1          33m   172.17.0.11   controlplane   <none>           <none>



controlplane $ kubectl logs coredns-f9fd979d6-gt9h2 -n kube-system
.:53
[INFO] plugin/reload: Running configuration MD5 = db32ca3650231d74073ff4cf814959a7
CoreDNS-1.7.0
linux/amd64, go1.14.4, f59c03d


# corednsというConfigMapがマウントされている事に注目
controlplane $ kubectl describe pod coredns-f9fd979d6-gt9h2 -n kube-system
Name:                 coredns-f9fd979d6-gt9h2
Namespace:            kube-system
Priority:             2000000000
Priority Class Name:  system-cluster-critical
Node:                 node01/172.17.0.15
Start Time:           Sun, 07 Mar 2021 03:12:45 +0000
Labels:               k8s-app=kube-dns
                      pod-template-hash=f9fd979d6
Annotations:          <none>
Status:               Running
IP:                   10.32.0.2
IPs:
  IP:           10.32.0.2
Controlled By:  ReplicaSet/coredns-f9fd979d6
Containers:
  coredns:
    Container ID:  docker://883a8b5d3e52f30990132ad757185eeea8298b27db3a04d7e0a72ae3e83f7afb
    Image:         k8s.gcr.io/coredns:1.7.0
    Image ID:      docker-pullable://k8s.gcr.io/coredns@sha256:73ca82b4ce829766d4f1f10947c3a338888f876fbed0540dc849c89ff256e90c
    Ports:         53/UDP, 53/TCP, 9153/TCP
    Host Ports:    0/UDP, 0/TCP, 0/TCP
    Args:
      -conf
      /etc/coredns/Corefile
    State:          Running
      Started:      Sun, 07 Mar 2021 03:13:52 +0000
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Sun, 07 Mar 2021 03:13:27 +0000
      Finished:     Sun, 07 Mar 2021 03:13:37 +0000
    Ready:          True
    Restart Count:  2
    Limits:
      memory:  170Mi
    Requests:
      cpu:        100m
      memory:     70Mi
    Liveness:     http-get http://:8080/health delay=60s timeout=5s period=10s #success=1 #failure=5
    Readiness:    http-get http://:8181/ready delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:  <none>
    Mounts:
      /etc/coredns from config-volume (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from coredns-token-6vm22 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  config-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      coredns # ここに注目！！
    Optional:  false
  coredns-token-6vm22:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  coredns-token-6vm22
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  kubernetes.io/os=linux
Tolerations:     CriticalAddonsOnly op=Exists
                 node-role.kubernetes.io/master:NoSchedule
                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason          Age                From               Message
  ----     ------          ----               ----               -------
  Normal   Scheduled       44m                default-scheduler  Successfully assigned kube-system/coredns-f9fd979d6-gt9h2 to node01
  Warning  Unhealthy       43m (x2 over 43m)  kubelet, node01    Readiness probe failed: Get "http://10.32.0.2:8181/ready": dial tcp 10.32.0.2:8181: connect: connection refused
  Normal   Killing         43m (x2 over 43m)  kubelet, node01    Stopping container coredns
  Normal   SandboxChanged  43m (x6 over 43m)  kubelet, node01    Pod sandbox changed, it will be killed and re-created.
  Normal   Pulled          43m (x3 over 44m)  kubelet, node01    Container image "k8s.gcr.io/coredns:1.7.0" already present on machine
  Normal   Created         43m (x3 over 44m)  kubelet, node01    Created container coredns
  Normal   Started         43m (x3 over 44m)  kubelet, node01    Started container coredns



controlplane $ kubectl get configmaps -n kube-system
NAME                                 DATA   AGE
coredns                              1      88m
extension-apiserver-authentication   6      88m
kube-proxy                           2      88m
kubeadm-config                       2      88m
kubelet-config-1.19                  1      88m
weave-net                            0      33m


controlplane $ kubectl describe configmap coredns -n kube-system
Name:         coredns
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>

Data
====
Corefile:
----
.:53 {
    errors
    health {
       lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
       ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf {
       max_concurrent 1000
    }
    cache 30
    loop
    reload
    loadbalance
}

Events:  <none>
```
</div></details>

## Web UI (Dashboard)
クラスター管理するためのウエブUI。

## Container Resource Monitoring
コンテナーに関する時系列メトリックをDBに保管し、そのデータを閲覧するためのUIを提供する要素。

## Cluster Level Logging
コンテナーのログを保管し、参照できるインタフェースを提供する要素。

<hr>

# Pod
## podの作成①
```my-pod-definition.yml
apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-command
spec:
  containers:
  - name: command-demo-container
    image: debian
    command: ["printenv"]
    args: ["HOSTNAME", "KUBERNETES_PORT"]
  restartPolicy: OnFailure
```

```bash
kubectl create -f my-pod-definition.yml
```

## podの編集①
my-pod-definition.ymlを開き変更を加えます。その後applyを使って反映

```bash
kubectl apply -f my-pod-definition.yml
```

## podの削除①
```bash
kubectl delete -f my-pod-definition.yml
```

---
**※ 上記のようにファイルに定義しないでコマンド実行することでPodの様々な操作が可能。**
## podの作成②
```bash
# nginxを使った「my-pod」というpodを作成
kubectl run my-pod --image=nginx

# コンテナー起動時のコマンドとポートを開けた状態のpodを作成
kubectl run alpine --image=alpine --port=8080 --command -- sleep 5000

# Podとサービスを一気に作成
kubectl run alpine --image=alpine --port=8080 --expose --command -- sleep 5000
```
<font color="blue">※--command=falseにするとargsとして登録されます。詳しくは***kubectl run --help***にて～</font>

**※ podを作成する場合は、以下のように定義ファイルを作成してから編集するのをお勧めする。**

```bash
kubectl run my-pod --image=nginx --replicas=2 --dry-run=client -o yaml > my-pod-definition.yml
```
<font color="red">Podを作成せずに定義ファイルを作ってくれるので、その後ファイルを編集するのが安心できるかも！！</font>


## podの編集②
```bash
kubectl edit pod <pod-name>
```

## podの削除②
```bash
kubectl delete pod <pod-name>
```

## podの情報取得
```bash
# default namespaceのすべてのpodを表示（-A or --all-namespaces追加することですべてのnamespace）
kubectl get pods

# 特定のpodの情報を取得
kubectl get pod my-pod

# 特定のpodの情報を取得
kubectl describe pod my-pod

# grepを使って必要な情報だけ取得することも可
kubectl describe pod ubuntu-sleeper | grep -i image -A1
    Image:         ubuntu
    Image ID:      docker-pullable://ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715
    Port:          <none>

# ちなみにこんなこともできるよ♪
kubectl get pods -o custom-columns=POD:.metadata.name,CONT:.spec.containers[0].name,IMG:.spec.containers[0].image
POD                CONT           IMG
ubuntu-sleeper     ubuntu         ubuntu
ubuntu-sleeper-2   ubuntu         ubuntu
ubuntu-sleeper-3   ubuntu         ubuntu
```
<font color="blue">※ 詳しくは、***kubectl get pod --help***</font>

## ログの表示
```bash
# 特定のpodのログを表示
kubectl logs <pod-name>

# 複数コンテナーがある場合はコンテナーの指定が必要
kubectl logs <pod-name> -c <container-name>
```
<font color="blue"><sub>※1つのPodに複数のコンテナーがある場合は「kubectl logs <pod-name> -c」入力してからTABキーを押すとコンテナー名が表示される。</sub></font>

## SSH to pod
```bash
# コマンド実行のみ
kubectl exec <pod-name> -- command

# interactiveモード
kubectl exec <pod-name> -it -- sh
```


---
# Replicaset
```replicaset-def.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend-rs
  labels:
    app: guestbook
    tier: frontend
spec:
  replicas: 3
  # selectorがReplicationControllerには存在しない！！
  selector:
    matchLabels:
      tier: frontend
  # ここからのしたはpodの定義（apiVersionとKindを抜いたもの）
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
```

- ReplicationControllerは古い仕様で現在は<ins>**非推奨**</ins>となっている
- ReplicationControllerには「selector」が存在しない
- ReplicaSetはこの定義ファイルで設定していないpodも指定できる仕様になっている。そのためselector.matchlabelsを使う


```bash
# ReplicaSetの一覧を取得
kubectl get replicasets # OR kubectl get rs

# 特定のRelicaSetの詳細情報
kubectl describe rs frontend-rs

# ReplicaSetの変更
kubectl replace -f replicaset-def.yml

# ReplicaSetの変更（変更できる項目が限られる）
kubectl edit rs frontend-rs

# Replicasの変更（ファイル指定）
kubectl scale --replicas=2 -f replicaset-def.yml

# Replicasの変更（レプリカ名指定）
kubectl scale --replicas=2 replicaset frontend-rs
```

# Deployment
```deploy-def.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2    
```

```bash
$ kubectl create -f deploy-def.yml 
deployment.apps/nginx-deployment created
```
- ReplicaSetの定義をほとんど変わらない（kind＝Deployment＆kind=ReplicaSet)
- 実は、RelicaSetのオブジェクトを作ってからDeploymentオブジェクトを作ります（そのため、deployment実行後、「kubectl get replicasets」を実行するとReplicaSet作られたことが確認できます。
- Deploymentの場合は「replicas」プロパティが任意です（つまり指定しなくてもいい；デフォルト値=1があるため）


```bash
$ kubectl get all
NAME                                   READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-877f48f6d-7mnsw   1/1     Running   0          49s
pod/nginx-deployment-877f48f6d-9t7tk   1/1     Running   0          49s
pod/nginx-deployment-877f48f6d-n6bgf   1/1     Running   0          49s

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

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   3/3     3            3           49s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-877f48f6d   3         3         3       49s

$ kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out
```

## Deploymentの編集
podのテンプレートの部分以外変更してもDeploymentのROが実行されない。
> Note: A Deployment's rollout is triggered if and only if the Deployment's Pod template (that is, .spec.template) is changed, for example if the labels or container images of the template are updated. Other updates, such as scaling the Deployment, do not trigger a rollout.

```bash
# 設定ファイルの中身がエディターで開かれます
kubectl edit deployment nginx-deployment

# コマンドを実行するだけでも可
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
```

## Deploymentの履歴の確認
```bash
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
```

※コマンドで変更をした時に**--record**引数を付けると、その時のコマンドも記録してくれます。

```bash
# 「nginx=nginx:1.16.2」の先頭のnginxはコンテナー名
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.2 --record
deployment.apps/nginx-deployment image updated

$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment/nginx-deployment nginx=nginx:1.16.2 --record=true
```


または、変更後、以下のようにアノテーションを付ける事も可能！

```bash
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.2"
```

## Deploymentの履歴（Revision）から詳細情報の確認
```bash
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
```

## RollBack
### 直前のバージョンに戻す
```bash
$ kubectl rollout undo deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment rolled back
```

### リビジョン番号を指定して戻す
```bash
# 現在のimageの確認
$ kubectl describe deployment nginx-deployment |grep -i image
                        kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.14.2 --record=true
    Image:        nginx:1.14.2


# リビジョンの一覧を指定
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
2         kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
3         kubectl set image deployment nginx-deployment nginx=nginx:1.14.2 --record=true



# 戻したいリビジョンの中身を確認
$ kubectl rollout history deployment nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
  Labels:       app=nginx
        pod-template-hash=7bb7dc4b6b
  Annotations:  kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
  Containers:
   nginx:
    Image:      nginx:1.16.2
    Port:       <none>
    Host Port:  <none>
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>



# Rollback
$ kubectl rollout undo deployment nginx-deployment --to-revision=2
deployment.apps/nginx-deployment rolled back



# 現在のimageの確認
$ kubectl describe deployment nginx-deployment |grep -i image
                        kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
    Image:        nginx:1.16.2

```

## Scale Deployment
```bash
$ kubectl scale deployment nginx-deployment --replicas=10
deployment.apps/nginx-deployment scaled

# CPUの利用状況に応じて勝手にスケーリングする事も可能
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled

$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>

```
※scaleしても履歴には反映されません。理由は上でも記載しましたが、「.spec.template」以外の変更はDeployment Rolloutとしてみなされないためです。

## Deployment Strategy(デプロイの戦略）
2種類ある。
### ①Recreate
既存のpodがすべてkillしてから新しく作る戦略。

```yaml
spec:
  replicas: 3
  strategy:
    type: Recreate
```

### ②RollingUpdate
一気にすべて削除するのではなく、部分的にkillし、新しいpodを作成する戦略。

```yaml
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0  # どれぐらいのpodが起動していればdeploymentを続けるかの戦略
                         # podの個数でもOK、個数のパーセンテージでもOK
                         # defalut=25%（0を指定してもデフォルト値になる）
                         # 例、30%が設定された場合
                         # maxUnavailable=30%とは、AVAILABLE=70%となる
                         #　つまり、70％のpodが起動していれば、ほかのpodをkillしてUpdateが可能
                         # 今度Updateされた分を入れて70%を起動すればほかのpodをkillする事が可能

      maxSurge: 2        # 一回にどれぐらいの新しいpodを作るかの戦略
                         # podの個数でもOK、個数のパーセンテージでもOK
                         # defalut=25%（0を指定してもデフォルト値になる）
                         # 例、30%が設定された場合
                         # 古いと新しいpodの数がDesired pod数の130%まで作成可能
                         # 古いpodを削除し、また130%なるように新しいpodを作成する
      # maxUnavailableとmaxSurge両方ゼロに設定してはいけません！
```

## コマンドを叩いてデプロイする方法 (Imperative Way)
```bash
kubectl create deployment webapp --image=nginx --replicas=3 --dry-run=client -o yaml
```

<details><summary>「kubectl create deployment」の使い方</summary><div>

```bash
$ kubectl create deployment --help
Create a deployment with the specified name.

Aliases:
deployment, deploy

Examples:
  # Create a deployment named my-dep that runs the busybox image.
  kubectl create deployment my-dep --image=busybox
  
  # Create a deployment with command
  kubectl create deployment my-dep --image=busybox -- date
  
  # Create a deployment named my-dep that runs the nginx image with 3 replicas.
  kubectl create deployment my-dep --image=nginx --replicas=3
  
  # Create a deployment named my-dep that runs the busybox image and expose port 5701.
  kubectl create deployment my-dep --image=busybox --port=5701

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or
map key is missing in the template. Only applies to golang and jsonpath output formats.
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the
object that would be sent, without sending it. If server strategy, submit server-side request
without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
      --image=[]: Image names to run.
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --port=-1: The port that this container exposes.
  -r, --replicas=1: Number of replicas to create. Default is 1.
      --save-config=false: If true, the configuration of current object will be saved in its
annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to
perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template,
-o=go-template-file. The template format is golang templates
[http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create deployment NAME --image=image -- [COMMAND] [args...] [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
```
</div></details>


## コマンドを叩いてデプロイする方法 (Imperative Way)
```bash
# Create a service redis-service to expose the redis application within the cluster on port 6379.
kubectl expose pod redis --port=6379 --type=ClusterIP --name=redis-service --dry-run=client -o yaml
```

<details><summary>「kubectl expose」の使い方</summary><div>

```
$ kubectl expose --help
Expose a resource as a new Kubernetes service.

 Looks up a deployment, service, replica set, replication controller or pod by name and uses the
selector for that resource as the selector for a new service on the specified port. A deployment or
replica set will be exposed as a service only if its selector is convertible to a selector that
service supports, i.e. when the selector contains only the matchLabels component. Note that if no
port is specified via --port and the exposed resource has multiple ports, all will be re-used by the
new service. Also if no labels are specified, the new service will re-use the labels from the
resource it exposes.

 Possible resources include (case insensitive):

 pod (po), service (svc), replicationcontroller (rc), deployment (deploy), replicaset (rs)

Examples:
  # Create a service for a replicated nginx, which serves on port 80 and connects to the containers
on port 8000.
  kubectl expose rc nginx --port=80 --target-port=8000
  
  # Create a service for a replication controller identified by type and name specified in
"nginx-controller.yaml", which serves on port 80 and connects to the containers on port 8000.
  kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000
  
  # Create a service for a pod valid-pod, which serves on port 444 with the name "frontend"
  kubectl expose pod valid-pod --port=444 --name=frontend
  
  # Create a second service based on the above service, exposing the container port 8443 as port 443
with the name "nginx-https"
  kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https
  
  # Create a service for a replicated streaming application on port 4100 balancing UDP traffic and
named 'video-stream'.
  kubectl expose rc streamer --port=4100 --protocol=UDP --name=video-stream
  
  # Create a service for a replicated nginx using replica set, which serves on port 80 and connects
to the containers on port 8000.
  kubectl expose rs nginx --port=80 --target-port=8000
  
  # Create a service for an nginx deployment, which serves on port 80 and connects to the containers
on port 8000.
  kubectl expose deployment nginx --port=80 --target-port=8000

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or
map key is missing in the template. Only applies to golang and jsonpath output formats.
      --cluster-ip='': ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set
to 'None' to create a headless service.
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the
object that would be sent, without sending it. If server strategy, submit server-side request
without persisting the resource.
      --external-ip='': Additional external IP address (not managed by Kubernetes) to accept for the
service. If this IP is routed to a node, the service can be accessed by this IP in addition to its
generated service IP.
      --field-manager='kubectl-expose': Name of the manager used to track field ownership.
  -f, --filename=[]: Filename, directory, or URL to files identifying the resource to expose a
service
      --generator='service/v2': The name of the API generator to use. There are 2 generators:
'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named
'default', while it is left unnamed in v2. Default is 'service/v2'.
  -k, --kustomize='': Process the kustomization directory. This flag can't be used together with -f
or -R.
  -l, --labels='': Labels to apply to the service created by this call.
      --load-balancer-ip='': IP to assign to the LoadBalancer. If empty, an ephemeral IP will be
created and used (cloud-provider specific).
      --name='': The name for the newly created object.
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --overrides='': An inline JSON override for the generated object. If this is non-empty, it is
used to override the generated object. Requires that the object supply a valid apiVersion field.
      --port='': The port that the service should serve on. Copied from the resource being exposed,
if unspecified
      --protocol='': The network protocol for the service to be created. Default is 'TCP'.
      --record=false: Record current kubectl command in the resource annotation. If set to false, do
not record the command. If set to true, record the command. If not set, default to updating the
existing annotation value only if one already exists.
  -R, --recursive=false: Process the directory used in -f, --filename recursively. Useful when you
want to manage related manifests organized within the same directory.
      --save-config=false: If true, the configuration of current object will be saved in its
annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to
perform kubectl apply on this object in the future.
      --selector='': A label selector to use for this service. Only equality-based selector
requirements are supported. If empty (the default) infer the selector from the replication
controller or replica set.)
      --session-affinity='': If non-empty, set the session affinity for the service to this; legal
values: 'None', 'ClientIP'
      --target-port='': Name or number for the port on the container that the service should direct
traffic to. Optional.
      --template='': Template string or path to template file to use when -o=go-template,
-o=go-template-file. The template format is golang templates
[http://golang.org/pkg/text/template/#pkg-overview].
      --type='': Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default
is 'ClusterIP'.

Usage:
  kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP]
[--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]
[options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
```
</div></details>

ちなみに上記の場合は「redis」podがすでに存在している前提です。以下のようにpodとサービスを1つのコマンドを実行して作ることも可能です。redis名前のpodとredis名前のサービスが作られる。

```bash
kubectl run redis --image=redis --port=6379 --expose
```

---
TODO - 下記のついては追って記載する。

- DaemonSet

---

# Service
podがいつ終了し、再作成されるかわからない。再生されるたびにIPアドレスが変わる可能性がある。１つのpodから別のpodへipアドレスでアクセスすると、ipが変われば使えなくなる。そのあたりをDNS名を利用し、podが再作成されてもアクセスできるようにするのがこの「service」という仕組み。podが何個作成されても１つのサービス名でアクセスできる。１つのIPアドレスをクラスタ内に公開し、そこにアクセスされたら、あらかじめ設定したルールに沿ってpodに転送するからくりです。
クラスタに公開する方法として下記4種類がある。

- ClusterIp
- NodePort
- LoadBalancer
- ExternalName


## ClusterIP
ClusterIPは、クラスタ内からのみアクセスできるIPアドレスを公開する。これはデフォルトのサービスタイプです。

```clusterip-def.yml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
```

## NodePort
nodeの特定のポートを公開し、そこで受けたアクセスをpodに転送してくれる。

```nodeport-def.yml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
      # By default and for convenience, the `targetPort` is set to the same value as the `port` field.
    - port: 80
      targetPort: 80
      # Optional field
      # By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
      nodePort: 30007
```

## Loadbalancer
各サービスをパブリックIPを使って公開する仕組みです。

```loadbalancer-def.yml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127
```

ここから下はハンズオンの形にしたい。そっちのほうが分かりやすいと思う！！

先ずは、以下のリソースを作成します。

- 複数ノードに配置されるアプリケーション「my-deployment」
- ClusterIpを使ったサービス「clusterip-service-to-nginx-deployment」
- NodePortを使ったサービス「nodeport-service-to-nginx-deployment」
- テスト用のpod「nginx-node1 」


```bash
$ kubectl get all -o wide --show-labels
NAME                                 READY   STATUS    RESTARTS   AGE   IP          NODE     NOMINATED NODE   READINESS GATES   LABELS
pod/my-deployment-57d86476b6-75c2w   1/1     Running   0          17m   10.40.0.3   node02   <none>           <none>            app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-dhnm7   1/1     Running   0          17m   10.46.0.3   node01   <none>           <none>            app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-htrfk   1/1     Running   0          17m   10.32.0.3   node03   <none>           <none>            app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-shlb9   1/1     Running   0          17m   10.46.0.2   node01   <none>           <none>            app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-twn4s   1/1     Running   0          17m   10.32.0.2   node03   <none>           <none>            app=my-deployment,pod-template-hash=57d86476b6
pod/nginx-node1                      1/1     Running   0          39m   10.46.0.1   node01   <none>           <none>            node=node01,tier=frontend

NAME                                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE     SELECTOR            LABELS
service/clusterip-service-to-nginx-deployment   ClusterIP   10.106.173.106   <none>        8080/TCP         5m31s   app=my-deployment   app=clusterip-service-to-nginx-deployment
service/kubernetes                              ClusterIP   10.96.0.1        <none>        443/TCP          47m     <none>              component=apiserver,provider=kubernetes
service/nodeport-service-to-nginx-deployment    NodePort    10.103.219.247   <none>        8080:31592/TCP   11m     app=my-deployment   app=nodeport-service-to-nginx-deployment

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR            LABELS
deployment.apps/my-deployment   5/5     5            5           17m   nginx        nginx    app=my-deployment   app=my-deployment

NAME                                       DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR                                         LABELS
replicaset.apps/my-deployment-57d86476b6   5         5         5       17m   nginx        nginx    app=my-deployment,pod-template-hash=57d86476b6   app=my-deployment,pod-template-hash=57d86476b6
```
上記の状態でテスト用のpod「nginx-node1」から通信できるかテストしてみます。

```bash
# NodePortを使って通信
$ kubectl exec nginx-node1 -- curl http://nodeport-service-to-nginx-deployment:8080
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
<!DOCTYPE html>
<html>
<head>
...
省略


# ClusterIPを使って通信
$ kubectl exec nginx-node1 -- curl http://clusterip-service-to-nginx-deployment:8080
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   612  100   612    0     0    99k      0 --:--:-- --:--:-- --:--:--   99k
<!DOCTYPE html>
<html>
...
省略
```
どちらでも問題なくアクセスできてます。**このようにpodをほかからアクセスできるようにする仕組みがサービス**です。

しかし、クラスターの外からアクセスすると通信ができません。

```bash
# NodePortを使って通信
$ curl http://nodeport-service-to-nginx-deployment:8080
curl: (6) Could not resolve host: nodeport-service-to-nginx-deployment

# ClusterIPを使って通信
$ curl http://clusterip-service-to-nginx-deployment:8080
curl: (6) Could not resolve host: clusterip-service-to-nginx-deployment
```

この時にNodePortの仕組みを利用すれば、実は外からも通信できます。

```bash
# 公開ポート(=31592)の確認
$ kubectl get svc nodeport-service-to-nginx-deployment -o wide
NAME                                   TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE   SELECTOR
nodeport-service-to-nginx-deployment   NodePort   10.103.219.247   <none>        8080:31592/TCP   27m   app=my-deployment

# 各ノードのIPアドレス確認
controlplane $ kubectl get nodes -o wide
NAME           STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
controlplane   Ready    master   49m   v1.19.0   172.17.0.12   <none>        Ubuntu 18.04.5 LTS   4.15.0-122-generic   docker://19.3.13
node01         Ready    <none>   49m   v1.19.0   172.17.0.13   <none>        Ubuntu 18.04.5 LTS   4.15.0-122-generic   docker://19.3.13
node02         Ready    <none>   49m   v1.19.0   172.17.0.15   <none>        Ubuntu 18.04.5 LTS   4.15.0-122-generic   docker://19.3.13
node03         Ready    <none>   49m   v1.19.0   172.17.0.24   <none>        Ubuntu 18.04.5 LTS   4.15.0-122-generic   docker://19.3.13

# node01のアプリケーションと通信（http://<node-ip>:31592）
$ curl http://172.17.0.13:31592
<!DOCTYPE html>
...
省略

# node02のアプリケーションと通信（http://<node-ip>:31592）
$ curl http://172.17.0.15:31592
<!DOCTYPE html>
...
省略

# node03のアプリケーションと通信（http://<node-ip>:31592）
$ curl http://172.17.0.24:31592
<!DOCTYPE html>
...
省略
```

<font color="red">ポート番号は、kube-api-serverを起動する時に指定した「--service-node-port-range」の値の範囲内に指定する必要があります。kube-api-serverに指定しなかった場合は、デフォルトで30000-32767が設定されます。</font>

でも、ノードのIP指定しないといけないのが不便ですよね。
これを解決するために「LoadBalancer」があります。

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

```
**クラスター外からアクセスできるIPアドレスが各サービスに設定されます。そのため、複数サービスを利用したい場合はその数のIPアドレスが必要です。**クラウド上で利用した場合はIPアドレスの購入が必要かもしれません。

これらの３つのサービスをまとめると

- clusterip: クラスター外からアクセスができない
- nodeport: クラスター外からアクセスできるが、ノードのIPを指定する必要がある
- loadbalancer: ノードのIPを気にしなくて済むが、サービスが複数ある場合はコストが高い

ここで登場するのが**INGRESS**様だ！

## Ingress

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80
```
Ingress 使うには下記が必要

- アプリケーション
- アプリケーション公開用サービス
- Ingressコントローラー
- Ingress
- 

```bash
# applications
app-space       pod/webapp-video-84f8655bd8-g6wtw          1/1     Running   0          29m
app-space       pod/webapp-wear-6ff9445955-jfwkp           1/1     Running   0          29m

# service
ingress-space   service/ingress                NodePort    10.108.18.119    <none>        80:30080/TCP             10m

# Ingress Controller
ingress-space   deployment.apps/ingress-controller   1/1     1            1           21m
ingress-space   pod/ingress-controller-5857685bf-qzvdr     1/1     Running   0          21m

# Ingress resource
app-space   ingress-weear-watch-my   <none>   *                 80      3m42s
```

詳細：[公式サイトにて](https://kubernetes.io/docs/concepts/services-networking/ingress/)


---
<details><summary></summary><div>

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pvviewer
automountServiceAccountToken: false

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pvviewer-role
rules:
- apiGroups: [""]
  resources: ["PersistentVolumes"]
  verbs: ["list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pvviewer-role-binding
subjects:
- kind: ServiceAccount
  name: pvview
  namespace: default
roleRef:
  kind: ClusterRole
  name: pvviewer-role
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: v1
kind: Pod
metadata:
  name: pvviewer
spec:
  serviceAccountName: pvviewer
  automountServiceAccountToken: false
  containers:
  - name: redis
    image: redis
```

## jsonpath
```bash

# get the list of private volumes
$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-log-1   100Mi      RWX            Retain           Available                                   23m
pv-log-2   200Mi      RWX            Retain           Available                                   23m
pv-log-3   300Mi      RWX            Retain           Available                                   23m
pv-log-4   40Mi       RWX            Retain           Available                                   23m

# first check the json format
$ kubectl get pv -o=json                                      
{
    "apiVersion": "v1",
    "items": [
        {
            "apiVersion": "v1",
...
省略

# get the value for single pv
$ kubectl get pv pv-log-1 -o=jsonpath='{.spec.capacity.storage}{"\n"}'
100Mi

# get the value for all pv
$ kubectl get pv -o=jsonpath='{..spec.capacity.storage}{"\n"}'
100Mi 200Mi 300Mi 40Mi
```


```bash
# first check the item in loop
$ kubectl get pv -o=jsonpath='{range .items[0]} {@} {end}{"\n"}'
{"apiVersion":"v1","kind":"PersistentVolume","metadata":{"creationTimestamp":"2021-03-09T13:10:51Z","finalizers":["kubernetes.io/pv-protection"],"managedFields":[{"apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}},"manager":"kube-controller-manager","operation":"Update","time":"2021-03-09T13:10:51Z"},{"apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:accessModes":{},"f:capacity":{".":{},"f:storage":{}},"f:hostPath":{".":{},"f:path":{},"f:type":{}},"f:persistentVolumeReclaimPolicy":{},"f:volumeMode":{}}},"manager":"kubectl-create","operation":"Update","time":"2021-03-09T13:10:51Z"}],"name":"pv-log-1","resourceVersion":"4586","selfLink":"/api/v1/persistentvolumes/pv-log-1","uid":"6191ac63-c32f-4bce-9cee-1ed4892216d0"},"spec":{"accessModes":["ReadWriteMany"],"capacity":{"storage":"100Mi"},"hostPath":{"path":"/pv/log","type":""},"persistentVolumeReclaimPolicy":"Retain","volumeMode":"Filesystem"},"status":{"phase":"Available"}} 

$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec} {end}{"\n"}'
 {"accessModes":["ReadWriteMany"],"capacity":{"storage":"100Mi"},"hostPath":{"path":"/pv/log","type":""},"persistentVolumeReclaimPolicy":"Retain","volumeMode":"Filesystem"} 

# then, search the specific item
$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec.capacity} {end}{"\n"}'
 {"storage":"100Mi"} 

$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec.capacity.storage} {end}{"\n"}'
 100Mi 

# if the item is found, then run the loop for all items
$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {end}{"\n"}'
 100Mi  200Mi  300Mi  40Mi 

$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {"\n"}{end}{"\n"}'
 100Mi 
 200Mi 
 300Mi 
 40Mi 

# sort
$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {"\n"}{end}{"\n"}' --sort-by=.spec.capacity.storage
 40Mi 
 100Mi 
 200Mi 
 300Mi 
```

Another way

```bash
$ kubectl get pv -o=custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage --sort-by=.spec.capacity.storage
NAME       CAPACITY
pv-log-4   40Mi
pv-log-1   100Mi
pv-log-2   200Mi
pv-log-3   300Mi
```


Filtering

```bash
$ kubectl config view --kubeconfig=my-kube-config 
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: KUBE_ADDRESS
  name: development
...
省略
contexts:
- context:
    cluster: kubernetes-on-aws
    user: aws-user
  name: aws-user@kubernetes-on-aws
- context:
    cluster: test-cluster-1
    user: dev-user
  name: research
- context:
    cluster: development
    user: test-user
  name: test-user@development
...
省略

$ kubectl config view --kubeconfig=my-kube-config -o=jsonpath='{.contexts[?(@.context.user=="aws-user")].name}'
aws-user@kubernetes-on-aws
```

## 補足
もし、jqコマンドが使えるなら要素探すのが楽です！！

```bash
kubectl get pv -o json | jq -c 'path(..)|[.[]|tostring]|join(".")'
""
"apiVersion"
"items"
"items.0"
"items.0.apiVersion"
"items.0.kind"
"items.0.metadata"
"items.0.metadata.creationTimestamp"
"items.0.metadata.finalizers"
"items.0.metadata.finalizers.0"
"items.0.metadata.managedFields"
...
省略

# grep を使うと探したい要素のパスが簡単に見つけられる
$ kubectl get pv -o json | jq -c 'path(..)|[.[]|tostring]|join(".")' |grep storage
"items.0.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.0.spec.capacity.storage"
"items.1.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.1.spec.capacity.storage"
"items.2.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.2.spec.capacity.storage"
"items.3.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.3.spec.capacity.storage"
```

[詳細は公式サイトにて](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#viewing-finding-resources)

</div></details>