Foreverly

メモ帳

# 202-service-mesh

Istioも0.8がリリースされたので、Istioの公式ドキュメントからサンプルアプリケーションを動かしたほうがよいです。 それでは続きをしていきます。

Service Mesh integration with Kubernetes

Service MeshコンポーネントをKubernetesクラスタに統合する方法を示します。 Service Meshは、マイクロサービス間の通信を管理するレイヤーで、クラウドネイティブアプリケーションにとって普及している サービス検出、負荷分散、自動再試行、回路遮断器、収集要求/応答メトリック、トレース情報などの重要な機能があります。

2つのよく知られているサービスメッシュ統合について検討します。

  • Linkerd
  • Istio

こちらもあわせて読みたいです。 Service meshとは何か

LinkerdとKubernetesの使用

Linkerdは、HTTP、Thrift、Mux、HTTP/2、およびgRPC経由でトラフィックをルーティングおよびロードバランスするレイヤ5/7のプロキシです。 それはFinagle(Twitterで構築)に基づいており、2017年1月にlinkerdがKubernetesとともにCNCFのメンバーになりました。

Linkerdは、回路破壊、待ち時間を考慮したロードバランシング、最終的に一貫した(「アドバイザリ」)サービス発見、デッドライン伝播、トレーシングと計測など、幅広い強力なテクニックを使用して、可視性、制御、および信頼性をアプリケーションに追加します。 今回Kubernetesクラスターで実行されているサービスの可視性に焦点を当てます。 k8sクラスタにlinkerdをインストールし、いくつかの簡単なマイクロサービスを実行し、linkerdが成功率、要求量、待ち時間などのトップラインサービスメトリクスをどのように取得するかを行います。 Linkerdの次のような機能をいくつか見ていきます。

  1. Service Mesh内のトラフィックの監視
  2. リクエストごとのルーティング

Kubernetesクラスタを作成する

3つのマスターノードと5つのワーカーノードを持つクラスタを用意

Linkerdをインストールする

kubectl でインストールします。 デフォルトのKubernetes名前空間で動作するDaemonSet(つまり、ホストごとに1つのインスタンス)としてlinkerdがインストールされます。

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/\
k8s-daemonset/k8s/linkerd.yml
configmap "l5d-config" created
daemonset "l5d" created
service "l5d" created

linkerd(l5dという名前の)ポッドが実行されていることを確認します。

$ kubectl get pods
NAME        READY     STATUS    RESTARTS   AGE
l5d-b8pht   2/2       Running   0          48s
l5d-jlpcl   2/2       Running   0          48s
l5d-kl98n   2/2       Running   0          48s
l5d-mp4vn   2/2       Running   0          48s
l5d-nnxqz   2/2       Running   0          48s

これは、5ワーカーノードクラスタからの出力です。 linkerdサービスが実行されていることを確認します。

$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP        PORT(S)                                        AGE
kubernetes   ClusterIP      100.64.0.1      <none>             443/TCP                                        5m
l5d          LoadBalancer   100.67.155.17   a8ac6926260d4...   4140:32573/TCP,4141:31565/TCP,9990:30298/TCP   2m

linkerdサービスの詳細もみてみます。

