小ネタ:kubernetes nodeへのROLES情報の付与

やりたいこと

以下のように、ROLES欄がブランクになっているので、ROLE情報を付与したい。

[root@liva01:~]#kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
liva01    Ready     <none>    47d       v1.10.3
liva02    Ready     <none>    42d       v1.10.3

実現方法

以下に書かれていた方法で、できた。
stackoverflow.com

ログ

[root@liva01:~]#kubectl label node liva01 node-role.kubernetes.io/master=master
node "liva01" labeled

[root@liva01:~]#kubectl label node liva02 node-role.kubernetes.io/worker=worker
node "liva02" labeled

#kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
liva01    Ready     master    47d       v1.10.3
liva02    Ready     worker    42d       v1.10.3

Kubernetes In Action Chapter11 Understanding Kubernetes Internals 読書メモ

Chapter11

この章で話すこと。 

  • k8sの構成コンポーネントとその相互作用
  • deployment作成から実際にpodがランニング状態になるまでの流れ
  • ruuning podの詳細
  • pod networkの詳細
  • serviceの詳細
  • 高可用性設計

11.1アーキテクチャ

構成要素

  • control plane
  • worker nodes

コントロールプレーンの構成要素

  • etcd
  • API server
  • scheduler
  • controller manager

worker nodesの構成要素

  • kubelet
  • kube-prox
  • container runtime

その他のアドオンコンポーネント

11.1.1 マイクロサービスとしてのk8s

11.1.2. k8sにおけるetcdの役割

  • k8sにおけるあらゆるオブジェクトは永続的な方法でどこかに情報が保存される必要がある。restartしても揮発しないようにするため。そのためにk8sでは分散kvsであるetcdを使う。
  • etcdと直接通信するのはAPIサーバのみ

上記のアーキテクチャの利点

  1. 楽観的ロックが可能
  2. APIサーバでリクエストに対するバリデーションを行うことができる
  3. ストレージへのアクセスの抽象化(利用したい時は単にAPIを叩けば良い)
  4. コンポーネント間の依存関係の疎結合性の担保

重要な点なので再度強調するとetcdはk8sにおいてデータを貯蔵する唯一のコンポーネントである。

楽観的並行性コントロール

楽観的並行性コントロールの概要 

更新するデータをロックするのではなく、バージョンを使ってロックをかける データが更新されるたびにバージョン番号が増加する。クライアントかデーターを更新する際に、

1.データとそれに付与のバージョン番号をread 2.WRITEするデータのpush直前に再度バージョン番号を確認 →この時に、バージョン番号が項番1のものより新しい場合は更新を破棄 →バージョン番号に変更がない場合はpushしバージョン番号を更新

という感じで動く。結果的に2つのクライアントが同時にアップデートしようとしても、片方のクライアントのみが更新に成功する。

※なので恐らく、2のチェックからpush&バージョン番号更新までの間に他のクライアントが書き込んでしまうことは防げない

  • あらゆるリソースは、 metadata.resourceVersion フィールドを持つ。このフィールドはリソースがアップデートされた時にクライアントからapiサーバに通知するために利用される。APIサーバはクライアントから通知のバージョンとetcdに保存されたバージョンを比較し一致しない場合アップデートリクエストをrejectする。

kubernetesのリソース情報はetcdに格納される

  • 本書の執筆時点では、etcdにはver2とver3の2つのAPIバージョンが存在するがパフォーマンス観点からバージョン3の使用が推奨されている。
  • バージョン2ではキーは階層構造のキースペースに保存される。この構造はファイルシステムに極めて近い。v3はこのようなディレクトリ構造を採用していないが、"キーは / を含めることができる"という書式ルールがあるため、違いをあまり意識しなくても同じような感覚でアクセスすふことができる。 ※kube-apiserverの —storage-backend オプションでバージョンの指定が可能
  • kubernetesはあらゆるデータを /registry に保存する。 ※kube-apiserverの —etcd-prefix オプションで指定する

サンプルとして、 etcdctl ls /regrstry の実行例。これはv2でのみ実行が可能。

etcdctl ls /regrstry

※ver3の場合は、 etcdctl get /regrstry —prefix=true とすべし

podsの情報を見たい時は、

etcdctl ls /regrstry/pods

default namespaceのpodsの情報を見たい時は、

etcdctl ls /registry/pods/default

注意

kubernetes 1.7以前では、Secretもetcdに格納されているのでセキュリティ観点で注意が必要。 etcdへのアクセス件を開放するとsecret情報が閲覧できてしまう。

