Kubernetes the hard way をvagrantでやってみる

# モチベーション
- k8sの理解のため、kopsやkubeadmなどのツールを使わずにk8sクラスタを構築する

# 実行環境
- Windows10 64bit
- Vagrant 2.2.4
- Virtual Box 6.0.4
- git version 2.20.1.windows.1
    - Linuxコマンドやシェルを実行するために使用

# 参考リポジトリ
## Kelsey Hightower版
- https://github.com/kelseyhightower/kubernetes-the-hard-way
    - オリジナルのkubernetes the hard way
    - GCPでの実行が前提となっている
    
## kenfdev版
- https://github.com/kenfdev/kubernetes-the-hard-way-vagrant
    - Vagrantで実行するためのシェルスクリプトが用意されている

# 進め方
- Kelsey Hightower版のドキュメントを参考にしつつkenfdev版の/scripts/k8s-the-hard-way配下のシェルスクリプトを随時実行する
- 対応した章番号がシェルスクリプト名に付与されている
- GCP関連のコマンドはスキップして問題ない

# 注意事項
- 計7台の仮想環境が立ち上がるため、それなりのリソースが必要になり、進めていくとレスポンスが悪くなることがある
- k8sでは奇数台のマスターが推奨されているが、気にならないのであればマスター・ノードそれぞれ台数を減らす等の考慮が必要

# VM構築
- 上記のスクリプトをcloneし、フォルダの中に移動する
- Vagrantfileがあるので、それを利用してvagrantを立ち上げる

```
$ vagrant up
```

- しばらくすると、ロードバランサー1台、マスター3台、ノード3台の計7台のマシンが立ち上がる。

```
$ vagrant status
Current machine states:

lb-0                      running (virtualbox)
controller-0              running (virtualbox)
controller-1              running (virtualbox)
controller-2              running (virtualbox)
worker-0                  running (virtualbox)
worker-1                  running (virtualbox)
worker-2                  running (virtualbox)
```

# 1. Prerequisites
- GCPに関する記述のためスキップ

# 2. Installing the Client Tools
## Install CFSSL
- cfsslとcfssljsonは公開鍵基盤とTLS証明書を生成するコマンドラインツール

```
$ curl -o cfssl https://pkg.cfssl.org/R1.2/cfssl_windows-amd64.exe
$ curl -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_windows-amd64.exe
```

```
# PATHを通すために/usr/bin/に移動するが、Git Bashでのsudoコマンドセットアップがうまくいかず
  泣く泣く手動で移動
$ sudo mv cfssl cfssljson /usr/bin/
```

- 以下のようにバージョンが表示されればOK

```
$ cfssl version
Version: 1.2.0
Revision: dev
Runtime: go1.6
```

## Install kubectl

```
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/windows/amd64/kubectl.exe
```
```
# 同じようにsudoコマンドがきかないので手動で移動
$ sudo mv kubectl /usr/bin/
```

- 以下のようにバージョンが表示されればOK

```
$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.0", GitCommit:"ddf47ac13c1a9483ea035a79cd7c10005ff21a6d", GitTreeState:"clean", BuildDate:"2018-12-03T21:04:45Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"windows/amd64"}
```

# Provisioning Compute Resources
- GCPを使用する場合のセットアップのため省略

# 3. Provisioning Compute Resources
- GCPの設定のためスキップ

# 4. Provisioning a CA and Generating TLS Certificates
- cfsslを使って公開鍵基盤を構築し、etcd、kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxyで使用するTLS証明書を生成する。

## Certificate Authority
- 証明書と鍵を生成する。

```
$ bash 0400-certificate-authority.sh

# Results
ca.csr
ca.pem
ca-config.json
ca-csr.json
ca-key.pem
```

## Client and Server Certificates
- adminユーザーとk8sクラスタコンポーネントのための証明書を生成する。

### The Admin Client Certificate

```
$ bash 0410-admin-client-certificate.sh

# Results
admin.csr
admin.pem
admin-csr.json
admin-key.pem
```

### The Kubelet Client Certificates
- k8sではNode Authorizerと呼ばれる、Kubeletから送信されたAPIを認可するための特別な認可方式が採用されている。
- これを利用するため各ノードで保持する証明書と秘密鍵を生成する。

```
$ bash 0411-kubelet-client-certificates.sh

# Results
worker-0.csr
worker-0.pem
worker-0-csr.json
worker-0-key.pem
worker-1.csr
worker-1.pem
worker-1-csr.json
worker-1-key.pem
worker-2.csr
worker-2.pem
worker-2-csr.json
worker-2-key.pem
```