$ kubectl describe svc/l5d
Name:                     l5d
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"l5d","namespace":"default"},"spec":{"ports":[{"name":"outgoing","port":4140},{...
Selector:                 app=l5d
Type:                     LoadBalancer
IP:                       100.70.56.141
LoadBalancer Ingress:     abf44db7dbe1211e7a7d00220684043f-1319890531.eu-central-1.elb.amazonaws.com
Port:                     outgoing  4140/TCP
TargetPort:               4140/TCP
NodePort:                 outgoing  30108/TCP
Endpoints:                100.96.3.2:4140,100.96.4.2:4140,100.96.5.4:4140 + 2 more...
Port:                     incoming  4141/TCP
TargetPort:               4141/TCP
NodePort:                 incoming  31209/TCP
Endpoints:                100.96.3.2:4141,100.96.4.2:4141,100.96.5.4:4141 + 2 more...
Port:                     admin  9990/TCP
TargetPort:               9990/TCP
NodePort:                 admin  32117/TCP
Endpoints:                100.96.3.2:9990,100.96.4.2:9990,100.96.5.4:9990 + 2 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age   From                Message
  ----    ------                ----  ----                -------
  Normal  CreatingLoadBalancer  3m    service-controller  Creating load balancer
  Normal  CreatedLoadBalancer   3m    service-controller  Created load balancer

Linkerdの管理ページ(ELB:9990)に行ってインストールを確認することができます。 ELB DNSが利用可能になるには、1〜2分かかります。 ロードバランサエンドポイントにアクセスする際に問題が発生した場合は、ファイアウォールまたはVPNがポート9990へのアクセスを妨げている可能性があります。

LINKERD_ELB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
open http://$LINKERD_ELB:9990

openコマンドがだめだったらブラウザからURLを入力していけます。

ダッシュボードを確認しましょう。

サンプルのmicroservicesアプリケーションをインストールする

linkerd examplesリポジトリに「hello」と「world」という2つのマイクロサービスアプリがあります。 それらはお互いに通信してリクエストを完了します。このコマンドを実行すると、デフォルトの名前空間にこれらのアプリがインストールされます。

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/\
k8s-daemonset/k8s/hello-world.yml
replicationcontroller "hello" created
service "hello" created
replicationcontroller "world-v1" created
service "world-v1" created

次のコマンドを実行してトラフィックを生成します。

http_proxy=$LINKERD_ELB:4140 curl -s http://hello

Linkerdは、提供されているリクエスト数、接続数、豊富なデータを表示します。

Install linkerd-viz

linkerd-vizは、PrometheusとGrafanaに基づく監視アプリケーションです。 k8sクラスタにインストールされているリンカーインスタンスとサービスを自動的に検索できます。

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-viz/master/k8s/linkerd-viz.yml
replicationcontroller "linkerd-viz" created
service "linkerd-viz" created

linkerd-viz ELBを開いてダッシュボードを表示できます

LINKERD_VIZ_ELB=$(kubectl get svc linkerd-viz -o jsonpath="{.status.loadBalancer.ingress[0].*}")
open http://$LINKERD_VIZ_ELB

前の例と同様に、ELB DNSが利用可能になるには1〜2分かかることがあります。

リクエストごとのルーティング

上記の例で使用したのと同じ「hello-world」アプリケーションを使用しますが、今回は「world」マイクロサービスのバージョン2をデプロイし、要求ごとにリクエストでv1かv2を使用するかどうかを指定します 「hello-world」アプリケーションをまだ配備していない場合は、今すぐデプロイしてください。

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/ \
k8s-daemonset / k8s / hello-world.yml

以前のリンカーのDaemonsetを削除してください。ConfigMapを更新して新しいものをインストールします

$ kubectl delete ds/l5d

アプリケーションに外部からアクセスできるようにlinkerd ingressをデプロイします。

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/\
k8s-daemonset/k8s/linkerd-ingress.yml
configmap "l5d-config" configured
daemonset "l5d" configured
service "l5d" configured

今、バージョン2の「world」マイクロサービスを導入してください。

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/\
k8s-daemonset/k8s/world-v2.yml
replicationcontroller "world-v2" created
service "world-v2" created

サービスのv1にリクエストを送信します。それは 'Hello world'と返信する必要があります。

INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
curl -H 'Host: www.hello.world' $INGRESS_LB

1〜2分後、次のHello worldように返信する必要があります。

Hello (100.96.1.12) world (100.96.1.14)

要求のヘッダーを変更して、サービスのv2に要求を送信します。

Hello (100.96.1.11) earth (100.96.2.14)

次のように「Hello Earth」と返信する必要があります

Hello (100.96.1.11) earth (100.96.2.14)

これは、worldサービスのv1とv2がクラスタ内で実行されていることを示しています。 また、要求ヘッダーに個々の要求をルーティングするサービスのバージョンを指定できます。 これでおしまい! linkerdの設定ファイルをlinkerdの例で見ることができます。

Cleanup

インストールしたコンポーネントの削除

kubectl delete -f install/kubernetes/addons/servicegraph.yaml
kubectl delete -f install/kubernetes/addons/prometheus.yaml
kubectl delete -f install/kubernetes/istio-auth.yaml
kubectl delete -f install/kubernetes/istio.yaml
./samples/bookinfo/kube/cleanup.sh
kubectl get all
kubectl get all --namespace istio-system

IstioとKubernetesの併用

Istioは、HTTP、WebSocket、HTTP/2、gRPC経由でトラフィックのルーティングとロードを行い、MongoDBやRedisなどのアプリケーションプロトコルをサポートするレイヤ4/7プロキシです。 IstioはEnvoyプロキシを使用して、サービスメッシュ内のすべての着信/発信トラフィックを管理します。 EnvoyはLyftによって建設され、2017年9月EnvoyはKubernetesと共にCNCFのメンバーになった。 Istioは、GoogleIBMLyftの共同開発です。

Istioには、A/Bテスト、段階的/カナリ・ロールアウト、障害回復、回路遮断器、レイヤー7ルーティング、ポリシー施行(すべてEnvoyプロキシによって提供される)など、アプリケーションコードの外にあるさまざまなトラフィック管理機能があります。 また、IstioはMixerコンポーネントを使用して、ACL、レート制限、クォータ、認証、要求トレース、テレメトリ収集をサポートしています。 Istioプロジェクトの目標は、アプリケーションの変更を必要とせずにトラフィック管理とマイクロサービスのセキュリティをサポートすることです。 これは、すべてのネットワーク通信を処理するside-carをポッドに注入することで行います。

この演習では、Istioが提供する次のような機能をいくつか見ていきます。

  • 加重ルーティング
  • 分散トレース
  • 相互TLS認証

Kubernetesクラスタを作成

3つのマスターノードと5つのワーカーノードを持つクラスタを使用

Istioをインストールする

Istioは、Envoy(side-car proxy)のサイドカーをポッドに挿入するためにマシンにバイナリをインストールする必要があります。 つまり、Istioをダウンロードする必要があります。Istioは自動的にside-carを注入することもできます。 詳細はIstioクイックスタートをご覧ください

curl -L  https://git.io/getLatestIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH

これで、istioctl CLI を実行できるはずです

$ istioctl version
Version: 0.8.0
GitRevision: 6f9f420f0c7119ff4fa6a1966a6f6d89b1b4db84
User: root@48d5ddfd72da
Hub: docker.io/istio
GolangVersion: go1.10.1
BuildStatus: Clean

kubectlを使用してIstioをインストールします。 これにより、Istioが独自の名前空間 istio-system にインストールされます。 上記の手順でIstioをダウンロードしたディレクトリに移動します。 side-car 間の相互TLS認証を有効にせずにIstioをインストールします。 既存のアプリケーションを持つクラスタ、Istioside-carを持つサービスが他の非Istio Kubernetesサービスと通信できる必要があるアプリケーション、生存度と準備性のプローブ、ヘッドレスサービス、またはStatefulSet を使用するアプリケーションには、このオプションを選択します。

kubectl apply -f install/kubernetes/istio-demo.yaml

Istioがインストールされていることを確認します。 Istioは独自の名前空間にインストールされています。

$ kubectl get all --namespace istio-system
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/istio-ca        1         1         1            1           1m
deploy/istio-egress    1         1         1            1           1m
deploy/istio-ingress   1         1         1            1           1m
deploy/istio-mixer     1         1         1            1           2m
deploy/istio-pilot     1         1         1            1           1m

NAME                          DESIRED   CURRENT   READY     AGE
rs/istio-ca-2651333813        1         1         1         1m
rs/istio-egress-2836352731    1         1         1         1m
rs/istio-ingress-2873642151   1         1         1         1m
rs/istio-mixer-1999632368     1         1         1         2m
rs/istio-pilot-1811250569     1         1         1         1m

NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/istio-ca        1         1         1            1           1m
deploy/istio-egress    1         1         1            1           1m
deploy/istio-ingress   1         1         1            1           1m
deploy/istio-mixer     1         1         1            1           2m
deploy/istio-pilot     1         1         1            1           1m

NAME                                READY     STATUS    RESTARTS   AGE
po/istio-ca-2651333813-pcr1f        1/1       Running   0          1m
po/istio-egress-2836352731-sfj7j    1/1       Running   0          1m
po/istio-ingress-2873642151-vzfxr   1/1       Running   0          1m
po/istio-mixer-1999632368-nz0mw     2/2       Running   0          2m
po/istio-pilot-1811250569-mmfdg     1/1       Running   0          1m

サンプルアプリケーションのデプロイ

私たちは、Istioチームが開発したサンプルアプリケーションを使用して、Istioの機能をチェックします。 Envoy(side-car proxy)をアプリケーションに手動で注入する方法を使用しているので、以下のように istioctl を使用する必要があります。

kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/kube/bookinfo.yaml)

これによりBookInfoアプリケーションが展開されます。 これは4つのマイクロサービスで構成され、それぞれが異なる言語で書かれており、共同して書籍の製品情報、書籍の詳細、書籍のレビューを表示します。 各マイクロサービスは専用ポッドに配置され、エンボイプロキシはポッドに注入されます。 Envoyは、ポッド間のすべてのネットワーク通信を引き継ぐようになります。 すべてのコンポーネントがインストールされていることを確認しましょう

$ kubectl get all
NAME                    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/details-v1       1         1         1            1           3h
deploy/productpage-v1   1         1         1            1           3h
deploy/ratings-v1       1         1         1            1           3h
deploy/reviews-v1       1         1         1            1           3h
deploy/reviews-v2       1         1         1            1           3h
deploy/reviews-v3       1         1         1            1           3h

NAME                           DESIRED   CURRENT   READY     AGE
rs/details-v1-39705650         1         1         1         3h
rs/productpage-v1-1382449686   1         1         1         3h
rs/ratings-v1-3906799406       1         1         1         3h
rs/reviews-v1-2953083044       1         1         1         3h
rs/reviews-v2-348355652        1         1         1         3h
rs/reviews-v3-4088116596       1         1         1         3h

NAME                    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/details-v1       1         1         1            1           3h
deploy/productpage-v1   1         1         1            1           3h
deploy/ratings-v1       1         1         1            1           3h
deploy/reviews-v1       1         1         1            1           3h
deploy/reviews-v2       1         1         1            1           3h
deploy/reviews-v3       1         1         1            1           3h

NAME                                 READY     STATUS    RESTARTS   AGE
po/details-v1-39705650-vc2x0         2/2       Running   0          3h
po/productpage-v1-1382449686-b7frw   2/2       Running   0          3h
po/ratings-v1-3906799406-11pcn       2/2       Running   0          3h
po/reviews-v1-2953083044-sktvt       2/2       Running   0          3h
po/reviews-v2-348355652-xbbbv        2/2       Running   0          3h
po/reviews-v3-4088116596-pkkjk       2/2       Running   0          3h

すべてのコンポーネントが正常にインストールされている場合は、製品ページを表示できるはずです。 これには、最初にIngressが作成されるのに1〜2分かかる場合があります。 また、Ingressが公開するサービスに接続する場合もあります。 予約商品ページが表示されるまでブラウザを更新してください。

ISTIO_INGRESS=$(kubectl get -n istio-system svc istio-ingressgateway -o jsonpath="{.status.loadBalancer.ingress[0].*}")      
open http://$ISTIO_INGRESS/productpage

加重ルーティング

サンプルアプリケーションは非常に便利です。 上記のコマンドkubectl get all では、複数の「レビュー」マイクロサービスのバージョンが展開されていることがわかります。 重み付けされたルーティングを使用して、トラフィックの50%をレビューマイクロサービスのv3にルーティングします。 v3ではレビューごとに星が表示されますが、v1では表示されません。 次に、bookinfoの商品ページに数回問い合わせを行い、評価のために星を含むレビューページが表示された回数を数えます。 これは、レビューページのv3にルーティングされていることを示します。

$ kubectl create -f samples/bookinfo/kube/route-rule-all-v1.yaml
routerule "productpage-default" created
routerule "reviews-default" created
routerule "ratings-default" created
routerule "details-default" created
$ kubectl replace -f samples/bookinfo/kube/route-rule-reviews-50-v3.yaml
routerule "reviews-default" replaced

エンボイプロキシは、異なるバージョンのマイクロサービスへのルーティングをラウンドロビンしません。 したがって、製品ページに2回アクセスすると、1つのリクエストでレビューのv1が使用される可能性は低くなり、2回目のリクエストではv3が使用されます。 しかし、100件を超えるリクエストのうち50%はレビューページのv3にルーティングする必要があります。以下のスクリプトを使用してこれをテストできます。 mfileこれを実行する前に、現在のフォルダで呼び出されているファイルがないことを確認してください。 このスクリプトcurlはbookinfo製品ページに100回のリクエストを送信します。 約30秒かかる場合があり、レスポンスに星があるものを数えます。製品ページhtmlには2人のレビューアが含まれているため、2人で区切られています。 curlsレビューページで「完全な星」を返しました。100本のカールのうち、50本は「完全な星」を含むと予想しています。

ISTIO_INGRESS=$(kubectl get -n istio-system svc istio-ingressgateway -o jsonpath="{.status.loadBalancer.ingress[0].*}")   
for((i=1;i<=100;i+=1));do curl  -s http://$ISTIO_INGRESS/productpage >> mfile; done;
a=$(grep 'full stars' mfile | wc -l) && echo Number of calls to v3 of reviews service "$(($a / 2))"

出力は次のように表示されます。

Number of calls to v3 of reviews service 72

最後に、一時ファイルを削除します。

rm mfile

この重み付きルーティングは、Istioがバージョン間のトラフィックをルーティングし、トラフィックの負荷に対応するためにレビューマイクロサービスをスケーリングすることによって処理されました。

分散トレース

Istioは各サイドポッドにside-car proxyとして配備されています。 つまり、マイクロサービス間のすべてのトラフィックフローを表示および監視し、メッシュトラフィックのグラフィカルな表現を生成できます。 前の手順でデプロイしたbookinfoアプリケーションを使用してこれを実演します。

まず、Prometheusをインストールします。 これはIstioから必要なメトリクスを取得します

$ kubectl apply -f install/kubernetes/addons/prometheus.yaml
configmap "prometheus" created
service "prometheus" created
deployment "prometheus" created

Prometheusが動作していることを確認してください.

$ kubectl -n istio-system get svc prometheus
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
prometheus   ClusterIP   100.69.199.148   <none>        9090/TCP   47s

Servicegraphアドオンをインストールします。 Servicegraphは、Istioからのメッシュトラフィックフローの詳細を取得するPrometheusをクエリします。

$ kubectl apply -f install/kubernetes/addons/servicegraph.yaml
deployment "servicegraph" created
service "servicegraph" created

Servicegraphが展開されたことを確認します。

$ kubectl -n istio-system get svc servicegraph
NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
servicegraph   ClusterIP   100.65.77.1   <none>        8088/TCP   5m

bookinfoアプリケーションへのトラフィックを生成。

ISTIO_INGRESS=$(kubectl get ingress gateway -o jsonpath="{.status.loadBalancer.ingress[0].*}")
open http://$ISTIO_INGRESS/productpage

サービスグラフUIを表示する - ポートフォワーディングを使用してこれにアクセスします。

kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=servicegraph -o jsonpath='{.items[0].metadata.name}') 8088:8088 &
open http://localhost:8088/dotviz

このような形の分散トレースが表示されます。 Servicegraphが利用可能になるまで数秒かかる場合がありますので、応答がない場合はブラウザを更新してください。

side-car 間の相互TLS認証を有効にする

Istio-auth は、サイドキャストプロキシ間の相互TLS通信を強制することによって、マイクロサービス間の安全な通信を可能にします。 これを実装するのは簡単です。 相互TLSを有効にしてIstioをインストールするだけです。

上記の例を実行した場合は、Istioをアンインストールします。

kubectl delete -f install/kubernetes/istio.yaml

Authモジュールを有効にして再インストールする. デフォルトでは、Istioをインストールし、side-car 間で相互TLS認証を実施します。 このオプションは、新しく展開されたワークロードでIstio-side-car がインストールされていることが保証されている新しいkubernetesクラスタでのみ使用してください。

kubectl apply -f install/kubernetes/istio-demo-auth.yaml

マイクロサービス間のすべてのトラフィックが暗号化されます。

Cleanup

インストールされているコンポーネントを削除する

kubectl delete -f install/kubernetes/addons/servicegraph.yaml
kubectl delete -f install/kubernetes/addons/prometheus.yaml
kubectl delete -f install/kubernetes/istio-auth.yaml
kubectl delete -f install/kubernetes/istio.yaml
./samples/bookinfo/kube/cleanup.sh

default 上記のクリーンアップスクリプト名前空間を受け入れます。

Istioを削除すると、出力にエラーが表示されることがあります。 これらはインストールしていないIstioコンポーネントに関連しているので、これらについては心配する必要はありません。 すべてがアンインストールされたことを確認するには、次のようにします。 IstioまたはBookinfoのコンポーネントは残る必要はありません。

kubectl get all
kubectl get all --namespace istio-system

リソースグラフの見方

cactiとgrafanaのグラフの見方について調べました。

cactiグラフの見方

まずグラフを見るときは長いスパンでの確認と単位に気を付けること

サーバステータス・OS系

  • CPU Utilization
    • コアごとにCPU使用率を表示させる
  • Context Switches
    • サーバ側がカウンタなので、前回の処理からの差分を描画
    • 「Context Switches」はCPUでの処理対象プロセスなどの切り替え回数を示している。
    • プロセスの並列度が高く単位時間あたりの処理が多いシステムでは、値が大きくなる。
  • Forks
    • サーバ側がカウンタなので、前回の処理からの差分を描画
    • 「Forks」はプロセス処理であるForkの実行回数を示している。
    • プロセスの生成はCPUコストのかかる処理。
    • このグラフの値が常時大きい場合には、無駄なプロセス生成や外部プロセス呼び出しをしていないか、 必要だとしても、それをライブラリ呼び出しに変更できないか要検討
  • Interrupts
    • サーバ側がカウンタなので、前回の処理からの差分を描画
    • 「Interrupts」はネットワーク送受信などによる割り込みの数
    • ネットワーク送受信が多かったりすると増える。
  • Load Average
    • サーバ側の値をそのまま表示
    • 1 Minute Average:データ取得時点から直近1分間の実行街キュー数の平均値
    • 5 Minute Average:データ取得時点から直近5分間の実行街キュー数の平均値
    • ロードアベレージの値を読み解くのが難しいため、性能面の指標としては使うことができない。
    • 値の変化は状況の変化を表している。 負荷の指標としては、そのシステムが提供するサービス(HTTPなどの)応答時間をチェックする 性能の限界を越えると一気にロードアベレージの値が跳ね上がる。 急激な変化があった場合には、他の指標と見比べて、ボトルネックが発生していないか確認する。 ロードアベレージが高いから処理が遅くなることはありえず、処理がおそくなっていることがロードアベレージとして現れるという指標
  • Memory
    • Used Real:実メモリ使用量
    • Buffers:バッファとして利用中のメモリ容量
    • Cache:キャッシュとして利用中のメモリ容量
    • Unused Real:仮想メモリ使用量
    • Used Swap:Swapの読み書き量
    • Total Real:全メモリ容量
  • ディスク関連のグラフ
    • Disk Elapsed IO Time (ms)
    • サーバ側がカウンタになっているので、前回の処理からの差分を描画
    • IO Time:I/O時間
    • IO Time Weighted:I/O総所要時間
    • 「IO Time」に対して「IO Time Weighted」が大きい場合、ディスクI/Oに対して性能が不足している。
  • Disk Operations
    • サーバ側がカウンタになっているので、前回の処理からの差分を描画
    • Reads:ディスク読み込み要求数
    • Reads Merged:マージされたディスク読み込み要求数
    • Writes:ディスク書き込み要求数
    • Writes Merged:マージされたディスク書き込み要求数
    • 「Reads」+「Writes」=「Io Ops
    • 「Merged」はmergeされたI/O要求数
    • I/O処理を効率化するためにサーバがI/O要求をまとめることがある。
    • 基本的なI/O要求数は「Reads」と「Writes」で確認でき、「Merged」を見つけることで効率化の程度が確認できる
  • Disk Read/Write Time
    • サーバ側がカウンタになっているので、前回の処理からの差分を描画
    • Time Spent Reading 読み込みに要した時間
    • Time Spent Reading 書き込みに要した時間
    • Disk Sectors Read/Written
    • Sectors Read:読み込みセクタ数
    • Sectors Written:書き込みセクタ数
  • Disk Space
    • Used:利用中のディスク容量
    • Total:全容量
  • TCP Connection
    • サーバの値をそのまま表示
    • 「ESTABLISHED or CLOSE-WAIT」「ESTABLISHED」ステータスのソケット数、「CLOSE_WAIT」ステータスのソケット数
    • ESTABLISHED や CLOSE-WAITはプロセスがアタッチされた状態のため、
    • この数が大きいということはサーバ側の処理の並列数が高い
  • Network Traffic
    • サーバ側がカウンタで、前回の処理からの差分を描画
    • Inbound Inbound Traffic(受信)
    • Outbound Outbound Traffic(送信)
  • ネットワーク帯域利用量
    • 数値が頭うちになっていれば、ネットワーク帯域不足
  • APC cache purges
    • Alternative PHP Cache (APC) は、PHP の実行コードをキャッシュする仕組み
    • ファイルキャッシュと、ユーザのキャッシュでAPCがキャッシュを削除したサイズ
  • APC file cache hits and misses
    • Hits:ファイルキャッシュのヒット率
    • Misses:ファイルキャッシュのミス率 キャッシュヒットとは、命令処理に必要なデータがキャッシュメモリに存在し、キャッシュメモリからデータを読み込むことができることです。 またキャッシュミスとは、命令処理に必要なデータがキャッシュメモリに存在せず、キャッシュメモリからデータを読み込むことができないことです。 キャッシュミスの場合、メインメモリ等にデータを探しに行きます。
  • APC file cache memory
    • OP CODE Cache: opcodeキャッシュにキャッシュされたファイル
    • User Itmes Cache:ユーザーおよびアイテムがキャッシュ
    • Memory Limit:APCキャッシュメモリの上限
  • APC user cache hits and misses
    • Hits:ユーザキャッシュのヒット率
    • Misses:ユーザキャッシュのミス率
  • Apache Bytes
    • Bytes Sent:送信バイト数
    • Apacheが送信したバイト数
  • Apache CPU Load
  • Apache Requests
    • 発生したリクエスト数
  • Apache Scoreboard
    • Apacheリクエストの管理状態を表示 pacheで実際にHTTPリクエストを処理するエンティティを「スロット」と呼ぶ。そして、スロットを集めたApacheのリクエスト処理の管理状態の記録をスコアボードと呼ぶ。 スコアボードは、処理系にもよるが、大抵はOSの共有メモリを利用しており、リクエスト処理をするプロセス間で共有可能な記憶領域となっている。 共有メモリが利用できない一部の旧式な処理系では、ファイルで管理するらしい。 [Apacheスコアボードの監視とチューニング ](http://www.ginnokagi.com/2008/03/apache.html
  • Apache Workers
    • Idle workers:アイドルなプロセス数
    • Busy workers:ビジーなプロセス数 負荷が高い時間帯にIdleWorkersがゼロになる率が高い場合はMinSpareServersの値が小さいということになります。もっと大きい値にして、プロセス生成のオーバーヘッドを下げてやる必要があります。 負荷が高い時間帯にIdleWorkersが大きな値を示している場合はプロセス=メモリーが無駄使いされていることになりますから、MinSpareServersをもっと小さい値にします。その分のメモリーをバッファキャッシュ等に回してほうがよい。 mod_statusでapacheの稼働状況を記録する

MySQL

ステータス関連のグラフ

  • MySQL Command Counters※Max 500
    • Questions:総ステートメント実行回数
    • Com xxx :xxxステートメントを実行した回数 SELECT文が実行された場合は「Com Select」がカウントアップ。 ただし、クエリキャッシュにヒットした場合は「Questions」に計上されるが「Com Select」には計上されない このグラフからのSQLの量・内容・集中傾向を確認することで、チューニングの手がかりになる。
  • MySQL Connections※Max 120
    • サーバ側の値をそのまま表示しているもの
    • Max Connections:設定上の最大コネクション数
      • 起動して以来の最大同時コネクション数
    • Max Used Connections:最大同時接続コネクション数
    • Threads Connected:接続中のコネクション数
      • 同時接続数 コネクションプールを使うと「Threads Connected」は多いものの。Connections」は少なくなる。
    • サーバ側がカウンタになっていて、前回の処理からの差分を描画しているもの
    • Aborted Clients:接続できたが切断されたコネクションの数
      • 接続が正常にできていたものの、「WAIT_TIMEOUT」や「INTERACTIVE_TIMEOUT」などにより、
      • 切断されたコネクションの数
    • Aborted Connects:接続できなかったコネクションの数
    • Connections:接続されたコネクションの数
  • MySQL Files and Tables※Max 2.0k
    • サーバ側の値をそのまま表示
    • Table Cache:テーブルキャッシュサイズ
    • Open Tables:開いたことのあるテーブル数
    • Open File:開いたことのあるファイル数
    • Opend Tables:今開いているテーブル数
  • MySQL Handlers※Max 600k
    • サーバ側がカウンタになっているので、前回からの処理からの差分を描画
    • Handler Write:「INSERT」の要求回数
    • Handler Update:「UPDATE」の要求回数
    • Handler Delete:「DELETE」の要求回数
    • Handler Read First:最初のエントリがインデックスから読み込まれた回数
      • この項目が多いときは、フルスキャンが多いかもしれないので要確認
    • Handler Read Key:キー(インデックス)に基づく読み込み回数
      • この項目が多いときは、適切にインデックスが付与されている証拠なのでいい傾向
    • Handler Read Next:キー順序での次レコードの読み込み要求回数
    • Handler Read Prev:キー順序での前レコードの読み込み要求回数
      • NextとPrevは範囲指定をしてインデックスカラムをスキャンした場合に増える
    • Handler Read Rnd:固定位置に基づくレコードの読み込み要求回数
      • SQL結果をソートすることが多い場合に増える。テーブルスキャンが多いか、インデックスなしの「JOIN」が多く、インデックスが適切に付与できていない可能性がある。
    • Handler Read Rnd Next:データファイルでの次レコードの読み込み要求回数
      • この項目が多いときは、テーブルスキャンが多く、インデックスが適切に付与できていない可能性あり
  • MySQL Network Traffic※Max i.0M
    • サーバ側がカウンタになっているので、前回の処理からの差分が描画
    • Bytes Sent:MySQLからクライアントに送信したデータ量
    • Bytes Received:MySQLがクライアントから受信したデータ量。 単位がbytesなので注意(bitではない)通常はSentが圧倒的に多いが、SQLが長い、または投入データが大きい場合はReceivedも大きくなる。
  • MySQL Processlist※Max 4.0
    • サーバ側の値をそのまま表示
    • State Closing Tables:データをディスクにフラッシュしテーブルをクローズ中
    • State Copying To tmp Table:メモリ上の一時テーブルにデータをコピー中
    • State End:データ操作処理中
      • SQL文の「ALERT TABLE」、「CREATE VIEW」、「DELETE」、「INSERT」、「SELECT」、「UPDATE」の終了処理(クリーンアップ前)の状態
    • State Freeing Items:アイテム開放処理中
      • クリーンアップの次の工程で、クエリキャッシュを含めたいくつかのアイテムを開放している状態です。
    • State Init:SQL実行のための初期化中
      • SQL文の「ALERT TABLE」、「CREATE VIEW」、「DELETE」、「INSERT」、「SELECT」、「UPDATE」の実行準備中の状態
      • 具体的にはバイナリログやInnoDBログのフラッシュ、クエリキャッシュのクリーンアップ等を実行しています。
    • State Locked:ロックされている(ロック開放待ち)
      • 「State」が「Locked」、「Table lock」、「Waiting for .*lock」の合算。
      • ここでリストアップされていないものは「State Other」にすべて計上されている。
    • State Login:ログイン(認証処理など)処理中
    • State Preparing:クエリオプティマイザ実行中
    • State Reading From Net:ネットワークからSQLを読み込み中
    • State Sending Date:SELECTによるデータ読みこみ、またはクライアントへのデータ送信中
    • State Sorting Result:一時テーブルを利用しないsort処理中
    • State Statistics:SQL実行計画決定の為の統計処理中
    • State Updating:UPDATEのためのデータ探索中またはUPDATE処理中
    • State Writing To Net:ネットワークへデータを草子中
    • State None:Stateなし
      • 「State」に値が設定されていないスレッド。
      • 例えばSLEEP中のスレッド等が該当します。
      • トランザクション内でSQLSQLの間もSLEEPになるので「State None」に計上されます。
    • State Other:その他
  • MySQL Thread※Max 8
    • サーバ側の値をそのまま表示しているものと、サーバ側がカウンタとなっていて、前回の処理からの差分を描画しているものがある。
      • サーバ側の値をそのまま表示
      • Thread Cache Size:スレッドキャッシュのサイズ
      • Thread Connected:接続中(利用中)のスレッド数
      • Threads Running:実行中ステータスのスレッド数
      • Threads Cached:キャッシュされていたスレッド数
    • 前回からの差分を描画
      • Threads Created:生成されたスレッド数 「Threads Created」が高い値を示し続けるなら、 「Thread Cache Size」を増やすと処理が効率化できるかもしれない。
  • MySQL Transaction Handler※Max600
    • サーバ側がカウンタになっているので、前回の処理からの差分を描画
    • Handler Commit:コミット要求数
    • Handler Rollback:ロールバック要求数
    • Handler Savepoint:セーブポイント要求数
    • Handler Savepoint Rollback:セーブポイントロールバック要求数 どの数値が多いから異常ということはないが、想定範囲から大幅に外れていないか確認は必要

性能関連のグラフ

  • MySQL Query Cache※Max 10k
    • サーバ側の値をそのまま表示
      • Qcache Queries In Cache:キャッシュに格納されているSQL
    • サーバ側がカウンタになって、前回の処理からの差分を描画
      • Qcache Hits:キャッシュヒットしたSQL
      • Qcache Inserts:キャッシュに新しく登録されたSQL
      • Qcache Not Cached:キャッシュしないSQL
      • Qcache Lowmem Prunes:キャッシュ容量不足によりキャッシュから削除されたSQL数 「Qcache Lowmem Prunes」が発生しているようであれば、クエリキャッシュのサイズを調整することで処理が効率化できるかもしれない 合計SQL数は「Qcache Inserts」+「Qcache Hits」+「Qcache Not Cached」
  • MySQL Query Cache Memory
    • サーバ側がカウンタで前回の処理からの差分を描画
    • クエリキャッシュではブロック長は可変なので、「Qcache Free Memory」が多くも、
    • 「Qcache Free Blocks」が少ないと、キャッシュできるSQL数は少なくなる。
    • Qcache Cache Size:クエリキャッシュのサイズ
    • Qcache Free Memory:クエリキャッシュの空き容量
    • Qcahce Total Blocks:クエリキャッシュの総ブロック数
    • Qcache Free Blocks:クエリキャッシュの空きブロック数
  • My Select Types
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Select Full Join:インデックスを利用しないJOINの数
    • Select Full Range Join:関連テーブルで範囲検索したJOINの数
    • Select Range:ファーストテーブルを範囲検索した部分を利用したJOINの数
    • Select Range Check:インデックスなしのJOINの数
    • Select Scan:ファーストテーブルでフルスキャンを実行したJOINの数 Select Full JoinとSelect Range Checkが0でない場合は、インデックスを見直す。
  • MySQL Sorts
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Sort Rows:ソートしたレコード数
    • Sort Range:範囲指定ソートの回数
    • Sort Merge Passes:ソートで必要としたマージパスの回数
    • Sort Scan:テーブルスキャンでソートした回数
  • MySQL Table Locks
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Table Locks Immediate:テーブルロックを直ちに実行した回数
    • Table Locks locks Waited:テーブルロックを実行するとき待ちが発生した回数
    • Slow Queries:スロークエリの数 テーブルロックが発生すると処理の並列度が著しく下がるため、「Table Locks Waited」が0になるようにする。
  • MySQL Temporary Objects
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Created Tmp Tables:作成した一時テーブルの数
    • Created Tmp Disk Tables:ディスク上に作成した一時テーブルの数
    • Created Tmp File:作成した一時ファイルの数 「Created Tmp Disk Tables」に計上される一時テーブルは、 一時テーブルのサイズが「tmp_table_size」を越えた場合にディスクに書き出されるもの。 「Created Tmp File」に計上される一時ファイルは「sort_buffer_size」を 越える大きな「ORDER_BY」や「GROUP_BY」により作成されます。

InnoDB関連のグラフ

  • InnoDB Buffer Pool Activity
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Pages Created:作成されたページの数
    • Pages Read:読み込まれたページの数
    • Pages Written:書き込まれたページの数
    • デフォルト1ページ16KB
  • InnoDB Buffer Pool
    • サーバ側の値をそのまま表示
    • Pool Size:バッファプールのサイズ(ページ数)
    • Database Pages:データがあるページ数
    • Free Pages:空きページ数
    • Modified Pages:書き換えが発生したダーティページ数
    • 単位がページ数で、デフォルトは1ページ16KB。
  • InnoDB I/O
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Fire Reads:OSでの読み込みI/O実行回数
    • Fire Writes:OSでの書き込みI/O実行回数
    • Log Reads:log書き込みI/O実行回数
    • Fire Fsysncs:OSでのfsyncs実行回数
  • InnoDB I/O
    • サーバ側の値をそのまま表示
    • このグラフの数値すべてが0でない場合、ディスクI/Oがボトルネックになっている可能性がある。InnoDB I/Oグラフと併せて確認する
    • Pending Aio Log Ios:insert bufferの非同期ログでの待ちI/O数
    • Pending Aio Sync Ios:insert bufferの非同期syncでの待ちI/O数
    • Pending Chkp Writes:チェックポイントでの待ち
    • Pending Ibuf Aio Reads:insert bufferの非同期ログ読み込みでの待ちI/O数
    • Pending Log Flushes:ログフラッシュでの待ち
    • Pending Log Writes:ログ書き込みでの待ち
    • Pending Normal Aio Log Reads:通常の読み込み非同期I/Oでの待ち
    • Pending Normal Aio Log Writes:通常の書き込み非同期I/Oでの待ち
    • Pending Buf Pool Flushes:バッファプールフラッシュでの待ち
  • InnoDB Insert Buffer
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Ibuf Inserts 実行した書き込み要求数
    • Ibuf Merged マージされたI/O要求数
    • Ibuf Merges マージ処理回数
  • InnoDB Lock
    • サーバ側がカウンタで前回の処理からの差分を描画とサーバ側の値をそのまま表示のものがある
    • サーバ側がカウンタで前回の処理からの差分を描画
      • Innodb Log Buffer Size:ログバッファのサイズ
      • Unflushed Log:ログから書き出されていないデータ量
    • サーバ側の値をそのまま表示のものがある
      • Log Bytes Written:ログに書き込まれたデータ量
      • Log Bytes Flushed:ログから書き出されたデータ量
  • InnoDB Row Operations
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Row Read 読み込まれた行数
    • Rows Delete 削除された行数
    • Rows Updated 更新された行数
    • Rows Inserted 挿入された行数
  • InnoDB Semaphores
    • サーバ側がカウンタで前回の処理からの差分を描画
    • SQL文の「SHOW ENGINE INNNODB STATUS」で取得する「SEMAPHORES」の値
    • Spin Rounds スピンロック獲得のためのラウンド数
    • Spin Waits スピンロック獲得待ち
    • Os Waits OSロック獲得待ち数
  • InnoDB Transactions
    • サーバ側がカウンタで前回の処理からの差分を描画とサーバ側の値をそのまま表示のものがある
    • 前回からの差分を描画
  • MyISAM Indexes
    • サーバ側がカウンタで前回の処理からの差分を描画
    • Key Read Requests キャッシュからのキーブロックの読み込み要求数
    • Key Reads ディスクからのキーブロックの読み込み回数
    • Key Write Requests キャッシュにキーブロックを書き込んだ要求数
    • Key Writes ディスクへのキーブロックの書き込み回数
    • SQL文の「SHOW GLOBAL STATUS」で取得する値
    • キャッシュミス率は「Key Reads」/「Key Read Requests」で計算
    • 「Key Reads」がほぼ0になるよう調整する

Grafanaの見方

5.1.6 サーバーステータス変数

# iptablesについて

iptablesについてまとめてみました。 設定ミスすると思わぬサービス影響が出るのでちゃんと理解したいところです。

オプション

オプション 意味
-N 新規チェインの追加
-X ユーザチェインの削除
-A ルールの追加
-D ルールの削除
-L チェインにあるルールの一覧表示
-F チェイン内容の全消去
-P 各チェインのデフォルトルール(ポリシー)を記述することができる
-I 選択されたチェインにルール番号を指定して 1 つ以上のルールを挿入する
-R 選択されたチェインにあるルールを置き換える
-Z すべてのチェインのパケットカウンタとバイトカウンタをゼロにする
-E ユーザー定義チェインを指定した名前に変更する。
-h ヘルプ

パラメータ

以下のパラメータは (-A, -D, -I, -R,コマンドで用いられて) ルールの仕様を決める。

パラメータ名 説明
-p(--protocol) プロコトル ルールで使うプロトコルtcpudp、icmp、all)を指定
-s(--source) IPアドレス[/mask] 送信元アドレス。IPアドレスのほかにホスト名などでも指定できる
-d(--destinationIPアドレス[/mask] 接続先アドレス。IPアドレスのほかにホスト名などでも指定できる
-i(--in-interface) デバイス パケットが入ってくるインターフェイス(eth0、eth1など)を指定
-o(--out-interface) デバイス パケットが出ていくインターフェイスを指定
-j(--jump) ターゲット パケットがマッチしたときのアクション(ターゲット)を指定
-t(--table) テーブル テーブル(filter、nat、mangle)を指定
! -p、-s、-dなどで、条件を反転する。「! 192.168.0.1」とすると、「192.168.0.1以外」という意味になる
-c このオプションを使うと、 (insert, append, replace 操作において) 管理者はパケットカウンタとバイトカウンタを 初期化することができる。
-f このオプションは、分割されたパケット (fragmented packet) のうち 2 番目以降のパケットだけを参照するルールであることを意味する。
  • -p プロトコル all は全てのプロトコルとマッチし、 このオプションが省略された際のデフォルトである。

  • ! -pではプロトコルの前に "!" を置くと、そのプロトコルを除外するという意味になる。 -sではアドレス指定の前に "!" を置くと、そのアドレスを除外するという意味になる。 フラグ --src は、このオプションの別名である。 -dではアドレス指定の前に "!" を置くと、そのアドレスを除外するという意味になる。 -iではインターフェース名の前に "!" を置くと、 そのインターフェースを除外するという意味になる。 -oではインターフェース名の前に "!" を置くと、 そのインターフェースを除外するという意味になる。 -fでは"-f" フラグの前に "!"を置くと、 分割されたパケットのうち最初のものか、 分割されていないパケットだけにマッチする。

  • -d --dst は、このオプションの別名である。

  • -j このオプションがルールの中で省略された場合、 ルールに マッチしてもパケットの行方に何も影響しないが、 ルールのカウンタは 1 つ 加算される。

  • -i パケットを受信することになるインターフェース名 (INPUT, FORWARD, PREROUTING チェインに入るパケットのみ)。 インターフェース名が "+" で終っている場合、 その名前で始まる任意の インターフェース名にマッチする。 このオプションが省略された場合、 任意のインターフェース名にマッチする。

  • -o パケットを送信することになるインターフェース名 (FORWARD, OUTPUT, POSTROUTING チェインに入るパケットのみ)。 インターフェース名が "+" で終っている場合、 その名前で始まる任意のインターフェース名にマッチする。 このオプションが省略された場合、 任意のインターフェース名にマッチする。

テーブルとは

チェインをグループ化したもの

テーブル名 利用できるチェイン
filter INPUT,FORWARD,OUTPUT
nat PREROUTING,OUTPUT,POSTROUTING
mangle PREROUTING,OUTPUT,※POSTROUTING,INPUT,FORWARD 

※3つのチェインはカーネル2.4.18からサポートされている。

  • filter パケットのフィルタリングに使用する。 これがデフォルトのテーブルである。 (-t オプションが指定されていない場合)

  • nat このテーブルは新しい接続を開くようなパケットに対して参照される。 IPマスカレードの設定を行う。 アドレス変換に使用される。

  • mangle このテーブルは特別なパケット変換に使われる。
    パケットをNAT以外の目的で置き換えるときに使用される。 TOSフィールドの書き換えなどパケットの 書き換えルールを設定する。QoSをするのに使う。

チェインとは

チェインは入力、出力、転送するパケットに適用するルールのリスト デフォルトでINPUT, FORWARD, OUTPUT, PREROUTING, POSTROUTINGの 合計5つのチェインが定義されているが新しく作成したり、既存のチェインとリンクさせることが可能

チェイン チェインの意味
INPUT コンピュータに入ってくるパケットに適用するルール)
FORWARD あるネットワークインターフェースから、別のネットワークインターフェースに中継されるパケットに適用するルール)
OUTPUT コンピュータから出てゆくパケットに適用するルール)
PREROUTING パケットが入ってきた場合、すぐにそのパケットを変換するためのチェイン)
OUTPUT ローカルで生成されたパケットをルーティングの前に変換するためのチェイン)
POSTROUTING パケットが出て行くときに変換するためのチェイン)
  • FORWARD このチェインはコンピュータがルータもしくはゲートウェイとして構成された場合に使用される。

