kubectlチートシート

# kubectl run関連

## 新しいpodで対話的シェルを起動

```
kubectl run <DEPLOYMENT NAME/POD NAME PREFIX> --image=<IMAGE>:<TAG> <CMD>
```

Alpine LinuxのEdgeでshを起動するなら以下のようにする

```
$ kubectl run mypod --tty -i --image=alpine:edge sh
```

C-d等で抜けたあともコンテナは起動し続ける。`run mypod`の結果、`mypod`というdeploymentと、`mypod-ランダムな文字列`というpodが作られている。

```
$ kubectl get deployments
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mypod     1         1         1            1           29m
nslkup    1         1         1            0           1m
```

```
$ kubectl get po
```

## kubectl run --overridesでNET_ADMINをつける

```
$ kubectl run -it --restart=Never --image=gcr.io/google-containers/ubuntu-slim:0.14 netadm-test --overrides '
{
  "spec": {
    "hostNetwork": true,
    "containers":[
      {
        "args": ["/bin/bash"],
        "stdin": true,
        "tty": true,
        "name": "netadm-test",
        "image": "gcr.io/google-containers/ubuntu-slim:0.14",
        "securityContext": {
          "capabilities": {
            "add": ["NET_ADMIN"]
          }
        }
      }
    ]
  }
}' -- /bin/bash
```

```
iptables-save
```

## kubectl run --overridesでpodのホスト名、サブドメイン等を指定する

```
$ kubectl run -it --image alpine:3.4 alpine --overrides '{"spec":{"template":{"spec":{"hostname":"foo","subdomain":"bar"}}}}' -- sh

/ # nslookup foo.bar.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve

Name:      foo.bar.default.svc.cluster.local
Address 1: 172.17.0.23 foo.bar.default.svc.cluster.local

/ # hostname
foo

/ # hostname -f
foo.bar.default.svc.cluster.local
```

## kubectl run --overridesでenvFromを指定する

Ref: https://github.com/kubernetes/kubernetes/issues/48361#issuecomment-342810925

```
kubectl run ubuntu --overrides='
{
      "spec": {
        "containers": [
          {
            "name": "app",
            "image": "ubuntu",
            "envFrom": [
              {
                "configMapRef": {
                  "name": "config-env"
                }
              },
              {
                "secretRef": {
                  "name": "secret-env"
                }
              }
            ]
          }
        ]
      }
}
'  --image=ubuntu --restart=Never --dry-run -o yaml -- bash -c "sleep 3 && env"
```

## AWS: kubectl runでIAMロールを割り当てる

※kube2iamやkiamがクラスタにインストールされている前提

````
pod=iamtest-$(date +%s)
role=k8s-managed-service-role

kubectl run -it --restart=Never --namespace kube-system \
  --image=kubeaws/awscli:0.9.0 $pod \
  --overrides '{"metadata":{"annotations":{"iam.amazonaws.com/role":"'$role'"}}}' -- bash
iamtest
```

起動したシェル上で`aws ec2 describe-instances --region ap-northeast-1`などを実行して、IAMロールが想定どおり割り当てられているかを確認できる。

# kubectl exec関連

## 実行中のpodで任意のコマンドを実行

```
# kubectl exec <POD NAME> <CMD>
kubectl exec mypod-1315135266-ceh0x echo hello world
```

応用すると、任意のpodでシェルを起動して、環境変数、ネットワーク、ファイル等を確認しながらデバッグできる。

```
# kubectl exec -it デバッグしたいpod名 sh
```

# pod一般

## podの削除

```
kubectl delete po(d) <POD NAME>
```

POD NAMEはget poなどで確認できる。

```
$ kubectl get po
NAME                     READY     STATUS    RESTARTS   AGE
mypod-1315135266-ceh0x   1/1       Running   1          20m
mysql-omsvn              1/1       Running   0          28m
$ kubectl delete po mypod-1315135266-ceh0x
pod "mypod-1315135266-ceh0x" deleted
```

## 実行中のpod一覧を得る

```
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
mypod-1315135266-ceh0x   1/1       Running   1          5m
```

## 特定DaemonSetやDeploymentのPodをすべて再起動

一気に再起動していいのであれば、以下のようにpodを削除してしまえばOK。削除したPodはDaemonSetやDeploymentによって再起動されるから。

```
$ kubectl delete pod $(k get po | grep fluentd | cut -d ' ' -f 1)
```

sleepを入れる場合は以下のようにする。

```
for pod in $(k get po | grep fluentd | cut -d ' ' -f 1); do
  k delete pod $pod
  sleep 3
