1クール続けるブログ

とりあえず1クール続けるソフトウェアエンジニアの備忘録

【読書メモ】 k8sで実践するクラウドネイティブDevOps

読書メモ

www.oreilly.co.jp

↑の書籍の自分用読書メモ
現在の知識からの差分もしくは知っていても整理できていなかった部分を中心に
途中、自分で調べた補足なども入っているので本の内容でない部分もあり

chapterごとに気になった点

3つの革命

  • クラウドの創造
  • DevOpsの黎明
    • 20世紀中頃、ソフトウェア開発もコンピュータの運用も非常に専門性が高く重なり合う部分が無かった
    • 新機能をリリースしたい開発者と安定性・信頼性を上げたい運用者は対立しがち
    • クラウドの登場で状況が変化
      • システムの運用に必要となる専門事項(障害からの復旧、バージョンアップグレード)をシステムの設計、アーキテクチャ、実装から切り離せない
      • システムは自社開発のソフトウェアだけで完結せず、ソフトウェアを書く人はシステム全体との関連性を理解する必要がある。運用者はソフトウェアが機能する仕組みを理解する。
    • クラウドが極めて大規模であり、DevOpsの動向はコラボレーション型でコード中心の性質を帯びていることから、運用はソフトウェアの問題へと変容している
  • コンテナの到来
    • これまでの状況
      • 構成管理を使うためにはあらかじめ、言語によって異なるランタイムを入れる必要がある
      • 仮想マシンイメージは重くて運用に適さない
      • 運用の観点からすると、こうした多種多様なパッケージを管理するだけでなく、それを実行する一連のサーバも管理する必要性がある -> 大変
    • SeaLand社はコンテナを用いて商品を従来より遥かに安く船舶輸送することによって成功を収めた。これをテクノロジ業界が取り入れたものがコンテナ
    • 仮想化されたワークロードは同等のコンテナと比較して実行速度が30%遅くなる(それほどコンテナが軽量かつ効率よくリソースを使用しているということ)
    • 運用チームとしても様々な種類のマシン/アーキテクチャ/OSを保守する代わりに、コンテナオーケストレータを実行するだけで良い
    • Kubernetesは、自動化、フェイルオーバ、集中ロギング、監視など、非常に優秀なシスアドが行うであろうことを実行する
    • クラウドネイティブの特性
    • 従来の運用の大半は他のチームに移譲するべき
      • そのためにはDevOpsエコシステムを構築およびサポートする中央チームが必要
      • チームの機能は運用ではなく開発者生産性工学(DPE)
    • 純粋なDevOpsモデルは中小でこそ機能するが、組織が成長するにつれ、インフラや信頼性に関する専門家が中央チームに引き寄せられていく
      • ソース:The human scalability of “DevOps” - Matt Klein - Medium
      • 75人を超える頃には確実に中央インフラチームが設置され製品チームに必要な共有の基盤を構築し始める
      • それでもいずれ回らなくなってくるので、そのときはSREを個々の開発チームに配属する
    • ソフトウェアエンジニアと運用エンジニアの明確な区別はなくなる

Kubernetes環境の選択

  • Kubernetes自体の運用については取り扱わないので、知りたい場合には別書籍読んでね
  • コントロールプレーン
    • kube-scheduler
      • 「全てのpodの情報を取得しNodeにassignされていなければする」という挙動を取っていると思われがちだが、実際にはControllerがactualとdesiredとの差分を見てqueueに追加、schedulerは継続的にそれをpopし配置する
      • How does the Kubernetes scheduler work? - Julia Evans
    • cloud-controller-manager
      • kubernetesのリリース周期とクラウドベンダー側の対応の周期が合わないため、kube-controller-managerから切り出した
  • セルフホスティングは特別な理由がない限りやめておけ!!辛いぞ!!!
  • 近年では、「納品後すぐに稼働できる状態で引き渡される」というターンキー方式が成長してきている
  • Run Less Software(=実行するソフトウェアを減らす)
  • ↑の哲学に従い、マネージドKubernetesを使用することを推奨
  • 基本はGKE、もし単一クラウドプロバイダーに縛られることなく24時間のテクニカルサポートを受ける場合にはHeptioがおすすめ

リソースの管理

  • CPUをlimit以上に使おうとするときにはスロットル処理の対象となる
  • gRPCのヘルスチェックには、標準のみだと難しいのでgrpc-health-probeツールを利用する
  • コンテナが起動していれば、podのステータスはRunningになるが、READY列はカウントされない
  • ファイルベースのReadiness Probeはトラブルシューティングに便利
    • 例えば、/tmp/healthyのファイルを削除することで、Serviceから除外する
    • (ただし、labelコマンド使った方が楽なんじゃないか説)
  • Readiness Probeが成功を返す状態がminReadySeconds続かないとServiceにつながらない(デフォルトはゼロになっている)
  • namespaceでネットワークトラフィックを管理する場合にはNetwork Policy使う
  • ResourceQuotaでnamespaceごとにリソース量を制限できる
  • LimitRangeリソースで、すべてのコンテナについてデフォルトのリソース要求と制限設定できる
  • 優れた経験則
    • ノードのサイズは典型的なpodを少なくても5つ実行するのに十分なサイズ
    • 取り残されたリソースの割合を10%程度以下に維持する
    • 大きいノードの方が費用対効果が高い(のでノードあたりのpod数は10個から100個目標にする)
  • Jobリソースを削除するためにTTLを設定できる
    • まだアルファなので代わりにThird Partyのkube-job-cleanerが使えそう
  • Kubernetesのannotationに所有者情報を入れるべし
    • 組織のドメイン名をprefixに付けるべき
    • example.com/owner: "Customer App Team"
  • 幾らかの割合でプリエンティブインスタンスを使うようにすることで費用削減
  • スケジューラはノード間でpodを移動しないため、アンバランスな配置になってしまうとが多い