iptableの起動確認

/etc/init.d/iptables status

  • 動いている場合
# /etc/init.d/iptables status
テーブル: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
5    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
6    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
7    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
8    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         
  • 動いていない場合
# /etc/init.d/iptables status
bash: /etc/init.d/iptables: そのようなファイルやディレクトリはありません

natテーブルの状態

オプション-t natで natテーブルを指定することができる。

# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 211 packets, 8772 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

設定追加した後にサーバ再起動時の動き

saveする前に再起動をすると追加した設定は消える。

iptablesの再起動時にファイアウォールルールを消去中:と出力されるので、 保存しなければ再起動時に設定が反映されない。

# /etc/init.d/iptables restart
iptables: チェインをポリシー ACCEPT へ設定中filter         [  OK  ]
iptables: ファイアウォールルールを消去中:                  [  OK  ]
iptables: モジュールを取り外し中:                          [  OK  ]
iptables: ファイアウォールルールを適用中:                  [  OK  ]

INPUTチェイン一番上部に追加してiptables -nvLの結果をみてみる

iptables -I 1 -m state --state NEW -p tcp -s 123.456.789.111 --sport 80 -j ACCEPT

  • iptables -nvLの結果
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       123.456.789.111      0.0.0.0/0           state NEW tcp spt:80
  404 33344 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    2   120 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 13 packets, 2948 bytes)
 pkts bytes target     prot opt in     out     source               destination         

SMTP(25ポート)にアタックが来ていると仮定して、遮断手順作成してみる

  • IP:123.456.789.222
  • ポート:25
  • プロトコル:TCP
  • チェインはINPUT
  • アタックを /var/log/maillog で確認
# /etc/init.d/iptables status
# cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_1}
# /etc/init.d/iptables save
# cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_2}
# iptables -nvL (iptables -nL)
# iptables -I INPUT -s 123.456.789.111 -p tcp --dport 25 -j DROP
# iptables -nvL
# /etc/init.d/iptables save

以下は実行ログ

# cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_1}
# /etc/init.d/iptables save
iptables: ファイアウォールのルールを /etc/sysconfig/iptable[  OK  ]中:
# cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_2}
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       123.456.789.111      0.0.0.0/0           state NEW tcp spt:80
  171 13020 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    4   240 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
    1   229 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 107 packets, 15828 bytes)
 pkts bytes target     prot opt in     out     source               destination         
# iptables -I INPUT -s 123.456.789.111 -p tcp --dport 25 -j DROP
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       123.456.789.222      0.0.0.0/0           tcp dpt:25
    0     0 ACCEPT     tcp  --  *      *       123.456.789.111      0.0.0.0/0           state NEW tcp spt:80
  189 14412 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    5   300 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
    1   229 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 4 packets, 576 bytes)
 pkts bytes target     prot opt in     out     source               destination         
# /etc/init.d/iptables save
iptables: ファイアウォールのルールを /etc/sysconfig/iptable[  OK  ]中:
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       111.111.111.111      0.0.0.0/0           tcp dpt:25
    0     0 ACCEPT     tcp  --  *      *       111.111.111.111      0.0.0.0/0           state NEW tcp spt:80
  204 15448 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    5   300 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
    1   229 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 15 packets, 3516 bytes)
 pkts bytes target     prot opt in     out     source               destination         
# /etc/init.d/iptables restart
iptables: チェインをポリシー ACCEPT へ設定中filter         [  OK  ]
iptables: ファイアウォールルールを消去中:                  [  OK  ]
iptables: モジュールを取り外し中:                          [  OK  ]
iptables: ファイアウォールルールを適用中:                  [  OK  ]
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       111.111.111.111      0.0.0.0/0           tcp dpt:25
    0     0 ACCEPT     tcp  --  *      *       111.111.111.111      0.0.0.0/0           state NEW tcp spt:80
   16  1168 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:3306
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 9 packets, 1236 bytes)
 pkts bytes target     prot opt in     out     source               destination

iptablesで遮断する手順も用意しました。

アタックがあった際iptablesにて遮断する手順

注意

  • どこのテーブルに設定を追加するか確認すること

アタックの判断基準

  • netstatの出力だけでアタックと判断しない
  • 海外IPだからという理由だけでアタックと判断しない
  • 必ず各ログを閲覧し、アタックと思われる出力を確認する

どこで遮断するか(サーバ、上流LB)

  • LBにぶら下がっているサーバに関しては、上流LBにて遮断を実施する。
  • その他については当該サーバにて遮断を実施する。

遮断手順

  1. root権限

      sudo su -
    
  2. 実施前に service iptables status で有効か確認する

     service iptables status
    
  3. 現在のiptablesの設定確認

     iptables -nvL --line
    
  4. ルールに差異がないかを確認

     diff /etc/sysconfig/iptables <(iptables-save)
    
  5. 設定ファイルをバックアップ

     cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`}
    
  6. 現在の設定を保存

     /etc/init.d/iptables save
    

    ※centos7系 iptables-save > /etc/sysconfig/iptables(wm_ml)

  7. 設定のバックアップ

     cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_2}
    
  8. 対象のIPを遮断

     iptables -I <チェイン名> 1 -p tcp -m tcp --dport <ポート番号> -s <IPアドレス> -j DROP
    
     iptables -I INPUT 1 -p tcp -m tcp --dport 80 -s 123.456.789.111 -j DROP
     iptables -I INPUT 1 -p tcp -m tcp --dport 80 -s 123.456.789.222 -j DROP
    
  9. 追加されたか確認

     iptables -nvL --line
    
  10. 疎通確認

    1. 正常な(遮断されるべきでない)疎通が取れるか確認する
    2. 別窓で当該サーバの遮断したポートに対してtelnetを実行

       telnet <サーバ> <ポート>
      
    3. 正常に接続できることを確認

  11. 現在の設定を吐き出す

    /etc/init.d/iptables save
    

    ※centos7系 iptables-save > /etc/sysconfig/iptables

差し戻し手順

  1. 直前のバックアップファイルから復元

     iptables-restore < /etc/sysconfig/iptables{,.$(date +%Y%m%d)}
    
  2. 確認

     iptables -nvL
    
  3. 疎通確認

     telnet <サーバ> <ポート>
    
  4. save

     /etc/init.d/iptables save
    

    ※centos7系 iptables-save > /etc/sysconfig/iptables

削除手順

  1. root権限

     sudo su -
    
  2. 実施前に service iptables status で有効か確認する

     service iptables status
    
  3. 現在のiptablesの設定確認

     iptables -nvL --line
    
  4. 設定のバックアップ

     cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`}
    
  5. 現在の設定を保存

     /etc/init.d/iptables save
    
  6. 設定のバックアップ

     cp -a /etc/sysconfig/iptables{,.`date +%Y%m%d`_2}
    
  7. 対象のIPを遮断

     iptables -D <チェイン名> <行番号>
    
  8. 追加されたか確認

     iptables -nvL --line
    
  9. 現在の設定を吐き出す

     /etc/init.d/iptables save
    

    ※centos7系 iptables-save > /etc/sysconfig/iptables

今度こそMySQLを覚えたい人のためのMySQL5.6入門

最近、今度こそMySQLを覚えたい!!と思いました。 では今からMySQL覚えるなら何から始めるのが良いでしょうか。MySQLは5.7や8も出てきました。 今回は日本語のドキュメントがある唯一のバージョンの5.6系をCentOS6にインストールします。

MySQL 5.6 リファレンスマニュアル

5.xもまだたくさんあり、今後数年は現役と思われるので、 基本的に捨てられた機能は忘れてよいと思いますが、 Query Cacheなどは結構使っていたりするので5.xでは知ってたほうが良いでしょう。

また、その他データベースの基礎知識についてはこちらも説明できるとよいです。

MySQLダウンロードページ MySQLのyumリポジトリ

CentOS6系に最新のMySQLリポジトリをインストール デフォルトで5.7をインストールするようになっているので、 MySQL5.6をインストールするように変更し MySQLをインストール。終わったらサービスを起動させる。

# yum install https://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm
# sudo vim /etc/yum.repos.d/mysql-community.repo
# Enable to use MySQL 5.6
[mysql56-community]
name=MySQL 5.6 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.6-community/el/6/$basearch/
enabled=1     # 0から1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

[mysql57-community]
name=MySQL 5.7 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/
enabled=0     # 1から0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
# yum install mysql-community-server
# service mysqld start
# mysql -v
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.38 MySQL Community Server (GPL)
  • rpmインストール

ダウンロードページから rpmパッケージを取得して、インストール

wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.38-linux-glibc2.12-x86_64.tar.gz
rpm -i MySQL-*.RPM
service MySQL

mysql_secure_installationでセキュアな設定

# mysql_secure_installation



NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): # 起動したてでrootパスワードが設定されていないので、そのまま「Enter」。
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] Y # Rootパスワードを設定するので「Y」。
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y # 誰でもログインできる状態になっているのでアノニマスユーザをRemoveするので「Y」。
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y # RootでMySQLにリモートログインできるのはセキュリティ的にNGなので「Y」。
 ... Success!

By default, MySQL comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y # testデータベースは不要のため「Y」。
 - Dropping test database...
ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist
 ... Failed!  Not critical, keep moving...
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y # 上記設定による権限の変更等を即時反映したいので「Y」。
 ... Success!




All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!


Cleaning up...

CREATE USER 命令でユーザ作成

rootはスーパユーザなので作業ユーザを作成しましょう。 今回は作業ユーザにmysqltestデータベースの権限を付与します。

% mysql -uroot -p
Enter password: root の パスワード を 入力
mysql > CREATE USER ユーザ名@localhost IDENTIFIED BY '*******';
mysql> GRANT ALL ON mysqltest.* TO ユーザ名@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