### The Controller Manager Client Certificate
- kube-controller-managerの証明書と秘密鍵を生成する。

```
$ bash 0412-controller-manager-client-certfiicate.sh

# Results
kube-controller-manager.csr
kube-controller-manager.pem
kube-controller-manager-csr.json
kube-controller-manager-key.pem
```

### The Kube Proxy Client Certificate
- kube-proxyの証明書と秘密鍵を生成する。

```
$ bash 0413-kube-proxy-client-certificate.sh

# Results
kube-proxy.csr
kube-proxy.pem
kube-proxy-csr.json
kube-proxy-key.pem
```

### The Scheduler Client Certificate
- kube-schedulerの証明書と秘密鍵を生成する。

```
$ bash 0414-scheduler-client-certificate.sh

# Results
kube-scheduler.csr
kube-scheduler.pem
kube-scheduler-csr.json
kube-scheduler-key.pem
```

### The Kubernetes API Server Certificate
- Kubernetes API Serverの証明書と秘密鍵を生成する。

```
$ bash 0415-kubernetes-api-server-certificate.sh

# Results
kubernetes.pem
kubernetes-csr.json
kubernetes-key.pem
```

## The Service Account Key Pair
- Kubernetes Controller ManagerはService Accountを生成する際にkey pairを使用する。
- Service Accountの証明書と秘密鍵を生成する。

```
$ bash 0420-service-account-key-pair.sh

# Results
service-account.csr
service-account.pem
service-account-csr.json
service-account-key.pem
```

## Distribute the Client and Server Certificates
- 証明書とkey pairをノードとマスターにコピーする。
- ローカルからVagrant環境にファイルをコピーする際にvagrant-scpプラグインを使用するため、インストールが未済の場合は以下を参照。
    - 参考：https://github.com/invernizzi/vagrant-scp

```
$ bash 0430-distribute-certificates.sh
```
- Could not create directoryのエラーが表示されたが、sshでログインしてみたところコピーは正常にできていたので先に進む、、(原因不明)

# 5. Generating Kubernetes Configuration Files for Authentication
- kubedonfigファイルを作成する

## Client Authentication Configs
- controller manager、kubelet、kube-proxy、scheduler、adminユーザー向けのkubeconfigファイルを作成する。

### The kubelet Kubernetes Configuration File
- kubeletのkubeconfigを作成する際、Nodeの名前が使用されるが、これによりNode Authorizerによる認可が機能していることが確認できる。

```
$ bash 0500-kubelet-kubeconfig.sh

# Results
worker-0.kubeconfig
worker-1.kubeconfig
worker-2.kubeconfig
```

### The kube-proxy Kubernetes Configuration File
- kube-proxyのkubeconfigを作成する

```
$ bash 0501-kube-proxy-kubeconfig.sh

# Results
kube-proxy.kubeconfig
```
### The kube-controller-manager Kubernetes Configuration File
- kube-controller-managerのkubeconfigを作成する

```
$ bash 0502-kube-controller-manager-kubeconfig.sh

# Results
kube-controller-manager.kubeconfig
```

### The kube-scheduler Kubernetes Configuration File
- kube-schedulerのkubeconfigを作成する

```
$ bash 0503-kube-scheduler-kubeconfig.sh

# Results
kube-scheduler.kubeconfig
```

### The admin Kubernetes Configuration File
- adminユーザー向けのkubeconfigを作成する

```
$ bash 0504-admin-kubeconfig.sh

# Results
admin.kubeconfig
```

## Distribute the Kubernetes Configuration Files
- kubeletとkube-proxyのkubeconfigを各ノードに、kube-controller-manager、kube-scheduler、adminユーザーのkubeconfigを各マスターにコピーする。

```
$ bash 0510-distribute-kubeconfig.sh
```

# 6. Generating the Data Encryption Config and Key
- k8sではクラスタの状態、アプリケーションconfigなど様々なデータを保存している。k8sではこのようなデータの暗号化をサポートしている。
- ここでは暗号化鍵とconfigを生成する。

## The Encryption Config File

```
$ bash 0600-encryption-config.sh
```
- encryption-config.yamlを各マスターにコピーする。

```
$ bash 0610-distribute-encryption-config.sh
```