クラスタの運用

  • ベンダやサービスがCNCFの期待するCertified Kubernetes標準を満たすかを示すマーク及びロゴがある
  • Sonobuoyを使って「クラスタが適切に設定され最新状態である」ことを確認できる
  • k8sguardはクラスタの問題をチェックしてくれるツールだが2年動きが無いらしいの代替のツール有れば欲しい
  • kubernetesのChaos Engineering
    • Chaoskube: ランダムにpodを落とす
    • kube-monkey: 対象となるDeploymentの何%までを落とす
    • powerfulseal: ほとんどのシナリオを網羅できる

Kubernetesの強力なツール

  • kubectlの自動補完はTABキーを使って行う
    • 出てこない場合には、有効になっていない可能性があるので、kubectl completion -hを打ってヘルプ見る
    • (…自動補完の設定してたものの、どうやって補完するんだ…?まあいいや、kube-prompt使おーとなってて完全に思考停止だった)
  • kubectlには--watchオプションがあり、ステータスが更新されると更新情報が表示れる
  • 基本、命令的モード(create,edit...)は使うべきでは無いが、マニフェストの生成役に立つ。--dry-runと-o yamlを使う
  • kubectl diffは良いぞー(分かる)
  • kubectl logsのオプション
    • tailで直近のみに絞り
    • --followでストリームとして随時表示
  • kubespyによってリソースの細かい時系列イベントの監視が出来る
  • busyboxと--rm、--restart=Neverを用いて調査できる
    • alias bb=$kubectl run busybox --image=busybox --rm -it --restart=Never$
  • バイナリのみ配置した軽量コンテナで普通に色々なコマンド叩きたいことがある。そのきはdockerビルド時にマルチステージビルドの要領でBusyboxコンテナから/bin/busyboxを持ってくる
    • COPY --from=busybox /bin/busybox /bin/busybox
  • squashというツールでライブデバッグできる
  • kubectl v1.14から、--selectorフラグを使ってラベルセレクタに一致する複数podのログを取得できるように

コンテナの実行

  • ダイジェストを使ったイメージ指定が確実
    • cloudnative/demo@sha256:${ダイジェスト}
  • 非rootとしてコンテナを実行
    • root実行はprinciple of least privilegeに反する
    • バグを利用して悪意のあるユーザがプログラムを乗っ取ることも考えられる
    • securityContext.runAsUserで実行ユーザのUIDを指定
      • Linuxシステムの多くでは、最初の非rootユーザにUID1000が割り当てられるめ、一般的にコンテナのUIDは1000以上の値を選択(ユーザが存在していなくても良い)
      • Dockerfile内で実行ユーザを指定できるが、runAsUserフィールドを設定するが良い
      • runAsUserで指定したUID → Dockerfileで指定したUID → root
      • セキュリティを最大限に高めるためにはコンテナごとに別のUIDを選択する必要がるが、同じデータボリュームにアクセスする場合は同じの方が良い
  • コンテナが自分自身のファイルシステムに書き込むことを防止すreadOnlyFilesystemを使うのもよい(ファイルの書き込みをしないコンテナのみ)
  • setuidバイナリが含まれる場合には、実行ユーザをroot以外にしていてもroot権限獲得する可能性がある。これを防ぐには、allowPrivilege Escalationをfalseにる。
  • コンテナのデフォルトのcapabilityはかなり寛容なので、最小権限の法則を鑑みると必要に応じてdrop, addする必要がある
    • セキュリティを最大限に高めるためには、全てのcapabilityを削除し、必要に応じ特定のcapabilityのみ追加する
  • podレベルでのsecurityContextの設定が可能なので、そこで権限昇格を無効にし、てのcapabilityを削除するのがベスト
  • クラスタレベルでpodのcapabilityを設定することも可能で、それにPodSecurityPolicyを使用する
  • プライベートレジストリからImageをpullする場合には、imagePullSecretsフィールドを使って設定する

Podの管理

  • kubectl get pods -l app!=demokubectl get pods -l app in(staging. production)のようなラベルクエリを書くことも可能(Serviceリソースは等価クエリのみ)
  • LabelとAnnotationの違い=リソースを識別するしないか(どちらもkeyvalueのメデータ)
    • Labelの目的は、関連するリソースのグループを選択すること
    • Annotationは識別には用いられず、Kubernetesの外部のツールやサービスが利用る
  • PodAffinityはスケジューラの自由を制約するため、アプリケーション間でトレードフが発生する -> 切り札として使うように
  • TaintとTolerationは特定のpodが特定の種類のノードの問題を許容できるようにすこともある
    • Nodeでネットワークが利用できなくなったとき、Kubernetesnode.kubernetesio/unreachableというTaintを自動的に追加する
    • 通常はNodeのkubeletがすべてのpodをnodeから退去させる
    • ネットワークが合理的な時間内に復旧することを期待して、一部のpodはそのまま実させておきたいケースがある
    • これを実現するためには、unreachableというTaintに一致するTolerationをpodに追加しておく
  • Podは通常コントローラによって管理される
    • StatefulSetはPodを特定の順序で起動及び終了させる
      • Redis, MongoDB, Cassandraなどの分散アプリケーションは独自のクラスタ作成することから、クラスタリーダを予測可能な名前で識別できる必要がある
      • 個々のPodは自身がredis-0で実行されているかを確認し、もしされているのでればクラスタリーダとして、そうでなければredis-0と連絡を取ることでクラスタ参加できる
      • 0から順に起動するため、クラスタリーダが起動した後に他のpodを起動させるこを保証できる
      • 終了時は逆に0を最後にシャットダウンさせる
      • Headless Serviceを使えば、redis-0.default.svc.cluster.localな各podが認識できるDNS名が与えられる
  • アルファの機能でPodPresetというのがあり、Mutating Admission Webhookを易に使用できるようなリソースのようで、定義した設定を個々のPodの設定とマージできる
  • オペレータの作り方