作業ユーザでログインします。 --default-character-set=utf8mb4 は接続の文字コードUTF-8に設定するオプションです。

[root@localhost src]# mysql -uユーザ名 -p --default-character-set=utf8mb4
Enter password:

mysqltestデータベースを作成します。 CHARSET utf8mb4 はDB配下で使う文字コードutf-8にします。

mysql> CREATE DATABASE mysqltest CHARSET utf8mb4;
Query OK, 1 row affected (0.01 sec)
mysql> use mysqladmin
Database changed

sql_modeを設定しましょう。

MySQLは標準では、指定された値のままレコードに格納できなくても、なるべくエラーにならないように処理を続けようとする(ERRORではなく警告になる)。 たとえば、 NULLを許さずデフォルト値も設定されていないカラムを指定せずにINSERTしてもエラーにならず、 型に応じた暗黙のデフォルト値が設定される。 また、 DATE 型のカラムに0000-00-00や2016-04-00などの0を含む値が許されています。 ほかにも、文字列カラムで最大長を超えた長さの文字列を格納しようとしてもエラーにならずに切り捨てられたり、 文字コード変換で正しく変換処理ができなかった場合などにもエラーになりません。 データベースには不正な値が入らないように設定は変更しましょう。 sql_modeで変更可能です。 クライアント接続ごとに SET sql_ mode =... を 発行するのではなく、すべての接続でsql_modeの設定を有効にしたい場合は、 mysqldの起動時オプションや設定ファイルで指定することができます。

ルーク!MySQLではkamipo TRADITIONALを使え!

mysql> SET sql_mode='TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec)

DB作成

みんなだいすきKEN_ALL.csv を用いてデータベースを作成しましょう。

# cd /usr/local/src/
# wget http://zipcloud.ibsnet.co.jp/zipcodedata/download?di=1364544418311 -O post.zip
# unzip post.zip
# nkf -w --overwrite KEN_ALL.CSV

以下はMySQLにログインして実行します。 CSVのインポートでエラーが出ました。 secure_file_privで設定されているディレクトリから出ないとインポートができないようです。 このエラーで検索するとsecure_file_privを無効化する力技の記事が多かった。。。

mysql> create database postaldb default character set utf8;
mysql> use postaldb;
Database changed
mysql> CREATE TABLE  `postal_codes` (`jis` varchar(10) DEFAULT NULL, `zip_old` varchar(5) DEFAULT NULL, `zip` varchar(7) DEFAULT NULL, `addr1_kana` varchar(100) DEFAULT NULL, `addr2_kana` varchar(100) DEFAULT NULL, `addr3_kana` varchar(100) DEFAULT NULL, `addr1` varchar(100) DEFAULT NULL, `addr2` varchar(100) DEFAULT NULL, `addr3` varchar(100) DEFAULT NULL, `c1` int(11) DEFAULT NULL, `c2` int(11) DEFAULT NULL, `c3` int(11) DEFAULT NULL, `c4` int(11) DEFAULT NULL, `c5` int(11) DEFAULT NULL, `c6` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.03 sec)
mysql> load data infile "/usr/local/src/KEN_ALL.CSV" into table postal_codes fields terminated bY ',' optionally enclosed by '"';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
mysql> SELECT @@secure_file_priv;
+-----------------------+
| @@secure_file_priv    |
+-----------------------+
| /var/lib/mysql-files/ |
+-----------------------+
1 row in set (0.00 sec)

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
# mv /usr/local/src/KEN_ALL.CSV /var/lib/mysql-files/
mysql> load data infile "/var/lib/mysql-files/KEN_ALL.CSV" into table postal_codes fields terminated bY ',' optionally enclosed by '"';
Query OK, 123400 rows affected (0.65 sec)
Records: 123400  Deleted: 0  Skipped: 0  Warnings: 0

mysql>
mysql> show tables;
+--------------------+
| Tables_in_postaldb |
+--------------------+
| postal_codes       |
+--------------------+
1 row in set (0.00 sec)
mysql> select * from postal_codes LIMIT 10;
+-------+---------+---------+--------------------+-----------------------------------+-------------------------------------------+-----------+--------------------+-----------------------------------------+------+------+------+------+------+------+
| jis   | zip_old | zip     | addr1_kana         | addr2_kana                        | addr3_kana                                | addr1     | addr2              | addr3                                   | c1   | c2   | c3   | c4   | c5   | c6   |
+-------+---------+---------+--------------------+-----------------------------------+-------------------------------------------+-----------+--------------------+-----------------------------------------+------+------+------+------+------+------+
| 01101 | 060     | 0600000 | ホッカイドウ       | サッポロシチュウオウク            | イカニケイサイガナイバアイ                | 北海道    | 札幌市中央区       | 以下に掲載がない場合                    |    0 |    0 |    0 |    0 |    0 |    0 |
| 01101 | 064     | 0640941 | ホッカイドウ       | サッポロシチュウオウク            | アサヒガオカ                              | 北海道    | 札幌市中央区       | 旭ケ丘                                  |    0 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600041 | ホッカイドウ       | サッポロシチュウオウク            | オオドオリヒガシ                          | 北海道    | 札幌市中央区       | 大通東                                  |    0 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600042 | ホッカイドウ       | サッポロシチュウオウク            | オオドオリニシ(1-19チョウメ)              | 北海道    | 札幌市中央区       | 大通西(1〜19丁目)                  |    1 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 064     | 0640820 | ホッカイドウ       | サッポロシチュウオウク            | オオドオリニシ(20-28チョウメ)             | 北海道    | 札幌市中央区       | 大通西(20〜28丁目)                |    1 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600031 | ホッカイドウ       | サッポロシチュウオウク            | キタ1ジョウヒガシ                         | 北海道    | 札幌市中央区       | 北一条東                                |    0 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600001 | ホッカイドウ       | サッポロシチュウオウク            | キタ1ジョウニシ(1-19チョウメ)             | 北海道    | 札幌市中央区       | 北一条西(1〜19丁目)                |    1 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 064     | 0640821 | ホッカイドウ       | サッポロシチュウオウク            | キタ1ジョウニシ(20-28チョウメ)            | 北海道    | 札幌市中央区       | 北一条西(20〜28丁目)              |    1 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600032 | ホッカイドウ       | サッポロシチュウオウク            | キタ2ジョウヒガシ                         | 北海道    | 札幌市中央区       | 北二条東                                |    0 |    0 |    1 |    0 |    0 |    0 |
| 01101 | 060     | 0600002 | ホッカイドウ       | サッポロシチュウオウク            | キタ2ジョウニシ(1-19チョウメ)             | 北海道    | 札幌市中央区       | 北二条西(1〜19丁目)                |    1 |    0 |    1 |    0 |    0 |    0 |
+-------+---------+---------+--------------------+-----------------------------------+-------------------------------------------+-----------+--------------------+-----------------------------------------+------+------+------+------+------+------+
10 rows in set (0.00 sec)

これでMySQL5.6系とデータベースもできました。 あとは実践ハイパフォーマンスMySQL 第3版と公式ドキュメントを読んでMySQLを覚えていきましょう!! 投げっぱなし感になってしまったので、今後も理解したらまとめていきます。

実践ハイパフォーマンスMySQL 第3版

実践ハイパフォーマンスMySQL 第3版

# シェルスクリプトで使える if,test,for,case,set,readコマンド

シェルスクリプトで使えるコマンドをまとめました。 最後に簡単なシェルスクリプトを実際に書いてみます。

if

if文は条件が真の時、偽の時で処理をわけることができます。

  • if文の文法
if 条件; then
   条件が真の時の処理
else
   条件が偽である時の処理
fi
  • if~else~elif文
if 条件1; then
   条件1が真の時の処理
elif 条件2; thne
   条件2が真の時の処理
elif 条件3; thne
   条件3が真の時の処理
else
   上記すべての条件が偽である時の処理
fi
if 条件1; then
    条件1が真の時の処理
    if 条件2; then
         条件1,2 ともに真の時の処理
   fi
fi
  • 引数がyesという文字列かどうか判定
#!/bin/bash

if [[ "$1" == yes ]]; then
    echo yes
else
    echo no
fi

演算子にはどのようなものがあるのかは、まとめて調べておくとよさそう。 以下、参照でも大丈夫そう。

testコマンド - []

[ は記号ではなく、if文の条件として使用されるコマンドです。 testコマンドと同様の動作をします。 [コマンドは引数に演算子を指定すると、文字列や数値の比較、ファイルの存在などを判定します。 結果が真なら0,偽なら1を終了ステータスとして返します。 終了ステータスは$?で確認できます。 ちなみに][コマンドの終わりを示す記号で[コマンドは最後の引数に]を指定しないといけない規則になっている。

hoge=yes
[ "$hoge" = "yes" ]
echo $? 

  • [[[ より条件式をよりシンプルにかけます。
    • AND演算やOR演算は -a , -o の代わりに &&, || を使用します。
  • 単語分割とパス名展開がされない。
  • パターンマッチ
      • などのパス名展開の機能が失われ、文字とみなされる。

&&と||

&&は コマンド1 && コマンド2 という形で使用し コマンド1を実行して終了ステータス0である時だけコマンド2を実行する。

||は コマンド1 || コマンド2 という形で使用し コマンド1を実行して終了ステータス0以外の時だけコマンド2を実行する。

これらと以下のコマンドを組み合わせることでシュルスクリプト記載することができると思います。

for

for 変数 in 単語list
do
  繰り返す処理
done

#!/bin/bash

for i in aaa bbb ccc
do
    echo $i
done

パス名展開でも使えます。 注意点は*.txt にマッチするファイルがなかったら、 *.txt という文字列そのものがfile変数に代入されるので注意

#!/bin/bash

for file in *.txt
do
    cp "$file" "${file}.back"
done

シェルスクリプトの引数に対して繰り返し処理をしたい場合は "$@" を使います。

#!/bin/bash

for i in "$@"
do
    echo $1
done
  • breakとcontinue

for文の処理の中でbreakを呼ぶと、その時点でforのループを抜けます。 for文の処理の中でcontinueを呼ぶと、繰り返し処理のそれ以降の部分を省略して次の繰り返しに移行します。

for i in {1..9}
do
    if [[ $i -eq 3 ]]; then
        continue
    elif [[ $i -eq 5 ]]; then
        break
    fi

    echo $i
done

case

caseは1つの文字列に対して複数のパターンを指定して、それぞれのパターンにマッチした処理を実行するための構文で 最初にマッチしたパターンの処理がおこなわれ、すべてのパターンにマッチしない場合は何も行われません。 case文の最後は esacです。

case 文字列 in
    パターン1)
        パターン1にマッチした場合の処理
        ;;
    パターン2)
        パターン2にマッチした場合の処理
        ;;
    パターン3)
        パターン3にマッチした場合の処理
        ;;
esac

case文では、パターンのところにパス名展開と同じワイルドカード記号が使用可能

#!/bin/bash

file="$1"
case "$file" in
    *.txt)
        head "$file"
        ;;
    *.tar.gz)
        tar zxf "$file"
        ;;
    *)
        echo "not supported file : $file"
        ;;
esac

パターンに | で複数指定することも可能です。 また最後の条件を * にすることでマッチしなかった場合の処理が書けます。

#!/bin/bash

file="$1"
case "$file" in
    *.txt)
      head "$file"
      ;;
    *.tar.gz | *.tgz)
      tar xzf "file"
      ;;
    *)
      echo "not supported file : $file"
      ;;
esac

while

whileは指定した条件が真である限り処理を繰り返す

while コマンド
do
    繰り返す処理
done

コマンドには [[ ]] を記述することも可能 breakやcontinueも使用できます。

#!/bin/bash

i=0
while [[ $i -lr 10 ]]
do
    echo "$i"
    i=$((i + 3))
done

until

untilはwhileとは逆で条件が偽であるかぎり処理を繰り返す

#!/bin/bash

i=0
until [[ $i -gt 10 ]]
do
    echo "$i"
    i=$((i + 3))
done

setコマンド

setコマンドの機能

  1. 現在設定されているシェル変数の一覧を表示
  2. シェルのオプションを有効または無効にする機能
  3. 位置パラメータの値を設定する機能

今回は2番目の機能の説明をする。

set -oで有効, set +oで無効にすることができる

オプション名 略称 内容
errexit -e コマンドの終了ステータスが0以外なら即座にシュルを終了する
nounset -u 未定義の変数を参照したときにエラーとする
pipefail なし パイプラインの戻り値が、終了ステータス0でない最後の値となる。

readコマンド

readは標準入力から1行分読み取るコマンドで、 その内容が引数で指定した名前の変数に代入される。

read 変数1 変数2 ...

下記のように書けばユーザのキーボード入力待ちになり readの引数であるinput変数に値が代入される。 これでユーザからの入力によって処理を分岐させることができる。

#!/bin/bash

echo 'delete'
read input

if [[ $input == yes ]]; then
    echo 'delete'
else
    echo 'cancel'
fi

readコマンドによってデータを読み取る際は、行の内容はIFS変数で指定されている文字によって単語に分割される。 IFS(シェルの区切り文字を指定する)変数で通常はスペース、タブ、改行が設定される。 それらの単語はreadコマンドの引数として指定した変数に順に代入される。 単語の数と比べて変数の数が少ない場合は、残った単語は最後の変数にまとめて代入される。 変数を1つしか指定しない場合は行全体がその変数に代入される。

標準入力の内容を一行ずつ読み取って処理することもできる。

#!/bin/bash

while read line
do
  printf '%s\n' "$line"
done

readコマンドは終了ステータスは通常0を返す。 EOF(ファイルの末尾)に到達した場合は0以外を返すので ループさせれば入力の先頭から末尾まで行単位で読みこむ。

readコマンド使用上の注意

readコマンドは\エスケープ文字として解釈するので\の後にIFSに含まれる文字が続いていても単語の区切りとしない。 行末に\があった場合は行の終わりとみなさず、次の行と合わせて1つの行として読み込む。 オプション-rでこの機能を無効化することができる。 次にreadコマンドは行を単語に分割する際、行の先頭と終わりにあるIFSに含まれる文字を取り除くので 上の例では先頭と末尾の空白文字が削除された後の値がline変数に代入されることになる。

例えば先頭行の空白文字を残したい場合は、次の要因IFS変数の値を空文字列とすれば、 readコマンドでの単語の分割は行われず、空白文字を残すことができます。

#!/bin/bash

while IFS= read -r line
do
  printf '%s\n' "$line"
done

シェルスクリプトを書いてみよう

最後に大きいファイルを削除するイメージでスクリプトを書いてみました。 実行すると同じディレクトリにある 100GB.img* のファイルを消します。

#!/bin/bash

set -euo pipefail

for file in 100GB.img*
do
    echo "対象のファイルは $file で間違いないですか?(y/n)"
    read input

    if [[ $input == "y" ]] || [[ $input == "yes" ]]; then
        ionice -c3 nice -n 19 rm $file
        sleep 30
        echo "$file を削除しました"
    else
        echo "CANCEL"
    fi
done

rmで大きいファイルを削除するとIOささり障害が出そうですね。 そんな時はtruncateコマンドでファイルサイズを小さくして削除するのがよいでしょう。 参考リンク: 大量・巨大なファイル操作を低負荷で行う方法

また、こちらの新しいシェルプログラミングの教科書はわかりやすくておすすめです。

新しいシェルプログラミングの教科書

新しいシェルプログラミングの教科書

aws-workshop-for-kubernetes(201-cluster-monitoring)

前回の続きから 201-cluster-monitoring

Kubernetes Cluster Monitoring

Introduction

今回、以下を使用してKubernetesクラスタを監視していきます。

  1. Kubernetesダッシュボード
  2. Heapster、InfluxDB、Grafana
  3. Prometheus, Node exporter、Grafana

Prometheusは、オープンソースのシステム監視とアラートツールキットです。Prometheusは、これらのターゲット上のHTTPエンドポイントからメトリックを抽出することで、監視対象からのメトリックを収集します。

HeapsterはKuberenetesコンテナメトリクスに限定されていますが、一般的な使用ではありません。HeapsterはPrometheusスクレイプターゲットとして使用できます。

前提条件

ここで説明する3つのマスターノードと5つのワーカーノードを持つクラスタを使用します。 Multi-Master Clusterで作成しておきます。。 ここでの設定ファイルはすべてcluster-monitoringディレクトリにあります。 コマンドを実行する前に、そのディレクトリに移動してください。

Kubernetes Dashboard

Kubernetes DashboardはKubernetesクラスタ用の汎用WebベースのUIです。

ダッシュボードでは、Kubernetes v1.8でBetaではなくGAに昇格されたRBAC APIを使用しているため、 実行中のKubernetesのバージョンに応じて異なるバージョンのダッシュボードを使用します。 次のコマンドを使用してあなたのKubernetesのバージョンを確認してください。 - Server Versionの値を確認してください。

 $ kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.2", GitCommit:"81753b10df112992bf51bbc2c2f85208aad78335", GitTreeState:"clean", BuildDate:"2018-04-27T09:22:21Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.3", GitCommit:"d2835416544f298c919e2ead3be3d0864b52323b", GitTreeState:"clean", BuildDate:"2018-02-07T11:55:20Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
ec2-user:~/environment $ 

v1.8以上を使用している場合は、次のコマンドを使用してDashboardをデプロイします。

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
secret "kubernetes-dashboard-certs" created
serviceaccount "kubernetes-dashboard" created
role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created
rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created
deployment.apps "kubernetes-dashboard" created
service "kubernetes-dashboard" created

ダッシュボードは、次のコマンドを使用して表示できます。

kubectl proxy --address 0.0.0.0 --accept-hosts '.*' --port 8080

さて、ダッシュボードには、Preview , Preview Running Application を介してアクセス可能

https://ENVIRONMENT_ID.vfs.cloud9.REGION_ID.amazonaws.com/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/

ENVIRONMENT_ID は Cloud9 IDE環境ID(内蔵ブラウザのアドレスバーを一度クリックすると表示されます)と REGION_IDAWS region(us-east-1など)

Kubernetes 1.7以降、Dashboardは認証をサポートしています。 詳細については、https://github.com/kubernetes/dashboard/wiki/Access-control#introduction を参照してください。認証にはbearerトークンを使用します。

kube-system ネームスペースの既存のsecretsをチェック

kubectl -n kube-system get secret

出力は次のように表示されます。