# 7. Bootstrapping the etcd Cluster
- k8sのコンポーネントはステートレスであり、クラスタの状態はetcdに保存される。
- 3つのノードからなるetcdクラスタを構築する。
- ここでのコマンドは3つのマスターノードにログインして行う。
    - マスターのOSはUbuntuのため、シェルをそのままマスターにコピーすると改行問題が発生してしまう。コピーする前にsedで改行コードを変換する。
    - ここでは変換したファイルのファイル名には先頭に_(アンダースコア)をつける
    - 以下がコピーするスクリプトの例

```bash

#!/bin/bash                                                                                                        
files=(`ls 07[0-9]*.sh`)                           
for filename in ${files[@]}; do                                                                                                                    
    sed "s/\r//g" ${filename} > _${filename}                                                                       
    linux_file=_${filename}                                                                                        
for instance in controller-0 controller-1 controller-2; do                                                         
    vagrant scp ${linux_file} ${instance}:~/                                                                           
done                                                                                                               
done                                                                                                               
```

## Bootstrapping an etcd Cluster Member
### Download and Install the etcd Binaries

- etcdのバイナリをGithubからダウンロードする。
- etcdサーバーとコマンドラインツールのetcdctlをインストールする。

```
$ bash _0700-download-and-install-etcd.sh
```

### Configure the etcd Server
- InstanceのInternal IPはクライアントからのリクエスト処理やetcd同士での通信に使われる。
- etcdの名前はクラスタ内でユニークである必要があるため、ホスト名と一致させる。
- etcd.serviceを作成する

### Start the etcd Server

```
$ bash _0702-start-etcd.sh
```

### Verification

```
$ bash _0710-verify-etcd.sh

# Output
3a57933972cb5131, started, controller-2, https://10.240.0.12:2380, https://10.240.0.12:2379
f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379
ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379
```

# 8. Bootstrapping the Kubernetes Control Plane
- k8sのコントロールプレーンを作成する。また、クライアントからAPI Serverにアクセスできるようにするため、ロードバランサーも併せて構築する。
- ここでインストールするコンポーネントは以下の通り
    - Kubernetes API Server
    - Scheduler
    - Controller Manager
- ここでのコマンドも前章と同じように各マスターで実行する。

## Provision the Kubernetes Control Plane
### Download and Install the Kubernetes Controller Binaries
- k8sオフィシャルのバイナリをダウンロードし、インストールを行う

```
$ bash _0800-download-and-install-k8s-controllers.sh
```

### Configure the Kubernetes API Server
- Internal IPはクラスタ内の他のメンバーと連携をとるために使用される。
- kube-apiserver.serviceを作成する

```
$ bash _0801-configure-k8s-api-server.sh
```

### Configure the Kubernetes Controller Manager
- kube-controller-managerのconfigを移動する
- kube-controller-manager.serviceを作成する

```
$ bash _0802-configure-k8s-controller-manager.sh
```

### Configure the Kubernetes Scheduler
- kube-schedulerのconfigを移動する
- kube-scheduler.yamlを作成する
- kube-scheduler.serviceを作成する

```
$ bash _0803-configure-k8s-schedueler.sh
```

### Start the Controller Services

```
$ bash _0804-start-controller-services.sh
```

### Verification

```
$ bash _0805-verify.sh

# Output
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-1               Healthy   {"health":"true"}
etcd-0               Healthy   {"health":"true"}
etcd-2               Healthy   {"health":"true"}
```

## RBAC for Kubelet Authorization
- ここではAPI Serverが各ノードのkubelet APIにアクセスできるようにRBACの設定を行う。
- metricsやログの収集、またexecコマンドを実行する際にkubelet APIへのアクセスが必要になる
- kubeletへのアクセスとPodの操作に関する一般的な権限を設定したClusterRoleを作成する
- 上記のClusterRoleとkubernetesユーザーを紐づける

```
$ bash _0810-rbac-for-kubelet-auth.sh

# Output
clusterrole.rbac.authorization.k8s.io "system:kube-apiserver-to-kubelet" created
clusterrolebinding.rbac.authorization.k8s.io "system:kube-apiserver" created
```

## The Kubernetes Frontend Load Balancer
- 実行環境でシェルを叩き、HTTPリクエストでバージョン情報を取得する。

```
$ KUBERNETES_PUBLIC_ADDRESS=10.240.0.40
$ curl --cacert /var/lib/kubernetes/ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}:6443/version
{
  "major": "1",
  "minor": "10",
  "gitVersion": "v1.10.2",
  "gitCommit": "81753b10df112992bf51bbc2c2f85208aad78335",
  "gitTreeState": "clean",
  "buildDate": "2018-04-27T09:10:24Z",
  "goVersion": "go1.9.3",
  "compiler": "gc",
  "platform": "linux/amd64"
}
```