設定と機密情報

  • ConfigMapの設定で楽なのはkubectl create configmap demo--from-file=config.yaml --dry-run -o yaml
  • configMapの情報は環境変数として読み込むこともできれば、volumeとして扱うことできます
  • ConfigMapの設定変更はすぐに反映される
  • Secretの読み取りや編集はRBACによって制御される。etcdにアクセス権限のあるユザは見れるかというと、そうではなくデータは保存時に暗号化されているため見れない。
  • 機密データの運用については、一旦SOPS(secrets operation)を試してみて不足がるようならVaultのようなツールを試すべき
    • SOPSはファイル全体を暗号化するのではなく、機密情報の値だけ暗号化する -> コドレビューが容易に
    • リポジトリで管理するときに暗号化し、デプロイ時に復号します
    • Amazon KMSやGoogle Cloud KMSをSOPSのバックエンドにすることも可能

セキュリティとバックアップ

  • ClairはコンテナスキャナでCDパイプラインに統合してデプロイ前にテストすることもきる
  • 他にも、TrivyAchore Engineなどのコンテナスキャンツールが存在する
  • レプリケーションはバックアップではない
    • 例えば、クリックする場所を間違えてボリュームを削除してしまうといった事故からってくれない
    • なのでバックアップを取る必要性がある
  • Veleroクラスタの状態と永続データをバックアップ及び復元できるツール
    • クラスタの状態がいつどのように変化したかも追える
    • クラスタ間で移行するためにも利用できる
  • Kubernetes DashboardはConfigMapやSecretの内容も表示できるのでDashboardに対する制限は厳しくしなければならない
    • インターネットに公開してはならず、代わりにkubectl proxyを利用する
    • 要らないなら実行しなくても良い

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

  • Helmについての記述が多かったが基本的には公開されているリポジトリ以外では使わいのでパラ見
  • kustomizeはv1.14からkubectlに入ったみたい
  • Conftestというツールでマニフェスト検証ができるので、CDパイプラインに追加しても良さそう
    • バージョンアップしたときに変更する必要性があるかをテストできる

開発ワークフロー

  • Skaffoldって変更を検知して、ファイルをユーザの代わりに自動的にデプロイするのすごい。コンテナレジストリへの明示的なPushが要らない。
  • Terepresenceはローカルマシンをリモートクラスタに参加させることができる、つまデプロイが要らない

Kubernetesにおける継続的デプロイ

  • コンテナベースのCDパイプラインツールを使う場合には、各ステップのコンテナをできるだけ小さくする

Observabilityと監視

  • ブラックボックス監視の限界
    • 「何が」壊れているのかは分かるが、「なぜ」壊れているのかはわからない
    • 事後対応であり、問題が発生した後にしか通知しない
    • ユーザがハッピーでなければ9の数に意味はない
      • 99,9%(スリーナインズ)だろうと99.99%(フォーナインズ)だろうと、ユーザにって機能してなければ意味がない
      • サイトの応答が遅すぎるのであれば、完全にダウンしているのと変わらない
  • メトリクスの導入
    • 「なぜか」という疑問の解決に役立つ
    • 問題の予測に役立つ
  • トレーシング
  • Obeservability Pipeline
    • kinesisとかのデータストリームにログデータやメトリクス全部突っ込んで、そっらLambdaとか使ってルーティングし、NewRelicやらStackdriverに流しましょうとうもの
    • Push型アーキテクチャのDatadogとかはそれが可能だけど、Pull型のPrometheusどうするのだろう
  • Kubernetesにおける監視
    • ブラックボックス型チェック
    • 内部ヘルスチェック
      • より高度なReadinessProbeとするなら、「このアプリケーションが仕事を遂行るには何が必要か」を問いかけるべき(ユーザがハッピーか?)
        • DBとのやり取りがあるなら、DBの接続が有効で応答するか?
        • 他のServiceに依存するなら、必要なServiceが利用できるかをチェック
      • Readinessのチェック失敗は「自分は問題ないが、今はユーザのリクエストを処できない」となる
        • つまりReadinessは、コンテナには何の問題もないが、依存関係にある要素のこかで障害が起こっているときに生きてくる
        • マイクロサービスの最終チェーンが障害を起こしたとして、初めは最後から2番のチェーンがReadinessProbeに失敗 -> それを受けて最後から3番目が失敗 ->... -> 一番最初のチェーンがReadinessに失敗しブラックボックステストでアート=これがサーキットブレイカーパターン
      • そもそもサービスを設計する際には、コンポーネントとなっているサービスの1つ上が利用できなくなったとして場合でもシステム障害となることは避けるべき
      • つまり優雅に劣化する