NAME                                     TYPE                                  DATA      AGE
attachdetach-controller-token-dhkcr      kubernetes.io/service-account-token   3         3h
certificate-controller-token-p131b       kubernetes.io/service-account-token   3         3h
daemon-set-controller-token-r4mmp        kubernetes.io/service-account-token   3         3h
default-token-7vh0x                      kubernetes.io/service-account-token   3         3h
deployment-controller-token-jlzkj        kubernetes.io/service-account-token   3         3h
disruption-controller-token-qrx2v        kubernetes.io/service-account-token   3         3h
dns-controller-token-v49b6               kubernetes.io/service-account-token   3         3h
endpoint-controller-token-hgkbm          kubernetes.io/service-account-token   3         3h
generic-garbage-collector-token-34fvc    kubernetes.io/service-account-token   3         3h
horizontal-pod-autoscaler-token-lhbkf    kubernetes.io/service-account-token   3         3h
job-controller-token-c2s8j               kubernetes.io/service-account-token   3         3h
kube-dns-autoscaler-token-s3svx          kubernetes.io/service-account-token   3         3h
kube-dns-token-92xzb                     kubernetes.io/service-account-token   3         3h
kube-proxy-token-0ww14                   kubernetes.io/service-account-token   3         3h
kubernetes-dashboard-certs               Opaque                                2         9m
kubernetes-dashboard-key-holder          Opaque                                2         9m
kubernetes-dashboard-token-vt0fd         kubernetes.io/service-account-token   3         10m
namespace-controller-token-423gh         kubernetes.io/service-account-token   3         3h
node-controller-token-r6lsr              kubernetes.io/service-account-token   3         3h
persistent-volume-binder-token-xv30g     kubernetes.io/service-account-token   3         3h
pod-garbage-collector-token-fwmv4        kubernetes.io/service-account-token   3         3h
replicaset-controller-token-0cg8r        kubernetes.io/service-account-token   3         3h
replication-controller-token-3fwxd       kubernetes.io/service-account-token   3         3h
resourcequota-controller-token-6rl9f     kubernetes.io/service-account-token   3         3h
route-controller-token-9brzb             kubernetes.io/service-account-token   3         3h
service-account-controller-token-bqlsk   kubernetes.io/service-account-token   3         3h
service-controller-token-1qlg6           kubernetes.io/service-account-token   3         3h
statefulset-controller-token-kmgzg       kubernetes.io/service-account-token   3         3h
ttl-controller-token-vbnhf               kubernetes.io/service-account-token   3         3h

「kubernetes.io/namespace-controller-token」タイプのシークレットを使用してログインできます。 ここでは、シークレットのトークnamespace-controller-token-423gh を使用してログインします。 このシークレットのトークンを取得するには、次のコマンドを使用します。

kubectl -n kube-system describe secret namespace-controller-token-423gh

出力リストから namespace-controller-token に置き換える必要があることに注意してください。

Name:         namespace-controller-token-423gh
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name=default
              kubernetes.io/service-account.uid=3a3fea86-b3a1-11e7-9d90-06b1e747c654

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1046 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZWZhdWx0LXRva2VuLTd2aDB4Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRlZmF1bHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIzYTNmZWE4Ni1iM2ExLTExZTctOWQ5MC0wNmIxZTc0N2M2NTQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06ZGVmYXVsdCJ9.GHW-7rJcxmvujkClrN6heOi_RYlRivzwb4ScZZgGyaCR9tu2V0Z8PE5UR6E_3Vi9iBCjuO6L6MLP641bKoHB635T0BZymJpSeMPQ7t1F02BsnXAbyDFfal9NUSV7HoPAhlgURZWQrnWojNlVIFLqhAPO-5T493SYT56OwNPBhApWwSBBGdeF8EvAHGtDFBW1EMRWRt25dSffeyaBBes5PoJ4SPq4BprSCLXPdt-StPIB-FyMx1M-zarfqkKf7EJKetL478uWRGyGNNhSfRC-1p6qrRpbgCdf3geCLzDtbDT2SBmLv1KRjwMbW3EF4jlmkM4ZWyacKIUljEnG0oltjA

この出力からトークンの値をコピーし、ダッシュボードのログインウィンドウで Token を選択し、テキストを貼り付けます。 SIGN IN をクリックすると、デフォルトのダッシュボードビューが表示されます。

ダッシュボード上でを Nodes をクリックすると、クラスタ内で実行されているノードに関するテキスト表現が表示されます。 Deploying applications using Kubernetes Helm chartsの説明に従って、 Javaアプリケーションをインストールします。 Pods を再度クリックすると、クラスタ内で実行中のポッドについてのテキスト表現が表示されます。 これは、Heapster、InfluxDB、Grafanaがインストールされた後に変更されます。

Deploying applications using Kubernetes Helm charts

HelmKubernetesチャート を管理するためのツールです。 チャートは、関連するKubernetesリソースのセットを記述するファイルの集まりです。 チャートの紹介 で詳細を読む。

前提条件

この章では、ここで説明する3つのマスターノードと5つのワーカーノードを持つクラスタを使用します。 設定ファイルはすべて helm ディレクトリにあります。コマンドを実行する前に、そのディレクトリに移動してください。

Helmをインストールする

Helmには2つの部分があります。Helm client(helm)とHelm server(tiller)です。 TillerはあなたのKubernetesクラスタの内部で動作し、あなたのチャートのリリース(インストール)を管理します。 ヘルムは、ラップトップ、CI/CD、またはどこでも実行するために実行されます。 このセクションでは、クライアントとサーバーの両方をインストールする方法を示します。

Helm clientをインストールする

Mac OSXにインストール

brew install kubernetes-helm

Heapster、InfluxDB、Grafana

Heapsterはmetrics aggregatorとプロセッサーです。クラスタ全体のポッドとしてインストールされます。 Kubeletと対話することにより、各ノードのすべてのコンテナの監視データとイベントデータを収集します。 Kubelet自体がcAdvisor からこのデータを取得します。 このデータは、ストレージ用の時系列データベースInfluxDBに保存されます。 Grafanaダッシュボードを使用してデータを可視化するか、Kubernetes Dashboardで表示することができます。

Heapsterは、コンピューティングリソースの使用状況、ライフサイクルイベントなどのさまざまな信号を収集して解釈し、RESTエンドポイントを介してクラスタメトリックをエクスポートします。

Heapster、InfluxDB、Grafanaは Kubernetesアドオン です。

インストール

Heapster、InfluxDB、Grafanaをインストールするには、次のコマンドを実行します。

$ kubectl apply -f templates/heapster/
deployment "monitoring-grafana" created
service "monitoring-grafana" created
clusterrolebinding "heapster" created
serviceaccount "heapster" created
deployment "heapster" created
service "heapster" created
deployment "monitoring-influxdb" created
service "monitoring-influxdb" created

Heapsterは、各ノードで実行されているcAdvisorインスタンスからメトリックを集計しています。 このデータは、クラスタ内で実行されているInfluxDBインスタンスに格納されます。 Grafanaダッシュボードは、https://ENVIRONMENT_ID.vfs.cloud9.REGION_ID.amazonaws.com/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy/?orgId=1 でアクセスし、クラスタについて今の情報を表示します。

注意 Kubernetesプロキシが動作していない場合、Grafanaダッシュボードは利用できません。 プロキシが実行されていない場合は、コマンドを使用してプロキシを開始できます kubectl proxy --address 0.0.0.0 --accept-hosts '.*' --port 8080

Graphanaダッシュボード

クラスタとワークロードを監視するためのダッシュボードが組み込まれています。それらは、画面の左上隅をクリックすることで利用できます。

クラスタダッシュボードには、すべてのワーカーノードとそのCPUおよびメモリメトリックが表示されます。選択した期間中に収集したメトリックを表示するには、ノード名を入力します。

クラスタダッシュボードは次のようになります。

Podsダッシュボードでは、クラスタ内のすべてのポッドのリソース使用率を確認できます。ノードと同様に、上部のフィルタボックスに名前を入力してポッドを選択できます。

Heapsterの展開後、Kubernetes Dashboardは、ポッドやノード、その他のワークロードのCPUやメモリ使用率などの追加グラフを表示するようになりました。 Kubernetes Dashboardクラスタの更新ビューは次のようになります。 ポッドの更新されたビューは次のようになります。

Clean

インストールされているすべてのコンポーネントを削除します。

kubectl delete -f templates/heapster/

プロメテウス、ノードエクスポータ、グラファナ

プロメテウスは、オープンソースのシステム監視とアラートツールキットです。 Prometheusは、これらのターゲット上のHTTPエンドポイントからメトリックをスクレイプすることにより、監視対象からのメトリックを収集します。

プロメテウスはKubernetesOperator によって管理されます。 この演算子カスタムリソースを使用しています。 KubernetesのAPIを拡張し、Prometheus、ServiceMonitorとAlertmanagerのようなカスタムリソースを追加する。

プロメテウスは、ServiceMonitorを追加することによって、動的に新しいターゲットをスクレイプすることができます。 kube-controller-manager、kube-scheduler、kube-state-metrics、kubeletとnode-exporterをスクレイプするためにそれらのいくつかを含まれている。

Node exporter は、* NIXカーネルによって公開されるハードウェアおよびOSメトリクスのPrometheus exporterです。 kube-state-metrics は、Kubernetes APIサーバーをリッスンし、オブジェクトの状態に関するメトリックを生成する単純なサービスです。

インストール

まず、新しいカスタムリソースを聞くPrometheus Operatorを導入する必要があります。

$ kubectl apply -f templates/prometheus/prometheus-bundle.yaml
namespace "monitoring" created
clusterrolebinding "prometheus-operator" created
clusterrole "prometheus-operator" created
serviceaccount "prometheus-operator" created
deployment "prometheus-operator" created

次にPrometheus Operatorが起動するまで待つ必要があります。

$ kubectl rollout status deployment/prometheus-operator -n monitoring
...
deployment "prometheus-operator" successfully rolled out

最後のステップとして、プロメテウスのカスタムリソース、サービスモニタ、クラスタロールとバインディング(RBAC)を導入する必要があります。

$ kubectl apply -f templates/prometheus/prometheus.yaml
serviceaccount "kube-state-metrics" created
clusterrole "kube-state-metrics" created
clusterrolebinding "kube-state-metrics" created
service "kube-scheduler-prometheus-discovery" created
service "kube-controller-manager-prometheus-discovery" created
daemonset "node-exporter" created
service "node-exporter" created
deployment "kube-state-metrics" created
service "kube-state-metrics" created
prometheus "prometheus" created
servicemonitor "prometheus-operator" created
servicemonitor "kube-apiserver" created
servicemonitor "kubelet" created
servicemonitor "kube-controller-manager" created
servicemonitor "kube-scheduler" created
servicemonitor "kube-state-metrics" created
servicemonitor "node-exporter" created
alertmanager "main" created
secret "alertmanager-main" created

プロメテウスが現れるのを待つ

$ kubectl get po -l prometheus=prometheus -n monitoring
NAME                      READY     STATUS    RESTARTS   AGE
prometheus-prometheus-0   2/2       Running   0          1m
prometheus-prometheus-1   2/2       Running   0          1m

Prometheus Dashboard

プロメテウスはさまざまなスクレイピングターゲットからメトリックを削り取り、ダッシュボードを次の方法で転送します。

$ kubectl port-forward $(kubectl get po -l prometheus=prometheus -n monitoring -o jsonpath={.items[0].metadata.name}) 9090 -n monitoring
Forwarding from 127.0.0.1:9090 -> 9090

ブラウザで http://localhost:9090/targets を開き、すべてのターゲットを次のように表示する必要がありますUP(データコレクタが初めて起動して実行されるまで数分かかる場合があります)。ブラウザは次のように出力を表示します。

Grafana Installation

次のコマンドでインストールできます

$ kubectl apply -f templates/prometheus/grafana-bundle.yaml
secret "grafana-credentials" created
service "grafana" created
configmap "grafana-dashboards-0" created
deployment "grafana" created

起動をまちます

$ kubectl rollout status deployment/grafana -n monitoring
...
deployment "grafana" successfully rolled out

Grafana Dashboard

grafanaダッシュボードをローカルポートに転送します。

$ kubectl port-forward $(kubectl get pod -l app=grafana -o jsonpath={.items[0].metadata.name} -n monitoring) 3000 -n monitoring
Forwarding from 127.0.0.1:3000 -> 3000

Grafanaダッシュボードは、http://localhost:3000/ にアクセスできるようになりました。トップにある検索ボタンを使用して、ダッシュボードの完全なリストを利用できます。

これらのダッシュボードを使用して、さまざまな指標にアクセスできます。

  1. Kubernetes Cluster Control Plane
  2. Kubernetesクラスタのステータス
  3. Kubernetesクラスタ容量計画
  4. Kubernetesクラスタ内のノード

 その他の便利なリンク

http://localhost:3000/dashboard/db/deployment&orgId=1 http://localhost:3000/dashboard/db/kubernetes-cluster-health?refresh=10s&orgId=1 http://localhost:3000/dashboard/db/kubernetes-resource-requests?orgId=1 http://localhost:3000/dashboard/db/pods?orgId=1

掃除

インストールされているすべてのコンポーネントを削除します。

kubectl delete -f templates/prometheus/prometheus-bundle.yaml

aws-workshop-for-kubernetes(101〜103)

101-start-here

Kubernetes - Cloud9開発環境の設定

aws-workshop-for-kubernetesの101-start-here

Cloud9を使うためにバージニアリージョンを選び、CloudFormationで既存のVPCを選び サブネットを選択して、次へを押せば、 k8s-workshopというスタックができ、出力タブにCloud9のURLが表示され Cloud9に接続できるようになった。

Cloud9IDEで以下のスクリプトを実行。

aws s3 cp s3://aws-kubernetes-artifacts/lab-ide-build.sh . && \
chmod +x lab-ide-build.sh && \
. ./lab-ide-build.sh

これでkubectlコマンドなどがインストールされました。

$ kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?

Cloud9 IDEが割り当てられたIAMインスタンスプロファイルを使用するためには、 「AWS Cloud9」メニューを開き、「Preferences」に移動し、「AWS Settings」に移動し、「AWS managed temporary credentials」を無効にする。

これで、ワークショップを続ける準備が整いました!

102-your-first-cluster

kopsを使ってKubernetesクラスタを作成する

複数のマスターノードとワーカーノードを複数の可用性ゾーンに分散して、可用性の高いクラスタを作成する。 クラスタ内のマスタノードとワーカーノードは、名前解決にDNSまたはWeave Meshの ゴシッププロトコルを使用できる。 ゴシッププロトコルベースの クラスタはセットアップが簡単で簡単で、ドメインサブドメイン、またはRoute53ホストゾーンを登録する必要がない。

ゴシッププロトコルを使用してクラスタを作成するには、接尾辞が .k8s.local になります。

シングルマスタークラスタとマルチマスタークラスタのどちらを作成するかを選択できるが、 ローリングアップデートを実演するなどもあるので、マルチマスタークラスタを作成するほうがよい。

マルチマスタークラスタ

次のコマンドでマルチマスター、マルチノード、およびmulti-az構成でクラスターを作成します。

$ kops create cluster \
  --name example.cluster.k8s.local \
  --master-count 3 \
  --node-count 5 \
  --zones $AWS_AVAILABILITY_ZONES \
  --yes

(中略)
kops has set your kubectl context to example.cluster.k8s.local

Cluster is starting.  It should be ready in a few minutes.

Suggestions:
 * validate cluster: kops validate cluster
 * list nodes: kubectl get nodes --show-labels
 * ssh to the master: ssh -i ~/.ssh/id_rsa admin@api.example.cluster.k8s.local
 * the admin user is specific to Debian. If not using Debian please use the appropriate user based on

--master-count オプションを使用し、マスターノードの数を指定することにより、マルチマスタークラスタを作成できます。奇数値を推奨します。 デフォルトでは、マスターノードは --zones オプションを使用して指定されたAZに分散されます。 --master-zones オプションを使用して、マスターノードのゾーンを明示的に指定することもできます。 --zones オプションは、ワーカーノードの配布にも使用されます。 --node-count オプションを使用して、ワーカーの数が指定されます。

クラスタkops validate cluster でします。

$ kops validate cluster
(中略)

Validation Failed

クラスタの作成には時間がかかりますね。ワーカーnodeがなく、Validation Failed になってました。 すべてのマスターが異なるAZにまたがっていることは確認できました。

20分ぐらいでワーカーノードもすべて起動しました。

Your cluster example.cluster.k8s.local is ready

Kubernetes Cluster Context

kubectl(Kubernetes CLI)を使用して、複数のKubernetesクラスタを管理できます。 各クラスタの構成は、「kubeconfigファイル」と呼ばれる構成ファイルに格納されています。 デフォルトでは、kubectl configはディレクトリ内で指定されたファイルを探します ~/.kube。 kubectl CLIは、kubeconfigファイルを使用して、クラスタを選択し、クラスタAPIサーバと通信するために必要な情報を検索します。

これでコンテキストを変更するだけで、さまざまな環境にアプリケーションを展開できる。 アプリケーション開発の典型的なフローは次のようになります。 

  1. 開発環境を使用してアプリケーションを構築する(おそらくラップトップにローカルに)
  2. コンテキストをAWS上に作成されたテストクラスタに変更する
  3. 同じコマンドを使用してテスト環境にデプロイする
  4. 一度満足すれば、コンテキストをAWSの実動クラスタに再度変更してください
  5. もう一度、同じコマンドを使用して運用環境に展開します

利用可能なコンテキストの概要を取得

$ kubectl config get-contexts
kubectl config get-contexts
CURRENT   NAME                        CLUSTER                     AUTHINFO                    NAMESPACE
*         example.cluster.k8s.local   example.cluster.k8s.local   example.cluster.k8s.local   

出力には、クラスタごとに1つずつ、kubectlで利用可能な別のコンテキストが表示されます。 NAME列にはコンテキスト名が表示され、* は現在のコンテキストを示す。

現在のコンテキストを表示

$ kubectl config current-context
example.cluster.k8s.local

複数のクラスタが存在する場合は、コンテキストを変更できます。

$ kubectl config use-context <config-name>

103-kubernetes-concepts

Kubernetesの概念

前提

クラスタが稼動しているので、Kubernetes CLIをkubectl(「キューブコントロール」)コマンドで探索することができる。 kubectl はクラスタ内のマスターノード上で動作するKubernetes API Serverと対話します。

プラットフォームとしてのKubernetesには、APIオブジェクトにマップされる多数の抽象的な要素があります。 これらのKubernetes APIオブジェクトは、実行中のアプリケーションやワークロード、コンテナイメージ、ネットワークリソースなどの情報を含む、 クラスタの望ましい状態を記述するために使用できます。 このセクションでは、最もよく使用されるKubernetes APIの概念と、それを介して相互作用する方法について説明する。