# 9. Bootstrapping the Kubernetes Worker Nodes
- 3つのノードの設定を行う。
- インストールされるコンポーネントは下記の通り
    - runc
    - gVisor
    - container networking plugins
    - containerd
    - kubelet
    - kube-proxy
- ここでのコマンドはノード内で実行する

## Provisioning a Kubernetes Worker Node
### Download and Install Worker Binaries
- バイナリをインストールする

```
$ bash _0900-download-and-install-workers.sh
```

### Configure CNI Networking
- Pod CIDR Rangeを判別して、bridgeとloopbackのconfigを作成する。

```
$ bash _0901-configure-cni.sh
```

### Configure containerd
- containerdのconfigとcontainerd.serviceを作成する。

```
$ bash _0902-configure-containerd.sh
```

### Configure the Kubelet
- kubelet-config.yamlとkubelet.serviceを作成する。

```
$ bash _0903-configure-kubelet.sh
```

### Configure the Kubernetes Proxy
- kube-proxy-config.yamlとkube-proxy.serviceを作成する。

```
$ bash _0904-configure-kube-proxy.sh
```

### Start the Worker Services

```
$ bash _0905-start-worker-services.sh
```

### Verification
- 実行環境でシェルを叩き、Nodeの情報を取得する

```
$ bash 0910-verify-worker.sh
NAME       STATUS    ROLES     AGE       VERSION
worker-0   Ready     <none>    1m        v1.10.2
worker-1   Ready     <none>    49s       v1.10.2
worker-2   Ready     <none>    39s       v1.10.2
Connection to 127.0.0.1 closed.
```

# Configuring kubectl for Remote Access
- adminユーザーとしてkubectlコマンドを打つためのkubeconfigを作成する

## The Admin Kubernetes Configuration File
- kubeconfigには接続するためのAPI Serverが必要になり、今回はロードバランサーのIPアドレスを指定する。
- ~/.kube/configにクラスタ"kubernetes-the-hard-way"の情報が追記され、current-contextも変更される。

```
$ bash 1000-admin-kubeconfig.sh
```

## Verification
- kubectl コマンドで疎通を確認する

```
$ kubectl get componentstatuses
NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-1               Healthy   {"health":"true"}
etcd-2               Healthy   {"health":"true"}
etcd-0               Healthy   {"health":"true"}
```

```
$ kubectl get nodes
NAME       STATUS    ROLES     AGE       VERSION
worker-0   Ready     <none>    5m        v1.10.2
worker-1   Ready     <none>    4m        v1.10.2
worker-2   Ready     <none>    4m        v1.10.2
```

# 10. Provisioning Pod Network Routes
- GCPの設定のためスキップ

# 11. Provisioning Pod Network Routes
- GCPの設定のためスキップ

# 12. Deploying the DNS Cluster Add-on
- サービスディスカバリを行うDNS-addonをデプロイする。

## The DNS Cluster Add-on
- オリジナルではcorednsが採用されているが、ここではkube-dnsをデプロイする。

```
$ kubectl create -f https://storage.googleapis.com/kubernetes-the-hard-way/kube-dns.yaml
service "kube-dns" created
serviceaccount "kube-dns" created
configmap "kube-dns" created
deployment.extensions "kube-dns" created
```
- デプロイされたPodを確認する。

```
$ kubectl get pods -l k8s-app=kube-dns -n kube-system
NAME                        READY     STATUS    RESTARTS   AGE
kube-dns-598d7bf7d4-z6bff   3/3       Running   0          1m
```

## Verification
- busyboxをデプロイする。

```
$ kubectl run busybox --image=busybox --command -- sleep 3600
deployment.apps "busybox" created
```

- busyboxを使って作成されたPodを確認する。
- タグを指定しない(latest)とうまく名前解決がうまくいかなかったためオリジナルに合わせて1.28に設定する

```
$ kubectl run busybox --image=busybox:1.28 --command -- sleep 3600
NAME                       READY     STATUS    RESTARTS   AGE
busybox-68654f944b-sq75k   1/1       Running   0          46s
```

- busybox Podの名前を取得し、Pod内でnslookupを実行する。
- Git BashではTTYを要求するコマンドを実行するときは先頭にwinptyを付ける必要がある。

```
$ POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
$ winpty kubectl exec -ti $POD_NAME -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10

Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
```