Kubernetesにおけるメトリクス

  • メトリクスはすべて数値であるため、ログと違い計算や統計を行うことができる
  • メトリクス値は大きく2つのタイプに分かれる
    • カウンタ:増えていく(または0にリセットする)ことしかできず、リクエストの数捕捉したエラーの数の測定に優れている
    • ゲージ:増減ともに可能で、CPU使用率のように継続的に変化する量や他の数量との率を表すのに便利
  • REDパターン
    • Requests-Errors-Duration
      • 1秒あたりの受信リクエスト数
      • エラーを返したリクエストの割合
      • リクエストの持続時間(レイテンシ)
    • サービスが示している性能と、それをユーザが体験している状況
    • 元記事はこれ
    • SRE本にあるThe Four Golden Signalsの派生
    • すべてのサービスで同じメトリクスを測定するメリットとは? -> 運用チームのスーラビリティが高まる。インシデントに対応する人は認知上の負担を軽くできる
  • USEパターン
    • Utilization-Saturation-Errors
      • リソースがリクエストの処理でビジーになっていた平均時間、またはリソースキパシティに対する現在の使用量
      • リソースが過負荷となっている程度、このリソースが利用できるのを待つリクエトが格納されているキューの長さ
      • リソースに対するオペレーションが失敗した回数
    • USEパターンの関心はサービスではなくリソース
    • CPUやディスクなどの物理的なコンポーネントやネットワークのインタフェイス
    • 元記事はこれ
    • ボトルネックを特定するときに用いられる
  • ビジネスメトリクス
    • 例えば…
      • ファネル分析(「ランディングページ閲覧人数」や「サインアップページへクリクスルーした人」)
      • 顧客あたりの収益
    • ログデータで集計するよりも、アプリケーションから時系列メトリクスを取得するこで可視化するほうが簡単
  • Kubernetesでのメトリクス収集
    • クラスタの健全性に関するメトリクス
      • ノードの数
      • ノードの健全性ステータス
      • ノードあたり、および全体のPodの数
      • ノードあたり、および全体のリソース使用量/割当て
    • Deploymentに関するメトリクス
      • Deploymentの数
      • Deploymentごとのレプリカの設定数
      • Deploymentごとの利用できないレプリカの数
    • コンテナに関するメトリクス
      • ノードあたり、および全体のコンテナ/Podの数
      • リソース要求/リソース制限に対する各コンテナのリソース使用率
      • コンテナのLiveness/Readinessの状況
      • コンテナ/Podの再起動回数
      • 各コンテナのネットワーク入出力トラフィックおよびエラー
    • ランタイムに関するメトリクス
      • ヒープとスタックの使用量
      • GC機能の実行時間など
      • 非ヒープメモリの使用率
  • 単純な平均の問題点
    • 単純平均はハズレ値の影響を受けやすい
    • 中央値の方が影響を受けにくく有用といえる
    • 最悪のケースの方に関心がある場合が多いので、90%タイルがより有用なケースも
  • どのサービスにおいてもダッシュボードのレイアウトは同じにしておく
    • サービスあたり1行
    • 左側にリクエスト数とエラー率
    • 右側にレイテンシ
    • 参考
  • マスタダッシュボードで情報ラジエータを使用するのが理想的
    • 重要なObservabilityデータを表示して関連するチームやオフィスの全員からみれようにする

感想

買ってよかった!
既知の内容少なかったし、監視周りはSRE本とそこから派生したブログ記事、入門監視あたりのエッセンスを集めてギュッとした感じがあって分かりやすかった。
仕事でも活かせやすい内容が多かったように思えます。

【AWS Re:Inventレポート】CON334-R1 - [REPEAT 1] Running high-security workloads on Amazon EKS

Running high-security workloads on Amazon EKS

5日目にして初めてセッションに参加しました。
セッション参加して思ったこととしては、まず前を取ることが重要だなと感じました。英語読むスピードはどうしても日本語より遅くなってしまうので、追いきれないと思ったスライドは写真に収めてしまうのが吉ですね。動画見ていても思うことではあるのですが、画面読んでると話聞けなくなるし、聞いてると画面読めないという板挟みにあいます。どうすれば…?
もちろん救いもあります。スライドと口頭の説明だけかと思いきや、デモとかもあって割と分かりやすいです。
あと、事前知識がまったくない分野の話になると、英語がまったくわからなくなります。今回のケースだと、SELinuxが全然分かりませんでした。「SELInuxわかんないのかよ。インフラエンジニアの癖に。」という石を投げるのはやめてください。

セッションの概要

Amazon EKSのセキュリティについてのお話です。Amazon EKSはKubernetes API層/Container Runttime Operating system層/AWS層というレイヤーで構築されていると思いますが、前者2つをセキュリティ性高くしていくにはどのようにすべきかという内容でした。

セッションの内容

(このパートは動画見た後に直すかもです)
最初にセキュリティを考える上での基礎に触れていたように思います。例えばCIAA modelだとかThe actor and capablities modelについてです。
EKSに対してどんな攻撃方法があるか?例えばL7での攻撃(XSS等)だとか、containerdやruncなどのオープンソースに潜んでいるバグを利用するもの、DDoS攻撃などが考えられます。

一つ例を挙げてみます。例えば、とあるブログの記事で見つけたyamlを適用したら、マルウェアが含まれていたケース。これはごく稀にあるかもしれないと思ってしまいますよね。curlで落としてきたマニフェストを確認せずにapplyしてしまったりとか。マルウェアは自分たちのシステムにアクセスできてしまうし、関連しているAWSのマネージド・サービス、例えばRDSなんかもそうです。

そういった驚異からの影響をどう小さくしていくか、緩和していくか
EKSの構造を Kubernetes API -> Container Runtime -> AWSの3層構造と考える

Kubernetes API

  • namespaces
  • ServiceAccounts
    • これはかなり効くと思っています。特に上であげた例のようなケースだと。
    • serviceAccountNameをマニフェストに追記することになるので、権限をかなり意識するようになる。
  • ResouseQuota/LimitRange
    • リソースをガンガン食いまくる系のマルウェアだった場合に制限がかけられる
  • NetWorkPolicy
  • RBAC
  • Dynamic Admission Webhooks
    • Mutableの方ではなく、おそらくvalidatingの方を使っての制限と思う
    • Admission Webhooksを使うとnamespaceとかも確認しつつ制限かけられるのは柔軟で良さそう
  • API AuditLogs
  • Pod Security Policies

PodSecurityPoliciesは下記のようなサンプルとともに深堀りされていました。確かにかなり効果的な制限が出来るようです。 これはClusterリソースでPodが作成・更新されるときにシステムに受け入れられるように必要な条件を定義できるものだそうです。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
spec:
  privileged: false # 
  allowPrivilegeEscalation: false
  requireDropCapabilities: ['all']
  volumes: ['configMap', 'secret', 'projected']
  hostNetwork: false
  hostIPC: false
  hostPID: false