done
```

# クラスタ全体

## 全ネームスペースのPod一覧

default以外のnamespaceも使っている場合は、`--all-namespaces`で全ネームスペース横断

```
$ kubectl get pods --all-namespaces
NAMESPACE   NAME                     READY     STATUS    RESTARTS   AGE
default     mypod-1315135266-ceh0x   1/1       Running   1          12m
default     mysql-omsvn              1/1       Running   0          19m
```

`-o wide`でそのpodがいるNodeも出る

```
$ kubectl get pods --all-namespaces -o wide
NAMESPACE   NAME                     READY     STATUS    RESTARTS   AGE       NODE
default     mypod-1315135266-ceh0x   1/1       Running   1          13m       default
default     mysql-omsvn              1/1       Running   0          21m       default
```

## 全ネームスペースのsvc一覧

`--all-namespaces`をつけると、k8sクラスタ自体の機能を構成するサービスも見える。以下だと`kube-dns`

```
$ kubectl get --all-namespaces svc
NAMESPACE     NAME         CLUSTER-IP    EXTERNAL-IP   PORT(S)         AGE
default       kubernetes   10.1.30.1     <none>        443/TCP         26m
default       mysql        10.1.30.223   <none>        3306/TCP        24m
kube-system   kube-dns     10.1.30.3     <none>        53/UDP,53/TCP   26m
```

## 複数種類のk8sオブジェクトの一覧をまとめて得る

```
# svc → service
# rc →　replication controller
$ kubectl get svc,pod,rc
NAME                     CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes               10.1.30.1     <none>        443/TCP    19m
mysql                    10.1.30.223   <none>        3306/TCP   17m
NAME                     READY         STATUS        RESTARTS   AGE
mypod-1315135266-ceh0x   1/1           Running       1          10m
mysql-omsvn              1/1           Running       0          17m
NAME                     DESIRED       CURRENT       AGE
mysql                    1             1             17m
```

# jsonpath

## kubectl get po --output jsonでpodのspec, status, metadataデータを見る

これで得られるデータのうち、[Kubernetes - Using the Downward API to Convey Pod Properties](http://kubernetes.io/docs/user-guide/downward-api/)で言及されているものが`fieldRef`等でコンテナの環境変数に渡せる。

```
$ kubectl get po --output json alpine-1094096498-lsxx1
{
    "kind": "Pod",
    "apiVersion": "v1",
    "metadata": {
        "name": "alpine-1094096498-lsxx1",
        "generateName": "alpine-1094096498-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/alpine-1094096498-lsxx1",
        "uid": "12a67f48-590f-11e6-8946-a25f995cc626",
        "resourceVersion": "2407713",
        "creationTimestamp": "2016-08-03T00:13:15Z",
        "labels": {
            "pod-template-hash": "1094096498",
            "run": "alpine"
        },
        "annotations": {
            "kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\",\"namespace\":\"default\",\"name\":\"alpine-1094096498\",\"uid\":\"12a53eaf-590f-11e6-8946-a25f995cc626\",\"apiVersion\":\"extensions\",\"resourceVersion\":\"2407685\"}}\n"
        }
    },
    "spec": {
        "volumes": [
            {
                "name": "default-token-w3x3w",
                "secret": {
                    "secretName": "default-token-w3x3w"
                }
            }
        ],
        "containers": [
            {
                "name": "alpine",
                "image": "alpine:3.4",
                "args": [
                    "sh"
                ],
                "resources": {},
                "volumeMounts": [
                    {
                        "name": "default-token-w3x3w",
                        "readOnly": true,
                        "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
                    }
                ],
                "terminationMessagePath": "/dev/termination-log",
                "imagePullPolicy": "IfNotPresent",
                "stdin": true,
                "tty": true
            }
        ],
        "restartPolicy": "Always",
        "terminationGracePeriodSeconds": 30,
        "dnsPolicy": "ClusterFirst",
        "serviceAccountName": "default",
        "serviceAccount": "default",
        "nodeName": "minikubevm",
        "securityContext": {},
        "hostname": "foo",
        "subdomain": "bar"
    },
    "status": {
        "phase": "Running",
        "conditions": [
            {
                "type": "Initialized",
                "status": "True",
                "lastProbeTime": null,
                "lastTransitionTime": "2016-08-03T00:13:15Z"
            },
            {
                "type": "Ready",
                "status": "True",
                "lastProbeTime": null,
                "lastTransitionTime": "2016-08-03T00:13:16Z"
            },
            {
                "type": "PodScheduled",
                "status": "True",
                "lastProbeTime": null,
                "lastTransitionTime": "2016-08-03T00:13:15Z"
            }
        ],
        "hostIP": "10.0.2.15",
        "podIP": "172.17.0.23",
        "startTime": "2016-08-03T00:13:15Z",
        "containerStatuses": [
            {
                "name": "alpine",
                "state": {
                    "running": {
                        "startedAt": "2016-08-03T00:13:15Z"
                    }
                },
                "lastState": {},
                "ready": true,
                "restartCount": 0,
                "image": "alpine:3.4",
                "imageID": "docker://sha256:4e38e38c8ce0b8d9041a9c4fefe786631d1416225e13b0bfe8cfa2321aec4bba",
                "containerID": "docker://f5fcc93e52a87533581b3a8daa7fdb5c9f8d0ea0c26c7f3ee8ad0ad91ceb7845"
            }
        ]
    }
}
```

# リソース関連

## Namespaceにリソース制限を設定する

Admission ControlのResource Quotaを設定する

```
$ cat quota.yml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: quota
spec:
  hard:
    memory: 1Gi
    cpu: 20
    pods: 10
    services: 5
    replicationcontrollers: 20
    resourcequotas: 1