# 13. Smoke Test
- ここではクラスタが正常に動作するかのテストを行う。
- kubectlコマンドを直接叩いた方が理解しやすいので、ここではシェルを利用しないで進める

## Data Encryption
- 暗号化を検証する。

```
$ kubectl create secret generic kubernetes-the-hard-way \
>   --from-literal="mykey=mydata"
secret "kubernetes-the-hard-way" created

$ vagrant ssh controller-0 \
>   --command "sudo ETCDCTL_API=3 etcdctl get \
>   --endpoints=https://127.0.0.1:2379 \
>   --cacert=/etc/etcd/ca.pem \
>   --cert=/etc/etcd/kubernetes.pem \
>   --key=/etc/etcd/kubernetes-key.pem\
>   /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |y.k8s:enc:aescbc|
00000040  3a 76 31 3a 6b 65 79 31  3a 2d f3 19 f7 d4 76 88  |:v1:key1:-....v.|
00000050  08 90 f2 8e e3 59 90 57  96 b8 93 52 9a f6 b0 c0  |.....Y.W...R....|
00000060  60 32 98 27 11 5a 58 4e  9a b4 d8 43 b1 45 46 83  |`2.'.ZXN...C.EF.|
00000070  bb 77 1b fd e7 9b 6a 5d  5f 7a ba 69 df c7 e8 92  |.w....j]_z.i....|
00000080  bb db f1 53 5b be 1f cd  f1 b5 0f 97 09 94 af 39  |...S[..........9|
00000090  4a 1e 28 f2 1c 59 da 62  9f ae d6 89 16 c9 7c 82  |J.(..Y.b......|.|
000000a0  ac 90 48 22 a7 12 e2 2a  2a f5 b4 cf 60 3b c4 03  |..H"...**...`;..|
000000b0  f4 a2 82 e8 01 83 dc e7  27 15 72 31 32 70 52 50  |........'.r12pRP|
000000c0  6a f6 c4 fb ee 8c 69 03  a1 86 68 f5 8e 14 a9 ce  |j.....i...h.....|
000000d0  93 d3 f2 61 21 ea 58 e5  2c 6d 64 57 89 f7 7f 31  |...a!.X.,mdW...1|
000000e0  e8 01 8e c8 b7 68 e9 dd  c4 0a                    |.....h....|
000000ea
Connection to 127.0.0.1 closed.
``` 

## Deployments
- nginxをデプロイしてDeploymentの検証を行う。

```
$ kubectl run nginx --image=nginx
deployment.apps "nginx" created

$ kubectl get pods -l run=nginx
NAME                     READY     STATUS    RESTARTS   AGE
nginx-65899c769f-24b5l   1/1       Running   0          3m
```

### Port Forwarding
-  port forwardingでアプリにアクセスできることを確認する。

```
$ POD_NAME=$(kubectl get pods -l run=nginx -o jsonpath="{.items[0].metadata.name}")
$ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
```

- 別のターミナルでHTTPリクエストを送信する。

```
$ curl --head http://127.0.0.1:8080
Server: nginx/1.15.9
Date: Thu, 21 Mar 2019 13:44:24 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Feb 2019 14:13:39 GMT
Connection: keep-alive
ETag: "5c754993-264"
Accept-Ranges: bytes
```

### Logs
- コンテナのログを確認する。

```
$ kubectl logs $POD_NAME
127.0.0.1 - - [21/Mar/2019:13:44:24 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.63.0" "-"
```

### Exec
- execコマンドを使ってPod内でコマンドを実行する。
- nginx -vコマンドでバージョンを表示する。

```
$ winpty kubectl exec -ti $POD_NAME -- nginx -v
nginx version: nginx/1.15.9
```

## Services
- Serviceでアプリケーションを公開する。
- NodePortでnginxを公開する。
- ポート番号を取得し、HTTPリクエストを送信する。

```
$ NODE_PORT=$(kubectl get svc nginx \
>   --output=jsonpath='{range .spec.ports[0]}{.nodePort}')
$ curl -I http://10.240.0.20:${NODE_PORT}
Server: nginx/1.15.9
Date: Thu, 21 Mar 2019 13:54:59 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Feb 2019 14:13:39 GMT
Connection: keep-alive
ETag: "5c754993-264"
Accept-Ranges: bytes
```

## Untrusted Workloads
- gvisorを使ったuntrustedなworkloadを検証する。
- Podを作成する。

```
$ cat <<EOF | kubectl apply -f -
> apiVersion: v1
> kind: Pod
> metadatas:
>   name: untrusted
>   annotations:
>     io.kubernetes.cri.untrusted-workload: "true"
> spec:
>   cont webserveainers:
>     - name: webserver
>       image: gcr.io/hightowerlabs/helloworld:2.0.0
> EOF
pod "untrusted" created

$ kubectl get pods -o wide
NAME                      READY     STATUS    RESTARTS   AGE       IP           NODE
busybox-744d79879-vr2n2   1/1       Running   0          57m       10.200.0.4   worker-0
nginx-65899c769f-24b5l    1/1       Running   0          38m       10.200.1.5   worker-1
untrusted                 1/1       Running   0          28s       10.200.0.5   worker-0
```

- Podが動いているNodeを取得し、sshでログインする。

```
$ INSTANCE_NAME=$(kubectl get pod untrusted --output=jsonpath='{.spec.nodeName}')
$ vagrant ssh ${INSTANCE_NAME}
```

- gVisorで動いているコンテナの一覧を取得する。

```
vagrant@worker-0:~$ sudo runsc --root /run/containerd/runsc/k8s.io list
I0321 14:19:46.079960   12649 x:0] ***************************
I0321 14:19:46.080087   12649 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io list]
I0321 14:19:46.080130   12649 x:0] Git Revision: 08879266fef3a67fac1a77f1ea133c3ac75759dd
I0321 14:19:46.080153   12649 x:0] PID: 12649
I0321 14:19:46.080177   12649 x:0] UID: 0, GID: 0
I0321 14:19:46.080199   12649 x:0] Configuration:
I0321 14:19:46.080219   12649 x:0]              RootDir: /run/containerd/runsc/k8s.io
I0321 14:19:46.080256   12649 x:0]              Platform: ptrace
I0321 14:19:46.080301   12649 x:0]              FileAccess: proxy, overlay: false
I0321 14:19:46.080348   12649 x:0]              Network: sandbox, logging: false
I0321 14:19:46.080392   12649 x:0]              Strace: false, max size: 1024, syscalls: []
I0321 14:19:46.083239   12649 x:0] ***************************
ID                                                                 PID         STATUS      BUNDLE
        CREATED                          OWNER