詳しくはこちら

kubernetes.io

Security Contextでシステムコールを制限できる。単純にprivillagedを使うんでなくSecurityContext使って極力権限を絞っていくと良い。

kubernetes.io

Container Runttime Operating system

SELInux勉強不足であまり理解出来なかったので、勉強しつつ動画みれるようになったら補足して書きます。

感想

セッションもかなり学びがあると思いました。もちろん動画公開もあるので、なんとも言えないのですが…。
これにてAWS Re:Inventは終わりでした!学習型カンファレンスと言われているように多くの学びがありました。反省点としては英語の能力が書けていたこと、同じ分野のワークショップを取り続けてしまったことでしょうか。
初めてのアメリカ、(ほぼ)はじめての海外旅行なので、色々戸惑った点などあったのですが、それはまた別で記事にしようと思います。

【AWS Re:Inventレポート】CMP318-R1 - [REPEAT 1] Kubernetes on Spot Instances: Optimize for scale and cost

Kubernetes on Spot Instances: Optimize for scale and cost

今まで受けてきたKubernetes系のWorkshopはカテゴリがContainerでしたが、今回はComputeです。最終日はセッション1つだけなので、Workshopとしては最後になります。どうやらEKSでも使用しているWorkshopをベースにして作成されたようです。運営は主にcomputeのスタッフさんが多かったですが、コンテナのエキスパートさんもいらっしゃって自分はその方に質問しました。
資料はこちら

ec2spotworkshops.com

午前にあったWorkshopとかぶる部分がちょいちょいあってその部分は割愛しています。午前のWorkshopはこちらの記事から。

t.co

Workshopの流れ

今までで一番親切なWorkshopの進行でした。後半になると内容の説明をしなくなってしまうスピーカーの方が多いのですが、このセッションはめっちゃ詳しく説明してくれて、例えばtaintsとtolerationとかも午前に比べて優しい説明(+優しい語彙)ですごくわかりやすかったです。
最初にスピーカーの方が、本番でKubernetes使っている方をお聞きしていましたが、かなりの人数いらっしゃいました。Advancedのセッションだとやはり経験者が多いですね。スポットインスタンスを合わせて使っている人というものだと自分含めて数人くらいまで減ったので、スポットインスタンス使えているのは結構少ないのではとも感じました。

導入

EKS系のworkshopではお決まりのEKSクラスター構築から入りました。ちなみに作成するのは全てオンデマンドインスタンスです。

そしてクラスターが出来上がるまでの時間で、EKSのアーキテクチャについての説明が入りました。しっかりこういった図を見るのが初めてだったので、このタイミングで気づいたのですが、Control Planeの前段にはNLBがあるそうな。ENI AttachmentもControl Planeからやっているんだ…どうやって実装しているのなど疑問におもいました。

https://ec2spotworkshops.com/images/using_ec2_spot_instances_with_eks/introduction/eks-architecture.svg

kube-ops-viewの導入

自分は存じ上げていなかったのですが、kube-ops-viewというKubernetesクラスターのnode/podを可視化するツールがあります。こちらはHelmを使って導入していきます。実際に入れてみると、エンドポイントが出来ます。エンドポイントにアクセスしてみると下記のように見えます。なかなか良さげです。CPUとメモリも一緒に見れるのがいいですね。ドット絵っぽい感じもいいです。

f:id:jrywm121:20191209194244p:plain

スポットインスタンスの導入

スポットインスタンスの復習から入りました。なんとなく理解していたことではありますが、下記のページは知らなかったので驚きました。Terminationの頻度が出ているの便利ですね。

aws.amazon.com

eksctlを使ってスポットインスタンス(もしくはMixed-Instances)のNodeGroupを作成するには、eksctlのコマンドオプションだけでは難しいので、ClusterConfigを作成する必要がある。labelとtaintsを同時に作成しているけど、これは午前のWorkshopと同じなので言及は割愛。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
    name: eksworkshop-eksctl
    region: $AWS_REGION
nodeGroups:
    - name: dev-4vcpu-16gb-spot
      minSize: 0
      maxSize: 5
      desiredCapacity: 1
      instancesDistribution:
        instanceTypes: ["m5.xlarge", "m5d.xlarge", "m4.xlarge","t3.xlarge","t3a.xlarge","m5a.xlarge","t2.xlarge"] 
        onDemandBaseCapacity: 0
        onDemandPercentageAboveBaseCapacity: 0
        spotInstancePools: 4
      labels:
        lifecycle: Ec2Spot
        intent: apps
      taints:
        spotInstance: "true:PreferNoSchedule"
      tags:
        k8s.io/cluster-autoscaler/node-template/label/lifecycle: Ec2Spot
        k8s.io/cluster-autoscaler/node-template/label/intent: apps
        k8s.io/cluster-autoscaler/node-template/taint/spotInstance: "true:PreferNoSchedule"
      iam:
        withAddonPolicies:
          autoScaler: true
          cloudWatch: true
          albIngress: true

ちなみにスポットとオンデマンドを混ぜるときには、結構工夫が必要。labelやtaintsをそれぞれで分けなくてはいけないから。CloudFormation側でコントロールする場合には、UserDataの中で下記のように スポットインスタンスかどうかを判断してあげて、Bootstrap.shにわたすコマンドオプションを分ける必要がある。

            ilc=`aws ec2 describe-instances --instance-ids  $iid  --query 'Reservations[0].Instances[0].InstanceLifecycle' --output text`
            if [ "$ilc" == "spot" ]; then
              /etc/eks/bootstrap.sh ${ClusterName} ${BootstrapArgumentsForSpotFleet}
            else
              /etc/eks/bootstrap.sh ${ClusterName} ${BootstrapArgumentsForOnDemand}
            fi