$ kubectl crerate --namespace=development quota.yml
```

## Namespace内のPodにリソース制限を設定する

Admission ControlのLimitsを設定する

```
$ cat limits.yml
apiVersion: v1
kind: LimitRange
metadata:
  name: limits
  namespace: default
spec:
  limits:
    - type: Container
      defaultRequests:
        cpu: 250m
$ kubectl create --namespae=development limits.yml
```

参考: [CoreOS Fest 2016: Kubernetes Access Control with dex // Speaker Deck](https://speakerdeck.com/ericchiang/coreos-fest-2016-kubernetes-access-control-with-dex)

### -o jsonpath=...で「.(ドット)」を含むキーを参照する

例えば以下のようなsecretのdb.confキーの値を抽出したい。

```yaml
data:
  db.conf: base64encodedcontent..
```

以下のように普通に.をキーに含めると何もとれないが、

```
kubectl get secrets mysecret -o "jsonpath={.data['db.conf']}"
```

以下のようにバックスラッシュでエスケープすればとれる。

```
kubectl get secrets mysecret -o "jsonpath={.data['db\.conf']}"
```

参考: https://github.com/kubernetes/kubernetes/issues/23386#issuecomment-305348170

# DaemonSet関連

## kubectl edit/applyを使わずにDaemonSetのローリングアップデート

コンテナイメージの変更だけであれば、edit/applyを使わずとも、set imageでできる。

```
kubectl set image ds/<daemonset-name> <container-name>=<container-new-image>

kubectl rollout status ds/<daemonset-name> 
```

参考: [Perform a Rolling Update on a DaemonSet | Kubernetes](https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#updating-only-the-container-image)


# Ingress関連

## Ingress Load Balancerのホスト名

```
k get ing -o jsonpath={.items[0].status.loadBalancer.ingress[0].hostname}
```

出力例:

```
ab94c9d72bac811e79231068c4de2c62-myaccountid.ap-northeast-1.elb.amazonaws.com
```

# 応用編

## 障害が起きたノードを隔離して、テスト用podだけをスケジュールさせる

障害が起きたノードを「ip-10-0-5-178.ap-northeast-1.compute.internal」として、

```
# 応急処置として、該当ノードに今後podがスケジュールされないようにする
# 既に何かpodが動いているなら、kubectl drainでも可。kubectl drainはkubectl cordon + 稼働中podの退避。
kubectl cordon ip-10-0-5-178.ap-northeast-1.compute.internal

# 状況調査のため、該当ノードにテスト用podだけスケジュールできるようにする準備
# dedicated=adminというtaintをつけて、taintに対抗するtolerationがあるpodだけスケジュールできるようにする。
# テスト用pod以外はtolerationがついていないとすると、テスト用podにtolerationをつければ結果的にやりたいことが実現できる。
kubectl taint node ip-10-0-5-178.ap-northeast-1.compute.internal dedicated=admin:NoSchedule

# taintしたので、cordonを解除してそもそもpodがスケジュール可能な状態に戻す
# 繰り返しになるが、スケジュール可能になっても前述の操作でtaintされているので、他のpodはこのノードにはスケジュールされない
kubectl uncordon ip-10-0-5-178.ap-northeast-1.compute.internal

# kubectl runの--overridesで
# (1)taintに対抗するtolerationをつける。これでスケジュール先ノードの選択肢として、障害が発生したノード「も」含まれるようになる
# (2)nodeSelectorを追加して、障害が発生したノード「にだけ」スケジュールされるようにする
kubectl run pod1 -i --tty --overrides='{ "apiVersion": "extensions/v1beta1", "spec": { "template": { "metadata": { "annotations": { "scheduler.alpha.kubernetes.io/tolerations": "[{\"key\":\"dedicated\", \"value\":\"admin\"}]" } }, "spec": { "nodeSelector": { "kubernetes.io/hostname": "ip-10-0-5-178.ap-northeast-1.compute.internal" } } } } }' --image alpine --command -- /bin/sh

# あとはshの中でよしなに調査を行う
```

## kubednsが動いているかをテストする

```
$ kubectl run mypod8 --restart=Never --image=alpine:edge -- sh -c 'nslookup kubernetes.default.svc.cluster.local localhost'
job "mypod8" created

$ kubectl get po -a
NAME                      READY     STATUS             RESTARTS   AGE
mypod8-3u9qi              0/1       Completed          0          1m

$ kubectl logs mypod8-3u9qi
```

## 全deploymentを消す

```
$ for DEPLOYMENT in $(kubectl get deployments -o json | jq -r '.items[].metadata.name'); do kubectl delete deployment  $DEPLOYMENT; done
```

# あわせて読みたい

- [Playing with kubectl output](https://gist.github.com/so0k/42313dbb3b547a0f51a547bb968696ba)