Service Discovery for Microservices with Kubernetes
302-app-discovery
Service Discovery for Microservices with Kubernetes
ハードコードされたIPアドレスを使用するのではなく、 アプリケーション内のさまざまなマイクロサービスがサービス検出を使用してインフラストラクチャ内で互いにどのように位置付けられるかの例を示す。
前提条件
3つのマスターノードと5つのワーカーノードを持つクラスタを使用
アプリケーションアーキテクチャ
サンプルアプリケーションでは、次の3つのサービスを使用
webapp
:Webアプリケーションのマイクロサービスはgreeter
、name
のマイクロサービスを使用して人のために挨拶を生成します。greeter
:マイクロサービスはgreet
、URLの名前/値のキーペアに基づいて挨拶を返します。name
:id
URLの名前/値のキーペアに基づいて人の名前を返すマイクロサービス。
これらのサービスは、Dockerイメージとして構築され、Kubernetesに配備されています。すべてのサービスはNode.jsアプリケーションとしてビルドされています。 サービスのソースコードは https://github.com/arun-gupta/container-service-discovery/tree/master/services にあります。
これらの webapp
サービスは name
と greeter
サービスと通信するに、以下の環境変数でサービスを構成する必要があります。
NAME_SERVICE_HOST
と GREETER_SERVICE_HOST
の環境変数は、そのラベルではなく、ポッドまたはホストのIPアドレスなどの静的参照することによって、これらのサービスを参照してください。
その利点は 存在している name
および/または greeter
ポッドがもはや操作可能でなくなった場合、それが依存するサービスを継続して実行するために十分なリソースがクラスタにある場合、 webapp
サービスは機能し続けます。
- NAME_SERVICE_HOST
- NAME_SERVICE_PORT
- NAME_SERVICE_PATH
- GREETER_SERVICE_HOST
- GREETER_SERVICE_PORT
- GREETER_SERVICE_PATH
3つの異なるサービスを持つ設定ファイルは、app.yml で定義されています。 webappサービスのレプリカセットには、次の環境変数があります。
spec: containers: - name: webapp-pod image: arungupta/webapp-service:latest env: - name: NAME_SERVICE_HOST value: name-service - name: NAME_SERVICE_PORT value: "8080" - name: NAME_SERVICE_PATH value: / - name: GREETER_SERVICE_HOST value: greeter-service - name: GREETER_SERVICE_PORT value: "8080" - name: GREETER_SERVICE_PATH value: /
環境変数は、アプリケーション構成で定義されているように、name
およびgreeter
サービスを指しています。
webapp
サービス用のイングレスロードバランサは、次のフラグメントを使用して作成されます。
spec: selector: app: webapp-pod ports: - name: web port: 80 type: LoadBalancer
全体として、サービスは次のように互いに通信します。
[Ingress LB (ELB)] → [WEBAPP] → /name-service → Name ↓ → /greeter-service → Greeter
アプリケーションのデプロイ
アプリケーションをデプロイする
$ kubectl create -f templates/app.yml service "name-service" created replicaset.extensions "name-rs" created service "greeter-service" created replicaset.extensions "greeter-rs" created service "webapp-service" created replicaset.extensions "webapp-rs" created
サービスのリストを取得
$ kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE greeter-service 100.64.44.23 <none> 8080/TCP 13s kubernetes 100.64.0.1 <none> 443/TCP 23m name-service 100.66.113.58 <none> 8080/TCP 13s webapp-service 100.71.126.195 a5427e1288472... 80:31234/TCP 12s
- サービスの詳細情報を取得
$ kubectl describe svc/webapp-service Name: webapp-service Namespace: default Labels: <none> Annotations: <none> Selector: app=webapp-pod Type: LoadBalancer IP: 100.71.126.195 LoadBalancer Ingress: a5427e128847211e782280a896fc2bfc-283874069.us-east-1.elb.amazonaws.com Port: web 80/TCP NodePort: web 31234/TCP Endpoints: 100.96.2.12:80 Session Affinity: None Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 30s 30s 1 service-controller Normal CreatingLoadBalancer Creating load balancer 29s 29s 1 service-controller Normal CreatedLoadBalancer Created load balancer
アプリケーションへアクセス
ブラウザやcurlでアプリケーションにアクセスする
http://<host> http://<host>?greet=ho http://<host>?id=1 http://<host>?greet=ho&id=1
<host>
はロードバランサのアドレスの入力値
$ kubectl get svc/webapp-service -o jsonpath={.status.loadBalancer.ingress[0].hostname} a5427e128847211e782280a896fc2bfc-283874069.us-east-1.elb.amazonaws.com
アプリケーション削除
$ kubectl delete -f templates/app.yml
k8sクラスタのアップグレード
203-cluster-upgrades
Kubernetesクラスタのアップグレード
AWS上のKubernetesクラスタのアップグレードは、kopsで簡単にできます。 今回Kubernetesクラスターを2つの方法でアップグレードする方法を試します。
インプレースアップグレード
Kopsを使用すると、インプレースを使用してクラスタをアップグレードすることは簡単です。 バージョン1.6.10のKubernetesクラスタをセットアップし、kopsを使用して1.7.2への自動ローリングアップグレードを実行します。
クラスタを作成
次のようにKubernetes 1.6.10バージョンクラスタを作成します。
kops create cluster \ --name example.cluster.k8s.local \ --master-count 3 \ --node-count 5 \ --zones $AWS_AVAILABILITY_ZONES \ --kubernetes-version=1.6.10 \ --yes
マルチAZ配備のクラスタにより、クラスタのアップグレード中にポッドやサービスがダウンタイムを起こさないことが保証されます。
クラスタを検証
$ kops validate cluster --name example.cluster.k8s.local Validating cluster example.cluster.k8s.local INSTANCE GROUPS NAME ROLE MACHINETYPE MIN MAX SUBNETS master-eu-central-1a Master m3.medium 1 1 eu-central-1a master-eu-central-1b Master m3.medium 1 1 eu-central-1b master-eu-central-1c Master c4.large 1 1 eu-central-1c nodes Node t2.medium 5 5 eu-central-1a,eu-central-1b,eu-central-1c NODE STATUS NAME ROLE READY ip-172-20-112-170.eu-central-1.compute.internal master True ip-172-20-117-204.eu-central-1.compute.internal node True ip-172-20-54-176.eu-central-1.compute.internal master True ip-172-20-55-115.eu-central-1.compute.internal node True ip-172-20-63-241.eu-central-1.compute.internal node True ip-172-20-71-25.eu-central-1.compute.internal master True ip-172-20-91-30.eu-central-1.compute.internal node True ip-172-20-93-220.eu-central-1.compute.internal node True Your cluster example.cluster.k8s.local is ready
$ kubectl get nodes NAME STATUS ROLES AGE VERSION ip-172-20-112-170.eu-central-1.compute.internal Ready master 7m v1.6.10 ip-172-20-117-204.eu-central-1.compute.internal Ready node 6m v1.6.10 ip-172-20-54-176.eu-central-1.compute.internal Ready master 7m v1.6.10 ip-172-20-55-115.eu-central-1.compute.internal Ready node 6m v1.6.10 ip-172-20-63-241.eu-central-1.compute.internal Ready node 6m v1.6.10 ip-172-20-71-25.eu-central-1.compute.internal Ready master 7m v1.6.10 ip-172-20-91-30.eu-central-1.compute.internal Ready node 6m v1.6.10 ip-172-20-93-220.eu-central-1.compute.internal Ready node 6m v1.6.10
クラスタ内の各ノードがバージョン1.6.10であることを示しています。
クラスタ構成の編集
1.6.10の既存のクラスタを1.7.4にアップグレードしましょう。クラスタ構成を編集します。
kops edit cluster example.cluster.k8s.local
これにより、クラスタ構成がテキストエディタで開きます。
kubernetesVersion
ターゲットバージョン(この場合は1.7.4)にキーを設定し、設定ファイルを保存します。
以前の値:
kubernetesVersion: 1.6.10
以下に変更されます:
kubernetesVersion: 1.7.4
変更を保存してエディタを終了します。Kubernetesクラスタは設定を再読み込みする必要があります。 これは、次のコマンドを使用して、クラスタのローリング・アップデートを強制することで実行できます。
このプロセスには30〜45分かかることがあります。その時間中に更新なしでクラスタを離れることをお勧めします。
$ kops update cluster example.cluster.k8s.local I1028 18:18:59.671912 10844 apply_cluster.go:420] Gossip DNS: skipping DNS validation I1028 18:18:59.699729 10844 executor.go:91] Tasks: 0 done / 81 total; 36 can run I1028 18:19:00.824806 10844 executor.go:91] Tasks: 36 done / 81 total; 15 can run I1028 18:19:01.601875 10844 executor.go:91] Tasks: 51 done / 81 total; 22 can run I1028 18:19:03.340103 10844 executor.go:91] Tasks: 73 done / 81 total; 5 can run I1028 18:19:04.153174 10844 executor.go:91] Tasks: 78 done / 81 total; 3 can run I1028 18:19:04.575327 10844 executor.go:91] Tasks: 81 done / 81 total; 0 can run Will modify resources: LaunchConfiguration/master-eu-central-1a.masters.cluster.k8s.local UserData ... cat > kube_env.yaml << __EOF_KUBE_ENV Assets: + - 7bf3fda43bb8d0a55622ca68dcbfaf3cc7f2dddc@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubelet - - a9258e4d2c7d7ed48a7bf2e3c77a798fa51a6787@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubelet + - 819010a7a028b165f5e6df37b1bb7713ff6d070f@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl - - 0afe23fb48276ad8c6385430962cd237367b22f7@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubectl - 1d9788b0f5420e1a219aad2cb8681823fc515e7c@https://storage.googleapis.com/kubernetes-release/network-plugins/cni-0799f5732f2a11b329d9e3d51b9c8f2e3759f2ff.tar.gz - c18ca557507c662e3a072c3475da9bd1bc8a503b@https://kubeupv2.s3.amazonaws.com/kops/1.7.1/linux/amd64/utils.tar.gz ... LaunchConfiguration/master-eu-central-1b.masters.cluster.k8s.local UserData ... cat > kube_env.yaml << __EOF_KUBE_ENV Assets: + - 7bf3fda43bb8d0a55622ca68dcbfaf3cc7f2dddc@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubelet - - a9258e4d2c7d7ed48a7bf2e3c77a798fa51a6787@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubelet + - 819010a7a028b165f5e6df37b1bb7713ff6d070f@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl - - 0afe23fb48276ad8c6385430962cd237367b22f7@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubectl - 1d9788b0f5420e1a219aad2cb8681823fc515e7c@https://storage.googleapis.com/kubernetes-release/network-plugins/cni-0799f5732f2a11b329d9e3d51b9c8f2e3759f2ff.tar.gz - c18ca557507c662e3a072c3475da9bd1bc8a503b@https://kubeupv2.s3.amazonaws.com/kops/1.7.1/linux/amd64/utils.tar.gz ... LaunchConfiguration/master-eu-central-1c.masters.cluster.k8s.local UserData ... cat > kube_env.yaml << __EOF_KUBE_ENV Assets: + - 7bf3fda43bb8d0a55622ca68dcbfaf3cc7f2dddc@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubelet - - a9258e4d2c7d7ed48a7bf2e3c77a798fa51a6787@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubelet + - 819010a7a028b165f5e6df37b1bb7713ff6d070f@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl - - 0afe23fb48276ad8c6385430962cd237367b22f7@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubectl - 1d9788b0f5420e1a219aad2cb8681823fc515e7c@https://storage.googleapis.com/kubernetes-release/network-plugins/cni-0799f5732f2a11b329d9e3d51b9c8f2e3759f2ff.tar.gz - c18ca557507c662e3a072c3475da9bd1bc8a503b@https://kubeupv2.s3.amazonaws.com/kops/1.7.1/linux/amd64/utils.tar.gz ... LaunchConfiguration/nodes.cluster.k8s.local UserData ... cat > kube_env.yaml << __EOF_KUBE_ENV Assets: + - 7bf3fda43bb8d0a55622ca68dcbfaf3cc7f2dddc@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubelet - - a9258e4d2c7d7ed48a7bf2e3c77a798fa51a6787@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubelet + - 819010a7a028b165f5e6df37b1bb7713ff6d070f@https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl - - 0afe23fb48276ad8c6385430962cd237367b22f7@https://storage.googleapis.com/kubernetes-release/release/v1.6.10/bin/linux/amd64/kubectl - 1d9788b0f5420e1a219aad2cb8681823fc515e7c@https://storage.googleapis.com/kubernetes-release/network-plugins/cni-0799f5732f2a11b329d9e3d51b9c8f2e3759f2ff.tar.gz - c18ca557507c662e3a072c3475da9bd1bc8a503b@https://kubeupv2.s3.amazonaws.com/kops/1.7.1/linux/amd64/utils.tar.gz ... LoadBalancer/api.cluster.k8s.local Lifecycle <nil> -> Sync LoadBalancerAttachment/api-master-eu-central-1a Lifecycle <nil> -> Sync LoadBalancerAttachment/api-master-eu-central-1b Lifecycle <nil> -> Sync LoadBalancerAttachment/api-master-eu-central-1c Lifecycle <nil> -> Sync Must specify --yes to apply changes
次のコマンドを使用して変更を適用します。
kops update cluster example.cluster.k8s.local --yes
出力します
$ kops update cluster example.cluster.k8s.local --yes I1028 18:22:53.558475 10876 apply_cluster.go:420] Gossip DNS: skipping DNS validation I1028 18:22:54.487232 10876 executor.go:91] Tasks: 0 done / 81 total; 36 can run I1028 18:22:55.750674 10876 executor.go:91] Tasks: 36 done / 81 total; 15 can run I1028 18:22:56.640322 10876 executor.go:91] Tasks: 51 done / 81 total; 22 can run I1028 18:22:59.756888 10876 executor.go:91] Tasks: 73 done / 81 total; 5 can run I1028 18:23:01.154703 10876 executor.go:91] Tasks: 78 done / 81 total; 3 can run I1028 18:23:01.890273 10876 executor.go:91] Tasks: 81 done / 81 total; 0 can run I1028 18:23:02.196422 10876 update_cluster.go:247] Exporting kubecfg for cluster kops has set your kubectl context to example.cluster.k8s.local Cluster changes have been applied to the cloud. Changes may require instances to restart: kops rolling-update cluster
クラスタのアップグレード
次のコマンドを使用して、いずれかのノードで再起動が必要かどうかを判断します。
kops rolling-update cluster example.cluster.k8s.local
このコマンドは、次のように出力します。
NAME STATUS NEEDUPDATE READY MIN MAX NODES master-eu-central-1a NeedsUpdate 1 0 1 1 1 master-eu-central-1b NeedsUpdate 1 0 1 1 1 master-eu-central-1c NeedsUpdate 1 0 1 1 1 nodes NeedsUpdate 5 0 5 5 5 Must specify --yes to rolling-update.
このSTATUS列には、マスターノードとワーカーノードの両方を更新する必要があることが示されています。 次のコマンドを使用してローリングアップデートを実行します。
kops rolling-update cluster example.cluster.k8s.local --yeskops rolling-update cluster example.cluster.k8s.loc
このコマンドの出力が表示されます。
NAME STATUS NEEDUPDATE READY MIN MAX NODES master-eu-central-1a NeedsUpdate 1 0 1 1 1 master-eu-central-1b NeedsUpdate 1 0 1 1 1 master-eu-central-1c NeedsUpdate 1 0 1 1 1 nodes NeedsUpdate 5 0 5 5 5 I1028 18:26:37.124152 10908 instancegroups.go:350] Stopping instance "i-0c729296553079aab", node "ip-172-20-54-176.eu-central-1.compute.internal", in AWS ASG "master-eu-central-1a.masters.cluster.k8s.local". I1028 18:31:37.439446 10908 instancegroups.go:350] Stopping instance "i-002976b15a2968b34", node "ip-172-20-71-25.eu-central-1.compute.internal", in AWS ASG "master-eu-central-1b.masters.cluster.k8s.local". I1028 18:36:38.700513 10908 instancegroups.go:350] Stopping instance "i-0d4bd1a9668fab3e1", node "ip-172-20-112-170.eu-central-1.compute.internal", in AWS ASG "master-eu-central-1c.masters.cluster.k8s.local". I1028 18:41:39.938149 10908 instancegroups.go:350] Stopping instance "i-0048aa89472a2c225", node "ip-172-20-93-220.eu-central-1.compute.internal", in AWS ASG "nodes.cluster.k8s.local". I1028 18:43:41.019527 10908 instancegroups.go:350] Stopping instance "i-03787fa7fa77b9348", node "ip-172-20-117-204.eu-central-1.compute.internal", in AWS ASG "nodes.cluster.k8s.local". I1028 19:14:50.288739 10908 instancegroups.go:350] Stopping instance "i-084c653bad3b17071", node "ip-172-20-55-115.eu-central-1.compute.internal", in AWS ASG "nodes.cluster.k8s.local". I1028 19:16:51.339991 10908 instancegroups.go:350] Stopping instance "i-08da4ee3253afa479", node "ip-172-20-63-241.eu-central-1.compute.internal", in AWS ASG "nodes.cluster.k8s.local". I1028 19:18:52.368412 10908 instancegroups.go:350] Stopping instance "i-0a7975621a65a1997", node "ip-172-20-91-30.eu-central-1.compute.internal", in AWS ASG "nodes.cluster.k8s.local". I1028 19:20:53.743998 10908 rollingupdate.go:174] Rolling update completed!
クラスタを再度検証します。
$ kops validate cluster Using cluster from kubectl context: example.cluster.k8s.local Validating cluster example.cluster.k8s.local INSTANCE GROUPS NAME ROLE MACHINETYPE MIN MAX SUBNETS master-eu-central-1a Master m3.medium 1 1 eu-central-1a master-eu-central-1b Master m3.medium 1 1 eu-central-1b master-eu-central-1c Master c4.large 1 1 eu-central-1c nodes Node t2.medium 5 5 eu-central-1a,eu-central-1b,eu-central-1c NODE STATUS NAME ROLE READY ip-172-20-101-20.eu-central-1.compute.internal master True ip-172-20-106-93.eu-central-1.compute.internal node True ip-172-20-109-10.eu-central-1.compute.internal node True ip-172-20-41-77.eu-central-1.compute.internal node True ip-172-20-44-33.eu-central-1.compute.internal master True ip-172-20-75-132.eu-central-1.compute.internal node True ip-172-20-85-128.eu-central-1.compute.internal master True ip-172-20-93-108.eu-central-1.compute.internal node True Your cluster example.cluster.k8s.local is ready
クラスタからノードのリストを取得
$ kubectl get nodes NAME STATUS ROLES AGE VERSION ip-172-20-101-20.eu-central-1.compute.internal Ready master 42m v1.7.4 ip-172-20-106-93.eu-central-1.compute.internal Ready node 36m v1.7.4 ip-172-20-109-10.eu-central-1.compute.internal Ready node 37m v1.7.4 ip-172-20-41-77.eu-central-1.compute.internal Ready node 3m v1.7.4 ip-172-20-44-33.eu-central-1.compute.internal Ready master 51m v1.7.4 ip-172-20-75-132.eu-central-1.compute.internal Ready node 5m v1.7.4 ip-172-20-85-128.eu-central-1.compute.internal Ready master 46m v1.7.4 ip-172-20-93-108.eu-central-1.compute.internal Ready node 44s v1.7.4
Blue/green Upgrade
Blue/green メソッドを使用してクラスターをアップグレードすることは、本質的にはより控えめであると考えられ、アプリケーションの高可用性を考慮します。 2つのk8sクラスタを設定します.1つは1.6.10バージョン、もう1つは1.7.2で、ポッドの展開とサービスは新しいクラスタに移行します。
シェルスクリプトでのリトライ処理とロック処理
サーバ運用で手動でApache再起動のような対応は辛いので アラートを検知したら自動でApache再起動を実施し、 メールで知らせてくれるスクリプトを書きたいと思い、 リトライ処理やロック処理をシェルスクリプトでどうやるか調べたのでまとめます。
リトライ処理
変数でリトライ回数とリトライ間隔を決めて whileループでカウントを1ずつ増やし、 sleepコマンドの引数にリトライ間隔の変数を与えることで リトライ処理を実装できた。
## リトライ処理 RETRY_COUNT=1 # リトライ回数 RETRY_INTERVAL=1 # リトライ間隔1秒 while [[ $COUNT -ne $RETRY_COUNT ]] do COUNT=`expr $COUNT + 1` sleep $RETRY_INTERVAL done
ロック処理
こちらの記事が参考になりました。https://heartbeats.jp/hbblog/2013/10/atomic03.html#more
シンボリックリンクを作成するときに、作成先にすでにファイルが存在するとエラーとなります。そのため、ロックファイルをシンボリックリンクとして作成を試みれば、ロックファイルが存在すればエラーが発生するため、ロックファイルが存在すると判断し処理を中断できます。ロックファイルが存在しなければ、ロックファイルがシンボリックリンクとして作成されます。「ロックファイルの確認」と「ロックファイルの作成」が同時に行われるため、安全にロックすることができるのです。普通のファイルとしてロックファイルを作成する方法での問題はシンボリックリンクの場合は起きません。
以下のようにシンボリックリンクを作成することでアトミックにロックファイルを作成することができます。
#!/bin/bash LOCK_FILE=$HOME/tmp/file.lock ## ロックファイルの確認と作成 if ! ln -s $$ $LOCK_FILE; then echo "LOCKED" exit 0
このようにロックファイルの確認と作成を別々に行うとアトミックなファイルの扱いにはならないので要注意です。
## ロックファイルの確認 if [ -f $LOCK_FILE ]; then echo "LOCKED" exit 1 fi
それでは実際にリトライ処理とロック処理を使ってシェルスクリプトを書いてみましょう。 Nagios監視でcheck_httpが何度か失敗し、check_loadでも失敗したら Apache再起動を実行し、1分間はApache再起動が実行されないスクリプトを書いてみます。 これをCronなどで3分毎に実行させればWEBサーバで応答に時間がかかっている時の障害対応を自動化できますね。 ロックファイルを設置して排他制御を行うことで、Apache再起動が何度も実行されないように実装ができます。
#!/bin/bash set -uo pipefail HOSTNAME=$(uname -n) MAIL_ADDRESS_TO="メールアドレス" LOCK_FILE="$HOME/restart.lock" RETRY_COUNT=5 # リトライ回数 RETRY_INTERVAL=5 # リトライ間隔5秒 COUNT=0 ## ロックファイルの確認 ## なければロックファイルの作成 if ! ln -s $$ $LOCK_FILE; then echo "LOCKED" exit 0 fi /usr/lib64/nagios/plugins/check_http -w 5 -c 7 -H localhost -u "/" -s "</html>" RETURN_HTTP=$? if [[ ${RETURN_HTTP} -ne 0 ]]; then ## check_httpの応答判断のリトライ処理 while [[ $COUNT -ne $RETRY_COUNT ]] do COUNT=`expr $COUNT + 1` sleep $RETRY_INTERVAL /usr/lib64/nagios/plugins/check_http -w 5 -c 7 -H localhost -u "/" -s "</html>" RETURN_HTTP=$? if [[ ${RETURN_HTTP} -eq 0 ]]; then exit 0 else continue fi done ## リトライ5回繰り返してもcheck_http監視がOKでないなら以下の再起動処理に進む if [[ ${RETURN_HTTP} -ne 0 ]]; then /usr/lib64/nagios/plugins/check_load -w 2,2,2 -c 3,3,3 RETURN_LOAD=$? if [[ ${RETURN_LOAD} -ne 0 ]]; then echo "/etc/init.d/httpd restart" RETURN=$? if [[ ${RETURN} -ne -0 ]]; then RESULT="Failed" else RESULT="Success" fi SUBJECT="${HOSTNAME} httpd restart ${RESULT}" BODY="${HOSTNAME} restart apache ${RESULT}" echo "${BODY}" | mail -s "${SUBJECT}" ${MAIL_ADDRESS_TO} ## 再起動後は1分スリープ後にロックファイルの削除 sleep 60 rm -f $LOCK_FILE fi fi fi
障害対応の自動化で他によいものがあれば教えて下さい。 また、今回のアトミックなファイルの取扱いの考え方は自分ひとりではなかなか気づかなかったです。
Linuxサーバをセキュアな環境にする
Linuxサーバでセキュアな設定についてまとめてみました。 OSはCentOS6なので古いですが。。 Wordpress周りはまだ調べられてないので どこかでまとめたい。
アドレススキャン対策
ブロードキャスト宛のICMP Echo Requestに対して回答しない
vim /etc/sysctl.conf net.ipv4.icmp_echo_ignore_broadcasts=1
OSやバージョンの確認
# yum -y install nmap # nmap -O example.com
telnet example.com 80
まずはこれぐらいはやっておきたいセキュアな設定
- OSはminimalで必要最小限でインストールする
- システム管理者用のユーザを作成して利用する
yum -y update
でパッケージを最新のものを利用する- 不要なサービスは停止する
- rootユーザのログインを禁止する
- コンソールからのrootログイン禁止
# echo > /etc/securetty
- SSHでのrootログイン禁止
# vim /etc/ssh/ssh_config #PermitRootLogin yes
↓
PermitRootLogin no
- SSHを受け付けるPort番号を変更する
# vim /etc/ssh/ssh_config Ports 20022
OSのセキュリティ
- GRUBのパスワード設定
grub-md5-crypt
を実行して出力内容を/boot/grub/grub.conf
に書くコム- title で始まる行よりも前に
password --md5 パスワード
の書式で記述する
- 一般ユーザのログイン管理
- 不要なユーザのロック
usermod -L hoge
- 不要なユーザのロック解除
usermod -U hoge
- シェルログインが不要なユーザの作成
useradd -s /sbin/nologon hoge
- hogeユーザのログインシェルを
/sbin/nologin
に設定usermod -s /sbin/nologin hoge
- 不要なユーザのロック
- コンソールからのrootログイン禁止
echo > /etc/securetty
- su コマンドを使えるユーザを制限
/etc/pam.d/su
ファイルをrootユーザで開き、 「auth required pam_wheel.so use_uid」という行を追加する- これでwheelグループに追加されたユーザのみがsuコマンドを利用できるようになる
usermod -G wheel hoge
でグループに所属させることが可能
- sudoコマンドの利用設定
visudo
を実行し/etc/sudoers
を開くhoge ALL=(ALL) ALL
ですべてのroot権限が必要なコマンドの実行を許可する
- Clam AntiVirusのインストール
メールサーバのセキュリティ
- ユーザログインの禁止
- メールサーバを利用するだけのユーザならログインする必要ないのでデフォルトシェルを無効にしておく
useradd -s /sbin/nologin newuser
main.cfの主な設定
- myhostname
- ホスト名をFQDNで指定
myhostname = windsor.example.com
- mydomain
- メールサーバのドメイン名を指定
mydomain = example.com
- myorigin
- メールアドレスの[@]以降が指定されなかった時、デフォルトで保管する値を指定する
myorigin = $mydomain
- inet_interfaces
- mydestination
- mynetworks
- 中継を許可するホストの存在する内部ネットワークアドレスを指定
- ここに指定したアドレスからのメールは無条件で中継される
mynetworks = 192.168.11.0/24, 127.0.0.1/8
- smtpd_banner
- SMTPの応答コードに続いて出力されるバナー情報を指定
- できるだけ情報は少ないほうがいいが、
$myhostname
は削除しないようにすること
- disabled_vrfy_command
- STMPのVRFYコマンドを禁止にする
- VRFYコマンドはメールサーバにどのようなアカウントがあるのかを知られる可能性がある
disable_vrfy_command = yes
- smtpd_helo_required
- smtpd_recipient_restrictions
- 通常は末尾にrejectを指定する
- smtpd_sender_restictions
- メールの送信元アドレスをチェックし、受信を拒否するかどうかを判断
設定の反映
service postfix reload
デフォルト値から変更されている項目のみを表示
postconf -n
FTPサーバのセキュリティ
CentOSではセキュアなvsftpdを使う
vsftpd.confの設定
- バナーの表示
- FTP接続確立時のバナーメッセージはftpd_bannerディレクティブで設定
ftpd_banner='FTP Login
- バナーメッセージを格納したファイルを指定するbanner_fileによって無視せれるので注意
- TCP Wrapperの利用有無
tcp_wraller=Yes
tcp_wraller=No
- ユーザリストファイル
userlist_file=/etc/vsftpd/user_list userlist_enable=YES userlist_deny=YES
- ホワイトリストの場合
userlist_file=/etc/vsftpd/user_list userlist_enable=YES userlist_deny=NO
/etc/vsftpd/user_list
にはFTP接続にかかわるユーザを登録。userlist_enable=NO
となっている場合/etc/vsftpd/user_list
内に指定されたユーザのみFTP許可されるが、/etc/vsftpd/ftpusers
にユーザ名が指定されている場合はFTPログインを禁止されてしまう- ファイルのアップロード
- FTPサーバをファイル配布用にするならアップロードは不要
write_enable=NO
でアップロードが禁止になる
- ユーザの設定
- ホームディレクトリ以外に移動できないように設定
chroot_local_user=YES #chroot_list_enable=YES # (default follows) chroot_list_file=/etc/vsftpd/chroot_list
- 一部のユーザにはホームディレクトリ以外に移動できないように設定
chroot_list_enable=YES
と設定して、chroot_list
にユーザを列挙する
chroot_local_user=YES chroot_list_enable=YES # (default follows) chroot_list_file=/etc/vsftpd/chroot_list
- ホームディレクトリ配下のFTPログイン用のサブディレクトリにログインするようにする
- 匿名FTPを許可の有無
- デフォルトでは有効になっている
anonymous_enable=YES
- 匿名FTPを使ってファイル配布したい場合は、匿名アカウントでのファイルアップロードを禁止しておく
anon_upload_enable=NO
write_enbale=NO
ならanon_upload_enable=YES
でもファイルのアップロードはできない
- FTPSを使う
- 証明書と秘密鍵をまとめてpemファイルを作る
cd /etc/pki/tls/certs cp mycerts.crt mycerts.pem cat mycerts.key >> mycerts.pem
- vsftpd.confに以下の行を追加
ssl_enable=YES #SSLの有効化 rsa_cert_file=/etc/pki/tls/certs/mycerts.pem #サーバ証明書秘密鍵のパス
force_local_logins_ssl=NO #FTPログイン時にSSL接続を強制しないように設定 force_local_date_ssl=NO #FTP転送時にSSL接続を強制しないように設定
- vsftpdのログ
- デフォルトでは
/var/log/xferlog
にファイル転送に関するログが記録される
- デフォルトでは
xferlog_enable=YES xferlog_std_format=YES
- ファイル転送のログに加えて、サーバへの接続に関するログも出力されるようにする
xferlog_std_format=NO vsftpd_log_file=/var/log/vsftpd.log
- syslogへ出力するようにもできる
syslog_enable=YES
安全なSSHサーバの設定
/etc/ssh/sshd_config
の設定
- Portの変更
Port 20022 #portの待受けを22番以外にする
- Protocolのバージョンを2にする
Protocol 2
- rootログインを許可しない
PermitRootLogin no
- パスワード認証を許可しない
PasswordAuthentication no
- ログイン認証認証の失敗を許容できる回数を変更
MaxAuthTries 3
pythonでしたいと思ったことまとめ①
print()でカンマ区切りで表示したい
print(a, b, c, sep=',')
行末の改行を削除したい
string.rstrip()
文字列の末尾部分を除去したコピーを返す。引数 chars は除去される文字集合を指定する文字列。
特定の文字を除去したい
文字列.replace() メソッドを利用します。
以下で改行を除去できる。
remove_enter = jugemu.replace('\n', '')
csvファイルなどのカンマで文字列を分割したい
string.strip(',')
ファイルの中身に追記していきたい
a
を使う、 w
だと上書きしてしまう。
with open('output/hoge.log', 'a', encoding='utf-8') as f:
現在の時刻を取得する
datetimeモジュールを使う
from datetime import datetime now = datetime.now()
日時.yearで日時の年の値を数値として取得できる。
print(str(now.year) + '年')
日時.monthで日時の月の値を数値として取得できる。
print(str(now.month) + '月')
日時.dayで日時の日の値を数値として取得できる。
print(str(now.day) + '日')
日時.hourで日時の時の値を数値として取得できる。
print(str(now.hour) + '時')
日時.minuteで日時の分の値を数値として取得できる。
print(str(now.minute) + '分')
日時.secondで日時の秒の値を数値として取得できる。
print(str(now.second) + '秒')
日時のオブジェクトを作成したい
datetime(年, 月, 日, 時, 分, 秒)と指定可能で時分秒を省略すると00:00:00になる。
one_day = datetime(2016, 1, 31, 10, 20, 30)
日時を文字列に変換したい
print(now.strftime('%Y/%m/%d')) # -> 2016/01/10 print(now.strftime('%Y-%m-%d')) # -> 2016-01-10 print(now.strftime('%Y年%m月%d日')) # -> 2016年01月10日
strftime
(フォーマット)を利用して変換できる
- %Y: 西暦(4桁)の10進表記を表します。
- %m: 0埋めした10進数で表記した月。
- %d: 0埋めした10進数で表記した月中の日にち。
- %H: 0埋めした10進数で表記した時 (24時間表記)。
- %M: 0埋めした10進数で表記した分。
- %S: 0埋めした10進数で表記した秒。
文字列を日付にしたい
strptime
を使う。
from datetime import datetime day_str = '2018/3/14 12:30:00' dt = datetime.strptime(day_str, '%Y/%m/%d %H:%M:%S') # 第二引数には変換したい文字列に一致したフォーマットを渡す print(dt) # 2018-03-14 12:30:00
X日前(後)の日付を表示したい
timedelta
を使う
from datetime import datetime from datetime import timedelta olympic_day = datetime(2020, 7, 24) before_3days = now - timedelta(days=3) # 3日前 after_3days = now + timedelta(days=3) # 3日後
Pathを結合したい
os.path.join(a, b, ...)
で指定可能
Pathが存在するか確認したい
os.path.exists(path)
で指定したpathが存在するか確認できる。
指定したpathがファイルかディレクトリか確認したい
ファイルなら
os.path.isfile(path)
ディレクトリなら
os.path.isdir(path)
指定されたディレクトリー内のファイル名と子ディレクトリー名をリストで返したい
os.walk(top)
で返せる。
for文に引数root, dirs, filesを指定すると、そこに各ディレクトリーごとのデータが代入されていく。
import os def directory_tree(target_path): for root, dirs, files in os.walk(target_path) : print(root) for dir in dirs: print('\t', dir) for file in files: print('\t', file)
AWS Summit Tokyo 2018の聴いたセッションのメモ
聞いたセッションのメモ セッションだけ聞くなら会場ではなくストリーミング配信をみるのが快適ということに気がついてしまった。
オペレーションの最適化
- ベストプラクティスに基づく準備
- 適切なモニタリング
適切な運用
Well-Architected framework
- 課題
AWS Trusterd Advisor
- 運用上の優秀正
- 実現のための大原則
- クラウドで運用するためのもの
確認のための質問
Operation as codeの実践
- config,cloudwatc→lambdaで対処するオペレーションの自動化
- 注釈でドキュメンテーションをする.デプロイしたらplaybookなりが更新される
- 頻繁に小さく可逆な変更を加える。ワークロード側も変えられる設計にすべき
- 頻繁に運用手順を見直そう。定期的にGamedayを実施して手順をレビューする。効果があるか、効率化できるポイントを探す。
- 障害を予想する。机上演習Pre-mortemを実施する。障害シナリオとそのインパクトを理解。対応手順が効果的であることぉ確認、チームがそれらに詳しくなる。
- イベントと障害対応から学ぶ。うまくいった対応も塩お愛した対応も振り返る。イベントから学んだことをチームで共有する。ログを集めて、可視化しておこう。athenaとか 確認のための質問 運用がビジネスにどんな影響をあたえるのか、運用が客観的に回るっているのか。
- 運用における優先度を決める要因はなにか
どのようにアプリケーション
実際のお客様環境によくある課題
- メンテナンスの通知は受け取れているのか
- awS HEalth API & AWS Heallth Github repository
- aws-health-tools を使えばチャットツールやsNS通知に自動化できる
- 大体の連絡先の活用
- 合うぃ急の連絡先、操作の連絡先、セキュリティの連絡先
- 複数のアカウントをまとめて管理する
- 部門ごとやアプリケーションごとにアカウントを作っているけど、ガバナンスを聞かせられない。
- 請求統合をおこなっているけど、各アカウンとの利用状況が把握できない
- 請求統合されたアカウント感でRIを管理はいや
- AWS Oraganizationによえう請求統合がソリューション
- Masterアカウントにまとめて一括請求、ボリュームディスカウントもこれに適用
- AWS Organization
- 一括請求のみを有効化
- 複数のAWSアカウントに適用するポリシーを集中管理できる
- AWSのサービスへのアクセス制御
- AWSアカウントんお作成と管理の自動化
- AWS Config連携、AWSFirewall Manager連携、SingleSignOn連携
- Cost Explorer API
- Cost Explorer API, CustomReport
- csvだけでなく、jsonでも取れる
- aws-cost-explorer-report
- api使うとお金がかかる
- Reservide Instanceの共有拒否設定
- 本当は複数のアカウントでサイズ関係なくうまくばらすこともできるので、共有してほしい。
- それでも共有したくないなら、RI割引共有の設定で共有したくないなら設定できる
- AWSサポートは活用できているか
- 複数のアカウント感でナレッジが共有されず、何度もの同じことを聞く
- 社内で使っている課題管理システムと連携したい
- サポートの調査が思うように進まない
-
- サポート問い合わせの自動化や問題管理ツールとの連携
- サポート問い合わせのエクスポート
- Trusted Advisortとの自動連系
- case_life_cycle.html, trustedadvisor.html
- ビジネス以上でないと古ファンクションは使えない
サポート問い合わせのベストプラクティス
- 一つのお問い合わせで関連性のない複数の質問をしない
- 問い合わせ対象リソースの所有者が起票していることを確認する
- 適切な緊急度を設定
- 問いあわせ時には以下の内容を添付
事象の発生時間(タイムゾーン) 事象が発生したリソースの詳細(リージョン・リソースID・名前) 発生した事象の詳細: SdKやCLIのエラ=であればそのエラー出力 可能であればAWSのCLIのの場合は--debug
Well-Architectを使って準備し、Trusted Advisorを使って環境を見直しておこう
Fargate
コンテナのメリット - パッケージング - 配布 - イミュータブルインフラストラクチャ
アプリケーション開発に集中
1台のサーバでDockerコンテナを使うのは簡単だが、サーバが増えると大変
- ECS
Fatgateはインスタンス管理不要 Fargateの上にTaskが起動。EC2インスタンスを増やすことなく仮想サーバー側の管理が不要 Taskだけがスケールされる
Codecommit codebuld ECR Fargate ECK
コンテナ管理にひつようなもの サービスディスカバリ Route53,ALB ロギング、モニタにリング CloudWatch セキュリティ IAM VPC パラメータストア スケジューリング タスクプレースメント
サービスディスカバリ サービス同士が疎結合になるように構成するのがベストプラクティス、生存時間が短いので各サービスが自身が接続する先を見つける必要がある ECSではALBと連携 ALBをエンドポイントとしてつかう ECAサービスディスカバリの利用 名前解決で、ALBを使わずRoute53のDNA名で自動的に登録することができる
ロギングとモニタにリング コンテナのアプリは外でSTDOUTに出力する コンテナインスタンスとかリソースよりサービスを管理するのがよい
CloudWatch awslogsでCloudWathLogsに送信される 1つのTask内に2種類のコンテナを定義する アプリケーションコンテナ ロギング用のコンテナ 一次共有ボリュームにログを出力しロギングコンテナがcloudwatch logsに転送 ロギング処理を別コンテナにまかせる サイドカー構成
Fargateはコンテナにインスタンスの管理は不要でタスクのみ。
Fargateより、より細やかなECSクラスタ管理をつげんできる ECSクラスタの状態変化をリアルタイムに検出する 監視システムにEventログを保存してくらすたの 状態を可視化する 特定のタスクが落ちたときに気づける状態変化に気づける
EventStreamによるリアルタイムなイベント検知 ECSクラスタの状態変化を通知する Evento通知の到達性は少なくとも1回
セキュリティ アクセス権限の考え方 IAMロールポリシーを使ってクラスターに対する権限や アプリケーションの権限、どのタスクがどのAWSリスースにアクセスできるか タスク管理に関する権限 ECRからのイメージのpull Clone
Taskに関するセキュリティ Task単位でIAMロールを割り当て Task単位でSecurity Groupを割り当て
Taskでどのようにパスワードをわたすのか Parameter Store,Secrets Managerを使ってKMSに置いてTaskに設定されたIAMロールの権限に応じて秘密情報を取得
スケジューリングとタスクプレースメント 管理が必要となる2つのレイヤー - CountainerInstanceのスケーリング Fargateは考慮不要。 - Taskのスケーリング アプリケーションオートスケーリングを利用することでTaskのオートスケーリングを実現可能
EC2インスタンス使うときのスケールイン タスクの数が減る。→コンテナインスタンスを削除
Fargateのスケールイン
タスクのみがスケールインすればよい。
Target Trackingを利用したアプリケーションオートスケーリング メトリクスに対してターゲット値を設定 その値に近づくようにアプリケーションオートスケーリングが自動的にTaskを調整
Taksの配置を管理するには Taskga可動するために必要な条件は 必要なCPU、メモリ、ポートが割り当て可能化
どのようにTaskを配置したいのか 特定のAZに置く 特定のインスタンスタイプのみ
Task配置に関するロジック CPUメモリーポートとAZ、インスタンスタイプ、AMI ID 配置戦略を満たすか 最終的なTaskの配置場所を決定
タスク配置例
コンテナインスタンスのroll out タスクdefinitionの更新時に新しいAMI IDを利用してコンテナインスタンスに配置する制約をつける 1ホスト1コンテナ distinctinstqnce constaraint + event stream + lambda
# 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の次のような機能をいくつか見ていきます。
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は、Google、IBM、Lyftの共同開発です。
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