午前にあったのと同じくスポットインスタンス削除のhandlerを入れるのですが、午前中に提示されたOSSと違ったので、少し戸惑いました。せっかくなので、聞いてみたのですが、どうやら午前中に提示されたものを使用するべきみたいです。どうやらコードのベースは同じみたいなのですが…。

ちなみに今回提示されたものは自分が現在使っているものでこちら(今後は保守されない…?)

github.com

今後はこっち使ったほうがいいよと言われたのがこちら

t.co

その後

サンプルアプリケーションのデプロイとHPAとCAの導入を行いました。

感想

すごく丁寧なWorkshopでした。スタッフの方もかなり親切に声をかけてくれました。最後にスポットインスタンスのステッカーをいただけたのですが、非常に可愛いステッカーで気に入っています。

【AWS Re:Inventレポート】CON206-R2 - [REPEAT 2] Management and operations for Amazon EKS

Management and operations for Amazon EKS

朝はDr. Werner VogelsのKeynoteを開始から1時間位みてきました。Firecrackerはcontainerdをベアメタルサーバごとに共通化させていて、それもオープンソースとして開発しているなど、非常に面白かったです。FargateとEC2の比較なんかも動画だとかなりわかりやすくてよかったです(本当に?とも思いましたが…)。 ほんの少しだけ、Getting Started on Kubernetesをかぶる内容もありましたが、EKSでスポットインスタンスを使う方法やロギングでEFK構成を取る方法などをWorkshopで学んでいきました。
実はCON203/CON205/CON206は続けて取ると丁度よくEKSのWorkshop全てを網羅出来るみたいです。
ちなみにこのセッション、Walk-Upで行こうと思って並んで腰をおろしてPC開いたら予約できるようになっていました。予約して部屋戻って休憩できたので良かったです。

導入

他のWorkshopと同じようにチームハッシュの書かれたシールを貰って、https://dashboard.eventengine.run/にアクセスしてハッシュ打ち込むのかなと思っていたんですが、シールが用意されていませんでした。こういったケースもあるんですね。チームハッシュの書かれた紙をスタッフの方が持っていて、その方が「これだよー」と提示して頂いて確認します。自分は写真を撮りました。

Workshopの流れ

他のKubernetesのセッションは3回目になるので、セットアップはかなりすんなり行きました。ここで結構詰まってしまう方が多いのと、eksctlクラスターを作成するまでに時間がかかるので、CON203と同じく質問コーナーが設けられました。
EKS on Fargate発表後というのもあり、そのへんの質問が多かったように感じます。Twitterでも議論になっていましたが、「Daemonsetは使えなくなるので、FluentdコンテナとかはSideCarコンテナで」など、EKS on EC2でのマニフェストをそのまま適用できるかというとそうでは無いようです。
資料は下記

eksworkshop.com

Health Checks

正直に言いますとここはEKSの話というより、純粋なKubernetesでの話なのでMustではないのかなと感じました。内容としてもベーシックな内容でした。

Using Spot Instances with EKS

EKSでSpotInstanceを上手く使う方法ですね。この辺を知りたくて来ました。このセッションでは、スポットインスタンスのNodeGroupを別で作成しています。作成の際にlifecycle=Ec2SpotというlabelとspotInstance: true:PreferNoScheduleというtaintsをつけています。これを上手く利用します。
taintsはtolerationsという概念とともにKubernetesで扱われる機能の一つです。Node側からSchedulingされるpodを制限できるのが強みです。pod側のnodeSelectorだと何も指定しなければ、どこのNodeでもスケジューリングされてしまいます。今回のケースでは、pod側でspotInstance: trueというtolerationsを持っていないものは、スポットインスタンスのnodeGroupには、スケジューリング出来ないことになります。taintsについているPreferNoScheduleはeffectと呼ばれるもので、Taintsを許容できないpodはSchedulingするのをなるべく避けるというものなっています。

SpotInstanceはTerminateの2分前にEc2メタデータを通して通知を行います。それをキャッチしてハンドリングしないと、いきなりpodが死ぬことになります。そこで下記のものを使います。11月くらいからCommitが始まっているのでかなり最近のプロダクトになると思います。
Terminateの通知を受けとったら、ノードにTaintをつけて他のpodがSchedulingされないようにします。その後に、Drainを行うことでpod内の各コンテナにSIGTERMを発行し、Graceful Shutdownを促します。

t.co

このDaemonSetはデフォルトで全てのNodeにSchedulingされますが、lifecycle=Ec2SpotというlabelのついたものだけにSchedulingされるように変更したほうがいい。

そしてサンプルアプリケーションfrontendのマニフェストで、Spotinstanceのtaintsを受容するようなtolerationsを設定し、nodeAffinityでlifecycle=Ec2Spotのラベルが付いたノードに優先的にスケジュールするように変更する。frontendのアプリケーションのみスポットインスタンスで運用されるようになった。

Logging with Elasticsearch, Fluentd, and Kibana (EFK)