前提条件

さきほど作成した、3つのマスターノードと5つのワーカーノードを持つクラスタを使用します。 01-path-basics/103-kubernetes-concepts/templates に必要な設定ファイルが置いてあります。

$ cd 01-path-basics/103-kubernetes-concepts/templates

ノードを表示

$ kubectl get nodes

以下の様にクラスタが出力されます。

NAME                             STATUS    ROLES     AGE       VERSION
ip-172-20-109-34.ec2.internal    Ready     master    1h        v1.9.3
ip-172-20-122-230.ec2.internal   Ready     node      1h        v1.9.3
ip-172-20-136-202.ec2.internal   Ready     node      1h        v1.9.3
ip-172-20-165-37.ec2.internal    Ready     node      1h        v1.9.3
ip-172-20-41-45.ec2.internal     Ready     node      1h        v1.9.3
ip-172-20-61-47.ec2.internal     Ready     master    1h        v1.9.3
ip-172-20-79-150.ec2.internal    Ready     node      1h        v1.9.3
ip-172-20-86-242.ec2.internal    Ready     master    1h        v1.9.3
$ kubectl run nginx --image=nginx
deployment "nginx" created

Podの作成

Nginxコンテナをクラスタに作成する

$ kubectl run nginx --image=nginx
deployment "nginx" created

deploymentsのリストをみる

$ kubectl get deployments
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     1         1         1            1           14s

Runnningのpodsを表示

$ kubectl get pods
NAME                   READY     STATUS    RESTARTS   AGE
nginx-8586cf59-bjsgp   1/1       Running   0          53s

以上でわかったpodの名前から、次のようにポッドの追加情報を取得します。

$ kubectl describe pod/nginx-8586cf59-bjsgp
Name:           nginx-8586cf59-bjsgp
Namespace:      default
Node:           ip-172-20-165-37.ec2.internal/172.20.165.37
Start Time:     Mon, 30 Apr 2018 14:52:42 +0000
Labels:         pod-template-hash=41427915
                run=nginx
