1クール続けるブログ

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

【AWS Re:Inventレポート】CON203-R1 - [REPEAT 1] Getting started with Kubernetes on AWS

Getting started with Kubernetes on AWS

去年のWorkshopの資料を見たことがあったので、行くか迷ったんですが、1年経ってアップデートがあるかも…?であったり復習としてはちょうど良いのではないかという気持ちで参加いたしました。
資料を見る限りでも135分では到底終わりそうにないボリュームが有ることが分かります。個人的にはHelmを飛ばして、Cluster AutoscalerやIAM Roleとの統合をやったほうがいいのではなんて思っていたりもしました。
資料はこちらです。con203というタグがセッション番号と紐付いているみたいです。

eksworkshop.com

Workshopの流れ

チームハッシュを入力して、Workshop専用のアカウントにログインし、Cloud9をセットアップするところまでは他のWorkshopと同じです。なぜかCloud9のテーマを変えるような指示があった点だけは違いますが…。ダークテーマのほうが見やすかったのは確かです。View -> Theme -> Solrized -> Darkで設定しました。
EKSに関してはCloud9から触れるように権限周りが対応出来ていないのか、追加の処理を行うことになります。まず一時認証情報をOFFにします。その後インスタンス一覧から見れるCloud9のインスタンスに、管理者権限のついたIAMRoleをアタッチします。最後に、Cloud9側の認証情報を消して、GetCallerIdentityで改めて認証情報の取得を行いました。

ここからの流れは実にシンプルで、ほとんどWorkshop資料のまま進んでいきました。

eksctl を使ったEKSクラスターの展開

この展開にかなり時間がかかってしまったため軽くKubernetesの説明や質問コーナーを設けていました 。 今になって面白いなと思うのは、参加者からEKS on Fargateはまだかという質問を受けたときに講師がちょっと待ってねと流して、GitHubに載っけているコンテナワークロードを紹介し始めたときです(さてはキーノートで出ること知ってての所業か)。

Kubernetes Dashboardのデプロイ

ここでダッシュボードにアクセスするためにkubectl proxyが使うのですが、実は使ったことがなく頭を捻りながらコマンド打ってました。既にこの時点で参加者間で進捗に大きな差が出来ており、あんまり説明などがされぬまま進んでいっていたように感じます。
kubectl proxylocalhostKubernetes API serverの間にProxy Server作るというもので、通信がKubernetes API Serverにフォワーディングされるものです。 実際にうったコマンドはkubectl proxy --port=8080 --address='0.0.0.0' --disable-filter=true & となるのですが、これはIP0.0.0.0のポート8080番の通信を行うと、リクエストにFilterをかけずに(XSRF脆弱性が生まれるらしいですが…)Kubernetes API Serverにフォワーディングされます。--disable-filter=trueに関しては実稼働環境に使うのは良くないが開発環境なら良いと注意書きがありました。