まずElastic Search Service(ESS)を構築します。自分は業務でESSに触ったことがなかったので新鮮でした。
それとは並行して、fluentdのdaemonsetを作成していきます、一つ驚きだったのは、fluentdのdeploymentです。fluent/fluentd-kubernetes-daemonsetのimageかつ、fluentdの設定をConfigMapで持つ場合には、多少工夫をしなくてはいけないようです。initContainersでConfigMapをマウントして、/fluent/etc配下にコピーする必要性があるようです。 (コンテナを扱うものとして恥ずかしくて仕方なかったものとしては/var/log/containers/*.logにコンテナのログが吐かれることを知らなかったことです)
このDaemonSetが稼働するようになると、CloudWatchにデータが流れるようになります。
CloudWatchの画面の「Action」ボタンからStream to Amazon ElasticSearch Serviceを選択するとESSに流せるようになります。簡単!ただそのデータ投入はLambdaを使ってやるようで、Roleの準備とコストの考慮が必要になります。

いざKibanaにログが入るとどうでしょう!?バージョン6.3のKibanaの画面きれい…! f:id:jrywm121:20191209185335p:plain

感想

Workshopは質問出来てなんぼという感じがしました。強みはいろんなことを気軽に聞けるところ。
自分の英語力がもっと高ければそういった機会を活かせたように感じました。

【AWS Re:Inventレポート】CON208-R1 - [REPEAT 1] Build your microservices application on AWS Fargate

Build your microservices application on AWS Fargate

Fargateの初心者向けセッションです。
選ぶときに興味のあるトピックであれば、レベル関係なく受けようと思っていたのが良くなかったです。このセッションが4日間で受けたWorkshopのどれよりも簡単で少し物足りない感じがありました。それと疲れが非常に溜まっており体力的に限界だったのもあり、全て終わらせて途中で抜けてきました。

導入

ECS、特にFargateを使う上でどんな利点があるかを説明してくれました。EC2インスタンスを意識する必要が無いとかそんなような説明だったと思います。後は、AWSのプロダクトなので、完全に他のAWSサービスと統合されていてそれが強みとも言っていました。
資料は下記リンクです。

ecsworkshop.com

業務で使っているのはawsコマンドですが、Workshopではecs-cliを利用しました。そういえばECS CLIのv2が出るってコンテナワークロードに出てきていたような…?
CloudFormationでクラスターとALB(+TargetGroup)を作成するところからスタートです。

完成したあとの構成は下記。 f:id:jrywm121:20191207015823p:plain

Workshopの流れ

まずFrontendのRailsのアプリからデプロイしていきます。docker-composeの構文に少し似てますよね。envsubstってなんだろ?って思ったんですが、テンプレートエンジンみたいで、環境変数を埋め込んでくれるようです。普通に使っていきたい。
通常CloudFormationで埋め込むパラメーター周りをecs-cli使うと、コマンド引数に持たせる感じになるようです。ファイルに持たせることも出来るんでしょうか?宣言的じゃないと使うのには躊躇があります。Fargateだと、aws-vpcモードがデフォルトだからか、vpcも指定が必要になってくるようです。自分が注目したのは、--private-dns-namespace--enable-service-discoveryです。

cd ~/environment/ecsdemo-frontend
envsubst < ecs-params.yml.template >ecs-params.yml

ecs-cli compose --project-name ecsdemo-frontend service up \
    --create-log-groups \
    --target-group-arn $target_group_arn \
    --private-dns-namespace service \
    --enable-service-discovery \
    --container-name ecsdemo-frontend \
    --container-port 3000 \
    --cluster-config container-demo \
    --vpc $vpc

ServiceDiscoveryがEnableです。確かECSはRoute53で実現されていたはずと思ってRoute53を見てみます。
Private Hosted Zoneが作成されて、それが--private-dns-namespaceの引数に渡されているものと対応しています。そして、それぞれのタスクがAレコードで入ってきていますね。DNSラウンドロビンで振り分けられる形になるわけです(おそらく…)。ヘルスチェックもRoute53から行われる形になりますね。

f:id:jrywm121:20191207015201p:plain

恐ろしいことにあとこの作業をただただ2回繰り返します。
最後にローカルでのテスト方法を行います。明快でタスク定義をdocker-compose.yamlにtranlateするコマンドがあるので、それを変換してdocker-composeを起動させるだけです。なんだか物足りない…。

感想

このWorkshopは出なくても良かったかも知れません。結局4日間でExpo行けていないので、もっと早めに切り上げてExpo行くなど柔軟に行動すべきでした。

【AWS Re:Inventレポート】DOP201-R2 - [REPEAT 2] DevOps essentials: Introductory workshop on CI/CD practices

DevOps essentials: Introductory workshop on CI/CD practices

米食べたい気持ちが最高潮に達してしまった3日目2つ目のワークショップです。 AWSのCodeシリーズを使ったWorkshopです。CodeBuild/CodeDeployは使ってみたほうがいいんだろうなとは昔から思っていたのですが、仕事に即活きるかとそうではないものだったため、ずっと手を出せずにいました。

Workshopの流れ

最初にDevOpsとは何かという説明から入りました。Shared Responsbilityのお話とかですね。実践するとどんな利益があるのか?頻度の高いDeliveryやReliabilityの向上に約立つなど基本的な内容が多かったように感じます。そこからCodeシリーズを使ってCI/CDはどのように実現できるかというざっくりとしてお話がありました。どのプロダクトがどのフェーズの役割を担っているか説明が終わった後に実際にWorkshopに入りました。

f:id:jrywm121:20191206034518p:plain

資料はGitHubにて既に公開されていました。

github.com

最終的には下記の図のようになります。

https://github.com/awslabs/aws-devops-essential/raw/master/img/CICD_DevOps_Demo.png

前提

一番最初に思わず「?」となってしまうことがありました。Prerequisitesとして、CodeCommitで構成するために必要な鍵を生成しろとあるんですが、Cloud9を使う場合には必要ありません。そして、その直後からCloud9を使います!はて?なぜ必要だったのかいまだに謎です。

起点はもちろんCodeCommitからになります。あまりガシガシとは使えていませんが、正直、GitHubやBitbucketにくらべ、物足りない印象は拭えませんでした。サンプルコードはJavaのようです。

CodeBuild

Codeシリーズで使用するRoleとS3バケットをCloudFormationで作成し、いざCodeBuildの登場です。
CodeBuildはProjectという単位でパイプライン群を分けていくようです。このプロジェクトでは、ソースとなるコードとアウトプットになるS3バケットが同じになるので、リポジトリと1対1で紐づくイメージを持っています。Jenkinsとかで言うところのパイプラインに相当すると認識です。また、実行する環境(Dockerイメージ)も共通となります。今回はJavaがインストールされたコンテナイメージを使用しています。
buildspec.yml というファイルを作成し、その中にビルド工程を宣言していくようです。実はJenkins以外のCI/CDをあまり使ったことが無いのですが、yamlで書くのはすごく今どきって感じがしますよね。GitHub ActionsやCircle CIがそうなので。
.artifact.filesで指定したものが最終的にzipに固めてS3にアップロードされます。

version: 0.1

phases:
  install:
    commands:
      - echo Nothing to do in the install phase...
  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
  build:
    commands:
      - echo Build started on `date`
      - mvn install
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - target/javawebdemo.war
  discard-paths: no

CodeCommitの直下にあるbuildspec.yml を読み取るので、作成したファイルをgit pushして上げて、CLIからaws codebuild start-build --project-name devops-webapp-projectってな感じです。CloudWatch Eventをトリガーにすることも出来るようですね。マージとかを契機にするには、その辺を組み込まなきゃいけないのが若干手間に感じました。

CodeDeploy

EC2インスタンスVPCを作成するCloudFormationを展開させます。なおEC2のUserDataでCodeDeploy Agentがインストールされているそうです。
deployment-groupというのを作っていきます。Applicationという括りの中にあって、どうやら本番・検証などのステージごとに作るみたいです。今回はEC2のタグでフィルターを掛けてKey=Name,Value=DevWebApp01を1つのグループとしています。appspec.ymlというファイルでこちらは定義していきます。

version: 0.0
os: linux
files:
  - source: /target/javawebdemo.war
    destination: /tmp/codedeploy-deployment-staging-area/
  - source: /scripts/configure_http_port.xsl
    destination: /tmp/codedeploy-deployment-staging-area/
hooks:
  ApplicationStop:
    - location: scripts/stop_application
      timeout: 300
  BeforeInstall:
    - location: scripts/install_dependencies
      timeout: 300
  ApplicationStart:
    - location: scripts/write_codedeploy_config.sh
    - location: scripts/start_application
      timeout: 300
  ValidateService:
    - location: scripts/basic_health_check.sh

合わせてbuildspec.ymlを修正します。直でCodeDeployが指定できるのはいいですね。どっちもAWSがやっている強みが出てますね。

f:id:jrywm121:20191206120955p:plain

CodePipeline

はいやっとパイプラインで統合できます。
これはGUIで作成していきます。これは本当に要求されるまま一つ一つ設定していくだけでした。
その後は本番用にdeployment-groupを作成し、Manual Judgmentを組み込みました。

f:id:jrywm121:20191206122216p:plain

感想

CodeStarというのを使えばこれらが一発ででき出来上がるというので、そちらも試してみたくなりました。普通に使い勝手が良かったような印象はあります。EC2へのデプロイだったので、ECSやEKSで使いますか?と言われると首を捻ってしまうかもです。

【AWS Re:Inventレポート】AIM223-R4 - [NEW LAUNCH!] [REPEAT 4] AWS DeepComposer: Get started with generative AI

AWS DeepComposer: Get started with generative AI

火曜のKeynoteの後に見たら偶然予約できました。おそらく新セッションが出てくるタイミングでUnreservedされた座席があったのだと思います。Walk-Upの列はとんでもないことになっていました。

正直、機械学習についての知識が全くない状態ではWorkshopの後半は、shift+Enterを繰り返すだけのただの人形と成り果ててしまいます。自分は人形と化しました。 悲しいですね。

GANsに関する説明

機械学習は3つに分類されるというお話から始まりました。正直自分が知っていたのはこのレベルまでです。

その中でGANsはUnsupervised learningに分類されるものだそうです。
generatorとdiscriminatorという2つのネットワークを利用するそうな。generatorはその名のとおり、物を生み出す側で、DeepComposerでは音楽を生み出します。discriminatorはそれを評価してフィードバックすることで、よりクオリティを上げていくというものだそうです。説明の中では、オーケストラに例えていました。generatorは演奏者たち、そしてdiscriminatorは指揮者にあたるもののようです。素人でもどこか腑に落ちる(ような気持ちになる)説明でした。

軽く説明を受けた後に簡単な小テストが行われました。上位に入るとスピーカーがもらえたようです。テスト自体は結構簡単だったのですが、なにより速さが足りない。スピーカーをもらうことが出来ませんでした。

サンプルのモデルでGANsを体験してみる

AWSコンソールからDeepComposerのページに飛んでみます。アカウントを頂いたのですが、どうやらre:Invent最終日の24時まで有効なようです。SageMaker使う部分に関してはお金かかると思いますし、結構複雑なアーキテクチャ組んでたので太っ腹ですね!

DeepComposerをPCにつなげて、実際に弾き、それを録音することで音をインプットさせます。そのインプットした音を、モデルを用いてアレンジさせます。サンプルのモデルとして用意されていたのは、「Pop」「Rock」「Symphony」などの5種類です。
みなさん思い思いにDeepComposerを奏でて、モデルによってアレンジさせていました。

SageMakerを利用してモデルを作ってみる

恥ずかしながら、まったく分かりませんでした!

SageMakerからJupiterNotebookを起動させると、音楽生成GANsに関する基礎知識とそれに対応するPythonの構文がざーっと書かれていました。一応それぞれGoogle翻訳にかけて読みましたが、後半はわからない単語の応酬でなかなか厳しいものがありました。

かろうじてわかったのはモデルを生成する部分のAWSアーキテクチャのみでした。

f:id:jrywm121:20191206032558p:plain

DeepComposerは無事ゲットすることが出来ました!セッションを受けてると、SWAG行ったときに貰えるようです。めちゃめちゃ嬉しい。