taxin's notes

読書、勉強メモ etc.

Kubernetes the hard way (GCP版) #13 (スモークテスト)

Kubernetes the hard way (GCP版)の続きです。

前回の記事はこちら

taxintt.hatenablog.com

Chap13. Smake Test(スモークテスト)

Chap12まででクラスターに関連する設定を一通り行いました。
このチャプターではクラスターが正常に動作しているかを確認するために、一連のタスクを実施します。

一部の作業ログが欠落しているので、手順の内容をそのまま記載している部分もありますがご了承下さい。

github.com

データの暗号化

Kubernetesで利用可能なリソースの一種であるSecretの暗号化機能を確認します。

kubernetes.io

SecretはKubernetesクラスター内で機密情報を管理するためのリソースとして利用されます。
データはControl Plane上のetcdに保管されるので、セキュリティの観点ではetcdの暗号化が必須になります。

qiita.com

最初に、機密情報のKey-Valueのペアを--from-literalで渡して検証用のSecretを作成します。
渡した値は自動的にBase64でencodeされます。

~/w/k/h/04 ❯❯❯ kubectl create secret generic kubernetes-the-hard-way \
  --from-literal="mykey=mydata"
secret/kubernetes-the-hard-way created
~/w/k/h/04 ❯❯❯ k get secrets
NAME                      TYPE                                  DATA   AGE
default-token-bn72d       kubernetes.io/service-account-token   3      178m
kubernetes-the-hard-way   Opaque                                1      14s


Secretの作成後に、Control Planeにログインしてetcd内のデータを確認します。
作成したSecret名を用いてディレクトリ(/registry/secrets/default/kubernetes-the-hard-way)を指定して、Key, Valueを取得します。

github.com

さらに取得したデータをhexdumpコマンドを利用して16進数とASCII文字でダンプします。
etcd上のデータにはk8s:enc:aescbc:v1:key1が付与されており、aescbcプロバイダがキー(key1)のデータを暗号化するために使用されたことを示しています。

kubernetes.io

~/w/k/h/04 ❯❯❯ gcloud compute 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"
Enter passphrase for key '/Users/nishikawatakushi/.ssh/google_compute_engine':
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 4e ed 61 e8 69 49 fa  |:v1:key1:N.a.iI.|
00000050  19 c2 58 32 f3 7b 5b 7b  f6 2b 67 0e af de a7 0c  |..X2.{[{.+g.....|
00000060  d6 cf 48 b2 e2 7a 2d 44  9d 19 f8 06 8b e8 3d 74  |..H..z-D......=t|
00000070  89 eb 0e ba d4 ec b8 78  0b 84 b0 01 12 83 18 72  |.......x.......r|
00000080  c8 1e a6 25 a7 ca aa c5  a8 3a 0a f4 59 fa 2d 1d  |...%.....:..Y.-.|
00000090  03 54 5b 08 62 c6 5e b1  da 02 1b a6 ab 8f d6 c3  |.T[.b.^.........|
000000a0  ea c6 69 56 53 93 68 b4  29 93 df 21 79 36 1d dd  |..iVS.h.)..!y6..|
000000b0  d3 05 fa fd c5 40 d2 d5  4b e8 c8 da 48 60 3e 6b  |.....@..K...H`>k|
000000c0  29 33 6b 4a 9f f3 1b 8a  02 da 00 45 cd 93 98 ce  |)3kJ.......E....|
000000d0  ac cc d7 a4 a6 93 e0 ae  1d bc 9c 1b 7c e3 c0 ef  |............|...|
000000e0  c9 b6 4e 7a 6f 46 41 12  0e 0a                    |..NzoFA...|
000000ea

Deploymentの作成

次にWorkloadsリソースの1種であるDeploymentを作成します。
kubectl createコマンドを利用することで、マニュフェストファイルを事前に用意することなく作成することが可能です。

$ kubectl create deployment nginx --image=nginx

$ kubectl get pods -l app=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-554b9c67f9-vt5rn   1/1     Running   0          10s

ポートフォワーディング

作成したDeployment(pod)に対して、ポートフォワーディングを行いクラスタ内のコンテナへアクセスします。
今回はnginxのコンテナを作成しているので、コンテナの80番ポートにアクセスします。

~/w/k/h/04 ❯❯❯ POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath="{.items[0].metadata.name}")
~/w/k/h/04 ❯❯❯ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

~/w/k/h/04 ❯❯❯ kubectl port-forward $POD_NAME 8080:80                                                                                                                     
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

~~~~~~~

~ ❯❯❯ curl --head http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Sat, 29 Feb 2020 07:28:01 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 21 Jan 2020 13:36:08 GMT
Connection: keep-alive
ETag: "5e26fe48-264"
Accept-Ranges: bytes


ログ出力

作成したPodに対して、標準出力からPodのログをダンプします。
(この部分は作業ログが無かったため、手順の内容をそのまま記載しています。)

kubernetes.io

手順の中では標準出力の内容を直接取得していますが、実際の運用では標準出力・標準エラー出力をログファイルに書き出してロギング用のAgentを用いて転送したり、sidecarを用いたり様々なケースが考えられます。
こういったロギングの方法については、 Kubernetesの公式ドキュメントにまとめられています。

kubernetes.io

$ kubectl logs $POD_NAME
127.0.0.1 - - [14/Sep/2019:21:10:11 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.52.1" "-"


コンテナ内でのコマンド実行

docker execコマンドと同様に、Kubernetesでも作成したコンテナ上でコマンドを実行することが可能です。
今回はnginxのバージョンを確認するコマンドを実行します。

$ kubectl exec -ti $POD_NAME -- nginx -v
nginx version: nginx/1.17.3


Serviceを用いたアプリケーションの実行

最後に、Serviceを作成してクラスタ外部から作成したコンテナにアクセスできるようにします。
kubectl exposeコマンドを用いて、事前に作成したDeploymentに紐付ける形でServiceを作成します。

kubernetes.io

$ kubectl expose deployment nginx --port 80 --type NodePort

$ NODE_PORT=$(kubectl get svc nginx \
  --output=jsonpath='{range .spec.ports[0]}{.nodePort}')


次に、払い出されたNodePortのポート番号(NODE_PORT)でアクセスできるようにGCPFirewall Ruleでアクセスできるように修正します。

$ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-nginx-service \
  --allow=tcp:${NODE_PORT} \
  --network kubernetes-the-hard-way


最後にNode(GCE)自体のIPアドレスを取得して、curlコマンドを実行します。
正常に設定が行われていれば、ポートフォワーディングの際と同じようなレスポンスが返ってくるはずです。

$ EXTERNAL_IP=$(gcloud compute instances describe worker-0 \
  --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')

$ curl -I http://${EXTERNAL_IP}:${NODE_PORT}
HTTP/1.1 200 OK
Server: nginx/1.17.3
Date: Sat, 14 Sep 2019 21:12:35 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 13 Aug 2019 08:50:00 GMT
Connection: keep-alive
ETag: "5d5279b8-264"
Accept-Ranges: bytes


今回は、Chap13の内容をまとめました。

これにて、Kubernetes the hard wayのブログシリーズは終了です。
(Chap14は作成したリソース類の削除なので、ブログ記事の作成は行いません。)
機会があれば、AWS, Azure版など他のクラウドでのHard wayや手順を一部変更した改造版などを実施してみようと思います。