Annotations:    kubernetes.io/limit-ranger=LimitRanger plugin set: cpu request for container nginx
Status:         Running
IP:             100.96.4.2
Controlled By:  ReplicaSet/nginx-8586cf59
Containers:
  nginx:
    Container ID:   docker://85d3dec6833b185416a9e45cc07f87437ff7ab21064a531a14a71b1f60b89a7c
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:0edf702c890e9518b95b2da01286509cd437eb994b8d22460e40d72f6b79be49
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 30 Apr 2018 14:52:47 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        100m
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-nqfr5 (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          True 
  PodScheduled   True 
Volumes:
  default-token-nqfr5:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-nqfr5
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                 Age   From                                    Message
  ----    ------                 ----  ----                                    -------
  Normal  Scheduled              2m    default-scheduler                       Successfully assigned nginx-8586cf59-bjsgp to ip-172-20-165-37.ec2.internal
  Normal  SuccessfulMountVolume  2m    kubelet, ip-172-20-165-37.ec2.internal  MountVolume.SetUp succeeded for volume "default-token-nqfr5"
  Normal  Pulling                2m    kubelet, ip-172-20-165-37.ec2.internal  pulling image "nginx"
  Normal  Pulled                 2m    kubelet, ip-172-20-165-37.ec2.internal  Successfully pulled image "nginx"
  Normal  Created                2m    kubelet, ip-172-20-165-37.ec2.internal  Created container
  Normal  Started                2m    kubelet, ip-172-20-165-37.ec2.internal  Started container
  ```

  デフォルトでは、ポッドはdefaultというnamespaceに作成されます。さらに、kube-systemというnamespaceはKubernetesのシステムのポッド用に予約されています。
  kube-systemという名前空間内のすべてのポッドのリストは、次のように表示できます。

  ```
  $ kubectl get pods --namespace kube-system
NAME                                                    READY     STATUS    RESTARTS   AGE
dns-controller-769b5f68b6-mcg59                         1/1       Running   0          1h
etcd-server-events-ip-172-20-109-34.ec2.internal        1/1       Running   1          1h
etcd-server-events-ip-172-20-61-47.ec2.internal         1/1       Running   0          1h
etcd-server-events-ip-172-20-86-242.ec2.internal        1/1       Running   0          1h
etcd-server-ip-172-20-109-34.ec2.internal               1/1       Running   0          1h
etcd-server-ip-172-20-61-47.ec2.internal                1/1       Running   0          1h
etcd-server-ip-172-20-86-242.ec2.internal               1/1       Running   0          1h
kube-apiserver-ip-172-20-109-34.ec2.internal            1/1       Running   0          1h
kube-apiserver-ip-172-20-61-47.ec2.internal             1/1       Running   0          1h
kube-apiserver-ip-172-20-86-242.ec2.internal            1/1       Running   1          1h
kube-controller-manager-ip-172-20-109-34.ec2.internal   1/1       Running   0          1h
kube-controller-manager-ip-172-20-61-47.ec2.internal    1/1       Running   0          1h
kube-controller-manager-ip-172-20-86-242.ec2.internal   1/1       Running   0          1h
kube-dns-7785f4d7dc-4vg2m                               3/3       Running   0          1h
kube-dns-7785f4d7dc-zt74c                               3/3       Running   0          1h
kube-dns-autoscaler-787d59df8f-mvt9d                    1/1       Running   0          1h
kube-proxy-ip-172-20-109-34.ec2.internal                1/1       Running   0          1h
kube-proxy-ip-172-20-122-230.ec2.internal               1/1       Running   0          1h
kube-proxy-ip-172-20-136-202.ec2.internal               1/1       Running   0          1h
kube-proxy-ip-172-20-165-37.ec2.internal                1/1       Running   0          1h
kube-proxy-ip-172-20-41-45.ec2.internal                 1/1       Running   0          1h
kube-proxy-ip-172-20-61-47.ec2.internal                 1/1       Running   0          1h
kube-proxy-ip-172-20-79-150.ec2.internal                1/1       Running   0          1h
kube-proxy-ip-172-20-86-242.ec2.internal                1/1       Running   0          1h
kube-scheduler-ip-172-20-109-34.ec2.internal            1/1       Running   0          1h
kube-scheduler-ip-172-20-61-47.ec2.internal             1/1       Running   0          1h
kube-scheduler-ip-172-20-86-242.ec2.internal            1/1       Running   0          1h

ポッドからログを取得

ポッドからのログを取得することができます(新しいnginxにはログがありません - サービスにアクセスした後にもう一度確認)

kubectl logs <pod-name> --namespace <namespace-name>

kubectl logs nginx-8586cf59-bjsgp --namespace default

@# 実行中のポッドでシェルを実行

ポッド内のシェルへのTTYを開く

$ kubectl get pods
$ kubectl exec -it <pod-name> /bin/bash
$ kubectl get pods
NAME                   READY     STATUS    RESTARTS   AGE
nginx-8586cf59-bjsgp   1/1       Running   0          11m
$ kubectl exec -it nginx-8586cf59-bjsgp /bin/bash
root@nginx-8586cf59-bjsgp:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

これでbashシェルが開き、コンテナのファイルシステムを見ることができる

掃除

これまでに作成されたKubernetesリソースをすべて削除

$ kubectl delete deployment/nginx
deployment.extensions "nginx" deleted

ポッド

ポッドは、作成、スケジュール設定、および管理が可能な最小の展開可能なユニットです。 これは、アプリケーションに属するコンテナの論理的な集合です。 ポッドは名前空間に作成されます。 ポッド内のすべてのコンテナは、名前空間、ボリューム、およびネットワーキングスタックを共有します。 これにより、localhostを使ってポッド内のコンテナ同士が互いを「見つける」ことができる。

ポッドの作成

Kubernetesの各リソースは、構成ファイルを使用して定義できます。たとえば、Nginxポッドは次のような設定ファイルで定義できます。

$ cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:

次のようにポッドを作成します。

$ kubectl apply -f pod.yaml
pod "nginx-pod" created

ポッドのリストを取得

$ kubectl get pods
NAME        READY     STATUS    RESTARTS   AGE
nginx-pod   1/1       Running   0          22s

ポッドが正常に起動したことを確認します(ポート8080で実行中のものがないことを確認してください)。

kubectl -n default port-forward $(kubectl -n default get pod -l name=nginx-pod -o jsonpath='{.items[0].metadata.name}') 8080:80

Cloud9 IDEでプレビューと実行中のアプリケーションのプレビューをクリック。プレビュータブが開き、NGINXのメインページが表示されるのを確認。

ポッド内のコンテナがログを生成する場合は、次のコマンドを使用して表示できます。

$kubectl logs nginx-pod
127.0.0.1 - - [30/Apr/2018:15:14:10 +0000] "GET / HTTP/1.1" 200 612 "https://us-east-1.console.aws.amazon.com/cloud9/ide/a776f598fd54453fb848b088e8bce324?region=us-east-1" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" "49.129.246.233"
ec2-user:~/environment/aws-workshop-for-kubernetes/01-path-basics/103-kubernetes-concepts/templates (master) $ 

もしくは

$ kubectl logs nginx-pod  --namespace default                                                                                                                                                               
127.0.0.1 - - [30/Apr/2018:15:14:10 +0000] "GET / HTTP/1.1" 200 612 "https://us-east-1.console.aws.amazon.com/cloud9/ide/a776f598fd54453fb848b088e8bce324?region=us-east-1" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" "49.129.246.233"
ec2-user:~/environment/aws-workshop-for-kubernetes/01-path-basics/103-kubernetes-concepts/templates (master) $ 

メモリおよびCPUリソースリクエス

ポッド内のコンテナには、メモリとCPUのリクエストと制限を割り当てることができる。 リクエストは、Kubernetesがコンテナに与えるメモリ/CPUの最小量で、 制限は、コンテナが使用できるメモリ/CPUの最大量。 Podのメモリ/CPUリクエストおよび制限は、Pod内のすべてのコンテナのメモリ/CPUリクエストおよび制限の合計。 要求が指定されていない場合、デフォルトに制限されます。制限のデフォルト値はノードの容量。

PodのメモリとCPUリクエストが満たされている場合、ノード上でPodをスケジュールすることができる スケジューリングにはメモリとCPUの制限は考慮されていない。

ポッド内のコンテナがメモリ要求を超えていない場合、ノードはノード上で操作を継続できる。 ポッド内のコンテナがメモリ要求を超えると、ノードがメモリ不足になるたびに追い出し対象になる。 ポッド内のコンテナがメモリの制限を超えると、それらは終了する。 Podを再起動できる場合、他のタイプのランタイムエラーと同様に、kubeletはそれを再起動する。 コンテナは、長時間にわたってCPU制限を超えてもしなくてもよい。 しかし、過度の使用のために殺されることはない

メモリとCPUのリクエスト/制限は、以下を使用して指定可能。

タイプ フィールド
メモリリクエス spec.containers.resources.requests.memory
メモリ制限 spec.containers.resources.limits.memory
CPU要求 spec.containers.resources.requests.cpu
CPU制限 spec.containers.resources.limits.cpu

メモリリソースはバイト単位で要求される。 接尾辞の一つで整数または小数でそれらを指定することができ E,P,T,G,M,K。 また、電源の-2当量で表すことができEi,Pi,Ti,Gi,Mi,Ki

CPUはCPU単位で要求できます。1 cpuユニットは同等の1 AWS vCPU。それはまた、0.5やる500メートルなどのmillicpuを分数や小数単位で要求することができる。

デフォルトメモリとCPU

デフォルトでは、ポッド内のコンテナにはメモリ要求/制限と100m CPU要求が割り当てられず、制限はない。これは、以前に開始したポッドを使用して確認できる。

$ kubectl get pod/nginx-pod -o jsonpath={.spec.containers[].resources}
map[requests:map[cpu:100m]]

メモリとCPUを割り当てる

以下の設定ファイルを使用して、Podにメモリ要求と制限を割り当てる。

$ cat pod-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod2
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      limits:
        memory: "200Mi"
        cpu: 2
      requests:
        memory: "100Mi"
        cpu: 1
    ports:
    - containerPort: 80

この設定ファイルの唯一の変更はspec.containers[].resourcesセクションの追加です。 制限はlimitsセクションで指定され、要求はrequestsセクションで指定される。

Podを作成

kubectl apply -f pod-resources.yaml
pod "nginx-pod2" created

リクエストと制限の詳細を取得。

$ kubectl get pod/nginx-pod2 -o jsonpath={.spec.containers[].resources}
map[limits:map[cpu:2 memory:200Mi] requests:map[cpu:1 memory:100Mi]]

NGINXコンテナは、メモリとCPUがかなり少なくて済みます。 したがって、これらの要求数と制限数は正常に機能し、ポッドは正しく開始されます。今 度は、同様の番号を使ってWildFlyポッドを開始しようとしましょう。 同じ設定ファイルが表示されます。

$ cat pod-resources1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: wildfly-pod
  labels:
    name: wildfly-pod
spec:
  containers:
  - name: wildfly
    image: jboss/wildfly:11.0.0.Final
    resources:
      limits:
        memory: "200Mi"
        cpu: 2
      requests:
        memory: "100Mi"
        cpu: 1
    ports:
    - containerPort: 8080

このポッド内のWildFlyコンテナに割り当てられるメモリの最大量は200MBに制限されています。 このポッドを作成してみよう。

$ kubectl apply -f pod-resources1.yaml
pod "wildfly-pod" created

ポッドの状態を確認。

$ kubectl get pods -w
NAME          READY     STATUS              RESTARTS   AGE
wildfly-pod   0/1       ContainerCreating   0          5s
wildfly-pod   1/1       Running   0         26s
wildfly-pod   0/1       OOMKilled   0         29s
wildfly-pod   1/1       Running   1         31s
wildfly-pod   0/1       OOMKilled   1         34s
wildfly-pod   0/1       CrashLoopBackOff   1         45s
wildfly-pod   1/1       Running   2         46s
wildfly-pod   0/1       OOMKilled   2         49s
wildfly-pod   0/1       CrashLoopBackOff   2         1m
wildfly-pod   1/1       Running   3         1m
wildfly-pod   0/1       OOMKilled   3         1m

OOMKilledでコンテナがメモリ不足で終了したことを示します。 pod-resources2.yamlspec.containers[].resources.limits.memoryの値を300Miに変更します。 既存のPodを削除し、新しいPodを作成します。

$ kubectl delete -f pod-resources1.yaml
pod "wildfly-pod" deleted
$ kubectl apply -f pod-resources2.yaml
pod "wildfly-pod" created
$ kubectl get -w pod/wildfly-pod
NAME          READY     STATUS              RESTARTS   AGE
wildfly-pod   0/1       ContainerCreating   0          3s
wildfly-pod   1/1       Running   0         25s

これで、Podが正常に開始されます。 Podに割り当てられたリソースの詳細を取得。

$ kubectl get pod/wildfly-pod -o jsonpath={.spec.containers[].resources}
map[limits:map[cpu:2 memory:300Mi] requests:map[cpu:1 memory:100Mi]

Quality of service

Kubernetesは、コンテナによって使用されていない場合、要求と制限の差を便宜的に排除します。 これにより、Kubernetesがノードをオーバーサブスクライブできるようになり、使用率が向上すると同時に、保証が必要なコンテナのリソース保証が維持されます。

Kubernetesは、QoSクラスの1つをPodに割り当てます。

  1. Guaranteed
  2. Burstable
  3. BestEffort

QoSクラスは、KubernetesによってPodのスケジュール設定と撤回に使用されます。

ポッド内のすべてのコンテナにメモリとCPUの制限が与えられ、オプションで非ゼロの要求が与えられ、それらが完全に一致すると、PodはGuaranteedQoS でスケジュールされます。これが最優先事項です。

ポッドがBurstableQoSを満たさずGuaranteed、少なくとも1つのコンテナにメモリまたはCPU要求がある場合、ポッドにはQoSクラスが与えられます。これは中間的な優先事項です。

ポッド内の任意のコンテナにメモリとCPUの要求または制限が割り当てられていない場合、ポッドはBestEffortQoS でスケジュールされます。これが最も低く、デフォルトの優先順位です。

起床が必要なポッドは、GuaranteedQoS を要求できます。あまり厳しくない要件のポッドは、より弱いQoSを使用することも、QoSを使用しないこともあります。

Guaranteed

GuaranteedQoS を備えたPodの例。

$ cat pod-guaranteed.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-guaranteed
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      limits:
        memory: "200Mi"
        cpu: 1
    ports:
    - containerPort: 80

ここでは要求値は指定されておらず、デフォルト値はlimitになる。

このポッドを作成

$ kubectl apply -f pod-guaranteed.yaml
pod "nginx-pod-guaranteed" created

リソースを確認

$ kubectl get pod/nginx-pod-guaranteed -o jsonpath={.spec.containers[].resources}
map[limits:map[cpu:1 memory:200Mi] requests:map[cpu:1 memory:200Mi]]

QoSを確認

$ kubectl get pod/nginx-pod-guaranteed -o jsonpath={.status.qosClass}
Guaranteed

制限と要求の明示的な値を持つ別のポッドが表示さ

$ cat pod-guaranteed2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-guaranteed2
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      limits:
        memory: "200Mi"
        cpu: 1
      requests:
        memory: "200Mi"
        cpu: 1
    ports:
    - containerPort: 80

このポッドを作成

$ kubectl apply -f pod-guaranteed2.yaml
pod "nginx-pod-guaranteed2" created

リソースを確認

$ kubectl get pod/nginx-pod-guaranteed2 -o jsonpath={.spec.containers[].resources}
map[limits:map[cpu:1 memory:200Mi] requests:map[cpu:1 memory:200Mi]]

QoSを確認

$ kubectl get pod/nginx-pod-guaranteed2 -o jsonpath={.status.qosClass}
Guaranteed

Burstable

次は、Burstable QoS を備えたPodの例

$ cat pod-burstable.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-burstable
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      limits:
        memory: "200Mi"
        cpu: 1
      requests:
        memory: "100Mi"
        cpu: 1
    ports:
    - containerPort: 80

ここでは、リクエスト値と制限値の両方を指定しました。

このポッドを作成。

$ kubectl apply -f pod-burstable.yaml
pod "nginx-pod-burstable" created

リソースを確認

$ kubectl get pod/nginx-pod-burstable -o jsonpath={.spec.containers[].resources}
map[limits:map[cpu:1 memory:200Mi] requests:map[cpu:1 memory:100Mi]]

QoSを確認

$ kubectl get pod/nginx-pod-burstable -o jsonpath={.status.qosClass}
Burstable

BestEffort

リソースを確認

$ kubectl get pod/nginx-pod -o jsonpath={.spec.containers[].resources}
map[requests:map[cpu:100m]]

QoSを確認

$ kubectl get pod/nginx-pod -o jsonpath={.status.qosClass}
Burstable

これは BestEffort になるべき kubernetes#55278

ポッドの削除

実行中のすべてのポッドを取得

$ kubectl get pods
NAME                    READY     STATUS    RESTARTS   AGE
nginx-pod               1/1       Running   0          6m
nginx-pod-burstable     1/1       Running   0          9m
nginx-pod-guaranteed    1/1       Running   0          23m
nginx-pod-guaranteed2   1/1       Running   0          12m
nginx-pod2              1/1       Running   0          6m
wildfly-pod             1/1       Running   0          6m

ポッドを削除

$ kubectl delete $(kubectl get pods -o=name)
pod "nginx-pod" deleted
pod "nginx-pod-burstable" deleted
pod "nginx-pod-guaranteed" deleted
pod "nginx-pod-guaranteed2" deleted
pod "nginx-pod2" deleted
pod "wildfly-pod" deleted
$ kubectl get pods
No resources found.

Deployment

ポッドの4つのレプリカなどの「望ましい状態」は、Deploymentオブジェクトに記述することができます。 Kubernetesクラスタ内のDeploymentコントローラは、望まれた状態と実際の状態が一致していることを確認します。 ワーカーノードに障害が発生したり再起動したりすると、Deploymentによってポッドが再作成されます。 ポッドが死ぬと、新しいポッドが開始されて、望ましい状態とと実際の状態のマッチが確実に行われます。 また、レプリカ数のアップスケーリングとダウンスケーリングが可能です。 これは、ReplicaSetを使用して実現されます。 Deploymentはレプリカセットを管理し、それらのポッドに更新を提供します。

Deploymentの作成

次の例では、NGINXベースイメージの3つのレプリカでDeploymentを作成する。 以下のテンプレートを確認して、試してみる。

 $ cat deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment # kubernetes object type
metadata:
  name: nginx-deployment # deployment name
spec:
  replicas: 3 # number of replicas
  template:
    metadata:
      labels:
        app: nginx # pod labels
    spec:
      containers:
      - name: nginx # container name
        image: nginx:1.12.1 # nginx image
        imagePullPolicy: IfNotPresent # if exists, will not pull new image
        ports: # container and host port assignments
        - containerPort: 80
        - containerPort: 443

このDeploymentでは、NGINXイメージのインスタンスが3つ作成されます。 次のコマンドを実行してDeploymentを作成

$ kubectl create -f deployment.yaml --record
deployment "nginx-deployment" created

この--recordフラグは、各リビジョンの変更を追跡します。 deploymentのdeployment状況を監視するには:

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

デプロイメントはレプリカの数を管理するレプリカセットを作成します。 既存のデプロイメントとレプリカセットを見てみましょう。 デプロイメント情報を確認

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           25s

deployment用のレプリカセットを取得

$ kubectl get replicaset
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-3441592026   3         3         3         1m

実行中のポッドのリストを取得

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-3441592026-ddpf0   1/1       Running   0          2m
nginx-deployment-3441592026-kkp8h   1/1       Running   0          2m
nginx-deployment-3441592026-lx304   1/1       Running   0          2m

デプロイメントのスケーリング

Deploymentのレプリカ数は、次のコマンドを使用してスケーリングできる。

$ kubectl scale --replicas=5 deployment/nginx-deployment
deployment "nginx-deployment" scaled

deploymentを確認

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   5         5         5            5           2m

deployment内のポッドを確認

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-3441592026-36957   1/1       Running   0          44s
nginx-deployment-3441592026-8wch5   1/1       Running   0          44s
nginx-deployment-3441592026-ddpf0   1/1       Running   0          3m
nginx-deployment-3441592026-kkp8h   1/1       Running   0          3m
nginx-deployment-3441592026-lx304   1/1       Running   0          3m

デプロイメントのアップデート

Podの仕様を編集することで、Deploymentのより一般的なアップデートを行うことができます。 この例では、最新のnginxイメージに変更しましょう。

最初に、次のように入力してテキストエディタを開きます。

$ kubectl edit deployment/nginx-deployment

次に、imageをnginx:1.12.1からnginx:latestに変更します。

これにより、展開のロール更新が実行されます。 リビジョン、イメージのバージョン、ポートなどの展開の詳細を追跡するには、次のように入力します。

$ kubectl describe deployments
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Mon, 23 Oct 2017 09:14:36 -0400
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision=2
                        kubernetes.io/change-cause=kubectl edit deployment/nginx-deployment
Selector:               app=nginx
Replicas:               5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:latest
    Ports:        80/TCP, 443/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-886641336 (5/5 replicas created)
Events:
  Type    Reason             Age                From                   Message
  ----    ------             ----               ----                   -------
  Normal  ScalingReplicaSet  4m                 deployment-controller  Scaled up replica set nginx-deployment-3441592026 to 3
  Normal  ScalingReplicaSet  1m                 deployment-controller  Scaled up replica set nginx-deployment-3441592026 to 5
  Normal  ScalingReplicaSet  32s                deployment-controller  Scaled up replica set nginx-deployment-886641336 to 1
  Normal  ScalingReplicaSet  32s                deployment-controller  Scaled down replica set nginx-deployment-3441592026 to 4
  Normal  ScalingReplicaSet  32s                deployment-controller  Scaled up replica set nginx-deployment-886641336 to 2
  Normal  ScalingReplicaSet  29s                deployment-controller  Scaled down replica set nginx-deployment-3441592026 to 3
  Normal  ScalingReplicaSet  29s                deployment-controller  Scaled up replica set nginx-deployment-886641336 to 3
  Normal  ScalingReplicaSet  28s                deployment-controller  Scaled down replica set nginx-deployment-3441592026 to 2
  Normal  ScalingReplicaSet  28s                deployment-controller  Scaled up replica set nginx-deployment-886641336 to 4
  Normal  ScalingReplicaSet  25s (x3 over 26s)  deployment-controller  (combined from similar events): Scaled down replica set nginx-deployment-3441592026 to 0

デプロイメントのロールバック

以前のバージョンにロールバックするには、まず更新履歴を確認します。

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         kubectl scale deployment/nginx-deployment --replicas=5
2         kubectl edit deployment/nginx-deployment

前のリビジョンにのみロールバックする場合は、次のコマンドを入力します。

$ kubectl rollout undo deployment/nginx-deployment
deployment "nginx-deployment" rolled back

Deploymentをロールバックしてnginx:1.12.1イメージを使用します。イメージ名を確認してください

$ kubectl describe deployments | grep Image
   Image:        nginx:1.12.1

特定のリビジョンにロールバックする場合は、次のように入力します。

$ kubectl rollout undo deployment/nginx-deployment --to-revision=<version>

デプロイメントの削除

$ kubectl delete -f deployment.yaml
deployment "nginx-deployment" deleted

Service

ポッドは一時的です。各ポッドには一意のIPアドレスが割り当てられます。 複製コントローラに属するポッドが消滅した場合は、再作成され、異なるIPアドレスが与えられます。 さらに、DeploymentまたはReplica Setを使用して追加のポッドを作成することもできます。 これにより、WildFlyなどのアプリケーションサーバーが、そのIPアドレスを使用してMySQLなどのデータベースにアクセスすることが困難になります。

サービスとは、論理的なポッドセットとそのポッドにアクセスするためのポリシーを定義する抽象化です。 サービスに割り当てられたIPアドレスは時間の経過とともに変化しないため、他のポッドに依存することができます。 通常、サービスに属するポッドは、ラベルセレクタによって定義されます。 これは、ポッドがレプリカセットにどのように属しているかと同様のメカニズムです。

ラベルを使用してポッドを選択するというこの抽象化は、疎結合を可能にする。 デプロイメント内のポッドの数は拡大または縮小されますが、アプリケーションサーバーはそのサービスを使用して引き続きデータベースにアクセスできます。

Kubernetesサービスは、論理的なポッドセットを定義し、マイクロサービスを介してそれらにアクセスできるようにします。

ServiceのDeploymentを作成

Podは、ラベルがPodに接続されている疎結合モデルを使用してServiceに属し、Serviceはそれらのラベルを使用してPodを選択します。

最初にDeploymentを作成して、ポッドの3つのレプリカを作成しましょう。

 $ cat echo-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: echo-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: echo-pod
    spec:
      containers:
      - name: echoheaders
        image: gcr.io/google_containers/echoserver:1.4
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

この例では、Elastic Load BalancerのHTTPヘッダーで応答するechoアプリケーションを作成します。 デプロイメントを作成するには、次のように入力します。

$ kubectl create -f echo-deployment.yaml --record

kubectl describe deployment コマンドを使って echo-appがデプロイされたことを確認する

  $ kubectl describe deployment
Name:                   echo-deployment
Namespace:              default
CreationTimestamp:      Mon, 23 Oct 2017 10:07:47 -0400
Labels:                 app=echo-pod
Annotations:            deployment.kubernetes.io/revision=1
                        kubernetes.io/change-cause=kubectl create --filename=templates/echo-deployment.yaml --record=true
Selector:               app=echo-pod
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  app=echo-pod
  Containers:
   echoheaders:
    Image:        gcr.io/google_containers/echoserver:1.4
    Port:         8080/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
OldReplicaSets:  <none>
NewReplicaSet:   echo-deployment-3396249933 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  10s   deployment-controller  Scaled up replica set echo-deployment-3396249933 to 3

Podのリストを取得

$ kubectl get pods
NAME                               READY     STATUS    RESTARTS   AGE
echo-deployment-3396249933-8slzp   1/1       Running   0          1m
echo-deployment-3396249933-bjwqj   1/1       Running   0          1m
echo-deployment-3396249933-r05nr   1/1       Running   0          1m

Podのラベルを確認

$ kubectl describe pods/echo-deployment-3396249933-8slzp | grep Label
Labels:         app=echo-pod

Serviceの作成

次の例では、echo-serviceサービスを作成

$ cat service.yaml
apiVersion: v1
kind: Service
metadata:
  name: echo-service
spec:
  selector:
    app: echo-pod
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

サービスの対象となるポッドのセットは、サービスにapp: echo-podと添付されているラベルによって決定されます。 また、コンテナ上の8080のターゲットポートへのインバウンドポート80を定義します。

Kubernetesは、TCPプロトコルUDPプロトコルの両方をサポートしています。

Serviceを公開する

type属性を使用して外部IPにサービスを公開することができます。この属性は、次のいずれかの値をとります。

  1. ClusterIP: クラスタ内のIPアドレスで公開されるサービス。これがデフォルト動作
  2. NodePort: 定義されたポートで各ノードのIPアドレスに公開されるサービス。
  3. LoadBalancer: クラウドにデプロイされている場合は、クラウド固有のロードバランサを使用して外部に公開される。
  4. ExternalName: externalNameフィールドにサービスが添付されています。値を持つCNAMEにマップされます。

ロードバランサのserviceを公開してサービスを公開し、LoadBalancerのtypeフィールドを追加してみましょう

このテンプレートはElastic Load Balancer(ELB)上にecho-appサービスを公​​開します。

$ cat service.yaml
apiVersion: v1
kind: Service
metadata:
  name: echo-service
spec:
  selector:
    app: echo-pod
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

次のコマンドを実行してサービスを作成します。

$ kubectl create -f service.yaml --record

サービスの詳細を取得

$ kubectl get service
NAME           TYPE           CLUSTER-IP       EXTERNAL-IP        PORT(S)        AGE
echo-service   LoadBalancer   100.66.161.199   ad0b47976b7fe...   80:30125/TCP   40s
kubernetes     ClusterIP      100.64.0.1       <none>             443/TCP        1h
$ kubectl describe service echo-service
Name:                     echo-service
Namespace:                default
Labels:                   <none>
Annotations:              kubernetes.io/change-cause=kubectl create --filename=templates/service.yaml --record=true
Selector:                 app=echo-pod
Type:                     LoadBalancer
IP:                       100.66.161.199
LoadBalancer Ingress:     ad0b47976b7fe11e7a8870e55a29a6a9-1770422890.us-east-1.elb.amazonaws.com
Port:                     http  80/TCP
TargetPort:               8080/TCP
NodePort:                 http  30125/TCP
Endpoints:                100.96.3.8:8080,100.96.4.9:8080,100.96.5.9:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age   From                Message
  ----    ------                ----  ----                -------
  Normal  CreatingLoadBalancer  58s   service-controller  Creating load balancer
  Normal  CreatedLoadBalancer   56s   service-controller  Created load balancer

出力はLoadBalancer IngressをElastic Load Balancer(ELB)のアドレスとして表示されます。 ELBがプロビジョニングされ、利用可能になるまでには約2〜3分かかるので数分待ってからサービスにアクセスするとよい。

$ curl http://ad0b47976b7fe11e7a8870e55a29a6a9-1770422890.us-east-1.elb.amazonaws.com
CLIENT VALUES:
client_address=172.20.45.253
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://ad0b47976b7fe11e7a8870e55a29a6a9-1770422890.us-east-1.elb.amazonaws.com:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=*/*
host=ad0b47976b7fe11e7a8870e55a29a6a9-1770422890.us-east-1.elb.amazonaws.com
user-agent=curl/7.51.0
BODY:
-no body in request-

出力に示されているclient_addressの値に注意してください。 これは、リクエストを処理するポッドのIPアドレスです。 このコマンドを複数回呼び出すと、この属性に異なる値が表示されます。

これで、deploymentのポッドの数を増減できます。 または、ポッドが終了して別のホストで再起動することがあります。 しかし、Serviceは、ポッドに付いているラベルがServiceによって使用されているため、それらのポッドを対象とすることができます。

サービスの削除

サービスを削除するには、次のコマンドを実行します。

$ kubectl delete -f service.yaml

バックエンドの展開も明示的に削除する必要があります。

$ kubectl delete -f echo-deployment.yaml

デーモンセット

デーモンセットは、Podのコピーが選択されたノードセットで実行されるようにします。 デフォルトでは、クラスタ内のすべてのノードが選択されます。 選択基準を指定して、限られた数のノードを選択することができる。

新しいノードがクラスタに追加されると、ポッドがクラスタ上で開始されます。 ノードが削除されると、ガベージコレクションによってポッドが削除されます。

デーモンセットを作成する

次は、Prometheusコンテナを実行するDaemonSetの例です。テンプレートから始めましょう。

$ cat daemonset.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: prometheus-daemonset
spec:
  template:
    metadata:
      labels:
        tier: monitoring
        name: prometheus-exporter
    spec:
      containers:
      - name: prometheus
        image: prom/node-exporter
        ports:
        - containerPort: 80

次のコマンドを実行することでReplicaSetとpodsが作成されます。

$ kubectl create -f daemonset.yaml --record

--recordフラグは各リビジョンの変更を追跡します。

$ kubectl get daemonsets/prometheus-daemonset
NAME                   DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
prometheus-daemonset   5         5         5         5            5           <none>          7s

DaemonSetの詳細を取得

$ kubectl describe daemonset/prometheus-daemonset
Name:           prometheus-daemonset
Selector:       name=prometheus-exporter,tier=monitoring
Node-Selector:  <none>
Labels:         name=prometheus-exporter
                tier=monitoring
Annotations:    kubernetes.io/change-cause=kubectl create --filename=templates/daemonset.yaml --record=true
Desired Number of Nodes Scheduled: 5
Current Number of Nodes Scheduled: 5
Number of Nodes Scheduled with Up-to-date Pods: 5
Number of Nodes Scheduled with Available Pods: 5
Number of Nodes Misscheduled: 0
Pods Status:  5 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  name=prometheus-exporter
           tier=monitoring
  Containers:
   prometheus:
    Image:        prom/node-exporter
    Port:         80/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From        Message
  ----    ------            ----  ----        -------
  Normal  SuccessfulCreate  28s   daemon-set  Created pod: prometheus-daemonset-pzfl8
  Normal  SuccessfulCreate  28s   daemon-set  Created pod: prometheus-daemonset-sjcgh
  Normal  SuccessfulCreate  28s   daemon-set  Created pod: prometheus-daemonset-ctrg4
  Normal  SuccessfulCreate  28s   daemon-set  Created pod: prometheus-daemonset-rxg79
  Normal  SuccessfulCreate  28s   daemon-set  Created pod: prometheus-daemonset-cnbkh

DaemonSetでポッドを取得

$ kubectl get pods -lname=prometheus-exporter
NAME                         READY     STATUS    RESTARTS   AGE
prometheus-daemonset-cnbkh   1/1       Running   0          57s
prometheus-daemonset-ctrg4   1/1       Running   0          57s
prometheus-daemonset-pzfl8   1/1       Running   0          57s
prometheus-daemonset-rxg79   1/1       Running   0          57s
prometheus-daemonset-sjcgh   1/1       Running   0          57s

特定のノードにDaemonSetsを制限する

Prometheusポッドがクラスタノードに正常に展開されたことを確認します。

$ kubectl get pods -o wide
NAME                         READY     STATUS    RESTARTS   AGE       IP           NODE
prometheus-daemonset-drqj8   1/1       Running   0          3m        100.96.3.9   ip-172-20-99-142.ec2.internal
prometheus-daemonset-l747p   1/1       Running   0          3m        100.96.4.7   ip-172-20-74-231.ec2.internal
prometheus-daemonset-vbd85   1/1       Running   0          3m        100.96.5.8   ip-172-20-185-78.ec2.internal
prometheus-daemonset-xr67t   1/1       Running   0          3m        100.96.6.8   ip-172-20-150-149.ec2.internal
prometheus-daemonset-xsdlp   1/1       Running   0          3m        100.96.7.7   ip-172-20-37-172.ec2.internal

ノードラベルの1つを次のように変更します。

$ kubectl label node ip-172-20-74-231.ec2.internal app=prometheus-node
node "ip-172-20-74-231.ec2.internal" labeled

次に、次のコマンドでDaemonSetテンプレートを編集します。

$ kubectl edit ds/prometheus-daemonset

spec.template.spec の中に変更したラベルに一致するnodeSelectorを含めるように変更。

      nodeSelector:
        app: prometheus-node

更新が実行された後、Prometheusを特定のノードで実行するように設定しました。

$ kubectl get ds/prometheus-daemonset
NAME                   DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR         AGE
prometheus-daemonset   1         1         1         0            1           app=prometheus-node   2m

デーモンセットを削除する

DaemonSetを削除するには、次のコマンドを実行します。

$ kubectl delete -f daemonset.yaml

ジョブ

ジョブは1つまたは複数のポッドを作成し、指定された数のポッドが正常に完了するようにします。ジョブは、ポッドの正常終了を追跡します。 指定した数のポッドが正常に完了すると、ジョブ自体は完了です。 ハードウェア障害のためにポッドに障害が発生したり削除されたりすると、ジョブは新しいポッドを開始します。 指定した数のポッドが正常に完了すると、ジョブが完了したことを意味します。

これは、特定の数のポッドが常に実行されていることを保証するレプリカセットまたはデプロイメントとは異なります。 したがって、レプリカセットまたは配備内のポッドが終了すると、そのポッドは再び再開されます。これにより、レプリカセットまたはデプロイメントは長期実行プロセスとなります。 これは、NGINXなどのWebサーバーに適しています。ただし、指定した数のポッドが正常に完了すると、ジョブは完了します。 これは、一度だけ実行する必要のあるタスクに適しています。例えば、ジョブは画像フォーマットを別のものに変換することができる。 レプリケーションコントローラでこのポッドを再起動すると、重複した作業が発生するだけでなく、場合によっては有害な可能性があります。

ジョブはレプリカセットを補完します。 レプリカセットは、終了する予定のないポッド(Webサーバーなど)を管理し、ジョブは終了すると予想されるポッド(バッチジョブなど)を管理します。

仕事を持つポッドにのみ適しているRestartPolicyに等しいですOnFailureかNever。

非並列ジョブ

ポッドに障害が発生しない限り、1ジョブにつき1つのポッドしか開始されません。 ポッドが正常に終了するとすぐにジョブが完了します。

これがジョブの仕様です。

 $ cat job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: wait
spec:
  template:
    metadata:
      name: wait
    spec:
      containers:
      - name: wait
        image: ubuntu
        command: ["sleep",  "20"]
      restartPolicy: Never

Ubuntuのコンテナを作成し、20秒間スリープ状態になります。 次のコマンドを使用してジョブを作成します。

$ kubectl apply -f job.yaml
job "wait" created

ジョブを見てみます。

$ kubectl get jobs
NAME      DESIRED   SUCCESSFUL   AGE
wait      1         0            0s

出力はジョブがまだ成功していないことを示しています。 ポッドの状態を確認して確認します。

$ kubectl get -w pods
NAME         READY     STATUS    RESTARTS   AGE
wait-lk49x   1/1       Running   0          7s
wait-lk49x   0/1       Completed   0         24s

まず、ジョブのポッドが実行中であることを示します。 ポッドは数秒後に正常に終了し、Completedステータスが表示されます。

ジョブの状態をもう一度見てみましょう。

$ kubectl get jobs
NAME      DESIRED   SUCCESSFUL   AGE
wait      1         1            1m

出力はジョブが正常に実行されたことを示します。

完了したポッドはkubectl get podsコマンドに表示されません。 代わりに、次のように追加のオプションを渡すことで表示できます。

$ kubectl get pods --show-all
NAME         READY     STATUS      RESTARTS   AGE
wait-lk49x   0/1       Completed   0          1m

ジョブを削除するには、このコマンドを実行します

$ kubectl delete -f job.yaml

パラレルジョブ

非並列ジョブはジョブごとに1つのポッドのみを実行します。 このAPIは、ジョブに対して複数のポッドを並行して実行するために使用されます。 完了させるポッドの数は設定ファイルの.spec.completions属性によって定義されます。 並行して実行するポッドの数は、構成ファイルの.spec.parallelism属性によって定義されます。 これらの属性の両方のデフォルト値は1です。

範囲 1〜.spec.completionsの各値に対して成功したポッドが1つある場合、ジョブは完了です。 そのため、固定完了カウントジョブとも呼ばれます。

ジョブの仕様は以下。

 $ cat job-parallel.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: wait
spec:
  completions: 6
  parallelism: 2
  template:
    metadata:
      name: wait
    spec:
      containers:
      - name: wait
        image: ubuntu
        command: ["sleep",  "20"]
      restartPolicy: Never

このジョブ仕様は、非並行ジョブ仕様に似ています。 これは、2つの新しい属性が追加されました .spec.completions.spec.parallelism。 つまり、6つのポッドが正常に完了すると、ジョブは完了します。 同時に最大2つのポッドが並行して実行されます。

次のコマンドを使用して並列ジョブを作成します。

$ kubectl apply -f job-parallel.yaml

次のようにジョブのステータスを確認します。

$ kubectl get -w jobs
NAME      DESIRED   SUCCESSFUL   AGE
wait      6         0            2s
wait      6         1         22s
wait      6         2         22s
wait      6         3         43s
wait      6         4         43s
wait      6         5         1m
wait      6         6         1m

出力は約20秒ごとに2つのポッドが作成されることを示しています。 別の端末ウィンドウで、作成されたポッドの状態を確認します。

$ kubectl get -w pods -l job-name=wait
NAME         READY     STATUS    RESTARTS   AGE
wait-f7kgb   1/1       Running   0          5s
wait-smp4t   1/1       Running   0          5s
wait-smp4t   0/1       Completed   0         22s
wait-jbdp7   0/1       Pending   0         0s
wait-jbdp7   0/1       Pending   0         0s
wait-jbdp7   0/1       ContainerCreating   0         0s
wait-f7kgb   0/1       Completed   0         22s
wait-r5v8n   0/1       Pending   0         0s
wait-r5v8n   0/1       Pending   0         0s
wait-r5v8n   0/1       ContainerCreating   0         0s
wait-r5v8n   1/1       Running   0         1s
wait-jbdp7   1/1       Running   0         1s
wait-r5v8n   0/1       Completed   0         21s
wait-ngrgl   0/1       Pending   0         0s
wait-ngrgl   0/1       Pending   0         0s
wait-ngrgl   0/1       ContainerCreating   0         0s
wait-jbdp7   0/1       Completed   0         21s
wait-6l22s   0/1       Pending   0         0s
wait-6l22s   0/1       Pending   0         0s
wait-6l22s   0/1       ContainerCreating   0         0s
wait-ngrgl   1/1       Running   0         1s
wait-6l22s   1/1       Running   0         1s
wait-ngrgl   0/1       Completed   0         21s
wait-6l22s   0/1       Completed   0         21s

すべてのポッドが完成したら、kubectl get podsは完成したポッドのリストは表示されません。 ポッドの一覧を表示するコマンドを以下に示します。

$ kubectl get pods -a
NAME         READY     STATUS      RESTARTS   AGE
wait-6l22s   0/1       Completed   0          1m
wait-f7kgb   0/1       Completed   0          2m
wait-jbdp7   0/1       Completed   0          2m
wait-ngrgl   0/1       Completed   0          1m
wait-r5v8n   0/1       Completed   0          2m
wait-smp4t   0/1       Completed   0          2m

同様に、kubectl get jobs完了後のジョブのステータスを示します。

$ kubectl get jobs
NAME      DESIRED   SUCCESSFUL   AGE
wait      6         6            3m

ジョブを削除すると、すべてのポッドも削除されます。ジョブを次のように削除します。

$ kubectl delete -f job-parallel.yaml
job.batch "wait" deleted
$ kubectl get jobs
No resources found.
$ kubectl get pods -a
Flag --show-all has been deprecated, will be removed in an upcoming release
No resources found.

Cron Job

前提条件

Kubernetesクラスタバージョン<1.8の場合、Cron JobはAPIバージョンbatch/v2alpha1で作成できます。 クラスタのバージョンを確認しましょう。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.2", GitCommit:"81753b10df112992bf51bbc2c2f85208aad78335", GitTreeState:"clean", BuildDate:"2018-04-27T09:22:21Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.3", GitCommit:"d2835416544f298c919e2ead3be3d0864b52323b", GitTreeState:"clean", BuildDate:"2018-02-07T11:55:20Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}

Cronジョブを作成する

Cronジョブは、Cron形式で書かれたスケジュールに従って実行されるジョブです。 主な使用例は2つあります。

  1. 指定した時点でジョブを1回実行する
  2. 特定の時点で繰り返し

ジョブの仕様です。

 $ cat cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: hello-cronpod
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello World!
          restartPolicy: OnFailure

このジョブは、現在のタイムスタンプと "Hello World"というメッセージを毎分出力します。 次のコマンドのように、Cron Jobを作成します。

$ kubectl create -f cronjob.yaml 
cronjob.batch "hello" created

--validate=false はkubectlのCLIバージョンが1.8などだった場合は必須です。このオプションを指定しないと、エラーが表示されます。

$ kubectl create -f cronjob.yaml --validate=false
cronjob.batch "hello" created

次のようにジョブのステータスを確認します。

$ kubectl get -w cronjobs
NAME      SCHEDULE      SUSPEND   ACTIVE    LAST SCHEDULE   AGE
hello     */1 * * * *   False     1         4s              1m

別の端末ウィンドウで、作成されたポッドの状態を確認します。

$ kubectl get -w pods -l app=hello-cronpod
NAME                     READY     STATUS      RESTARTS   AGE
hello-1525775460-z24xb   0/1       Completed   0          1m
hello-1525775520-2lvvg   0/1       Completed   0          24s

いずれかのポッドからログを取得

 $ kubectl logs hello-1525775460-z24x

Hello World!

Cronジョブを削除

次のコマンドのように、Cron Jobを削除します。

$ kubectl delete -f cronjob.yaml
cronjob.batch "hello" deleted

Namespace

Namespaceを使用すると、物理クラスタを複数のチームで共有することができます。 Namespaceは、作成されたリソースを論理的に名前のついたグループに分割することを可能にします。 各ネNamespaceは以下の機能を提供します。

  1. 名前の衝突を回避するためのリソースのためにユニークなスコープ
  2. 信頼できるユーザーへの適切な権限を確保するポリシー
  3. リソース消費の制約を指定する機能

これにより、Kubernetesクラスタは複数のグループによってリソースを共有し、各グループごとに異なるレベルのQoSを提供できます。 ある名前空間で作成されたリソースは、他の名前空間から隠されています。 潜在的にそれぞれ異なる制約を持つ複数の名前空間を作成できます。

デフォルトNamespace

名前空間のリストは、次のコマンドを使用して表示できます。

$ kubectl get namespace
NAME          STATUS    AGE
default       Active    2m
kube-public   Active    2m
kube-system   Active    2m

デフォルトでは、Kubernetesクラスタ内のすべてのリソースはdefaultNamespaceに作成されます。 kube-publicはすべてのユーザーが読み取ることができる名前空間で、認証されていないユーザーも含まれます。 kubeadmで起動されたクラスタは、cluster-infoConfigMapがあります。 このクラスタはkopsを使用して作成されるため、このConfigMapは存在しません。

kube-system Kubernetesシステムによって作成されたオブジェクトの名前空間です。

Deploymentを作成しましょう

$ kubectl apply -f deployment.yaml
deployment "nginx-deployment" created

namespaceを確認

$ kubectl get deployment -o jsonpath={.items[].metadata.namespace}
default

カスタムNamespace

新しい名前空間は、設定ファイルまたはkubectlを使用して作成できます

  1. 次の設定ファイルを使用して名前空間を作成できます。
$ cat namespace.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: dev
  labels:
    name: dev
  1. 新しい名前空間を作成
$ kubectl apply -f namespace.yaml
namespace "dev" created
  1. 名前空間のリストを取得する
$ kubectl get ns
NAME          STATUS    AGE
default       Active    3h
dev           Active    12s
kube-public   Active    3h
kube-system   Active    3h
  1. ネームスペースの詳細を取得
$ kubectl describe ns/dev
Name:         dev
Labels:       name=dev
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"labels":{"name":"dev"},"name":"dev","namespace":""}}