勉強不足でKubernetes APIを通してServiceにアクセス出来ることを知らなかったので、知れてよかったです。こちらのドキュメントに記載ありました(Access Services Running on Clusters - Kubernetes

Exampleアプリのデプロイ

基本はDeploymentとServiceリソースをapplyしていくだけの作業です。
冷静にサンプルアプリの1つのサービスにCrystal使われてるのびっくりでしたね(AWS社内では使われてたり…?)。
使用しているアカウント内で初めてELBを作る場合には、ELBに紐づくRoleが無いらしいので、作ってあげる必要があるようです。 aws iam get-role --role-name "AWSServiceRoleForElasticLoadBalancing" || aws iam create-service-linked-role --aws-service-name "elasticloadbalancing.amazonaws.com"というコマンドでした。
あとはscaleコマンド使ってpod増やしてみたりしました。

Helm

Helmのセットアップを行います。
nginxをHelm使ってデプロイしていきます。リポジトリの追加方法やパッケージの削除方法を学びます。 ExampleアプリをHelm使ってデプロイすることを通じて、Helmパッケージの作り方を学びます。

(自分は途中退出)

行きたい別のセッションがあったため、残りが40分ほどありましたが、退出しました。残りも基本的には知っている部分(ClusterAutoScalerやaws-auth, metrics-server)だったので一旦大丈夫でしょう。

他、気になったところで言うと、Managed WorkerNodeがこの前出たので、eksのコマンドがeksctl create cluster --managedのように--managedオプションが付くようになってました。ただ資料上、ClusterAutoscalingでノードグループの台数いじるところはまだASGのキャプチャだったので、対応出来ていない部分もあったのかもしれません。
当たり前ですが、Managed WorkerNode推奨って感じですね。

【AWS Re:Inventレポート】SVS201-R - [REPEAT] Build a serverless web app for a theme park

SVS201-R - [REPEAT] Build a serverless web app for a theme park

セッション会場(MGM)まで

初日の朝8時半に滞在先のTreasure Islandを出て、Mirageシャトルバス乗り場に向かいました。 Mirageシャトルバス乗り場は北口にあり、前日に行ったVenetianに比べ遥かにわかりやすかったこともあり、すんなり乗り場までたどり着けました。 シャトルバスも特に混むことなく、ゆったり過ごせた印象があります。

MGMに入った後に荷物検査を行うところがあるのですが、ゲート的なところを通るときにセンサーがあり、それに引っかからなければ荷物検査を受けることになるみたいです。なぜか自分は引っかかってしまい、荷物を見せる形になりました。
階段を上がると、DeepRacerの大きな会場が左手に見えます。自分はそこから右手に行く形となりました。レストラン街を進むとT字路が現れましたが、そこを左に行き、階段を下り右亭に行くと会場が見えました。そこでも荷物検査があったのですが、なぜか引っかかりませんでした(なぜ?)。

Walk-Up初挑戦

行こうと思っていたセッションはReserve出来ていなかったので、Walk-upで入ることにしました。ask meの方にどこがWalk-upの列かを聞き並びました。並ぶと前後の方とかで世間話があったんですが、自分の英語力の無さ故に入れず悔しい思いをしました。これはWorkshopの間続きます(悲しい)。

Workshopの内容

テーマパークのアプリを作成することになります。機能は下記です。

  • アトラクションを地図上に表示する
  • 待ち時間見積もりの更新を受け取り表示する
  • グリーンバックで撮った写真を加工し背景をテーマパーク風に加工する

使用したAWSサービスは下記でした

  • Cloud9
  • Amplify
  • Lambda
  • CodeCommit
  • DynamoDB
  • S3
  • CloudFormation(samを通して)

資料は既にパブリックになっています。

github.com

Workshopの流れ

イベント用のページURLが書かれている紙がテーブルに用意されているので、それを利用する。一緒に書かれているチームハッシュを入力すると、AWSコンソールに入れるようになる。
スピーカーの人がハンズオン用のURLを共有してくれるので、それを手で打って開始。
ほとんどリスニングでなくリーディングになるので、結構楽です。ただテーブルを囲む形で着席するので、会話が活発に起こっているテーブルもありました(自分のいたテーブルです)。

感想

自分が扱っているサービスはコンテナとそれに関わるサービスだけなので、S3以外は初めて触りました。
Lambdaのデプロイはコンソールからとsam-cli経由のものが経験できてよかったです。Cloud9はAWSに買収される前に使っていたので懐かしい気持ちになりました…(見た目の感じはだいぶ変わっていましたが)。

それぞれの連携のされ方は実際触ってみると勉強になりますね。 AmplifyとCodeCommitだと下記のような形です。
CodeCommitの中身(https://innovator-island.s3-us-west-2.amazonaws.com/front-end/theme-park-frontend.zip) -> Vue.jsを使ったPWA

  • CodeCommitでリポジトリを作成する
  • AmplifyのセットアップでCodeCommitのリポジトリ(+ブランチ)を指定する
  • CodeCommitのPushごとにAmplifyのデプロイが走る

f:id:jrywm121:20191203060809p:plain
Amplifyでデプロイされる様子

SAMで色々作っていたのもびっくりしました。DynamoDBからCognitoまで…本番運用されるときにここまでSAMに任して大丈夫なのかはちょっと分かりませんが…。
下記のリソースをデプロイしていました。

  • 2 Lambda functions and a Lambda Layer
  • 3 S3 buckets
  • A DynamoDBTable
  • A Cognito UserPool
  • An AWS IoT thing
  • Several IAM Roles and Policies.

使ったことないサービスを使って実際に動かせるのは得だなーと思いました。

AWS Summit 2019 Day2に参加してきました

幕張で開催されたAWS Summit2019にDay2から参加してきました!各セッションの感想を書いていきたいと思います。
セッションの他にもブース等回ろうと思っていましたが時間がなく、認定者ラウンジにちょっと立ち寄ったのみでした。ラウンジでは自撮りブースというものがあり、そこで自身の経歴もしくは資格を取って活きたこと、受験者に向けてのアドバイス等5つの設問から選んで、ビデオカメラに向けて話すとTシャツがもらえるとのことだったので、参加してもらってきました。
(背面のキャラクターかわいいけど誰なんだ…?)

f:id:jrywm121:20190614193500p:plain

英語力強くしたかったので、英語のセッションに関しては翻訳ではなくそのまま聞いています。
もしかしたら解釈違いなどあるかもしれません。

コンテナ化されたアプリケーションのAWSでの構築・運用指針

全体的に真新しい話はありませんでしたが、コンテナワークロードのメリットや近年の機能追加を再確認できるセッションだったかと思います。

Fargateの強み

インスタンスをManageする必要がなくなるため、Operationも非常にシンプルなり、ビジネスロジックに注力できる。
またSecurityに関してもAWS側で随時パッチを当てるので、その部分の対応コストもいらないし安全である。
Securityにも関わることですが、実行基盤のFirecrackerも同時に紹介されていました。

下記の点からAWSはFargateをもっと使ってもらいたいのかなと感じた

  • Fargate利用者が伸びていることをスライドで紹介
  • コンテナをテーマにしたセッションの中でServerlessを強く推していたこと
  • 年末年始にFargateの価格が大幅に下がったことにも触れていた

CDKを是非使ってほしい

※ Developer Preview
十数行〜何百行のyamlを書かずともJS×CDKで書くことで、yamlよりかなり簡潔な記述でAWSのInfrastructureを構成することが可能。
対応言語としては「C#/ .NETJavaJavaScriptPython、TypeScript」 裏ではCloudFormationが動いていてスタックとしてProvisioningされるようです。 下記の記事にはAWS FargateをTypescriptでProvisioningするサンプルコードがありますが、かなり簡潔に書けるようです。このサンプルだと600行超のコードが21行で記述できてます。
暗黙でセットしている値や作成しているリソースが多そうなのでそこは気をつけたいですね。

docs.aws.amazon.com

Elastic Container Services for Kubernetes

KubernetesAWSの既存のサービスの統合にはかなり力を入れているとのことでした。 特にCNIプラグイン周り。 また、Maste NodeをAZ3箇所で冗長化を図っているのというのはびっくりしました。GCPはデフォルトだと1Zoneのみなので、AWSがマルチゾーンに展開していると思っていませんでした。
セッションの中でUpstreamであることを強調されていた印象です。Amazon AuroraのようにForkしてAWS独自の改修を加えているわけではないとのことで、ベンダーロックインの無い状態でKubernetesを使える+オープンソースコミュニティに寄り添っているという主張だったのでしょうか。嬉しいです。

ここ1年間でのLaunch

事例紹介

UberEatsなどの配信プロバイダと連携するためのプラットフォーム
ECSやSQSを組み合わせて100msecのレイテンシで20000order/secまで拡張が可能

aws.amazon.com

サーバーレスのエンタープライズへの拡大とベストプラクティス

サーバーレスのメリットなどは既に分かっている前提で、では現在ある問題点に対してAWSはどうアプローチしているかという観点でのお話が多かったと思います。Lambdaを使う上で自分も問題だなと思う点はだいたい網羅されていたように感じます。
Lambda Layer × AWS Configの話はもうちょっと掘って理解したいと思います。

サーバーレスへの懸念

  • 新しい開発者がLambdaに適合できるか
  • SecurityやGovernanceはどのように担保するのか
  • MonitoringやLoggingはどのように行えばいいのか
  • Performanceはどうチューニングすればいいのか

AWS SAM

FaaS開発の速度を爆速にしてくれる。
CloudFormationをServerless用に拡張したものテンプレートが構成要素の一つ。Serverless用のResourceTypeが用意されている。例えば、コードに紐付けるAPI Gatewayも同時に定義することができるApiリソースやDynamoDBのテーブルを定義できるSimpleTableなどが存在する。
非ServerlessリソースもSAMテンプレートには含めることができる。例えば併せて使うことが多いS3などは通常のCloudFormationの定義と同じように書ける。

SAMの構成要素の一つでコアな部分を担っているのがaws sam-cliです。
ログの追跡やローカルでの関数の呼び出しAPI Gatewayの実行が可能になる。
ローカルで実行できるDynamoDBと併せて使うとなおよし。

Security & Governance

2つのPolicyを使い分けて権限を操作する - 同期・非同期呼び出しのときはFunction Policy - ストリーム呼び出しのときはExecution Role SAMテンプレートにPolicyも記述できる。権限に関してもコードで管理できる。

Lambdaを外から見たときのGovernanceという観点では下記の2つ - CloudTrail - API呼び出しをCaptureする - AWS Config - AWS Config が AWS Lambda 関数のサポートを追加

ではコード自体のガバナンスをどうするか - PipelineでCodeを自動チェックする - レイヤーの作成を追跡可能にする - レイヤーはイミュータブルで更新はバージョニングで行われる - SAM テンプレートでレイヤを定義することができる

Monitoring/Logging/Trouble Shooting

ビルトインのMetricsも充実しているが、lambdaのsdkを使えば、putMetricDataでカスタムメトリクスも収集が可能。
"debug: in "という記述とともにログ出力するとinsightで見つけやすい。

Performance

Memory割当てを少なくすればするほど安くなるとは限らない。
Menory割当によってCPUの割当が変わるので、実行しているアプリケーションがCPUバインドなのかそうでないのか見極めてMemoryを割り当てるべき。

構成されているメモリの量に比例して CPU パワーが直線的に割り当てられます。1,792 MB では、関数は 1 つのフル vCPU (1 秒あたりのクレジットの 1 vCPU 秒) に相当

DeNA の QCT マネジメント IaaS 利用のベストプラクティス

オンプレからそのままクラウドに移行すると単純にコストが増加するという話は非常にうなずけるお話でした。クラウドに適合する形にしつつ、オンプレのナレッジが潤沢にある企業の場合はどのような戦略を取っていくのかというのが見られて勉強になりました。

オンプレから全面クラウド移行

オンプレでのナレッジがものすごく溜まっていてそれを活かそうとする構成にするために最適化させた構成にしているという印象でした。
基本は全てApp on EC2の構成。一番前段にALBを置いていて、それより後ろのレイヤではMyDNSを使ってServiceDiscoveryを行っているそうです。Route53のAutoNaming APIとかに乗っかってもいいのではと個人的には思いましたが、おそらくそれでは要件を満たせなかったのだと思います。
Scalingに関しても、ASGやCloudWatchを使わず自前で実装を行っていましたが、これも柔軟性を求めた結果なのだと思います。スクラッチで組み上げてしまうなんて、ものすごい技術力のある会社さんだなと思いました。

スポットインスタンスの終了処理

スポットインスタンスが強制Terminateされたときのハンドリングについてですが、リンクローカルアドレスを数秒間間隔で叩くDaemonを用意する。terminateのエンドポイントが200で帰ってきたら終了処理。
ログの扱いについてですが、終了直前のログが転送できないという課題を持っていたそうです。おそらくfluetndを使った高頻度での転送などは行っていなかったのだと思います。そのためEBSをインスタンスがTerminateされるタイミングで削除せず、そのまま残してバッチ処理で残っているログを転送するという形にしたそうです。

スポットインスタンスの枯渇対策

スポットインスタンスの大量Terminateが起こることがある。例えば、AmazonのCyber MondayやBlack Fridayでは顕著にその傾向が見られた。そのため、20プールの確保をするようにした。 プール=AZ × インスタンスタイプ × 世代。ファミリーを統一してタイプをバラバラにすることでアプリケーションの挙動差異を少なくしている。コア数が多いものが起動したときはIP数を増やして(ENIをアタッチして)その分多くリクエストをさばくようにする。

Serverless/AppSync によるモバイル開発の今

アプリ開発のバックエンド周りは疎い自分でも多くのメリットを享受できることが分かるセッションでした。

AppSync概要

AppSyncはManaged GraphQL Service
GraphQLはクライアントからQuery / Mutation / Subscription出来るようにするためのデータ言語。GraphQLのクエリではクライアント側がレスポンスの形式を指定。SubscriptionはMutationをトリガーとしてリアルタイムでのデータ更新を行う(Websocket通信)。Mutationはオフラインの状態で更新したら、復帰した段階でサーバ側と同期を取ってくれる。 AppSyncのデータソースはLambdaやDynamoDB、ElasticSearchなど…。

Gunosy事例

グノシースポーツでの事例。
各スポーツによって画面の仕様や欲しい情報などが異なることがあるため、クライアント側で定義できるGraphQLを採用。

導入手順 - スキーマ定義 - Resolver Mapping Templateの作成 - デフォルト値の定義やValidation, Format, データの変換などを行う - 厳密には下記の2つ - リクエスマッピングテンプレート - レスポンスマッピングテンプレート

試合のスコアなどをリアルタイムに更新 - DynamoDBにUpdateが行われる - DynamoDB streamでLambdaをキック - LambdaからAppSyncにpublish - AppSyncがアプリと同期する

新規開発時の悩みが解消 - 仕様書書くのだるい - 必要なデータを選ぶのはアプリエンジニア - UIの細かい改善がフロントだけで出来るようになる

Demo

amplifyを使ってSPA+AppMeshの構成でアプリケーションを作成していました。amplifyを知りませんでしたが、あそこまでシームレスにアプリが構築できてしまうのを見ると用途によってはゴリゴリ使えるような気がしますね。
amplify add apiAWSリソースがProvisionされました。本当に簡単でした。びっくり。
DemoのPartに入られる前にこのPartが本当に怖いよとおっしゃっていたのがキュートで印象的でしたね。

Amazon Managed Blockchainの使いどころとソニー・ミュージック様における使用事例について

AWSが提供しているブロックチェーンのマネージドサービスの一つ。サポートしているアルゴリズムHyperledger Fabricで、ethereumも近日サポート予定になっている。ブロックチェーンネットワークの作成・管理を行うことができる。

ユースケース

  • ヘルスケア
    • カルテの電子化管理
  • 製造業
  • デジタルコンテンツ
    • 画像や写真の所有権の管理

AWSブロックチェーン関連サービス

re:Inventで発表されていたものの、あまり具体的なユースケースが自分の中で分かっていなくてモヤモヤしていた部分のブロックチェーン関連サービス。
国内事例やQLDBとの使い分けを聞くことで、何かに使えないかと意識するきっかけになりました。

  • QLDB
    • 所有権が一元化された台帳の機能を持つ
    • Amazon.comで既に使用されているらしい
  • Block chain partner
    • Blockchainのsolutionを提供するAWS Partner Network
  • AWS Blockchainテンプレート
    • EtheriumとHyperledger Fabricに対応
    • CloudFormationのテンプレート

よくいただく相談

  • どうやってスケールさせるか
    • ノードのスケーラビリティをお客様自身で設定
    • スケール設定によってはリーズナブルにPoCが可能

構築フロー

鍵管理のベストプラクティス

コンプライアンス要件を厳しいケースにはKMSではなくCloudHSMを使用
他のネットワークから分離するためにVPCも併せて利用することで厳しい要件をクリアできる またCloudHSMがサポートsecp256k1をサポート(ブロックチェーンの鍵は楕円曲線暗号で暗号化される必要がある?ため)

ブロックチェーンの主な2つのユースケース

  • 信頼された中央機関による台帳
  • 分散機関によるトランザクション実行(Managed Blockchain)
    • peer-to-peerの金融取引

ここが詳しい

ソニー・ミュージックの事例

音楽業界の課題という背景から、実際に使用されてみたTips、デモなどをして頂いたのですが、自分に音楽業界とブロックチェーンのどちらの知識も無くちゃんと内容追えなくなってしまいました。スライド公開されたらゆっくり理解したいと思います。

事業責任者も必見!AWS Well-Architected Frameworkのビジネスへの有効活用

既にスライドが公開されています。
CAという大きな会社で高品質のインフラを維持するためには、社内向けのWell-Architected Frameworkを作るというのが非常にプラスにつながっていくんだなと感じました。マルチクラウドで共通のチェックシートを作成する+項目を絞って75項目にするという作業は非常に難しかったのではないかと思います。特にプライベートクラウドもあるわけですし…。
また定期的なチェックというのは凄く良いよなと思いました。新機能のリリースなどで初期の頃に仕方なくイケてない形で構築したものなどを改善できるケースは多くありそうです。

事業責任者も必見! AWS Well-Architected Frameworkの ビジネスへの有効活用 / AWS Well-Architected Framework - Speaker Deck

AWSのマネージドサービスを活かした Kubernetes 運用とAmazon EKS によるクラスタのシングルテナント戦略について

こちらも既にスライドが公開されていました。 どうしてシングルテナントを選んだのか?namespaceで分けるのではなくクラスターごと分けるという意味です。自分の勤めている会社ではSREというポジションが無いのですが、SREが陥ってしまった状況とその問題点からそれを解決するための権限と業務の委譲、シングルテナントを選択するに至った動機が丁寧にストーリーに落とし込まれていて、とても知見でした。
移譲する上で品質の低下や移譲先の負荷を高めないと言う点での取り組みも勉強になりました。例えばクラスター作成用のeksclstという社内ツール作成している点などです。

AWSのマネージドサービスを活かした Kubernetes 運用とAmazon EKS によるクラスタのシングルテナント戦略について - Speaker Deck

まとめ

コンテナなど慣れ親しんでいるサービスからAppsyncやManaged Blockchainなどのあまり関わったことのないサービスまで多くの知見が得られました!
来年も行きたい!

AWSソリューションアーキテクト アソシエイトに合格したので試験の雰囲気や勉強方法について書きます

何番煎じかも分からない記事にはなってしまいますが、こういう人もいるぞという材料にしていただければ幸いです。

当日・結果

試験の登録を行った際に、確認のメールが届くのですがそこに下記のような記載があります。 なので、パスポートと免許証を持ってく必要がありました。

You are required to present two forms of original (no photo copies), valid (unexpired) IDs; one needs to be government-issued with registered name, photo, and signature and the second with registered name and signature or recent recognizable photo.

テストセンターで試験を受けるのはSPIや玉手箱以来でした。その時には無かったと記憶しているのですが、この試験ではデジタル署名と写真撮影を行いました。

試験時間は最初の説明と最後のアンケート含め140分と時間が取られていますが、自分は4〜50分ほど残して試験を終えました。 本試験前に模試を受けていたのですが、その模試は25問/30分だったのに対し、本番は65問/120分だったので、模試のペースより少し遅めに解いてもだいぶ余裕がありました。

結果は以下になります。100点〜1000点の間で評価されて、720点以上で合格するそうです。

f:id:jrywm121:20190519013304p:plain

準備

自分のプロフィール

  • 業務でAWSを使い始めたのちょうど1年前
  • インフラ関連の業務に関わり始めたのも同じタイミング
  • 持っている資格はIPAのやってるFE/AP/DBで、LPICなどのインフラ系の資格は無し
  • 主に業務で扱ってるのはECS、ECR、EC2(ASG)、CW、EKSとコンテナ関連がほとんど

勉強方法

基本的には学んだすべてのことをdynalistにまとめていって、試験前におさらいしていました。

黒本を読む

徹底攻略 AWS認定ソリューションアーキテクト アソシエイト教科書 を読みました。1章で軽く主要なサービスをおさらいして、その後の章でWell-Archetected Frameworkに沿った観点での記述が見れたのが、個人的には頭を整理しやすくてよかったです。 パフォーマンスに関する記述はそのサービスを使っていないと意識できていない点なので、しっかり叩き込みました。例えば、EBSでRAID 0を使うとI/0の効率が良くなるなどです。

book.impress.co.jp

わからない箇所をBlackBeltやDevelopers.ioで確認する

サービスが全くつかめないという場合には、 AWS クラウドサービス活用資料集 | サービス別資料 からBlackbeltを読むようにしました。試験によく出やすいEC2やEBS、ELBは絶対読んでおいたほうが良いと思います。本だけではつかみにくいKinesisやOpsworksなども読んでおくと点数取りやすいのではないかと思います。 ネットワーク関係に関しては、いろんなサイトで勉強しました。Internet GatewayがStatic NATで、NAT GatewayはDynamic NATであるだとか、ENIにより、DHCPサーバーから毎回同じMACアドレスIPアドレスが付与されるなど、内部の動きに言及しているものを見つけると理解が深まりました。

模試を受けてみる

AWS training and certification から模試を受けました。全問題スクショを取りました。どの問題で間違ったとかはわかりませんが、各分野で何%とれているかは出るので、それをもとにこの問題が間違っているのではなど推測して復習しました。模試よりも本試験のほうが難しいとはお聞きしていましたが、正答率92%だったので受けても大丈夫と判断し、模試を受けた5日後に本試験をセッティングしました。

復習がてら他の方が試験のためにまとめたノートを読む

英語ですが、下記のサイトが非常に良くまとまっていてよい復習になりました。S3のストレージクラスのあたりが最高で、可用性や耐久性がどう違うのか非常に覚えやすかったです。

loige.co

まとめ

今後AWSのサービスを使う上で基盤となる知識を体系的に学ぶことが出来て非常に良かったです。 業務では、GCPも使ってるので、次はGoogle Cloud Proffesional Archetect取ってみようかなと考えています。 最近GoやってないのでGoがっつりやるのも良いかもしれない。

ローカル開発環境(apache/tomcat)をコンテナ化+SSL化

ローカルのapache+tomcatで動いているアプリケーションをdockerに乗っけてみました。 SSL込みで設定していきました。Docker for Macを使用しています。

成果物をこちらのリポジトリにあげておきます。

github.com

Apache

ApacheでVirtualHostで3つのFQDNの通信を扱うようにしていきます。SSLの設定も行っていきますが、その際にはmkcertを使用してローカル認証局と鍵の作成を行います。

httpd.confの作成

SSL通信を有効にするため、conf/httpd.confをベースのdockerイメージからコピーしてきて変更を加えていきます。以下の項目のコメントアウトを外します。

#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
...
#LoadModule ssl_module modules/mod_ssl.so
...
#Include conf/extra/httpd-ssl.conf

今回はVirtualHosts+Proxy Moduleを使っていきたいと思うので下記のコメントアウトも外します。tomcatへの通信をhttpで行うために必要なモジュールもついでに外します。

#Include conf/extra/httpd-vhosts.conf
...
#LoadModule proxy_module modules/mod_proxy.so
...
#LoadModule proxy_http_module modules/mod_proxy_http.so

各VirtualHostsで共有の鍵を使いたいので、httpd-ssl.confに鍵の設定をして、httpd-vhosts.confの設定がhttpd-ssl.confより後にくるように記述の位置を変えます。下記のようになるはずです。

...
# Secure (SSL/TLS) connections
Include conf/extra/httpd-ssl.conf

# Virtual hosts
Include conf/extra/httpd-vhosts.conf
...

鍵の作成

mkcertを使って認証局+鍵の作成を行っていきます。Goで作られているらしいので興味ある方はぜひ。

github.com

brew install mkcert
brew install nss  # Firefoxでアクセスする際には必要のようです
mkcert -install # ローカル認証局作成 Macの方はキーチェーンアクセスを見ると出来ているのが分かる
mkcert localhost "*.example.com " "*.cool.com"
# generateされた下記のファイル2つをdockerコンテキストに配置

httpd-ssl.confの設定

httpd-ssl.confの下記をコメントアウトします。今回は先程生成した2つのpemファイルを利用するためです。

SSLCertificateFile "/usr/local/apache2/conf/server.crt"
...
SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"

そして下記のように記述を加えます。

SSLCertificateFile "/usr/local/apache2/conf/localhost+2.pem"  # 後ほどDockerfileでCOPYするように宣言します
SSLCertificateKeyFile "/usr/local/apache2/conf/localhost+2-key.pem"

httpd-vhosts.confの設定

tomcatのコンテナへajpで通信するように設定を加えます。 通常は静的ファイルはDocumentRoot配下を参照させて、それ以外はtomcatと通信という形になるかと思いますが、今回はとりあえず全部tomcatコンテナに流します。 下記のような形としました。VirtualHostのセクション内です。

   <Directory "/usr/local/apache2/docs/one.cool.com">
        Options Indexes 
        Require all granted
    </Directory>

   <Location /todolist>
        ProxyPass http://app:8080/todolist/
    </Location>

/private/etc/hostsに今回設定したFQDNを追加

本題とは関係ないですが自分のPCからアクセスできるように、/private/etc/hostsに記述しておきます。

127.0.0.1       www.example.com
127.0.0.1       one.cool.com
127.0.0.1       two.cool.com

Dockerfileの作成

設定ファイルと鍵、httpのドキュメントをコンテナにCOPYしポート80番と443番をListenします。イメージはなるべく軽くしたいのでDebian系OSがベースのものでなく、alpineベースのものを選んでいます。

FROM httpd:2.4-alpine

# copy configuration files
COPY --chown=root:www-data conf/httpd.conf /usr/local/apache2/conf
COPY --chown=root:www-data conf/extra /usr/local/apache2/conf/extra

# copy keys for ssl/tls
COPY --chown=root:www-data keys /usr/local/apache2/conf

# copy document
WORKDIR /usr/local/apache2/docs
RUN chown root:www-data /usr/local/apache2/docs
COPY --chown=root:www-data docs .

EXPOSE 80 443

httpdがうまく動いているかテスト

docker-compose.yamlを作成し、下記のようにhttpdの設定を宣言します。

version: '3'
services:
  web:
    container_name: httpd
    build: ./httpd
    ports:
    - "9080:80"
    - "9443:443"

以下のURLにSSLでアクセスできることが確認できました。

Tomcat

kotlin + SpringBootで作成した簡単なアプリケーションをコンテナに乗っけてみます。黒べこ本のサンプルに載っているTodoアプリです。

kotlinのアプリケーションの設定を一部変更

最初にkotlinのアプリケーションのbuild.gradleに変更を加えていきます。今回はwarを作成してそれをデプロイするため、下記のように記述を加えていきます。

apply plugin: 'war'
dependencies {
    providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")  // SpringBoot組み込み以外のTomcatを利用するときに必要みたいです
}

次に、warファイルをTomcatに展開するにあたって必要らしいServletInitializerというclassをエントリポイントのあるclassと同パッケージに配置します。下記のような内容のclassです。

package com.example.todolist

import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer

class ServletInitializer : SpringBootServletInitializer() {

    override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
        return application.sources(TodolistApplication::class.java)
    }
}

Dockerfileの作成

Warに固める作業自体はローカルのIntelliJで行います。Dockerコンテキスト配下にソースを置いてそこに成果物を固めて良いのですが、今回は単純にcopyしてコンテキスト配下に盛ってきたいと思います。いちいちその作業をやるのが面倒くさいのでMakefileを作ります。
※ AutoDeployしてDockerで都度都度検証したい場合には、Volumeマウントして動かしたほうが良いとは思います。

build:
  cp ~/ideaProjects/todolist/build/libs/todolist.war tomcat/build
  docker-compose up --build

run: 
  docker-compose up 

makefileに記述したように、warはtomcat/build配下に格納するので、そのwarをdockerの方にcopyするだけです。なのでDockerfileは下記のようになります。tomcat側もイメージは軽くしたいのでalpineを使います。 またSpringBootは環境変数からコンテキストパスを設定できるのでしておきます。SpringBoot1.x系は別の変数名になるらしいので注意です。

FROM tomcat:9.0.16-jre8-alpine

ENV SERVER_SERVLET_CONTEXT_PATH /todolist
COPY build/todolist.war /usr/local/tomcat/webapps
EXPOSE 8080

動作を検証する

docker-comopseに下記を追記し、make buildしてみます。[https://one.cool.com:9443/todo]にアクセスしてみるとアプリケーションの画面が表示されました。

  app:
    container_name: tomcat
    build: ./tomcat
    ports:
    - "8080:8080"

f:id:jrywm121:20190218021406p:plain
表示された画面

まとめ

アプリケーションをBuildするところからDockerでできるように今度する。マルチステージビルドが使えそう。

SpinnakerのPipeline Expressionsで他stageの情報を取ってくる

SpinnakerのPipeline Expressions

KubernetesAmazon ECSを絡めたCI/CDでは既にデファクト感のあるSpinnakerですが、日本語の記事が少ないのと公式ドキュメント自体も不足はしてないのですが若干物足りない部分があります。KubernetesのBlue/Green Deployを構築した際にPipeline Expressionsで他stageの情報を取ってくるということをしたんですが、ちょっと分かりづらかったので記事に残しておきます。

とはいえ下記のページ見ていただければ十分とも思います。

Pipeline Expressions Guide - Spinnaker

やりたいこと

以下のような流れでパイプラインを構築したいと考えました。項目はStageの単位と対応しています。 providerはKubernetes V2です。

  • 新しいReplicaSetをDeploy(ただしPod数は1)。
  • Enableし新しいReplicaSetにもTrafficが流れるようにする。
  • manual judgement。このままデプロイを続けるかRollbackするか選択させる。
  • Continue
    • 新しいReplicaSetを本番相当までスケールアウト
    • 古いReplicaSetをDisableしTrafficが流れないようにする
    • 古いReplicaSetのサイズを0にする
  • Rollback
    • 新しいReplicaSetをDisableにする
    • 新しいReplicaSetをdeleteする <- ここが問題になった

ScaleやEnableは、対象をstaticとdynamicに分かれます。staticは固定値かつ既に存在するReplicaSetしか選べないので今回の用途に合いません。Dynamicでは、NewestやSecond Newest等の選択肢があります。逆にそれらの選択肢からしか選べません。常に現在動いているReplicaSetが最新のものである前提でないとPipelineの設定がうまくいきません。そのためRollbackではReplicaSetを削除する必要があります。
このDeleteのstageなんですが、ScaleやEnableと違って削除するリソースをNewestやSecond Newestから選べません。namespace/リソースタイプに加え、リソースの名前もしくはラベルを直接指定する必要があります。リソースの名前を指定するのが手っ取り早そうなのですが、なぜかPipeline Expressionsを記述してSaveしても消えてしまったので、タグの方で実装しました。

Pipeline ExpressionsでDeploy時のラベル情報をとってくる

Spinnakerはデプロイ時にこちらが指定したマニフェストに更に情報を付加するので、最終成果物からラベルを取ってくる必要性があります。 結論から言うと以下です。

${ #stage("Deploy new ReplicaSet").context["outputs.manifests"][0].metadata.labels["moniker.spinnaker.io/sequence"].toString() }

Key名moniker.spinnaker.io/sequenceだけ取ってきていますが、他のラベルに関しては固定値のため取ってくる必要性がありません。 この情報は、http://localhost:8084/pipelines/${PIPELINE_ID}で取ってこれるJSONをベースにアクセスしていきます。PIPELINE_IDは、パイプライン実行結果のDetailを選択し展開されたウィンドウの右下のSourceをクリックして飛ぶURLに含まれています…というか先程のURLそのものになっています。 #stage("ステージ名")でstages配列の中の指定したstageのJSONをルートにしてアクセスできます。outputs.manifestsのようにKeyに.(ドット)が含まれる場合にはmap形式でアクセスしないとだめです。

Pipeline Expressionsをテストする

以下のようにcurlを叩くことでテストできます。

curl  http://localhost:8084/pipelines/${PIPELINE_ID}/evaluateExpression \
-H "Content-Type: text/plain" \
--data '${ #stage("Deploy new ReplicaSet").context["outputs.manifests"][0].metadata.labels["moniker.spinnaker.io/sequence"].toString() }'

まとめ

お家でSpinnkerを試せるような環境が作れれば良いのだけれど…。 お家でKubernetes触りたいときには、Katacodaで今まで動かしていたので、minikube+Spinnakerに自分のPCのスペックが足りるかどうか。

試して理解 Linuxのしくみ 読みました 1章~3章

gihyo.jp

上記を読んだので学んだことをアウトプットしたいと思います。大学の授業で低レイヤのことを学んできませんでした。そのため、本書でLinuxに関して体系的に学べたの非常に良かったです。
本書の中で手を動かすパートに関しては、C言語Pythonの代わりにGo言語を使って試してみてます。また、PCはMacを使っているのですが、Linuxの環境で試したいという気持ちが有ったので、Dockerで仮想的にDebian系のOS上で動かすようにしています。リポジトリは以下になります。

github.com

第1章概要

ハードウェアの動作の流れ

1.外部デバイスから処理を依頼される

2.メモリに存在する命令を読み出してCPUにおいて実行
3.出力する

  • HDDやSSDに書き込む
  • ネットワークを介して別のコンピュータに転送する
  • 出力デバイスを介して人間に見せる

4.1に戻る

コンピュータの起動

  1. BIOSUEFIと呼ばれるハードウェア組込ソフトウェアによるハードウェア初期化処理
  2. 起動させるOSを選択するブートローダが動作
  3. ストレージデバイスからOSを読み出す コンピュータにとってストレージデバイスは欠かせない存在

2章ユーザモードで実現する機能

ユーザモードとカーネルモード

バイスの操作やプロセス管理、メモリ管理、プロセススケジューラなど、通常のプロセスから実行できると困る、OSの核となる処理をまとめたプログラムをカーネルという。
これらは特権モード、即ちカーネルモードで動作する。
OS=カーネルではなく、カーネル以外にもユーザモードで動作する様々なプログラムから構成される。
ユーザモードのプロセス処理から、システムコールを通じてカーネルの処理を呼び出す。それを呼び出すのは、プロセス固有のコードやそれが使用するライブラリ(OS提供のもの・そうでないもの)

CPUのモード遷移

システムコールを発行すると、CPU割り込みが発生。これによって、CPUでは、ユーザモードからカーネルモードに遷移して、カーネルの処理を行う。終わったらユーザモードに戻る。

システムコールの呼び出し

sh main.sh -d 02-syscall-and-non-kernel-os/hello
上述のリポジトリにて、上のコマンドを実行すると以下のような結果を得られました。

-------------------------PROGRAM START-------------------------
hello world
--------------------------PROGRAM END--------------------------
-------------------------SYSCALL START-------------------------
execve("/go/bin/app", ["/go/bin/app"], [/* 7 vars */]) = 0 <0.000401>
arch_prctl(ARCH_SET_FS, 0x54c6b0)       = 0 <0.000087>

***(省略)*******************************************************

fcntl(2, F_GETFL)                       = 0x1 (flags O_WRONLY) <0.000139>
write(1, "hello world\n", 12)           = 12 <0.000149>  
exit_group(0)                           = ?
+++ exited with 0 +++
--------------------------SYSCALL END--------------------------

下から3行目のwriteがデータを画面やファイルに出力する「write()」システムコール。省略している部分もシステムコールだが、それはプログラムの開始処理が発行するもの。

ユーザモードとカーネルモードの割合

自前のアプリケーションを走らせない場合

以下のようにUbuntuの環境でsarコマンドを発行してみた

docker run --rm -it ubuntu:xenial /bin/bash
# apt-get update
# apt-get install -y sysstat
# sar -P ALL 1 1

結果は以下のように得られた

12:36:45        CPU     %user     %nice   %system   %iowait    %steal     %idle
12:36:46        all      0.00      0.00      0.50      0.00      0.00     99.50
12:36:46          0      0.00      0.00      0.00      0.00      0.00    100.00
12:36:46          1      0.00      0.00      0.99      0.00      0.00     99.01

Average:        CPU     %user     %nice   %system   %iowait    %steal     %idle
Average:        all      0.00      0.00      0.50      0.00      0.00     99.50
Average:          0      0.00      0.00      0.00      0.00      0.00    100.00
Average:          1      0.00      0.00      0.99      0.00      0.00     99.01

各行が1つのコアに対応する。今回は殆どがidleモードとなっている。

  • %user -> ユーザモード
  • %nice -> ユーザモード
  • %system -> カーネルモード
  • %idle -> 何もしていない時間

自前の無限ループするだけのアプリケーションを走らせた場合

sh main.sh -d 02-syscall-and-non-kernel-os/loop
上述のリポジトリにて、上のコマンドを実行すると以下のような結果を得られました。

Linux 4.9.93-linuxkit-aufs (aad086a81679)    01/14/19    _x86_64_    (2 CPU)

13:18:18        CPU     %user     %nice   %system   %iowait    %steal     %idle
13:18:19        all     50.00      0.00      0.50      0.00      0.00     49.50
13:18:19          0      0.00      0.00      1.00      0.00      0.00     99.00
13:18:19          1    100.00      0.00      0.00      0.00      0.00      0.00

Average:        CPU     %user     %nice   %system   %iowait    %steal     %idle
Average:        all     50.00      0.00      0.50      0.00      0.00     49.50
Average:          0      0.00      0.00      1.00      0.00      0.00     99.00
Average:          1    100.00      0.00      0.00      0.00      0.00      0.00

CPUコア1上でユーザプロセス、すなわちloopプログラムが常に動作していることがわかる。

自前の親プロセス取得を無限ループするアプリケーションを走らせた場合

sh main.sh -d 02-syscall-and-non-kernel-os/ppidloop
上述のリポジトリにて、上のコマンドを実行すると以下のような結果を得られました。

Linux 4.9.93-linuxkit-aufs (4bbb02f02797)    01/14/19    _x86_64_    (2 CPU)

13:26:00        CPU     %user     %nice   %system   %iowait    %steal     %idle
13:26:01        all     20.71      0.00     30.30      0.00      0.00     48.99
13:26:01          0     41.00      0.00     59.00      0.00      0.00      0.00
13:26:01          1      0.00      0.00      1.02      0.00      0.00     98.98

Average:        CPU     %user     %nice   %system   %iowait    %steal     %idle
Average:        all     20.71      0.00     30.30      0.00      0.00     48.99
Average:          0     41.00      0.00     59.00      0.00      0.00      0.00
Average:          1      0.00      0.00      1.02      0.00      0.00     98.98

CPUコア0上でppidloopプログラムを41%の割合で実行し、親プロセス取得のシステムコールを59%の割合で実行していた。

システムコールのラッパー関数

システムコールC言語などの高級言語から直接呼び出せない。アーキテクチャ依存(amd64とかarmとか?)のアセンブリコードを使って呼び出す必要がある。もしシステムコールをラップする関数を内包するライブラリ群がなければ、アーキテクチャ依存のアセンブリソースを書かなくてはいけない。

標準Cライブラリ

GNUプロジェクトが提供するglibcLinuxの標準Cライブラリとして使用する。glibcシステムコールをラップする関数を内包している。またPOSIXという規格に定義されている関数も提供。
プログラムがどのようなライブラリをリンクしているかは以下でlddコマンドでわかる。

% docker run --rm -it golang:1.11.4 /bin/bash
# which go
/usr/local/go/bin/go
# ldd /usr/local/go/bin/go
    linux-vdso.so.1 (0x00007ffef2965000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe2c2ba2000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe2c2803000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe2c2dbf000)

第3章プロセス管理

fork関数

同じプロセスの処理を複数のプロセスに分ける際に呼び出される(例:Apacheで子プロセスを生成する)。 子プロセス用メモリ領域を作成し、親プロセスのメモリをコピーする。fork関数はカーネルモードからユーザモードに処理が再び移るときに、親プロセスには子プロセスのプロセスIDを、子プロセスには0を返す。これを利用して親子で処理を分岐させる。

sh main.sh -d 03-process-management/fork
上述のリポジトリにて、上のコマンドを実行すると以下のような結果を得られました。 fork()されたときに同じプログラムが複製されて2個同時に動いているような感覚。

I'm parent! my pid is 7 and the pid of my child is 11.
I'm child! my pid is 11.

execve関数

全く別のプログラムを生成するときに呼び出される(例:bashからsleepコマンド実行)。 ます実行ファイルを読み出し、その後現在のプロセスのメモリを上書く。 実行ファイルの中身 * プロセスの実行に必要なコード、データ * コードを含むデータ領域のオフセット(ベースアドレスに加えられるアドレスの数)-> ファイルの情報 * コードを含むデータ領域のサイズ * コードを含むデータ領域のメモリマップ開始アドレス -> コンピュータのメモリのどこにマッピングするか * 最初に実行する命令のメモリアドレス(エントリポイント)

Linuxの実行ファイルはELFというフォーマットを使用する。
エントリポイントのアドレスを得るには「-h」オプション、ファイル内オフセット、サイズ、メモリマップ開始アドレスを得るには「-S」オプション

% docker run --rm -it ubuntu:xenial /bin/bash
# apt-get update
# apt-get install binutils
# readelf -h /bin/sleep
ELF Header:
------(省略)---------------------------------------------
  Entry point address:               0x401760
------(省略)---------------------------------------------

# readelf -S /bin/sleep
There are 29 section headers, starting at offset 0x7370:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
------(省略)--------------------------------------------------------
  [14] .text             PROGBITS         00000000004014e0  000014e0
       0000000000003319  0000000000000000  AX       0     0     16
------(省略)--------------------------------------------------------
  [25] .data             PROGBITS         00000000006071c0  000071c0
       0000000000000074  0000000000000000  WA       0     0     32
------(省略)--------------------------------------------------------

Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

全く新規のプロセスを新規生成する場合には、親となるプロセスからfork()を発行して、復帰後に子プロセスがexec()を発行する。 sh main.sh -d 03-process-management/execve
上述のリポジトリにて、上のコマンドを実行すると以下のような結果を得られました。fork()の直後にexec()が動いています。

sh main.sh -d 03-process-management/execve
I'm parent! my pid is 6 and the pid of my child is 10.
I'm child! my pid is 10.
hello

第4章プロセススケジューラ