EKS for Fargateの検証しました!
お久しぶりです…! 生きております…!
激動の10,11月だったため、更新が滞っておりました。来年こそはもっと密に更新していきたい…!
さて、裏では12/5にGAされたEKS for Fargateの検証をしておりました。あとは業務でDjangoいじったり、Lambda関数作ったり…
その時の記事がこちらのアドベントカレンダーで公開されておりますので、よろしければご覧いただき、「いいね!」いただけると泣いて喜びます!!
EKS for Fargate the Hard Way 〜 EKS for Fargateをeksctlに頼らず構築する
ちなみに、明日もう一個記事を公開します…!
ElastAlertでEFKスタックで収集したログを監視する
お久しぶりです。生きております…!
最近はコンテナ基盤の監視やログ収集について勉強しておりました。定番のPrometheus+GrafanaやEFKスタックについてですね。前者ではcadvisor、node-exporterを使った一般的なDockerホスト監視やbackbox-exporterを使った外形監視、後者ではfluentdの設定ファイルの記述方法を勉強してコンテナやsystemdサービス、kernelログを収集する方法について学びました。
ところでEFKスタックでログ収集をしたら、ERROR
やFAIL
などの文字列を検出してSlack等に通知したくなりますよね…? Elastic製品ではWatherという、x-pack(https://www.elastic.co/guide/jp/x-pack/current/index.html)内のコンポーネントを使ってこれを実現できるそうですが、x-packは有償なんです… OSSだけで同じことをやろうとしたら、KibanaをやめてGrafanaを使うという手もありますが、ログの検索/一覧性でGrafanaはKibanaには勝てない…
呆然とさまよっていたところで見つけたのがElastAlertというOSSです! ElastAlertを使うとPrometheusのAlertManagerのようにYAMLベースで監視ルールを書いて、Slackを始めとした様々な媒体に通知することができます。またコンテナイメージやKibanaのプラグインがbitsensor社によって提供されているため、導入も簡単です。
使い方はbitsensor社のGitHubリポジトリ上の説明が丁寧なので全ては記載しませんが、概ね以下のように進めればOKです。
監視ルールはKibana上にElastAlert
という項目が追加されているので、Creat rule
からエディタを起動し、以下のようなルールを書きます。
es_host: <Elasticsearchのホスト名/IPアドレス> es_port: 9200 name: Alert on any error index: logstash-* timestamp_field: "@timestamp" type: any filter: - query: query_string: query: "message:/ERROR/i" alert_subject: "Error!!" alert_text_type: alert_text_only alert_text: "occur error on some components!" alert: - slack slack_webhook_url: "https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ"
Test
ボタンで試験的にqueryを発行し、アラートを飛ばすことができます。意図したとおりであればSave
をクリックして、アラートを保存して完了です。
kata containers + firecrackerを試してみた
コンテナのセキュリティレベルを上げるためにホストOSとの分離レベルをあげようというモチベーションで開発されたプロダクトがいくつかあります。gVisorやrunV、kata containersなどがそれです。今回はその中のkata containersを検証してみました。kata containersはfirecrackerというAWSがFargateやLambdaの実行環境として利用しているVMMを利用することもできるので、合わせて使ってみたいと思います。
前提
- Ubuntu 18.04 LTS のCloud image
検証手順
まず、docker ceをインストールします。kata containersのマニュアルに従い、バージョンは最新ではなく、18.06を用います。
sudo apt-get update sudo apt-get -y install apt-transport-https \ ca-certificates \ curl \ software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" sudo apt-get install docker-ce=18.06.3~ce~3-0~ubuntu
次にkata containersとfirecrackerのバイナリをDLし、展開します。
wget https://github.com/kata-containers/runtime/releases/download/1.5.0/kata-static-1.5.0-x86_64.tar.xz sudo tar -xvf kata-static-1.5.0-x86_64.tar.xz -C /
Dockerのデフォルトruntimeの設定をkata containers + firecrackerとします。
sudo su - cat <<EOF > /etc/docker/daemon.json { "default-runtime": "kata-fc", "runtimes": { "kata-fc": { "path": "/opt/kata/bin/kata-fc" } }, "mtu": 1450, "storage-driver": "devicemapper" } EOF exit sudo systemctl daemon-reload sudo systemctl restart docker
最後に必須カーネルモジュールの読み込み設定をしてインストールは完了です。
sudo su - cat <<EOF > /etc/modules-load.d/vhost_vsock.conf vhost_vsock EOF exit sudo modprobe vhost_vsock
ではnginxを起動して、ホストからnginxプロセスが見えるか確かめてみましょう。
sudo docker run -d nginx sudo ps -ef | grep nginx
grepコマンドの結果のみになっているはずです。ちなみに、containerdで同じことをやると以下のようになりました。
root 8216 8194 0 22:02 ? 00:00:00 nginx: master process nginx -g daemon off; systemd+ 8275 8216 0 22:02 ? 00:00:00 nginx: worker process tatsuno+ 8278 5237 0 22:02 pts/0 00:00:00 grep --color=auto nginx
StatefulSetのノード障害時の挙動と対応
前回、Kubernetesのノード障害時の挙動について記事を書きました。このときはDeploymentを使って挙動を確かめていたですが、前回の記事を見た方から「StatefulSetだと挙動が違ったはず」とのご意見を頂戴しました。
https://twitter.com/tzkb/status/1116597587186814977
そこでStatefulSetだとノード障害時、どんな挙動になるか試してみました。
クラスタの状態は前回の状態からスタートします。
# kubectl get node NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 2d22h v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 2d22h v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 45h v1.14.0 test-cluster-7ajeznlcoium-minion-2 Ready <none> 2d16h v1.14.0
今回はElasticSearchのステートフルセットをデプロイしてみます。KubernetesのGitリポジトリをクローンします。
# cd ~ # git clone https://github.com/kubernetes/kubernetes
Cluster Add-Onからfluentd-elasticsearch
ディレクトリに入ります。
# cd kubernetes/cluster/addons/fluentd-elasticsearchds
デフォルトではElasticsearchのStatefulSetはvolumeClaimTemplates
を利用するように書かれていないので、以下のようにes-statefulset.yaml
を書き換えます。
# Elasticsearch deployment itself apiVersion: apps/v1 kind: StatefulSet metadata: name: elasticsearch-logging namespace: kube-system labels: k8s-app: elasticsearch-logging version: v6.6.1 kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile spec: serviceName: elasticsearch-logging replicas: 2 selector: matchLabels: k8s-app: elasticsearch-logging version: v6.6.1 template: metadata: labels: k8s-app: elasticsearch-logging version: v6.6.1 kubernetes.io/cluster-service: "true" spec: serviceAccountName: elasticsearch-logging containers: - image: gcr.io/fluentd-elasticsearch/elasticsearch:v6.6.1 name: elasticsearch-logging resources: # need more cpu upon initialization, therefore burstable class limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: db protocol: TCP - containerPort: 9300 name: transport protocol: TCP volumeMounts: - name: elasticsearch-logging mountPath: /data env: - name: "NAMESPACE" valueFrom: fieldRef: fieldPath: metadata.namespace # Elasticsearch requires vm.max_map_count to be at least 262144. # If your OS already sets up this number to a higher value, feel free # to remove this init container. initContainers: - image: alpine:3.6 command: ["/sbin/sysctl", "-w", "vm.max_map_count=262144"] name: elasticsearch-logging-init securityContext: privileged: true volumeClaimTemplates: - metadata: name: elasticsearch-logging spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
ではおもむろにデプロイしてみます。
# kubectl apply -f es-statefulset.yaml # kubectl get pod -n kube-system -o wide -l k8s-app=elasticsearch-logging NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES elasticsearch-logging-0 1/1 Running 0 3m34s 10.100.2.221 test-cluster-7ajeznlcoium-minion-2 <none> <none> elasticsearch-logging-1 1/1 Running 0 99s 10.100.0.97 test-cluster-7ajeznlcoium-minion-0 <none> <none>
ここでtest-cluster-7ajeznlcoium-minion-2
のkubeletを停止します。
(test-cluster-7ajeznlcoium-minion-2) # sudo systemctl stop kubelet
すると。。。
# kubectl get pod -n kube-system -o wide -l k8s-app=elasticsearch-logging NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES elasticsearch-logging-0 1/1 Terminating 0 11m 10.100.2.221 test-cluster-7ajeznlcoium-minion-2 <none> <none> elasticsearch-logging-1 1/1 Running 0 9m56s 10.100.0.97 test-cluster-7ajeznlcoium-minion-0 <none> <none>
StatefulSetの場合は、PodのTerminate処理が完了してから新しいPodが上がるので、kubeletが反応しない以上Terminate処理が完了できず、stuckしてしまうみたいです。
ではどうするか。。。その際の解の一つがTwitter上でご指摘いただいた方から教わったkube-fencingです。
kube-fencingを使うと、NotReadyなノードが生じた場合、その上のk8sオブジェクトを全て削除してノードをフェンシング(強制再起動)してくれます。k8sオブジェクトの削除対象にはNodeオブジェクトも含まれるので、その上に乗ったPodはTerminateどころかetcdから消えます。したがって新しいPodが間違いなく作られるという仕組みで回避しようというのです。
では早速インストールしてみましょう。ソースコードをDLします。
# cd ~ # git clone https://github.com/kvaps/kube-fencing
manifest群が置いてあるディレクトリに移動します。
# cd kube-fencing/examples
私が管理しているノード群はOpenStack上に乗っているので、openstack
コマンドを使ってfencingを実現したいと思います。以下のようにfencing-script.yaml
を書き換えます。
apiVersion: v1 kind: ConfigMap metadata: name: fencing-scripts namespace: fencing data: fence.sh: | #!/bin/bash NODE="$1" source /openstack/openrc-file openstack server reboot --hard $1
fencing-scriptに与えるopenrcファイルを用意し、secretオブジェクトを作成します。Secretオブジェクトを作るために、fencing
Namespaceも一緒に作ります。
# kubectl create ns fencing # kubectl create secret generic openrc-file --from-file=openrc-file=openrc-file -n fencing
作ったSecretをマウントするように、またimageもopenstackコマンドがインストールされたものを指定するようにfencing-agents.yaml
を書き換えます。
apiVersion: apps/v1 kind: Deployment metadata: name: fencing-agents namespace: fencing spec: replicas: 1 selector: matchLabels: app: fencing-agents template: metadata: labels: app: fencing-agents spec: nodeSelector: node-role.kubernetes.io/master: "" tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule hostNetwork: true containers: - name: fencing-agents image: bbrfkr0129/kube-fencing-agents command: [ "/usr/bin/tail", "-f", "/dev/null" ] volumeMounts: - name: scripts mountPath: /scripts - name: openrc-file mountPath: /openstack volumes: - name: scripts configMap: name: fencing-scripts defaultMode: 0744 - name: openrc-file secret: secretName: openrc-file defaultMode: 0400
manifestを適用します。
# kubectl apply -f .
ノードがNotReady時にfencingしてほしいノードはlabel付けをしておく必要があります。ワーカーノードをラベル付けしておきます。
# kubectl label node test-cluster-7ajeznlcoium-minion-0 fencing=enabled # kubectl label node test-cluster-7ajeznlcoium-minion-1 fencing=enabled # kubectl label node test-cluster-7ajeznlcoium-minion-2 fencing=enabled
これでインストール完了です! 早速kubeletを停止させてみましょう。
(test-cluster-7ajeznlcoium-minion-2) # sudo systemctl stop kubelet
どうなるかというと。。。今度は新しいPodが上がってきません。。。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES elasticsearch-logging-0 1/1 Running 0 3m51s 10.100.0.98 test-cluster-7ajeznlcoium-minion-0 <none> <none> elasticsearch-logging-1 0/1 Init:0/1 0 53s <none> test-cluster-7ajeznlcoium-minion-0 <none> <none>
describeでログを見ると当然で、PVが違うインスタンスにアタッチされていて、移動できない旨のメッセージが表示されます。しかもたちの悪いことにノードオブジェクトは削除/再作成が行われているため、自分にPVがアタッチされていることを覚えていません。
ではやはりkube-fencingでもStatefulSetは救えないのか。。。というと、実は最後の砦があります。それは
もう諦めて、StatefulSetにはファイルシステムベース(NFSなど)のPVを使う、ということです。こうすれば、PVの取り合いが起きてもどのノードもPVをアタッチ/マウントできるので問題を回避できます。nfs-client
external-storage-provisionerなどを使って、興味がある方は試してみてください。
結論としては
- kube-fencingでもBlock DeviceベースのStatefulSetは救えない。FileSystemベースなら大丈夫。
ということでした。
Kubernetesのノード障害時の挙動とノード復帰後の再スケジューリング
Kubernetes上のアプリケーションの可用性について調べていたところ、ノード障害時に気をつけたほうが良い点を見つけたので記事にしてみます。
Kubernetesのノード障害時にはノードのステータスがNotReady
になります。Kubernetesクラスタが以下の通り構成されていたとしましょう。
# kubectl get node NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 147m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 147m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 147m v1.14.0 test-cluster-7ajeznlcoium-minion-2 Ready <none> 147m v1.14.0
さらに、Podは次のように起動していたとしましょう。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-4jl4z 1/1 Running 0 20s 10.100.0.13 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-h7kjb 1/1 Running 0 20s 10.100.1.18 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-vd9xs 1/1 Running 0 20s 10.100.2.14 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-g8fjl 1/1 Running 0 26s 10.100.1.17 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-lp4fv 1/1 Running 0 26s 10.100.0.12 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-xdkfn 1/1 Running 0 27s 10.100.2.13 test-cluster-7ajeznlcoium-minion-2 <none> <none>
ここで、ワーカーノードtest-cluster-7ajeznlcoium-minion-2
のkubeletサービスを停止します。
(test-cluster-7ajeznlcoium-minion-2) # sudo systemctl stop kubelet
40秒ほど経つと、STATUS
がNotReady
になるはずです。
# kubectl get node NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 148m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 149m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 149m v1.14.0 test-cluster-7ajeznlcoium-minion-2 NotReady <none> 148m v1.14.0
ノードがNotReady
だから、Podも移動しているだろう。。。と思いませんか?
ですが。。。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-4jl4z 1/1 Running 0 3m50s 10.100.0.13 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-h7kjb 1/1 Running 0 3m50s 10.100.1.18 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-vd9xs 1/1 Running 0 3m50s 10.100.2.14 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-g8fjl 1/1 Running 0 3m56s 10.100.1.17 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-lp4fv 1/1 Running 0 3m56s 10.100.0.12 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-xdkfn 1/1 Running 0 3m57s 10.100.2.13 test-cluster-7ajeznlcoium-minion-2 <none> <none>
2分経っても移動しません。。。
実は、v1.13.0からTaintBasedEvictionというPod退避機能がデフォルトで有効になったようです。この機能ではTaintとeffect
がNoExecute
なTolerationを使って、Podを退避させます。具体的にはノードがNotReady
になると自動的にノードにtaint node.kubernetes.io/not-ready
が付くようになり、加えて全てのPodに対してデフォルトのtolerationとしてこのtaintに対するNoExecute
tolerationが付与されます。これにより当該機能を実現しています。
デフォルトではPod退避の猶予期間であるtolerationSeconds
パラメータは300秒(5分)です。このため、デフォルトでは5分経たないとPodは再スケジューリングされなかったのです。この猶予期間を短くするには、kube-apiserverの起動オプションに以下を指定します。この例では30秒にしています。
--default-not-ready-toleration-seconds=30 --default-unreachable-toleration-seconds=30
では再チャレンジ。。。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 4m7s 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 4m8s 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-l9tkd 1/1 Terminating 0 4m7s 10.100.2.15 test-cluster-7ajeznlcoium-minion-2 <none> <none> httpd-6b77d6648-qjmfm 1/1 Running 0 12s 10.100.1.24 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-hh5gk 1/1 Terminating 0 4m1s 10.100.2.16 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 12s 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 4m1s 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-wq2hg 1/1 Running 0 4m1s 10.100.1.22 test-cluster-7ajeznlcoium-minion-1 <none> <none>
見事、30秒程度で退避できました! でもちょっとまってください。もしこの状態でノードが復活したらどうなるでしょう。
NAME STATUS ROLES AGE VERSION test-cluster-7ajeznlcoium-master-0 Ready master 173m v1.14.0 test-cluster-7ajeznlcoium-minion-0 Ready <none> 174m v1.14.0 test-cluster-7ajeznlcoium-minion-1 Ready <none> 174m v1.14.0 test-cluster-7ajeznlcoium-minion-2 Ready <none> 173m v1.14.0
Podの稼動状態はこのようになりました。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 5m51s 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 5m52s 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-qjmfm 1/1 Running 0 116s 10.100.1.24 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 116s 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 5m45s 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none> nginx-7db9fccd9b-wq2hg 1/1 Running 0 5m45s 10.100.1.22 test-cluster-7ajeznlcoium-minion-1 <none> <none>
test-cluster-7ajeznlcoium-minion-2
には再スケジューリングされません。Podが片寄状態になってしまっています。もしこの状態でたくさんPodがのったノードが停止してしまうと。。。
という事態を防ぐためにdeschedulerというプロダクトがあります!
これはKubernetesのJobとして機能させることで、Podのスケジューリングの偏りを検知して、再スケジューリングをかけてくれます。早速導入してみます。
git clone https://github.com/kubernetes-incubator/descheduler cd descheduler/kubernetes kubectl apply -f rbac.yaml kubectl apply -f configmap.yaml cat <<EOF | kubectl apply -f - apiVersion: batch/v1beta1 kind: CronJob metadata: labels: run: descheduler-cronjob name: descheduler-cronjob namespace: kube-system spec: concurrencyPolicy: Allow jobTemplate: spec: template: metadata: name: descheduler-pod annotations: scheduler.alpha.kubernetes.io/critical-pod: "" spec: containers: - name: descheduler image: bbrfkr0129/descheduler:latest volumeMounts: - mountPath: /policy-dir name: policy-volume command: - "/bin/descheduler" args: - "--policy-config-file" - "/policy-dir/policy.yaml" - "--v" - "3" restartPolicy: "Never" serviceAccountName: descheduler-sa volumes: - name: policy-volume configMap: name: descheduler-policy-configmap schedule: '*/3 * * * *' EOF
この例ではCronJobを用いて3分ごとに再スケジューリングするようにしています。
3分後、見事偏りがなくなりました。。。!!
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-6b77d6648-7hf2x 1/1 Running 0 14m 10.100.0.14 test-cluster-7ajeznlcoium-minion-0 <none> <none> httpd-6b77d6648-dshdc 1/1 Running 0 14m 10.100.1.21 test-cluster-7ajeznlcoium-minion-1 <none> <none> httpd-6b77d6648-zvznn 1/1 Running 0 44s 10.100.2.18 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-hqj72 1/1 Running 0 44s 10.100.2.20 test-cluster-7ajeznlcoium-minion-2 <none> <none> nginx-7db9fccd9b-q9psw 1/1 Running 0 10m 10.100.1.23 test-cluster-7ajeznlcoium-minion-1 <none> <none> nginx-7db9fccd9b-r2td2 1/1 Running 0 14m 10.100.0.15 test-cluster-7ajeznlcoium-minion-0 <none> <none>
Rancher Submarinerを動かしてみた
3/12にRancher公式ブログで発表された、「Submariner」という新しいOSSを動かしてみましたので、軽く所感を書きます。
Submarinerってなに?
複数のKubernetesクラスタのPodネットワークおよびServiceネットワークを繋げるプロダクトです。NodePortサービスを作って外部公開せずとも、複数Kubernetesクラスタ内のPod同士で通信することが可能になります。
公式では以下の用途にマッチするとしています。
利用手順概要
ここからは私が試した手順の概要を記載いたします。といっても公式GitHubが秀逸なので、特に面白い内容ではないですが。。。
- Kubernetesクラスタを3つ準備
submarinerを試すには最低限3つのKubernetesクラスタが必要です。2つは実際に接続したいクラスタ「west」と「east」、残りの1つは「broker」という、westとeastのネットワーク情報を同期する仲介役として動きます。 クラスタ要件として以下が求められるので、ユーザが自由に制御可能なバニラKubernetesで試すのがおすすめです。
* 任意のクラスタ間でpodネットワークcidrおよびserviceネットワークcidrおよびcluster local domainが異なること * 任意のクラスタ間でインターネットを通じて直接通信できるか、同じネットワークに所属していること
- brokerクラスタに対し、以下のコマンドを実行
# helmの初期化 kubectl -n kube-system create serviceaccount tiller kubectl create clusterrolebinding tiller \ --clusterrole=cluster-admin \ --serviceaccount=kube-system:tiller helm init --service-account tiller helm repo update # submariner-brokerのインストール SUBMARINER_BROKER_NS=submariner-k8s-broker helm install submariner-latest/submariner-k8s-broker \ --name ${SUBMARINER_BROKER_NS} \ --namespace ${SUBMARINER_BROKER_NS}
- brokerクラスタの情報を収集
SUBMARINER_BROKER_URL=$(kubectl -n default get endpoints kubernetes -o jsonpath="{.subsets[0].addresses[0].ip}:{.subsets[0].ports[0].port}") SUBMARINER_BROKER_CA=$(kubectl -n ${SUBMARINER_BROKER_NS} get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='${SUBMARINER_BROKER_NS}-client')].data['ca\.crt']}") SUBMARINER_BROKER_TOKEN=$(kubectl -n ${SUBMARINER_BROKER_NS} get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='${SUBMARINER_BROKER_NS}-client')].data.token}"|base64 --decode)
- IPSec通信するための事前共有キーの作成
SUBMARINER_PSK=$(cat /dev/urandom | LC_CTYPE=C tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1)
- westクラスタに対し、以下のコマンドを実行
# eastクラスタに対する通信のゲートウェイとなるノードにラベル付け kubectl label node <GATEWAY_NODE> "submariner.io/gateway=true" # helmの初期化 kubectl -n kube-system create serviceaccount tiller kubectl create clusterrolebinding tiller \ --clusterrole=cluster-admin \ --serviceaccount=kube-system:tiller helm init --service-account tiller # submarinerのインストール helm install submariner-latest/submariner \ --name submariner \ --namespace submariner \ --set ipsec.psk="${SUBMARINER_PSK}" \ --set broker.server="${SUBMARINER_BROKER_URL}" \ --set broker.token="${SUBMARINER_BROKER_TOKEN}" \ --set broker.namespace="${SUBMARINER_BROKER_NS}" \ --set broker.ca="${SUBMARINER_BROKER_CA}" \ --set submariner.clusterId="west-cluster" \ --set submariner.clusterCidr="<westクラスタのpod network cidr>" \ --set submariner.serviceCidr="<westクラスタのservice network cidr>" \ --set submariner.natEnabled="false"
- eastクラスタに対し、以下のコマンドを実行
# westクラスタに対する通信のゲートウェイとなるノードにラベル付け kubectl label node <GATEWAY_NODE> "submariner.io/gateway=true" # helmの初期化 kubectl -n kube-system create serviceaccount tiller kubectl create clusterrolebinding tiller \ --clusterrole=cluster-admin \ --serviceaccount=kube-system:tiller helm init --service-account tiller # submarinerのインストール helm install submariner-latest/submariner \ --name submariner \ --namespace submariner \ --set ipsec.psk="${SUBMARINER_PSK}" \ --set broker.server="${SUBMARINER_BROKER_URL}" \ --set broker.token="${SUBMARINER_BROKER_TOKEN}" \ --set broker.namespace="${SUBMARINER_BROKER_NS}" \ --set broker.ca="${SUBMARINER_BROKER_CA}" \ --set submariner.clusterId="east-cluster" \ --set submariner.clusterCidr="<eastクラスタのpod network cidr>" \ --set submariner.serviceCidr="<eastクラスタのservice network cidr>" \ --set submariner.natEnabled="false"
- westクラスタ上にnginx deploymentとserviceを作る(動作確認)
kubectl run nginx --image nginx kubectl expose deploy nginx --port 80
- 作成したサービスのIPを取得(動作確認)
NGINX_SERVICE_IP=$(kubectl get svc nginx -o jsonpath="{.spec.clusterIP}")
kubectl run busybox --restart=Never --image busybox:1.28 -- sleep 3600 kubectl exec -it busybox -- wget -q -O - ${NGINX_SERVICE_IP}
無事、nginxのスタートページが表示されればOKです。
まとめ
submarinerをざっと試してみましたが、そもそもKubernetesクラスタはプロジェクトやチームなど意味あるかたまりで分割されるであろうことから、そもそもpodネットワークやserviceネットワークをつなぎたい需要ってそんなにあるのかな? と疑問に思っています。 Rancherの提示している使い方以外に使えるとすれば、PVのクラスタ間移行なんかには便利に使える気はしますね。
現時点ではクラスタ超えのDNSには対応していないので、クラウドネイティブに使うとなるとちょっと物足りないところ。今後の発展に期待です!
Kubernetesの認定資格「CKA」を取得しました 〜これから受ける方へのアドバイス〜
この度、Kubernetesの認定資格「CKA(Certified Kubernetes Administrator)」を取得いたしました! 今後受ける方のお役に立てばと、受験レポートを残しておきます。
要約 〜忙しい人はここだけ読んでね〜
- 試験に関する説明の書かれている英語のドキュメント「Handbook」「Important Tips」を熟読しよう!
- 「Kubernetes完全ガイド」の4章から8章は可能な限り、9章から12章は余力と相談して押さえておこう!
- 「Kubernetes The Hard Way」を1度実施し、各オペレーションの意味を理解しておこう!
受験動機
私の場合は、今まで培ってきたKubernetesの技術知識を試すことが目的でした。また副次的な目的で、社内でコンテナ技術推進活動をしているため、その発言に説得力をもたせる意味もありました。
「Kubernetesの技術を身につけるきっかけにする」というパターンの方もいるかと思います。
自分がやったこと
自分が受験をするぞ!と決めてやったことは以下の4つです。私の場合は既にKubernetesを結構触ってしまっていたので役に立つかわからないですが、かけた時間を括弧付けで示しておきます。
- パスポート取得(1週間)
- 貸し会議室押さえ(30分)
- 試験のHandbookとImportant Tipsに目を通す(6時間くらい)
- Kubernetesの機能復習(8時間くらい)
パスポート取得
CKAを受験するには氏名がローマ字記載の写真付き身分証明書が必要になります。おそらくパスポート一択な気がします。
私は国際旅行等で海外に出たことが一回もなく、人生で初めてパスポートを取得しました。まさか資格試験のためにパスポートを取得することになろうとは…
パスポートの発行は私の居住する地域だと1週間程度かかりました。もし受験する熱意があるけどお持ちでない方は、受験予定日を決めたら早めに取得することをおすすめします。
ちなみに発行料は5年パスポートで1万円程度でした。
貸し会議室押さえ
CKAの受験は準備も含めて3時間半程度、誰もいない、誰も入ってこない、静かで、机・椅子以外ほぼ何もないスペースが必要になります。
私の場合は会社の会議室で試験を実施するのが難しい事情があったため、貸し会議室を予約し、受験することにしました。
試験日のスケジューリングをしてから空いている会議室を探すのが良いと思います。2000円くらいあれば借りられると思います。
試験のHandbookとImportant Tipsに目を通す
CKAは国際試験なので現状、試験に関する情報は英語になります。ですので、試験のレギュレーションを理解する時間をしっかり取りました。
Kubernetesの機能復習
先人の方々が残してくれた受験記はチラ見していましたが、なかなか実際の問題のイメージが膨らまなかったので、今まで触ってきた機能の復習は少々行いました。
具体的にはCyberAgentの青山さんが書いた本「Kubernetes完全ガイド」の4章〜12章くらいを見直したことと、Kubernetesクラスタをスクラッチで構築するハンズオン「 Kubernetes The Hard Way」を通しで1回、やり直してみました。
試験当日の対応
試験日当日の流れは以下のようになります。
Webカメラ有効化・デスクトップ共有
試験当日は予約した会議室で試験サイトにアクセスし、試験官と英語のチャットでやり取りする形になります。まずはじめにWebカメラを有効化し、デスクトップを有効化するよう、指示されました。
パスポート提示
Webカメラが有効になったら、カメラ経由でパスポートの顔写真が写っているページを試験官に見せます。ここはすんなり通りました。
受験部屋の状態確認
次に試験を受験する部屋を一周くまなくカメラで見せるように指示があります。この際、特に机上を注意してみているようで、机上をゆっくり見せてほしいと指示がありました。
Webカメラ位置調整
試験中は基本的に休憩を申し出ない限りは、受験用端末のスクリーンを見続けていなければなりません。
顔がきれいに試験官に見えていなかったのか、Webカメラを少し下げるように指示されました。ディスプレイに付属のカメラを使う人は辛いディスプレイの角度で受験することになるかもしれないです。私は許容範囲でしたが…
許容できなければ外部Webカメラがあるとよいかも…?!
受験開始
以上の準備を終えて、試験官が試験ページを更新し、問題文とコンソールが表示されました。そしたら試験開始です。開始の合図は特にありませんでした。
試験に受かるために必要だと思うこと
私が考えるCKA合格に必要なことは以下の5点になります。
- 試験レギュレーションの事前理解
- kubectlの便利機能の知識
- 基本的なKubernetesオブジェクトの知識
- Kubernetesクラスタの運用の知識
- ツールに頼らないKubernetesクラスタの構築知識
試験レギュレーションの事前理解
これが大前提になります。試験のルールは全て英語で記載されたHandbook、Important Tipsしかないので、抵抗がある方もいらっしゃるかと思いますが、禁止事項を理解しておかないと即時試験終了されてしまう恐れがあるので、HandbookとImportant Tipsの中身はよく理解するようにすると良いです。
特に、試験中に参照できるWebページの制限(k8sの公式ドキュメント、ブログ、公式GitHubのみ)には注意が必要です。Kubernetes公式ドキュメントからドキュメント検索をかけると、外部ページも引っかかるため、不意にそれらのページリンクをクリックしてしまうと不正行為になります。また、表示できるタブの数(試験サイト以外、一つのみ)も注意が必要なルールの一つです。
kubectlの便利機能の知識
kubectlを使ってオブジェクトの名前だけをリストしたり、特定のラベルを持つオブジェクトだけを検索したりする等、普段使っていない方もkubectlの効率的な使い方は理解しておいたほうが良いでしょう。青山さんの本「Kubernetes完全ガイド」だと4章を網羅的に理解しておけば十分でしょう。
基本的なKubernetesオブジェクトの知識
Deployment、ReplicaSet、Pod、各種Serviceなどの本当に基本的なオブジェクトの作り方から、マニフェストの書き方はしっかり押さえておくべきでしょう。マニフェストのサンプルはKubernetes公式ドキュメントから引っ張ってこれますし、kubectl run --dry-run -o yaml
でも確認できるので、ゼロから作るというよりかは各パラメータの意味を理解してカスタマイズできるかが重要になります。
なおその他のオブジェクトについても、私が受けた感覚では「Kubernetes完全ガイド」の5章〜8章は可能な限り押さえ、余力があれば9章、10章を理解しておくぐらいで十分かなと思います。
Kubernetesクラスタの運用の知識
Kubernetesを運用するための知識として、「Kubernetes完全ガイド」の11章の知識は押さえておきましょう。またnode selector
やtaint
、toleration
などを用いたPodスケジューリングは覚えておいて損はないと思います。
ツールに頼らないKubernetesクラスタの構築知識
「kubeadm」などのツールを用いてしかKubernetesクラスタを構築したことがない方はぜひ一度Kubernetes The Hard Way」を1度実施してください。そしてオペレーションの一つ一つの意味を理解しておくほうが良いです。
結果 〜スコアと証書〜
上記準備で、無事CKAを取得することができましたが、スコアは80%と、合格ライン74%と比較してギリギリでした。一問以外はわからない問題ではなかったのですが、失点の理由が知りたいのがホンネ…
本レポートが今後CKAを受験する方のお役に立つことを願っております!