一貫性の保証とオブジェクト保存時のバリデーションの実行

  • kubernetesの前身となるborgとomegaでもクラスターのstateを保持するcentralized storeを保持していたが、あらゆるコンポーネントが直接そのデータストアと通信をする設計になっていた。そのため、データ更新処理のコンフリクトが発生しうるので楽観的ロック機構を全てのコンポーネントに実装し、そのような状態を適切に処理する必要があった。1つでもそのような機構を持たないコンポーネントが存在する場合それはデータの一貫性が損なわれることを意味した。
  • kubernetesでは、全てのコンポーネントAPIサーバを通じてデータストアにアクセスするアーキテクチャにすることで上記の問題を回避している。楽観的ロック機構が動作するのはAPIサーバ上のみであり、そのためにデータの一貫性が損なわれる危険は最小に抑えられる。またAPIサーバがあることで、データストアへの書き込み要求がバリデーション済みのものであること、リクエストの発行が認可されたクライアントからのみなされることが保証される。

複数ノードから構成されるetcdクラスタにおける一貫性の保証

  • 高可用性を達成するためにetcdクラスタを複数ノードで構築することが可能。この際、データの一貫性を保証するためにRAFTアルゴリズムが使われる。RAFTアルゴリズムによりクラスタ内の各ノードのstateは過半数のノードの合意を取り付けた結果のものであることが保証される ※所謂分散合意アルゴリズム
  • 分散合意アルゴリズム、RAFTはstateが状態を遷移するためにクラスタ内の過半数のノードの合意を必要とする。これにより、スプリットブレインが発生しノードの分断が発生した状況においても、それぞれのノードが持つstateが一貫性のない別々の状態に遷移しないことが保証される。(このようなケースにおいては、過半数のノードを有するノード群のみがstateの更新(状態遷移)を実行できる。過半数を持たないノード群については、スプリットブレインが解消後に過半数を有するノードが持つstateが同期される。
  • 上記の理由から、etcdクラスタは奇数ノードで構築されることが推奨される。大規模な環境においても、5台 or 7台のノードがあれば十分であろう。(この場合は2-3台のノードの同時故障においてもetcdクラスタは動作を続けることができる。)

11.1.3. APIサーバの役割

  • kube-apiserver はkuberntesにおいてハブとなるコンポーネントであり、それ以外の全てのコンポーネントに対しAPIインターフェース機能を提供する。(これには、人間向けのクライアントツールであるkubectlも含まれる)
  • APIサーバにより、1.etcdにオブジェクト情報を格納する手続きの一貫性が保たれるだけでなく、2.オブジェクト情報の定義に誤りがないかどうかのバリデーションチェック機能が提供される(これにより誤ったコンフィグ値のオブジェクトが格納されないことが保証される)3. また、楽観的ロックにより複数のコンポーネントからの単一オブジェクトへの同時書き込みによりオブジェクトの更新が競合する問題が回避される
  • kubectlもまた、APIサーバのクライアントの1つである。JSONファイルからオブジェクトを作成する際、実際にはAPIリクエストが送信される。

  • 最初にAPIリクエストは1つ以上のauthenticationモジュールにより認証される。APIサーバはこれらのモジュールを順番に呼び出していく、これはいずれかのモジュールがHTTPリクエストを精査してauthenticationの対象となるユーザが確定されるまで続く。authenticationメソッドに従い、クライアントの持つcertificateまたはHTTPヘッダを元にユーザー情報が組み立てられる(例えば8章で扱ったAuthorizationなど)

authorization pluginによるクライアントのauthorize(認可)

  • APIサーバは、authenticationと同様にauthorizationについても専用のモジュールの呼び出しを行う。その役割はクライアントが利用要求を出しているリソースや機能に対し許可を与えるか否かの判定だ。i.e. podの作成要求など

admission control pluginによるリクエストのバリデーションと修正

  • リクエストがリソースの作成/修正/削除を試みる時、その要求はadmission controlへ送信される。(ここでも通常複数のプラグインが実行される) これらのプラグインはいくつかの条件により、リソースの要求の変更要否を判断して変更が必要な場合は変更を行う。例えば、リソースの仕様上必須であるフィールドの情報がリクエストに含まれていない場合、それを初期化したり、場合によっては上書きをしたりする。またリクエストにて明示的な指定がないがリクエストに関連する他のリソースの修正をしたり、理由があればリクエスト自体のリジェクトも行う。リソースは全てのアドミッションコントローラープラグインにて処理される。

アドミッションコントロールプラグインの具体例

  • AlwaysPullImages: podのimagePullPolicyをalwaysに上書きすることで、podがデプロイされる度にdocker imageをpullすることを強制する
  • Service Account: 明示的に使用するservice accountを定義していないpodに対しデフォルトのservice accountを適用する ※—Service Account をkube-apiserverの起動オプションに付与することで有効化
  • NamespaceLifecycle: 削除中/削除済みのnamespaceでのpodの作成を抑制 ※これもkube-apiserverの起動オプションで有効化
  • Resource Quota: 特定のnamespce内でpodsが使うCPUとメモリの合計使用量が設定値を超えないことを保証 ※これも起動オプション
  • それ以外のadmission controllerについてはこちらを参照

Using Admission Controllers

バリデーションが完了したリクエストの以降の処理

  • リクエストが全てのadmission control pluginを通過すると、APIサーバはオブジェクトのバリデーションを行い、オブジェクト情報をetcdに保存し、レスポンスをクライアントに返す

11.1.4. リソースが変更された際のAPIサーバからクライアントへの通知

  • ReplicaSetリソースが作成された際のpod作成やserviceリソースが作成された際のエンドポイントの管理などの実タスクはAPIサーバではなく、コントローラーマネージャー配下のコントローラーにより行われる
  • では、APIサーバの役割は何かと言うとこれらのコントローラーや他のコンポーネントがデプロイされたリソースが変更された時に気づけるよう可観測性を提供することである。コントロールプレーンを構成する各コンポーネントはリソースのCRUD処理が行われた時に通知をもらうようAPIサーバにリクエストすることができる。これにより各コンポーネントクラスターのメタデータの変更を契機に必要なタスクを実行することが可能になる。

DesigningDataIntensiveSystem_読書メモ(1)

読み始めたので少しずつ読書メモを書いていきます.

Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems

Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems

Introduction

データを使って我々が達成したいことの類型

  • 後でそれを取り出すことを目的としてデータを貯蔵する (databases)
  • コストの高いread処理の結果を記憶し、次回実行時に高速に処理できるようにする (caches)
  • ユーザーがキーワードを使って情報を検索できるようにする (search indexes)
  • タスクが非同期的に処理されるよう、他のプロセスにmessageを送信する (stream processing)
  • 定期的に蓄積された大量のデータの処理を行う (batch processing)

感想・メモ

  • (メモ) 筆者によると一口にデータベースと言っても様々な特性を持つ設計・実装が存在するとのこと.以下の論文では様々なタイプのデータベースの特性の比較をしている. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.68.9136&rep=rep1&type=pdf

  • (感想) mysql とかは、4.1での議論の類型で言うと、process after store 型のシステムで、 disk io latencyにpeformanceが引きずられるのを回避するために、 on memory cache(buffer cache) を採用するアーキテクチャになっている。 他方、ActiveMQ+kaha DB は、streaming 型の処理をしているが、 設定によってはenqueue時のディスクへの同期書き込みを強制する。 なので、結果的に多分mysqlより遅い。

設計を考える際の重要な要検討事項

  • データが正しい値を保持し完全性を維持することをどうやって保証するか?内部コンポーネントに故障が発生した際にもそれを保証するためには何が必要なのか?

  • clientアプリケーションからのアクセスに対し、良好なパフォーマンスを安定的に維持するためにはどうしたらいいか?システムにおいてデグレードが発生した際もそれを維持するためには何が必要か?

  • 負荷が増加した時にシステムをどうのようにしたスケール(アップ/アウト)させるのか?

  • そのシステムにおける「良く設計されたAPI I/F」とはどのようなものであるべきか?

3つの設計観点

信頼性(Reliability)

  • システムにおいて障害が発生した際も、システムが適切に機能する状態が維持されること
  • "適切に機能する"
    • (1)機能的に正しく動作する
    • (2)望ましいレベルのパーフォーマンスが維持される
  • "障害"
    • H/W故障
    • S/W故障
    • 人間の操作ミス

スケーラビリティ(Scalability)

  • システムの規模が拡大した際に、それに伴い新たに発生する問題を適切に処理する方法が容易されていること
  • "拡大"の具体例

メンテナンス性(Maintainability)

  • システムは通常、様々な役割のエンジニアによって長きにわたり開発・運用されることになる。
  • メンテナンス性観点で、適切に設計されたシステムにおいて、開発者や運用者は生産性高く彼らの仕事を遂行することができる

信頼性(reliability)

  • 信頼性(reliability) という言葉を使う時に我々が抱く期待は、典型的には以下の通り

    • The application performs the function that the user expected.
    • It can tolerate the user making mistakes or using the software in unexpected ways.
    • Its performance is good enough for the required use case, under the expected load and data volume.
    • The system prevents any unauthorized access and abuse.
  • 総合すると、"適切に動作し続ける" という表現がこの概念を適切に表している。

  • フォールトトレラント(fault tolerant) という言葉は、「このシステムはあらゆる障害に対し障害耐性を有している」と、 錯覚させるという意味でミスリードな言葉である。あらゆる障害シナリオに耐えうるシステムというのは存在しない。「コンポーネントの単体障害については耐障害性設計ができているが、複数のコンポーネントの多段故障については対象外性設計できていない」みたいなのはよくある話なので「このシステムはどの障害シナリオに対して体制を持っていてどの障害シナリオについては"その限りにあらず"なのか?弱点はどこか?」と考えるのはとても有意義なこと。

  • 著者はfaultとfailureという言葉は全然意味が違うと考えている。 faultは顧客影響につながる"障害"と呼ばれるべき事象で、failureは顧客影響を発生させない単一コンポーネントの故障のような局所的な故障というイメージ?

  • chaos engineeringについても、言及されている。

    Counterintuitively, in such fault-tolerant systems, it can make sense to increase the rate of faults by triggering them deliberately?for example, by randomly killing individual processes without warning. Many critical bugs are actually due to poor error handling [3]; by deliberately inducing faults, you ensure that the fault-tolerance machinery is continually exercised and tested, which can increase your confidence that faults will be handled correctly when they occur naturally. The Netflix Chaos Monkey [4] is an example of this approach.

次に具体的な障害シナリオが示される

ハードウェア障害

割と最近まで、単に冗長化しておけばわりとなんとかなった だけど最近は巨大データを扱うシステムが増えた。AWSのように耐障害性よりはプロビジョニングの速度や容易さを重視する設計思想の仮装基盤も増えた。 それにより一つの環境上で動作するVM台数が増える傾向にあり、障害の際の影響範囲も大規模なものになる事例が増えた。仮想基盤の故障による大規模障害は(仮想サーバレベルの?)冗長化だけだとなんともしようがない。ので、 ソフトウェアでなんとかする方向を考える必要がある。全断すら乗り越えるシステムが理想。 メンテの時にローリングアップデートをするという意味でもそうすべき。

ソフトウェア障害(バグとか)

引用されているブログが面白い。

要点として - 設計というのはある種の構想やコンセプトであってそれ以上の何かではない - 「あるシステムが"そのような設計になっている"ということは"そのような実装になっておりあらゆるケースにおいて確実に機能する"ということを意味しない」 - 先進的な枯れていないシステムはだいたいバグを抱えているのでコンセプトが優れていてもそういう実装的な瑕疵で台無しになることが多い - システムの振る舞いを考えるときは机上で議論してる暇あったらとにかく動かしてみて測定して実世界での振る舞いを見るべきであって、そうやって得られる実際の結果以上に有益な結果はない

It isn’t that system design is meaningless, it is worth discussing the system design as it does act as a kind of limiting factor on certain aspects of reliability and performance as the implementation matures and improves, but don’t take it too seriously as guaranteeing anything.So why isn’t this kind of empirical measurement more talked about? I don’t know. My pet theory is it has to do with the somewhat rigid and deductive mindset of classical computer science. This is inherited from pure math, and conflicts with the attitude in scientific disciplines. It leads to a preference for starting with axioms, and then proving various properties that follow from these axioms. This world view doesn’t embrace the kind of empirical measurements you would expect to justify claims about reality (for another example see this great blog post on programming language productivity claims in programming language research). But that is getting off topic.Suffice it to say, when making predictions about how a system will work in the real world I believe in measurements of reality a lot more than arguments from first-principles.

ヒューマンエラー

スケーラビリティ

スケーラビリティ という言葉を使って我々がしたいのは

そのシステムが負荷を適切に扱う能力を記述すること(describe a system’s ability to cope with increased load)

つまり、そのシステムが増加する負荷に対してどう適切に適応できるのか?

という検討や議論なんだけど、だからといって、

「このシステムはスケーラブルである/スケーラブルではない」みたいに単一の物差しで0/1で考えるのは意味のない議論。そうではなく、

  • サービスが成長した際に適切に対応する方策としてどんな選択肢が考えられるだろうか?
  • 増大する負荷をさばくためにどのようにしてサーバリソースを追加すべきか?

みたいに現実的な文脈で具体的な議論をすることが本当の意味で スケーラビリティを考えるということ。

※(感想)これは暗黙的に最初に「最初にサチるのはどのリソース?(現在のシステムのリソース的なボトルネックはどこ?)」という質問を含んでいる。

改善すべき性能指標を明確にする

上記のような議論をするためには、 「我々のシステムにおいて改善すべき性能指標は◯◯です」 みたいな感じで簡潔に現状の課題を指標で表す必要がある。

性能指標/負荷特性は、いくつかのパラメーター、監視マトリクスを組み合わせて表現することが望ましいが、あるゆるシステムにおいて有用たり得る銀の弾丸的な監視メトリクスは存在しない。どの監視メトリクスを使うべきか?という問いに対する答えは、システムのアーキテクチャやそのシステムがやりたいことに依存する。

Twitter社の事例

ただ、そうはいっても、具体例がないと具体的な議論ができないので、ここではTwitter社の事例を取り上げる。データの出典は2013年の以下のプレゼンテーション。

timelines at scale

要点は以下となる。

  • webサービスとしてのtwitterの機能と負荷は要約すると以下となる。ツイート機能については比較的容易に一定のパフォーマンスを維持することができたが、タイムラインの閲覧についてはパフォーマンスチューニングにとても苦労した。

    • 1.ツイート(投稿): 12,000 req/s ※ピーク時
    • 2.タイムラインの閲覧: 300,000 req/s
  • 最初は、あるユーザーがタイムラインの読み込みを実行する度に、フォロワー全てのツイートをSELECTしてJOINしていたが、ユーザ数が増えるとパフォーマンス劣化が発生しすぐに破綻した。

  • そこで、ユーザーのタイムラインをキャッシュに保存するアーキテクチャに変更した。これにより一定の改善が達成されたが、今度はあるユーザーがツイートすると、そのユーザをフォローするフォロワーの数だけキャッシュへのレコード追加が発生するようになった。このようなアーキテクチャにおいて沢山のフォロワーを有している人の処理は非常にコストが高いものとなってしまう。100万人のフォロワーがいるユーザーのツイート1件で、100万個の独立のキャッシュ領域へのpushが発生してしまう。(辛い)

上記から、その当時における同社のパフォーマンスエンジニアリングにおける重要な監視対象メトリクスは、アクティブ率によって重み付けされたユーザー毎のフォロワー数の分布、であったと推定される。

※後日、再度のアーキテクチャ変更が行われ以下の方式に変更されたとのこと。たしかにこれなら、非アクティブユーザーのタイムラインのために割く資源が減るので合理的かもですな。。

  • フォロワー数の少ないユーザのツイートは今まで通りフォローしている各ユーザのキャッシュに追加する
  • フォロワー数の多い人のツイートは、read要求が発行された時に初めてSELECTしcacheに加える

パフォーマンス傾向を把握する

運用しているシステムの負荷特性が明確になると、負荷が増えた時のパフォーマンスの変化について検討することが可能になる。主要な観点は以下の2点。

  • When you increase a load parameter and keep the system resources (CPU, memory, network bandwidth, etc.) unchanged, how is the performance of your system affected?
  • When you increase a load parameter, how much do you need to increase the resources if you want to keep performance unchanged?

パフォーマンスという言葉は定量的に具体的な統計値で検討される必要がある。

レスポンスタイムとパーセンタイル値

具体例として、レスポンスタイムが重要な監視パラメーターである仮装的なケースを検討する。個々のリクエストのレスポンスタイムは一般に一定範囲内でバラツキを見せる。統計学ではこれを「分散」と呼ぶ。

これら一定の分散を持つデータセットについて統計的な解釈を試みる際だが、素朴に平均値を算出しても誤った解釈を誘発しがちなミスリードな情報しか得られないことが多い。なので、代わりにパーセンタイル値を使うことをお勧めする。

  • 50%値(中央値)を使うことで、平均値よりもより有用な情報が得られることが多い。
  • 95%, 99%, 99.9%値を使うことで、レイテンシの外れ値(tail latency)がどの程度ひどいのかを観測することができる。

※平均値がミスリーディングな値を算出してしまう話については、こちらのブログの話が面白かった

※実際にWeb系の企業で使用されているレスポンスタイムのグラフを見ていると、複数のパーセンタイル値を同時に表示するグラフがしばしば出てくる。最近のデファクトなやり方なんだろう。

『詳解システムパフォーマンス』の2.8章でも、統計値の扱い方については色々な議論がなされている。  SLOやSLAにパーセンタイル値を使う手法が提案されている。 「rseponsetimeの50パーセンタイル値が200msであることをサービスレベル目標とする」みたいに宣言して  課題抽出のためのKPI化するのは面白そう。全てのリクエストのレスポンスタイムが記録できていることが前提だけど。 自分の今までの現場では、この手のSLOやSLA稼働率のみで定義されることが多かった。レスポンスタイムをパーセンタイル値で目標設定するのは割とリーズナブルな提案に見える。

負荷の増大への対応手法

リソース増強によって性能の改善を試みる際は、
通常、 (1) スケールアップ( vertical scaling ) (2)スケールアウト( horizontal scaling )の2つの手法が選択肢となる。

一般に我々はシステムの収容/拡張性を設計する際に、 負荷が増えた時に必要となるパスォーマンスを維持するためにどのリソースをどのような手順で増設するのがいいか? などと考えるわけだが、その検討自体が対象とするシステムに対しての無数の前提や仮定のもとに成り立っている。

基本的に、あらゆるケースに適用可能な万能のベストプラクティスは存在しない。
システム毎にケースバイケースで個別に最適な解を考えていく必要がある。

また最近は、負荷を扱う手法として、パブリッククラウドを使ったオートスケールという強力な選択肢も増えた。

メンテナンス性(Maintainability)

  • メンテナンス性の観点は以下の3つに分類される。
    • 運用のしやすさ
    • 構成のシンプルさ
    • 進化のしやすさ

運用のしやすさ

  • 優れた運用チームは設計に問題のあるシステムをカバーし得るが、運用チームが機能していない状況をシステムが補うことは難しい。だから、運用チームというのはシステムの稼働における生命線である。一般に運用チームは次のような業務領域にコミットしている。

    • Monitoring the health of the system and quickly restoring service if it goes into a bad state
    • Tracking down the cause of problems, such as system failures or degraded performance
    • Keeping software and platforms up to date, including security patches
    • Keeping tabs on how different systems affect each other, so that a problematic change can be avoided before it causes damage
    • Anticipating future problems and solving them before they occur (e.g., capacity planning)
    • Establishing good practices and tools for deployment, configuration management, and more
    • Performing complex maintenance tasks, such as moving an application from one platform to another
    • Maintaining the security of the system as configuration changes are made
    • Defining processes that make operations predictable and help keep the production environment stable
    • Preserving the organization’s knowledge about the system, even as individual people come and go
  • 運用のしやすさ という観点でシステムが優れているとは、運用負荷が最小に抑えられており 、 運用チームの人的資源が重要な価値を生むコア領域に集中できる状態が維持できているという事である。
    具体的には(システムの開発側として)以下のようなことができているとよい。

    • 優れた監視システムを導入することにより、アプリケーションのランタイムとシステムの内部構造に対するvisibilityを提供する
    • 自動化と標準ツールとの連携に対する良質のサポートを提供する
    • Avoiding dependency on individual machines (allowing machines to be taken down for maintenance while the system as a whole continues running uninterrupted)
    • 優れたドキュメントを作成し、理解の用意な運用モデルを定義する("もし手順Xを実行すると、Yが起こる")
    • デフォルト設定でシステムが適切に動作するように設計する。正し、システム管理者が必要に応じて別の振る舞いをするように追加設定できる余地を残しておく
    • 適切に動作するセルフヒーリング機構を導入する。正し、必要な時に人間がマニュアル操作でそれに介入できるようにしとおく
    • システムの振る舞いについて「〇〇というシチュエーションの時は、このシステムは△△のように振る舞うだろう」みたいな感じで  人間がその動きを予想しやすいものにする。逆に言うと、人間が予測しないような振る舞うをシステムがする機会をできるだけ減らす

構成のシンプルさ: 複雑さのコントロール

  • シンプルなのはいいことだ
  • 良い抽象化は人間がシステムを理解するコストを下げる

進化のしやすさ:構成変更が容易であること

Kubernetes In Action Chapter3 Pods:running container in Kubernetes 読書メモ

Kubernetes in Action

Kubernetes in Action

Chapter3 Pods

  • dokcerのcontainerのdesignは、1process = 1 container. そうすることで、containerをrestartするだけで障害対応が可能になる(3.1.1)
  • ただ、それでもある種のProcessの集まりをGroupとして表現し、完全にisolateするのではなく、ある程度Resourceを共有したいというニーズがGoogleにあった. だから Pod を作った。Pod 間のContainerは以下のリソースを共有する(3.1.2)
    • NetworkとUTS Namespace
    • IPC Namespace
    • PID Namespace ※最新verで利用可能なoption機能. デフォルトでは無効
  • podのmanifestの基本構造(3.2.2.)

f:id:peanweb:20190126221406p:plain

  • ↑の項番6のportの宣言はなくてもいいのだけど、podの通信仕様を明示するという意味でしばしば使われる。
  • kubectl explain でmanifestfileの文法の確認ができる
  $ kubectl explain pods
  $ kubectl explain pod.spec
  • その他、基本的なコマンドたち
 $ kubectl create -f kubia-manual.yaml
 $ kubectl get po kubia-manual -o yaml
 $ kubectl get po kubia-manual -o json
 $ kubectl get pods
 $ kubectl logs kubia-manual
  • serviceを使わないでlocal machineとpodを繋ぎたい時は以下のようにする。local 8888とpod 8080を接続(3.2.5)
$ kubectl port-forward kubia-manual 8888:8080
... Forwarding from 127.0.0.1:8888 -> 8080
... Forwarding from [::1]:8888 -> 8080
  • k8sを運用している間、podは無限増殖を続ける。管理コストを低減するためにpodのグルーピングが必要になってくる。k8sではそのために、 label というkey value型のアトリビュートが用意されている(3.3)
  • 例えば、2種の label を組み合わせることで、以下のようなマトリクスでpodを整理分類することが可能になる f:id:peanweb:20190126221717p:plain

  • pod に label を付与する時の manifest fileの書き方 f:id:peanweb:20190126221742p:plain

  • podの label を確認したい

$ kubectl get po --show-labels
  • 特定のラベルの値を横断的に確認したい
$ kubectl get po -L creation_method,env
  • 特定のlabel/値を持つ組み合わせのpodだけを絞り込んで表示したい(label selector)
$ kubectl get po -l creation_method=manual

iostatの結果の見方

正確に理解したくて色々調べた結果を図に落としてみました。
※理解に誤りがありましたらご指摘ください

#参考文献
Two traps in iostat: %util and svctm - Marc's Blog
iostat はどのように %util を算出しているか(3) - ablog
Etsukata blog: iostat -x の出力を Linux Kernel ソースコードから理解する

O'Reilly Japan - 詳解 システム・パフォーマンス


f:id:peanweb:20180805110244p:plain

Centos7でetcdを試す

参考

http://qiita.com/hana_shin/items/602f98bd9b153d22e50c

etcdとは

etcdとは、Kubernetesに使用されていることで有名な 分散型のKVSです。 クラスタに所属しているノード間でデータを同期させることが できる特性を活かし、Kubernetesでは 各サーバの保持するIPアドレスの相互伝達に使用されています。

概要

VirtualBox上のCentos7×2台に etcdを導入し、動作の確認を行ってみました。

環境

  • VirtualBox5.1.22r115126 on WIndows10
  • CentOS Linux release 7.3.1611 (Core)
  • etcd Version: 3.1.7

各ノードの情報

VirtuallBox上にCentOSVMを2台作成しました。

  • node1(CentOS Linux release 7.3.1611 (Core))

    • enp0s3(NAT IF) :10.0.2.101/24
    • enp0s8(HostOnlf IF):192.168.56.101/24
  • node2(CentOS Linux release 7.3.1611 (Core))

    • enp0s3(NAT IF) :10.0.2.107/24
    • enp0s8(HostOnlf IF):192.168.56.107/24

手順

etcdのインストール(node1)(node2)

#yum install etcd

設定ファイルの作成

各サーバが他のクラスタに属するサーバをディスカバリする方法として、

  • etcd.confの'ETCD_INITIAL_CLUSTER'にあらかじめ全てのサーバのIPを記載する
  • ディスカバリサーバを別に作成し、専用のURL/Tokenを発行し、それを使って ディスカバリする

の2つが存在しますが、ここでは前者の方法を使ってクラスタを構築します。

(node1)

[root@node1 ~]# cat /etc/etcd/etcd.conf |grep -v ^# |grep -v ^$
ETCD_NAME=node1
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.56.101:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.56.101:2380"
ETCD_INITIAL_CLUSTER="node1=http://192.168.56.101:2380,node2=http://192.168.56.107:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.56.101:2379"

(node)

[root@node2 ~]# cat /etc/etcd/etcd.conf |grep -v ^# |grep -v ^$
ETCD_NAME=node2
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="192.168.56.107:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.56.107:2380"
ETCD_INITIAL_CLUSTER="node1=http://192.168.56.101:2380,node2=http://192.168.56.107:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.56.107:2379"

etcdの起動(node1)(node2)

# systemctl enable etcd
# systemctl start etcd
# systemctl status etcd

etcdのバージョンの確認(node1)(node2)

# etcdctl --version
etcdctl version: 3.1.7
API version: 2

起動後の正常性確認

今回採用のディスカバリ方法の場合は相手ノードの2380番Portに接続できればディスカバリできるため、その接続性を確認します。

(node1)

自サーバにて、Port2380でlistenできているか確認

[root@node1 ~]# ss -natu | grep LISTEN | grep 2380
tcp    LISTEN     0      128    192.168.56.101:2380                  *:*

[root@node1 ~]# curl http://192.168.56.101:2380/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}[root@node1 ~]#

相手サーバへの接続性を確認

[root@node1 ~]# curl http://192.168.56.107:2380/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}[root@node1 ~]#

クラスタに相手サーバが組み込まれていることを確認

[root@node1 ~]# etcdctl member list
275f7358be9c56b9: name=node2 peerURLs=http://192.168.56.107:2380 clientURLs=http://192.168.56.107:2379 isLeader=false
ca933ab8cfffe553: name=node1 peerURLs=http://192.168.56.101:2380 clientURLs=http://192.168.56.101:2379 isLeader=true

(node2)

自サーバにて、Port2380でlistenできているか確認

[root@node2 ~]# ss -natu | grep LISTEN | grep 2380
tcp    LISTEN     0      128    192.168.56.107:2380       

[root@node2 ~]# curl http://192.168.56.107:2380/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}[root@node2 ~]#

相手サーバへの接続性を確認

[root@node2 ~]# curl http://192.168.56.101:2380/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}[root@node2 ~]#

クラスタに相手サーバが組み込まれていることを確認

[root@node2 ~]# etcdctl member list
275f7358be9c56b9: name=node2 peerURLs=http://192.168.56.107:2380 clientURLs=http://192.168.56.107:2379 isLeader=false
ca933ab8cfffe553: name=node1 peerURLs=http://192.168.56.101:2380 clientURLs=http://192.168.56.101:2379 isLeader=true

KVSに格納される値が同期されることを確認

(node1)

[root@node1 ~]# etcdctl --debug set os linux
start to sync cluster using endpoints(http://127.0.0.1:2379,http://127.0.0.1:4001)
cURL Command: curl -X GET http://127.0.0.1:2379/v2/members
got endpoints(http://192.168.56.101:2379,http://192.168.56.107:2379) after sync
Cluster-Endpoints: http://192.168.56.101:2379, http://192.168.56.107:2379
cURL Command: curl -X PUT http://192.168.56.101:2379/v2/keys/os -d "value=linux"
linux
[root@node1 ~]# etcdctl --debug get os
start to sync cluster using endpoints(http://127.0.0.1:2379,http://127.0.0.1:4001)
cURL Command: curl -X GET http://127.0.0.1:2379/v2/members
got endpoints(http://192.168.56.107:2379,http://192.168.56.101:2379) after sync
Cluster-Endpoints: http://192.168.56.107:2379, http://192.168.56.101:2379
cURL Command: curl -X GET http://192.168.56.107:2379/v2/keys/os?quorum=false&recursive=false&sorted=false
linux

(node2)

[root@node2 ~]# etcdctl --debug get os
start to sync cluster using endpoints(http://127.0.0.1:4001,http://127.0.0.1:2379)
cURL Command: curl -X GET http://127.0.0.1:4001/v2/members
cURL Command: curl -X GET http://127.0.0.1:2379/v2/members
got endpoints(http://192.168.56.101:2379,http://192.168.56.107:2379) after sync
Cluster-Endpoints: http://192.168.56.101:2379, http://192.168.56.107:2379
cURL Command: curl -X GET http://192.168.56.101:2379/v2/keys/os?quorum=false&recursive=false&sorted=false
linux

walログ

etcdはKVSに書き込まれた情報を随時、/var/lib/etcd配下のwalログ(write ahead log)に書き込んでいるようです。

[root@node2 ~]# ps aux | grep etcd
etcd      2614  2.5  3.2 10771728 33060 ?      Ssl  11:02   2:53 /usr/bin/etcd --name=node2 --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379
root     10469  0.0  0.0 112664   960 pts/0    R+   12:56   0:00 grep --color=auto etcd

[root@node2 ~]# lsof -p 2614 | grep var
etcd    2614 etcd  cwd       DIR              253,0       26  8409202 /var/lib/etcd
etcd    2614 etcd  mem-W     REG              253,0 16805888  8409204 /var/lib/etcd/default.etcd/member/snap/db
etcd    2614 etcd    7uW     REG              253,0 16805888  8409204 /var/lib/etcd/default.etcd/member/snap/db
etcd    2614 etcd    8uW     REG              253,0 64000000 12920852 /var/lib/etcd/default.etcd/member/wal/0000000000000000-0000000000000000.wal
etcd    2614 etcd    9r      DIR              253,0       64 12920837 /var/lib/etcd/default.etcd/member/wal
etcd    2614 etcd   10wW     REG              253,0 64000000 12920851 /var/lib/etcd/default.etcd/member/wal/0.tmp

動作メモ

  • 2380番Portがサービスディスカバリ/ヘルスチェックに使用される
  • 2379番PortがClientコマンド(etcdctl)向けのAPI Endpointとして使用される
  • etcctlに' -debug'オプションをつけると実際に実行している、curlコマンドが見えるので実態が把握しやすい
  • DBデータは/var/lib/etcd配下に格納される。Clusterが壊れたときは、最悪ここを消して、etcdを上げなおせば起動可能

windowsでjavacが起動できない

環境

Windows10 jdk 1.8.0_112

問題

OracleのHPよりjavaをDLし、 CMDよりjavaプログラムをコンパイルしようとするが、 OSがjavacのパスを見つけられずエラーを返す

原因

JDKインストール時に自動的に設定されるシステム環境変数PATHが 適切に動作していない?

対処

以下の記事を参考に、既存のシステム環境変数を削除し、 jdkのbinのパスを追加

Javaの環境変数の設定 ( アプリ開発 ) - かじきの魚拓 - Yahoo!ブログ