8dbdb306a869eefcb747e3339db9ca845355d335b3cc8eefb9a5ab6e62fb0abc   11994       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/8dbdb306a869eefcb747e3339db9ca845355d335b3cc8eefb9a5ab6e62fb0abc   2019-03-21T14:14:53.302758241Z
aec51937497e585eeed6da85e063ba5e405bc7bc29df92f07b18371953f4fa26   12047       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/aec51937497e585eeed6da85e063ba5e405bc7bc29df92f07b18371953f4fa26   2019-03-21T14:14:58.509457802Z
I0321 14:19:46.088036   12649 x:0] Exiting with status: 0
```

- Pod ID、Container IDからプロセスを取得する。

```
$ POD_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \
  pods --name untrusted -q)
$ CONTAINER_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \
  ps -p ${POD_ID} -q)
$ sudo runsc --root /run/containerd/runsc/k8s.io ps ${CONTAINER_ID}
I0321 14:35:15.612283   13669 x:0] ***************************
I0321 14:35:15.613463   13669 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io ps aec51937497e585eeed6da85e063ba5e405bc7bc29df92f07b18371953f4fa26]
I0321 14:35:15.614861   13669 x:0] Git Revision: 08879266fef3a67fac1a77f1ea133c3ac75759dd
I0321 14:35:15.615856   13669 x:0] PID: 13669
I0321 14:35:15.616925   13669 x:0] UID: 0, GID: 0
I0321 14:35:15.617997   13669 x:0] Configuration:
I0321 14:35:15.619143   13669 x:0]              RootDir: /run/containerd/runsc/k8s.io
I0321 14:35:15.620464   13669 x:0]              Platform: ptrace
I0321 14:35:15.620497   13669 x:0]              FileAccess: proxy, overlay: false
I0321 14:35:15.620532   13669 x:0]              Network: sandbox, logging: false
I0321 14:35:15.620552   13669 x:0]              Strace: false, max size: 1024, syscalls: []
I0321 14:35:15.620572   13669 x:0] ***************************
UID       PID       PPID      C         STIME     TIME      CMD
0         1         0         0         14:14     40ms      app
I0321 14:35:15.624833   13669 x:0] Exiting with status: 0
```

# 14. Cleaning Up
- 作成した環境を削除する。
- Vagrantfileがあるパスに移動する。

```
$ vagrant destroy
```