Status:  Active

No resource quota.

No resource limits.
  1. 構成ファイルを使用して、この新しい名前空間に配置を作成
 $ cat deployment-namespace.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment-ns
  namespace: dev
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.12.1
        ports:
        - containerPort: 80
        - containerPort: 443

主な変更はnamespace: devの追加です

  1. デプロイメントの作成
$ kubectl apply -f deployment-namespace.yaml
deployment "nginx-deployment-ns" created
  1. 次の-nように追加のスイッチを用意することによって、ネームスペース内の配置を照会することができます。
$ kubectl get deployments -n dev
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment-ns   3         3         3            3           1m
  1. この展開のNamespaceを照会
$ kubectl get deployments/nginx-deployment-ns -n dev -o jsonpath={.metadata.namespace}
dev

別の方法として、名前空間kubectlを使っても作成することができます。

  1. Namespaceを作成
$ kubectl create ns dev2
namespace "dev2" created
  1. Deploymentの作成
$ kubectl -n dev2 apply -f deployment.yaml
deployment "nginx-deployment-ns" created
  1. 新しく作成されたNamespaceにDeploymentを取得
$ kubectl get deployments -n dev2
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment-ns   3         3         3            3           1m
  1. すべてのNamespaceでのdeploymentを取得
$ kubectl get deployments --all-namespaces
NAMESPACE     NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
default       nginx-deployment      3         3         3            3           1h
dev           nginx-deployment-ns   3         3         3            3           1h
dev2          nginx-deployment-ns   3         3         3            3           1m
kube-system   dns-controller        1         1         1            1           5h
kube-system   kube-dns              2         2         2            2           5h
kube-system   kube-dns-autoscaler   1         1         1            1           5h

クォータと制限

各ネームスペースにはリソースクォータを割り当てることができます。クォータを指定すると、ネームスペース内のすべてのリソースで消費できるクラスタリソースの量を制限できます。 リソースクォータは、ResourceQuotaオブジェクトで定義できます。名前空間にResourceQuotaオブジェクトが存在すると、リソースクォータが強制されます。 名前空間内には最大でも1つのResourceQuotaオブジェクトが存在します。現在、複数のResourceQuotaオブジェクトが許可されています。 これはkubernetes#55430として提出されています。

クォータは、CPUやメモリなどの計算リソース、PersistentVolumeやPersistentVolumeClaimなどのストレージリソース、および指定されたタイプのオブジェクトの数に指定できます。 ResourceQuotaを使用して制限できるリソースの完全なリストは、https://kubernetes.io/docs/concepts/policy/resource-quotas/ にリストされています。

ResourceQuotaを作成する

ResourceQuotaは、構成ファイルまたはkubectlを使用して作成できます。

  1. 次の設定ファイルを使用してResourceQuotaを作成できます。
$ cat resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: quota
spec:
  hard:
    cpu: "4"
    memory: 6G
    pods: "10"
    replicationcontrollers: "3"
    services: "5"
    configmaps: "5"

この設定ファイルは、ネームスペースに次の要件を設定します。

  1. 作成されるすべての新しいコンテナには、メモリとCPUの制限が必要です ii. この名前空間内のポッドの総数は10を超えることはできません iii. この名前空間内のReplicationControllerの総数は3を超えることはできません iv. この名前空間内のサービスの総数は5を超えることはできません
  2. この名前空間内のConfigMapの総数は5を超えることはできません

  3. 新しいResourceQuotaを作成します。

$ kubectl apply -f resource-quota.yaml
resourcequota "quota" created

あるいは、kubectlCLI を使用してResourceQuotaを作成することもできます。 どちらの場合も、この場合、これらの制限はdefaultネームスペースに置かれます。 別の名前空間は、構成ファイルで指定するか、またはCLIkubectl--namespaceオプションを使用して指定することができます。

kubectl create -f ./resource-quota.yaml --namespace=myspace
  1. ResourceQuotaのリストを取得
$ kubectl get quota
NAME      AGE
quota     5m
  1. ResourceQuotaの詳細については、次を参照してください。
$ kubectl describe quota/quota
Name:                   quota
Namespace:              default
Resource                Used  Hard
--------                ----  ----
configmaps              0     5
cpu                     300m  4
memory                  0     6G
pods                    3     12
replicationcontrollers  0     3
services                1     5

出力には、default名前空間に3つのPodと1つのサービスが既に存在していることが示されています。

ResourceQuotaを使用してリソースを拡大

ResourceQuotaが作成されたので、これが作成された新しいリソースや拡張された既存のリソースにどのように影響するのかを見てみましょう。

私たちは既にデプロイメントを持っていますnginx-deployment。割り当てられたクォータを超えるようにレプリカの数をスケーリングし、何が起こるかを見てみましょう。

  1. Deploymentのレプリカ数を調整します。
$ kubectl scale --replicas=12 deployment/nginx-deployment
deployment "nginx-deployment" scaled

コマンド出力には、展開がスケーリングされていることが示されます。

  1. すべてのレプリカが利用可能かどうかを確認してみる
$ kubectl get deployment/nginx-deployment -o jsonpath={.status.availableReplicas}
3

3つのレプリカしか利用できないことを示しています。

  1. 詳細は次を参照してください。
$ kubectl get deployment/nginx-deployment -o jsonpath={.status.conditions[].message}
Deployment does not have minimum availability.

現在の理由が出力に表示されます。

ResourceQuotaでリソースを作成する

次の設定ファイルを使ってPodを作成しましょう

$ cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

このポッドを作成する前に、以前実行していたポッドまたはデプロイメントを削除する必要があります。

$ kubectl apply -f pod.yaml
Error from server (Forbidden): error when creating "pod.yaml": pods "nginx-pod" is forbidden: failed quota: quota: must specify memory

エラーメッセージは、ResourceQuotaが有効であり、Podがメモリリソースを明示的に指定しなければならないことを示します。

設定ファイルを次のように更新します。

$ cat pod-memory.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      requests:
        memory: "100m"
    ports:
    - containerPort: 80

ここに定義された明示的メモリリソースがあります。今度は、ポッドを作成してみてください:

$ kubectl apply -f pod-memory.yaml
pod "nginx-pod" created

ポッドは正常に作成されます。

Podの詳細を取得

$ kubectl get pod/nginx-pod -o jsonpath={.spec.containers[].resources}
map[requests:map[cpu:100m memory:100m]]

ResourceQuotaの詳細については、次を参照してください。

$ kubectl describe quota/quota
Name:                   quota
Namespace:              default
Resource                Used  Hard
--------                ----  ----
configmaps              0     5
cpu                     400m  4
memory                  100m  6G
pods                    4     12
replicationcontrollers  0     3
services                1     5

CPUとメモリリソースがどのように増分された値になっているかに注意してください。

kubernetes#55433 ResourceQuotaでポッドを作成するために明示的なCPUリソースが必要ない方法の詳細を提供します。

$ $ kubectl delete quota/quota
resourcequota "quota" deleted

これで、ワークショップを続ける準備が整いました!

次回は201-cluster-monitoringからです。