もうずっといなかぐらし

かたいなかのブログ

TOEIC L&R 980 取得記

2020年9月13日に行われた第252回 TOEIC® Listening & Reading 公開テストにて 980 点を取得しました。他の方の参考になればと思い、使用した参考書や行った勉強法を共有します。

f:id:katainaka0503:20201006170913p:plain

TL;DR

  • 目標点をとる上で自分に足りない能力はなにか」「しっかり負荷がかかる学習が行えているか」を意識しながら学習を行うことが一番大事
  • DUO3.0Core1900で基礎的な英単語をみっちり鍛えることでTOEIC対策に耐える基礎力をつけましょう。時間をかければ新しい単語や表現の意味を思い出せる状態でやめないこと。英会話レッスン等と組み合わせて覚えた単語を自在に使える状態まで持っていくことが重要。
  • 速読速聴・英単語 TOEIC TEST GLOBAL 900TOEICの問題に似た文章で英単語を覚えていく形式であり、TOEIC風の文章に慣れながら単語を覚えていけるため強くおすすめできる。
  • Part2とPart5は対策が効きやすいパートであり、対策のコスパが非常に高い。
  • 公式模試を解き終わったら本番より難しめの模試を解くのがおすすめ。私は精選模試2のリスニングリーディングを使用

具体的な学習内容以前の話

使った参考書やWebサービス等の解説の前に先に書いておきたいのですが、「この記事に書いてあったからこの本をやる」「この記事に書いてあったから参考書をN回繰り返す」というスタンスで勉強に取り組んでいるうちは個人的にはどこかでTOEICの点数が頭打ちになってしまう可能性が高いんじゃないかと思っています。

あくまでこの記事で書かれていることは参考程度にとどめ、「目標を達するために自分に今足りない能力はなにか」「どのようなトレーニングを行うと目標に近づけるか」「今の学習方法はしっかり負荷がかかる方法になっているか(特にシャドウイング)」を常に自問自答し、学習法を決めていくことをおすすめします。

具体的な学習内容

英語学習スタート前の状態

  • 小中学校では英語が比較的得意だった
  • 高校時代にDUO3.0を使ったことがある
  • 大学受験をしなかったので大学受験のための英語学習は未経験
  • TOEIC受験経験なし

TOEIC用の勉強開始前(2019.06 ~ 2020.5)

この頃は特に資格試験を受けるつもりはなく、「英語のドキュメントや海外カンファレンスの動画を理解できるのってかっこいいな」という単純な動機で学習をはじめました。

当初の動機は仕事で活かすことでしたが次第にレアジョブのレッスン内でいかにうまく話せるかということに主眼が移っていきました。

今から考えるとすぐにTOEIC対策に取り掛からず、DUO3.0やCore1900および英会話レッスンで基礎的な英語力をじっくり高めたことが、後のTOEICでの高得点につながったのではないかと思います。

英会話レッスン(レアジョブ)

この時期に英語学習の中心になっていたのはレアジョブというサービスでの1日25分の英会話レッスンでした。

レアジョブのレッスンでは、最初は日常会話用の教材を使っていたのですが、レッスンに慣れた後はDaily News Articleという教材を使っていました。この教材は毎日配信される記事を題材にディスカッションするというもので、記事の内容が面白く毎回レアジョブの先生と議論するのが楽しかったのを覚えています。

ただレッスンを惰性で受けるだけでは受動的な学習になってしまい効果が薄いと感じたため、瞬間英作文の練習やDUO3.0/Core1900の音読・シャドウイングを行った直後にレッスンを受けるようにしていました。これにより、覚えたばかりの能動的に使うことができない語彙を自然と背伸びして使うことになったため、結果として能動語彙が増え、能動語彙が増えると英会話のレッスンが楽しくなるという良いループが生まれていました。

瞬間英作文

英会話のレッスンを受け始めてすぐに、言いたいことを文章の形で伝えることができないという壁にぶつかったため瞬間英作文の練習を行いました。

中学校で習うような英文を文字通り瞬間的に英作文する学習法です。

上記2冊の参考書でしばらくトレーニングを行うことで、簡単な英文であれば一瞬で口から出せるようになりました。

ある段階で瞬間英作文は卒業して単語帳のシャドウイングに練習の中心を移したのですが、TOEIC用の勉強を始めた後も特定の文法が苦手(使役動詞等)だと感じたら瞬間英作文風に作文して練習するなど、文法を能動的に使える状態に持っていく方法としては学習期間を通して活用していました。

単語帳

よく使われる表現を覚え英会話で役立てるためにDUO3.0とCore1900という2つの単語帳を使用しました。この頃はTOEICの受験は考えていませんでした。

DUO3.0

DUO3.0は1600個の重要単語と熟語1000個を560本の基本例文を通して覚えていく、いわゆる短文型の単語帳です。Natto smells awful but tastes terrific. のような短文の中に覚える必要がある単語が散りばめられており、例文を暗記するだけで重要な単語を効率的に覚えられます。短文自体も退屈にならないように工夫がされており、ドジなボブの話などクスッと笑ってしまうような短文も多いです。

別売りで基礎用と復習用の2種類のCDが発売されているのですが、CDのあるなしで学習効率が段違いなのでかならずCDを入手し耳も使って覚えていくと良いと思います。基本的には復習用のみ買えばシャドウイング等の練習には十分です。

レアジョブのレッスン前の準備体操として毎日1冊の1/4程度をシャドウイングし、土日など時間がある時に音読をするという感じで1ヶ月程度使用していました。高校時代に学習教材として使っていて内容を半分程度覚えていた状態だったため、完全に初見の方はもう少し長めにやっても良いかもしれません。

速読速聴・英単語 Core1900

速読速聴・英単語は単語帳の中で個人的に最もおすすめできるシリーズです。

このシリーズはいわゆる"文脈型"単語帳であり覚える必要がある単語が散りばめられた 120 語程度の文章を使って単語を学習していきます。長文を使って学習していくので、シャドウイングや音読の教材として使うことで新しい単語を覚えることにとどまらず、リスニングや長文読解等すべての英語力をバランス良く伸ばせる教材だと感じています。

Core1900はPart1とPart2に分かれていて、Part1は120語程度のニュース記事とその中に登場した見出し語がまとまっているいわゆる文脈型単語帳の形式、Part2はDUOのような短文型単語帳形式です。特にPart1の文章には「光害の問題」など読み物としても普通に面白い記事が多くおすすめできます。

新しい記事に取り組む際には以下のようにしていました。

  • 英文を一度も読んでいない状態で音声を3回程度聞き、耳だけで英文を理解する練習をする
  • 英文を読んで聞き取れなかった部分・新しい単語を確認
  • 3回音読
  • シャドウイングを数回(1.2 倍速まで次第にスピードアップ)

この本で出た表現は、2ヶ月程度この本音読・シャドウイングをした直後に英会話レッスンを受けることを繰り返すことで、一部の難しい表現を除いて英会話の中で自然に使える状態を目指してトレーニングを行っていました。これにより基礎的な単語の運用力がかなり鍛えられました。

TOEIC 勉強開始(2020.05 ~ 2020.07)

レアジョブのレッスン内で自信がついたので、力試しを兼ねてTOEICを受けてみようと学習を開始しました。

この時期に最も重視したのは以下です。

  • TOEIC用単語の習得
  • TOEICのリーディングパートより少し難しい記事の多読によるリーディングスピードの向上
  • Part2対策(対策が行いやすいため早めにスタート)
  • Part5対策(対策が行いやすいため早めにスタート)

TOEIC用単語

速読速聴・英単語 TOEIC TEST GLOBAL 900

TOEIC用単語の習得には主に速読速聴・英単語 TOEIC TEST GLOBAL 900を用いました。

TOEICのPart3,4,6,7のような文章を使って単語を覚えていく文脈型単語帳です。使用法はCore1900のときとほぼ同様で、音読・シャドウイングを繰り返し、直後に英会話レッスンを受けることでなるべく新しく学んだ語彙を能動的に使える状態を目指して練習しました。

個人的にはこの本で飽きるまでTOEICっぽい文章を音読・シャドウイングしたことでリスニング力とリーディング速度の両方に効いたと感じており、TOEIC対策単語帳として強くおすすめできます。

金のフレーズ

GLOBAL 900の補助としてTOEIC L & R TEST 出る単特急 金のフレーズ(通称金フレ)を使用しました。こちらは語彙に抜けがないことやTOEIC特有の語義等をチェックするために使いました。ただ、個人的にフレーズで覚えていくスタイルが肌に合わなかったので2周程度でやめてしまいました。

Japan Timesの記事を読む

TOEIC のリーディングパートよりやや難しい文章でリーディング速度向上トレーニングをするため、Japan Timesの記事を空き時間で読むようにしていました。

新しい記事を読む際には以下のように読んでいました

  1. 時間を計測しながら読む
    • 意味がわからなくなったり文章構造が掴めなくなってもなるべく戻り読みをしない
    • 英単語の意味は調べない
    • どのあたりに何が書いてあったかなんとなく理解できる程度の理解度で読めるのが理想(Part7のような問題を解くために必要な情報が文章のどのあたりに書かれていたかぼんやりわかるぐらい)
  2. 読み終わったら単語数を時間で割り、おおよその WPM を確認する(私の場合はWPM160ぐらいで理解度を最大にするため、WPMを元に読み方を調整していました)
  3. 同じ記事を時間をかけて文章構造を正確に把握することを意識しながらもう一度読む。英単語は記事の意味を理解するのに支障がある場合だけ調べる

Part5 対策

Part5 の対策としては、まず Evergreen(旧 Forest)を問題集を合わせて一通り通読しました。

後から考えるとこの本は重箱の隅をつつくような文法事項の解説も多く、通読するよりも辞書的に使ったほうが効率的だったかもしれません。

その後、Evergreen(旧 Forest)を 7 割程度頭に入れた状態で以下の問題集を使って対策を行いました。

多いようですが、Part5は明らかに対策が効きやすいパートであると感じていたため、対策を重点的に行いました。

Part2 対策

Part2 の対策としては、以下の問題集を用いて問題演習および聞けなかった問題の復習を繰り返しました。

Part2 の勉強では必然的にたくさんの短い文を聞くことになるため、自分がリスニングする上で苦手な音や表現を自覚することができました。

以下の参考書もレビューが良いので Part2 が苦手な方は追加で取り組んでも良いかもしれません

受験直前期(2020.07 ~ 2020.09)

直前期には以下の模試をひたすら解いていました。

精選模試は本番より難しいという評判なのですが、難しい問題を高地トレーニングとして解き、また一度解いた難しい問題を使ってリスニングの練習等を行ったことで、本番ではかなり余裕を持って解答できました。

模試を解くときには以下のようにしていました。

  • 新しい模試を解く・採点
  • 間違えた問題・わからなかった単語の確認
  • Part2 で聞けなかった問題をリストアップ・数回聴く
  • Part3,4 を1.3倍速でシャドウイング(何日かに分けて 3~5 周)
  • 1.3倍速にしてリスニングパートを再度解く(リーディングパートは解かなかった)

1.3倍速でリスニングパートを再度解いたのは、先読み等の解答プロセスに集中した練習を行うためでした。模試を解く中で先読みが苦手だと感じていましたが、一度解いた問題を1.3倍速再生しながら先読みの練習をすることで、普通の速度で問題を解く時に余裕を持って先読みが行えるようになりました。

模試の素点

個人的に模試を解いている際に、「模試の素点が何点ぐらいなら本番で目標点に達するか」がわからなくてとても不安だったため、せめてもの目安になればと私が模試を解いた際の素点を晒しておきます。

L R 備考
公式模試 6 T1 91 92
公式模試 6 T2 94 97
精選模試 2 T1 77 93 精選模試の洗礼で大きく L が下がる
精選模試 2 T2 93 91
精選模試 2 T3 88 93
精選模試 2 T4 89 94
精選模試 2 T5 89 98
公式模試 5 T1 98 94
公式模試 5 T2 98 97
公式模試 4 T1 97 97
公式模試 4 T2 99 94

精選模試には本番での予想得点の換算表が載っているのですが、私個人の話で言うと本番では換算表の点数より+20~30点ぐらいの点数が出たのでこちらも参考として。

まとめ

ここに紹介したような対策でTOEICの本番では980点を獲得することができました。誰かのお役に立てば幸いです。

Kubernetesにシステム系コンポーネントを入れるときは監視も一緒に設定しよう

Kubernetesの利点の一つとしてOSSのコミュニティで開発された独自のシステム系コンポーネントを導入することで、自分たちのニーズに合わせた運用性の向上が望めるという点があります。

転職会議でもALB Ingress ControllerやSealedSecrets等のシステム系コンポーネントを導入しています。

このようなコンポーネントは多くの場合ドキュメントに従って手を動かすだけで(場合によってはYAMLクラスタに適用するだけで)導入が完了するほど容易に導入できるのですが、ここで見落としがちなのが導入後の運用です。運用を滞りなくおこなうためには導入されたコンポーネント当然監視されている必要があります。

転職会議ではDatadogのAutodiscovery機能を使用してPrometheusのエンドポイントからDatadogにメトリクスを取得して監視を行っているのでその設定例等を紹介します。

何を監視したいか

転職会議ではEKS上に以下のようなコンポーネントを導入しています。

  • Flux
  • Sealed Secrets
  • Velero
  • Reloader
  • AWS ALB Ingress Controller
  • Cluster Autoscaler
  • ExternalDNS

このとき例えば以下のような問題が起きたらすぐにSlack等に通知させたいです。

転職会議ではSREだけではなくアプリケーションエンジニアも自分が担当するサービスのKubernetesYAMLを日々編集しています。そのためSREとしては、上のような問題が起きた場合には本番だけでなくステージングや開発環境でもなるべく早く開発者に知らせてあげることで、安心してKubernetesYAMLを修正しやすい環境を作りたいと考えています。

そのため、独自システムコンポーネントの監視によって問題発生時にはすぐに通知されることは重要です。

どうやって監視するか

実は多くの場合独自のシステム系コンポーネントにはPrometheusのエンドポイントが生えているため、Prometheus形式のメトリクスに対応したツールを使うことでこれらのメトリクスを監視に用いることができます。

例えばALB Ingress Controllerであれば 10254 番ポートの /metrics というパスにアクセスすることで以下のようなPrometheus形式のメトリクスが返ってきます。

...略....
aws_alb_ingress_controller_aws_api_errors{operation="DescribeListenerCertificates",service="elasticloadbalancing"} 2
aws_alb_ingress_controller_aws_api_errors{operation="DescribeLoadBalancers",service="elasticloadbalancing"} 9
aws_alb_ingress_controller_aws_api_errors{operation="DescribeTargetGroups",service="elasticloadbalancing"} 15
aws_alb_ingress_controller_aws_api_errors{operation="GetToken",service="ec2metadata"} 1
aws_alb_ingress_controller_aws_api_errors{operation="ModifyRule",service="elasticloadbalancing"} 38
aws_alb_ingress_controller_aws_api_errors{operation="RegisterTargets",service="elasticloadbalancing"} 7
...略....

このようなPrometheusのエンドポイントから取得したアプリケーションの動作を表すメトリクスを用いて問題発生時にアラートを飛ばすことができます。監視ツールとしてPrometheusを使用している場合はAlertmanager等を使ってアラートを飛ばすことができます。

転職会議では監視にDatadogを使用しているため一旦Datadogにメトリクスを集めて、Datadogからアラートを飛ばすようにしています。

その際に使用しているのがDatadogのAutodiscovery機能です。監視対象のPodに以下のようにアノテーションを設定するだけで、Datadog AgentがPodのアノテーションを解釈し自動的にメトリクスをDatadogに送るようになります。

# 以下はCluster AutoScalerでの設定例
# Podのアノテーション
annotations:
  # datadogでPrometheusエンドポイントからメトリクスを取得する
  # ad.datadoghq.com/<コンテナ名>から始まるアノテーションを設定
  # コンテナ名はPodのcontainers[].nameで指定している名前
  ad.datadoghq.com/cluster-autoscaler.check_names: '["openmetrics"]'
  ad.datadoghq.com/cluster-autoscaler.init_configs: '[{}]'
  ad.datadoghq.com/cluster-autoscaler.instances: '[
    {
      # Prometheusエンドポイント
      # "prometheus_url": "http://%%host%%:<ポート番号>/metrics",
      "prometheus_url": "http://%%host%%:8085/metrics",
      # Datadogのメトリクスのnamespace。
      # これによりDatadog上でのメトリクスが"<ここで設定したnamespace名>.<メトリクス名>"というような名前になる
      "namespace": "prometheus",
      # 取得するメトリクス名のフィルタ 
      # "metrics": ["<metrics名のフィルタ>"]
      # Goのランタイムのメトリクス等も取りたいなら以下
      # "metrics": ["*"]
      "metrics": ["cluster_autoscaler_*"]
    }
  ]'

あとはDatadogの機能で普通にアラートを設定するだけです。Slackに通知すると以下のような感じです。

f:id:katainaka0503:20200811164840p:plain

まとめ

運用を楽にするような独自コンポーネントを導入しやすいのはKubernetesの大きな利点です。この大きな利点を最大限に利用するためにも、新しいコンポーネントを入れる際には監視やアップデートを含めたプロダクトのライフサイクルで起こりそうな問題を考えておくようにしましょう。

参考資料

EKSのIAM Role for Service Accountsを使用するときにはSTSのリージョナルエンドポイントを使うように設定しようという話

先日、DynamoDBにアクセスするAPIをLambdaからEKS上への再実装・載せ替えを行いました。その際、IAM Role for Service Account(IRSA)を使用した一時クレデンシャル取得時のレイテンシが大きく高まる事象に遭遇しました。

原因と解決策を調査から解決に至るまでの過程とともにご紹介します。

TL;DR

IRSAを使用する際は一時クレデンシャル取得時にSTSにリージョナルエンドポイントを使用させるためAWS_STS_REGIONAL_ENDPOINTS=regionalという環境変数を設定することを検討すること。

経緯

現在転職会議ではECS or Lambdaで実装された既存のサービスを順次EKS上に載せ替えていっています。

先日、私がLambdaで実装されていたAPIをGoで再実装しEKS上に載せ替えました。このAPIはDynamoDBの中身をレスポンスとして返すという極めてシンプルなAPIです。

リプレース後、レイテンシの平均をとってみると以前のLambdaでの実装よりも速くはなっていたのですが、1時間おきにレスポンスが2s程度まで跳ねあがる現象が発生しました。

f:id:katainaka0503:20191225185947p:plain
レイテンシの最大値

Datadog APMでレイテンシ急増時のフレームグラフを見てみると、2秒かかっているうちDynamoDBへのアクセスにかかっているのはリクエスト処理時間のうち最後の方の0.2秒程度だけであることが分かりました。

f:id:katainaka0503:20191225191141p:plain

ここまでのことから、DynamoDBにアクセスする前に必要な処理でありかつ1時間おき発生する処理が原因と考えられ、その両方に当てはまるIAM Role for Service Accounts(IRSA)による一時クレデンシャルの取得処理が疑わしいと考えました。

そこで、行われている動作をもう少し詳しく調べるため、ステージング環境でtcpdumpで調べてみることにしました。具体的な手順としては以下です。

  1. kubectl execAPIサーバのコンテナに入る
  2. tcpdumpをコンテナにインストール
  3. tcpdumpでダンプを取得
  4. ダンプファイルをkubectl cpでローカルにコピー
  5. Wiresharkでダンプファイルを見る

ダンプファイルを見てみると、STSとの通信ログからSTSへのアクセスに1.5s程度時間がかかっていることがわかりました。どうやら、Kubernetesの発行したトークンで一時クレデンシャルを取得するSTSAssumeRoleWebIdentityで時間がかかっているようです。 f:id:katainaka0503:20200106180125p:plain

ダンプの中身を詳しく見てみると、DNSの通信ログからそのSTSへのアクセスにグローバルエンドポイント(sts.amazonaws.com)が使用されていることがわかります。

STSでは可能な場合はリージョナルエンドポイント(sts.<region名>.amazonaws.com)を使用することが推奨されています。そこで、AWS_STS_REGIONAL_ENDPOINTS=regionalという環境変数を設定してリージョナルエンドポイントが使用されるように設定しました。

すると、デプロイ直後と1時間毎に発生している一時クレデンシャル取得時のAPIのレイテンシが2秒から0.4秒程度まで大きく改善しました!

f:id:katainaka0503:20200106182058p:plain
レイテンシの最大値

念の為ダンプファイルをとってみると、変更後は一時クレデンシャル取得時にはちゃんとSTSのリージョナルエンドポイントと通信していました。

f:id:katainaka0503:20200106181535p:plain

まとめ

IRSAにより一時クレデンシャルを取得してAWSAPIへアクセスするときはAWS_STS_REGIONAL_ENDPOINTS=regionalという環境変数を設定することを検討してください。この環境変数は最近のバージョンのAWS SDKおよびAWS CLIであれば使用できるようです。(ほかにSTSのリージョナルエンドポイントを使用させるもっとよい方法があればこっそり教えて下さい)

問題調査をするときには必要とあれば抽象化の皮を剥がして調査する能力が大事だと強く感じる事件でした。

参考資料

株式会社リブセンスに入社して1ヶ月が経ちました

はやいもので明日でリブセンス入社1ヶ月目の業務が終わり今年の仕事納めとなります。

今回の記事では私の入社1ヶ月での業務内容や入社1ヶ月目の所感などを書いていきます。

やったこと

キャッチアップ

入社時点で配属先である転職会議のインフラ周りがかなり整っていたことや、1on1等を厚めに行ってくれたこともあり、現状の把握に大きく時間を取られることがありませんでした。

AWS Lambda(Node.js)で作られたAPIをGo(Gin) on EKSにリプレース

  • コピペされることを想定してKubernetesYAMLは基本的なベストプラクティスを意識して作成
    • limit, requestsの設定
    • preStopでsleep
    • PodDisruptionBudget
  • Webサーバも最低限必要そうな事項を意識して実装
  • IRSAを使用したことに関連するパフォーマンスバグ対応(後日記事化)

DatadogのエージェントをEKSクラスタに導入

RDSの証明書更新対応準備

  • メンテ日時の設定
  • ステージング環境でのリハーサル

HackDays(年末最終週がリリース禁止であるため、その間エンジニアが好きな技術で遊んで成果を発表する社内イベント)

その他

  • Node.js製APIサーバにDatadogのAPMのトレーサーを仕込む
  • メールのテスト用に使用していたmailhogをECSからEKS上に移行
  • DynamoDBをオンデマンド化

入社1ヶ月の所感

事業会社のSREとして働くのは初めての経験でしたが、周りの方のサポートもありスムーズに入っていくことができました。一緒に働くエンジニアの方々はみんなそれぞれレベルが高く、担当領域を超えたところにも改善を行っていく強いマインドを持っていて一緒に働いていてとても楽しい1ヶ月でした。

コミュニケーションの面でも1 on 1やエンジニアが全員集まって課題を話し合うMTGなどうまく交通整理されており、かなりやりやすさを感じました。

転職会議のインフラ面での現在の課題である全面EKS化に向け、来年はさらに気合いを入れて頑張っていきたい所存です。

EKS上でもBerglasみたいにクレデンシャルをいい感じにしたい!!!

こちらはAmazon EKS #1 Advent Calendar 2019 4日目の記事です。

こんにちは、かたいなかです。株式会社リブセンスに入社してはや一ヶ月弱が経過しました。

私が所属する転職会議事業部では、ECSからEKSへの移行を進めています。その中で現在議論が白熱しているのがクレデンシャルの管理方法についてです。検討の中で「GCPにはBerglasという便利ツールがあり、Podに渡す環境変数をよしなに指定するとSecret Managerにあるクレデンシャルをいい感じに展開してくれる」という話を同僚に聞きました。

github.com

そこで、今回はMutationWebhookの実装の素振りを兼ねてEKS上でAWS Secrets ManagerからBerglas同様にクレデンシャルを取得するしくみを作ってみましたのでご紹介します。

TL;DR

Beglas風にAWS Secrets Managerからクレデンシャルを取ってきてくれるツール(Not Production Ready)を試験的に作成。MutationWebhookは便利だが劇薬なので用法用量注意が必要。

Berglasとは

BerglasはGCPが提供しているGCP上に保存されたクレデンシャルを便利に扱うツールです。

BerglasのCLIにはberglas exec --というコマンドで実行するラッパーの機能があります。このコマンドを実行する際、berglas://<credentialへの参照>という形式の値を持つ環境変数があると、当該の環境変数を参照先から取得した実際の値に置き換えてラップされたコマンドを実行します。

$ export API_KEY="berglas://<credentialへの参照>"
#"API_KEY"の値が参照先のクレデンシャルの値で置き換わった状態で"--"の後ろに指定したコマンドを実行
$ berglas exec -- some command

MutationWebhook

前節で紹介したCLIツールをどのようにKubernetesと連携させればよいかについては、BerglasのGitHubリポジトリKubernetesのMutationWebhookのサンプル実装が置かれています。(https://github.com/GoogleCloudPlatform/berglas/tree/master/examples/kubernetes)

このサンプル実装では、Podの作成時にberglas://<credentialへの参照>環境変数が設定されている場合、initContainerでBergalsのコンテナからemptyDirのボリュームにバイナリをコピーする設定を追加します((1)の部分)。そして、commandを書き換え、もともと指定されていたコマンドをberglas exec --でラップするように設定します((2)の部分)。以下のようなYAMLが作成されます。

apiVersion: v1
kind: Pod
metadata:
  name: envserver
spec:
  # ボリュームにberglasのbinを流し込むinitContainersを追加(1)
  initContainers:
    - name: copy-berglas-bin
      image: gcr.io/berglas/berglas:latest
      imagePullPolicy: IfNotPresent
      command: ["sh", "-c", "cp /bin/berglas /berglas/bin/"]
      # berglasのバイナリ流し込み用ボリューム
      volumeMounts:
        - name: berglas-bin
          mountPath: /berglas/bin/
  containers:
    - name: server
      image: katainaka0503/server
      imagePullPolicy: Always
      # もとのPodで指定していたcommandを「"berglas exec --"でラップして実行するように修正(2)
      # command: ["/bin/server"]
      command: ["/berglas/bin/berglas"]
      args: ["exec", "--", "/bin/server"]
      env:
        # berglas://の形式の環境変数がある場合にPodを編集
        - name: API_KEY
          value: berglas://berglas-test-secrets/api-key
        - name: TLS_KEY
          value: berglas://berglas-test-secrets/tls-key?destination=tempfile
      # berglasのバイナリ流し込み用ボリューム
      volumeMounts:
        - name: berglas-bin
          mountPath: /berglas/bin/
  volumes:
    # berglasのバイナリ流し込み用ボリューム
    - name: berglas-bin
      emptyDir:
        medium: Memory

これにより以下のような利便性が提供されます。

  • 環境変数GCP上に保存されたSecretの参照を指定するかたちのため、リポジトリ上でのYAMLの暗号化等は不要
  • 実行時にemptyDirボリューム経由でラッパーのバイナリを埋め込むことで、アプリケーションのDockerfileに手を入れることなくKubernetesデプロイ時にラッパーを実行
  • Podのenv等にクレデンシャルが展開されたりもしないので機密性が高い

ただし、Podの設定のcommand, argsで指定しているコマンドをラッパースクリプトの中で実行させる仕組みであるため、command, argsがPodのYAMLの中で明示的に指定されている必要があります。(Dockerfileで指定したENTRYPOINT, CMDをそのまま使わせることができない)

AWSでもBerglas風にクレデンシャルを管理したい

さて、ここからが本題です。GCPでできることはAWS上でも同じようにやりたくなるのが自然な心理です。そこで、今回はBerglasと同様の仕組みでSecretsManagerから値を取得できるようなWebhookおよびCLIを写経を兼ねて実装してみました。

今回のコードは私が自身の学習用に作成したものです。継続的にメンテナンスするつもりは現在のところないので、そのまま使用することはおすすめしません。

動作

今回作成したものをデプロイした状態で以下のようなYAMLでPodを作成しようとすると、

apiVersion: v1
kind: Pod
metadata:
  name: server
  annotations:
     eks.amazonaws.com/role-arn: hogehoge
spec:
  containers:
    - name: server
      image: server:any-tag
      command: ["/bin/server"]
      # berglas-aws://<Secrets ManagerのARN>の形式の環境変数がある場合にPodを編集
      env:
        - name: API_KEY 
          value: berglas-aws://arn:aws:secretsmanager:<REGION>:<ACCOUNT_ID>:secret:<SECRET_ID>

以下のようなYAMLに修正されてPodが作成されます。

apiVersion: v1
kind: Pod
metadata:
  name: server
  annotations:
     eks.amazonaws.com/role-arn: hogehoge
spec:
  # ボリュームにberglas-awsのbinを流し込むinitContainersのを追加
  initContainers:
    - name: copy-berglas-aws-bin
      image: katainaka0503/berglas-aws:latest
      imagePullPolicy: IfNotPresent
      command: ["sh", "-c", "cp $(which berglas-aws) /berglas-aws/bin/"]
      # berglas-awsのバイナリ流し込み用ボリューム
      volumeMounts:
        - name: berglas-aws-bin
          mountPath: /berglas-aws/bin/
  containers:
    - name: server
      image: katainaka0503/server
      imagePullPolicy: Always
      # もとのPodで指定していたcommandを「"berglas exec --"でラップして実行するように修正(2)
      # command: ["/bin/server"]
      command: ["/berglas-aws/bin/berglas-aws"]
      args: ["exec", "--", "/bin/server"]
      env:
        # berglas-aws://<Secrets ManagerのARN>の形式の環境変数がある場合にPodを編集
        - name: API_KEY 
          value: berglas-aws://arn:aws:secretsmanager:<REGION>:<ACCOUNT_ID>:secret:<SECRET_ID>
      # berglas-awsのバイナリ流し込み用ボリューム
      volumeMounts:
        - name: berglas-aws-bin
          mountPath: /berglas-aws/bin/
  # berglas-awsのバイナリ流し込み用ボリューム
  volumes:
    - name: berglas-aws-bin
      emptyDir:
        medium: Memory

これにより、特定の形式で環境変数を指定するとAWS Secrets Managerに保存した値を取ってきて環境変数に設定した状態でコマンドを実行してくれるようになります。

CLI

CLI部分はBerglasの実装を参考に実装しました。

https://github.com/katainaka0503/berglas-aws

本家Berglasと同様に、ラップされたコマンドを実行する際に、berglas-aws://<SecretsManagerのARN>という形式の環境変数があればSecretManagerから取得した実際のシークレットの値で当該環境変数を置き換えます。

$ export API_KEY="berglas-aws://<SecretsManagerのARN>"
#"APK_KEY"の値が参照先のAWS Secrets Managerに保存された値で置き換わった状態で"--"の後ろに指定したコマンドを実行
$ berglas-aws exec -- some command

Webhookの実装

Webhookの部分も同様にBerglasのKubernetesへのデプロイのサンプルを参考にkube-webhookというフレームワークを使用して作成しました。

https://github.com/katainaka0503/berglas-aws-webhook

こちらも本家と同様の仕組みで、Pod作成時にberglas-aws://<SecretsManagerのARN>という形式の環境変数がある場合にcommandargsをいじってberglas-aws exec --でラップして実行されるように修正します。

Kubernetesへのデプロイ

最後にWebhookをKubernetesにデプロイする部分です。

https://github.com/katainaka0503/berglas-aws-webhook/tree/master/deploy

MutationWebhookを設定する際には、Webhookサーバ用の証明書とkube-apiserverがWebhookサーバが提供する証明書を検証するためのルート証明書が必要です。今回はCertManagerを使用して証明書を発行しました。それ以外は概ね通常のDeploymentとServiceを使用したAPIサーバの構成です。

まとめ

Secret管理方法の検討とMutationWebhookの学習を兼ねてBerglas風にAWS Secrets Managerからクレデンシャルを取得できるツールを作成して遊んでみました。想像の数倍容易に実装できたので意外でした。実装したツールを継続的にメンテナンスしていける組織であれば、このようなWebhookの仕組みを用意する方法がシークレットの管理方法として選択肢に入ってくるのかもしれません。

今回のコード

参考資料

補足: ECSでは

ちなみにECSでは、ここまで紹介してきたようなECSのタスク起動時にクレデンシャルの値をとってきて環境変数に設定する機能がすでに提供されています。タスク定義内のコンテナ定義のsecretsという属性にAWS Secrets Manager/AWS Systems ManagerパラメータストアのARNを指定すれば、参照先から保存された値を取ってきてくれます。

dev.classmethod.jp

EKSでの認証認可 〜aws-iam-authenticatorとIRSAのしくみ〜

こちらはAmazon EKS #1 Advent Calendar 2019 7日目の記事です。

EKSでIAM RoleをUserAccountに紐付けたり、ServiceAccountをIAM Roleに紐付けたりする際、AWSのドキュメントに従って設定してはいるものの、その設定によって実際にどんな処理が行われているかを具体的に知らない方も多いのではないでしょうか?(私も今回の記事のために調べるまではそうでした。)

そこで今回の記事では、Kubernetesの認証認可の仕組みを解説したあと、AWSのIAMの認証情報をKubernetes内のUserAccountに紐付けるaws-iam-authenticatorの動作の仕組みとKubernetesのService AccountにIAM Roleを紐づける仕組みについて設定方法のレベルから一段掘り下げて実際の動作に焦点を当てながら説明していきます。

目次

Kubernetesの認証認可・AdmissionControl

まずは事前知識として、Kubernetesの認証認可およびAdmission Controlの仕組みについておさらいしていきましょう。KubernetesでのAPIサーバへのリクエストは、実際にその内容に従って処理を行う前に以下の各stageで順番に処理されます。

  1. Authentication(認証)
  2. Authorization(認可)
  3. Admission Control (リクエストのバリデーション・変更等)

それぞれ順番に見ていきましょう。

Authentication(認証)

認証方法

KubernetesではBasic認証を使用した方法やクライアント証明書を使用する方法など、様々な認証方法が提供されています。

EKSでは主に以下の2つの認証方法が使用されています。

  • Service Account Tokens
    • ServiceAccountに紐付いたトークンをAPIサーバに送信し、APIサーバがそのトークンを検証します。
    • 後のServiceAccountの節で詳しく説明します。
  • Webhook Token Authentication
    • クライアントからAPIサーバに送られたトークンをさらに別のプロセスにWebhookで投げて検証を委譲します。
    • aws-iam-authenticatorによるIAMとUserAccountのリンクはこれにより実現されています。

認証主体

Kubernetesの認証主体は以下の2種類です。

  • ServiceAccount
  • UserAccount
ServiceAccount

ServiceAccountはKubernetesAPIによって管理される名前空間に紐付いたリソースです。

ServiceAccountごとに、Kubernetesクラスタが発行したトークンをクラスタ内のSecretとして保持しています。Podのコンテナにこのトークンを埋め込み、Pod内のプロセスにこのトークンを使用させることでkube-apiserver から認証されます。

ServiceAccountは以下のようなYAMLで定義します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: test
  namespace: default
secrets: # ServiceAccount作成後のSecret作成に伴って追加される
- name: test-token-mfb7n

ServiceAccountを作成すると、TokenControllerによってトークンを保持する以下のようなSecretが作成されます。

# 見やすいよう項目の順番を入れ替えた
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  # 省略
  name: test-token-xxxxx
  namespace: default
  # 省略
data:
  ca.crt: LS0...(省略)...= # APIサーバのCA証明書がBase64エンコードされたもの
  namespace: ZGVmYXVsdA== # 名前空間名がBase64エンコードされたもの
  token: ZXI...(省略)...= # JWT形式のトークンがBase64エンコードされたもの

このようなSecretはServiceAccountを指定してPodを作成すると、自動でマウントされます。具体的には、後述するAdmission Controllerの仕組みによってPodに以下のような設定が追加されます。

volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
  name: test-token-xxxx
  readOnly: true
  volumes:
  - name: test-token-xxxx
    secret:
      defaultMode: 420
      secretName: test-token-xxxxx

これにより、コンテナ内の/var/run/secrets/kubernetes.io/に以下のような3つのファイルが作成されます。

なお、ServiceAccountを指定せずにPodを作成すると、Podと同じnamepaceのdefault という名前のServiceAccountの指定が追加され、defaultのServiceAccountに紐付いたトークンが埋め込まれます。これも後述するAdmission Controlによるものです。

KubernetesのGo ClientではPodにトークンが埋め込まれた状態で以下のような設定をすることで、APIサーバへのアクセス時にAuthorization: Bearerヘッダでトークンを送信するようになり、認証された状態で操作を行うことができるようになります。(エラーハンドリング処理は省略)

config, err := rest.InClusterConfig()
clientset, err := kubernetes.NewForConfig(config)
UserAccount

UserAccountはServiceAccountとは違い、Kubernetesの外部で管理されているユーザです(=kubectlでUserAccountを作成するようなことはしない)。外部の認証情報と連携して使用されることが意図されており、例えばGKEではGCPのアカウントとリンクしていたりします。

EKSの場合はaws-iam-authenticatorという仕組みを使用し、IAMの認証情報から得たトークンを使用しKubernetes内のユーザに紐付けることができます。こちらは後ほど詳しく解説します。

Authorization(認可)

Kubernetesでの認可はRBAC(Role Based Access Control)と呼ばれる仕組みです。RBACではRole or ClusterRoleで許可する操作を定義し、RoleBinding or ClusterRoleBindingでServiceAccount等に紐付けます。Role or ClusterRoleはAWS IAMロールと名前は似ていますが認証される主体ではなく、むしろ権限を定義するIAMポリシーに近いものです。

以下はClusterRoleとClusterRoleBindingでServiceAccountにPodに対する操作を許可する場合の例です。

まず、ClusterRoleで許可する操作を定義します。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

これをClusterRoleBindingでServiceAccountに紐付けます。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-pods-test
subjects:
- kind: ServiceAccount
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

これにより、ServiceAccountが紐付いたPod内からClusterRoleで許可された操作が行えるようになります。

Admission Control

Kubernetesでは、認証及び認可の処理が終わったリクエストを実行する前に、さらにAdmission Controlという仕組みで内容のバリデーションと修正を行います。

様々なAdmissionControllerが用意されており、基本的にはkube-apiserverと一緒にコンパイルされ同じバイナリにまとめられています。ただし、MutatingAdmissionWebhookValidatingAdmissionWebhook を使用することで Webhookで外部のプロセスにバリデーションおよび修正の処理を委譲できます。このようなWebhoookの設定はKubernetesのリソースとして管理されており、EKSではデフォルトで以下のような設定が生えています

$ kubectl get mutatingwebhookconfiguration
NAME                   CREATED AT
pod-identity-webhook   2019-11-22T12:59:57Z

先程のServiceAccountの解説の中でPod作成時に自動的にトークンがマウントされたり、ServiceAccountが指定されていないときにはdefaultのServiceAccountの指定が追加されていましたが、これはTokenControllerによりPodの作成のリクエストが修正されたためです。

また、後で説明するServiceAccountにIAMロールを紐づける仕組みの中でもトークンや環境変数の設定を MutatingAdmissionWebhook でPodに追加しています。

EKSのUserAccount(aws-iam-authenticator)

EKSではaws-iam-authenticatorによりIAMのエンティティとKubernetesのUserAccount/Groupを紐付けます。

ここでは、紐付けに必要な設定を見たあとで、実際にどのような処理が行われているかを掘り下げてみていきます。

設定内容

aws-iam-authenticatorでIAMのエンティティとKubernetesのUserAccount/Groupを紐づけを定義するのは以下のような aws-auth ConfigMapです。

apiVersion: v1
data:
  mapRoles: |
    - rolearn: arn:aws:iam::XXXXXXXXXXXX:role/<ワーカーノードのロール名>
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
  mapUsers: |
    - userarn: arn:aws:iam::XXXXXXXXXXXX:user/admin
      username: admin
      groups:
        - system:masters
kind: ConfigMap
metadata:
  # 省略
  name: aws-auth
  namespace: kube-system
  # 省略

EKSのkube-apiserverにIAMの認証情報からトークンを作成してアクセスするにはaws eks update-kubeconfigコマンド等で以下のようなkubeconfigファイルを作成します。

# 省略
users:
- name: arn:aws:eks:ap-northeast-1:<アカウントID>:cluster/<クラスタ名>
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: aws
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - <クラスタ名>

これらの設定により、クライアント側のIAMエンティティとaws-auth ConfigMapで定義した紐付けに従ってKubernetesのUserAccount/Groupとして認証されます。

余談ですが、将来のaws-iam-authenticatorのバージョンでは、このようなCustomResourceにより管理するようになるようです。これにより、1つの大きなConfigMapを使ってすべての紐付けを管理せず、IAMエンティティごとに別々に紐付けを定義するようになるようです。(https://github.com/kubernetes-sigs/aws-iam-authenticator/pull/116)

実際の処理

では、実際には前節の設定でどんな処理が行われているのでしょうか?

aws-iam-authenticator による認証の流れは以下のようになります。

f:id:katainaka0503:20191126011641p:plain

まず、kubeconfigの設定により、kube-apiserverへのアクセス前に、トークンを取得するためaws eks get-tokenコマンドが実行されます。これにより、STSGetCallerIdentityの署名付きURLが発行され、これをもとにトークンが作成されます。

トークンの検証時にはこのトークンから抜き出した署名付きURLでGetCallerIdentityを実行します。GetCallerIdentity では署名付きURLを発行したIAMエンティティの情報が得られます。これにより、クライアントが特定のIAMのエンティティであることが確かめられるというわけです。

クライアントがAPIサーバにリクエストする際には、Authorization: Bearerヘッダでトークンをいっしょに送信します。

ここから先はEKSのコントロールプレーン内での処理です。

トークンを受け取ったkube-apiserverはWebhook Token Authenticationの仕組みでaws-iam-authenticatorサーバにトークンの検証を委譲します。

aws-iam-authenticatorサーバではトークンから抜き出した署名付きURLでGetCallerIdentityを実行します。結果として得られたIAMのエンティティの情報とaws-auth ConfigMapの情報を突き合わせてIAMのエンティティに紐づくUserAccount/Groupを取得します。そして、kube-apiserverにUserAccount/Groupの情報を返します。

このような流れにより、リクエストが特定のグループの特定のユーザからのものとして認証されます。

ServiceAccountのIAM ロール(IRSA)

先程のaws-iam-authenticatorの仕組みは、IAMのエンティティをKubernetesのユーザアカウントに紐付ける仕組みでした。

逆に、Kubernetes内部にいるPodのService Accountの認証情報を使用してIAM Roleを引き受けるためにはいくつかの方法があります。

  • Service Accountのトークンを使用してIAM Roleを引き受ける(IAM Role for Service Account 以下 IRSA)
  • ノードのiptablesをいじくって、メタデータエンドポイントへのアクセスを横取りしていい感じにAssumeRoleできるようにする(KIAM/kube2iam)
  • AWSの認証情報をSecretにして埋め込む

ここでは、IRSAによりService AccountにAWSのロールを紐付ける方法をみていきます。

実際にはeksctlの便利なコマンドが用意されているため、実際にどのような設定が行われるのか深く意識せずとも使えますが、ここでもあえて一段掘り下げて何をやっているのかを順番に見ていきます。

概要

実際の動作のフローとしては以下のようになります。

  1. EKSクラスタが発行したトークンを信頼させるため、IAMのOIDCプロバイダーというエンティティを作成

  2. IAMロールがアノテートされたServiceAccountを準備

  3. ServiceAccountのトークンでのAssumeRoleを許可したIAMロールを準備

  4. このServiceAccountを指定したPod作成時、AdmissionControllerによりSTS向けのServiceAccountのトークンの埋め込みと必要な環境変数の設定が行われる

  5. 以下に示すバージョンより新しいAWS SDK動作時にはコンテナに埋め込まれているトークンを元にAssumeRoleWithWebIdenityを実行し、IAM Roleを引き受ける

図にすると以下です(Amazon Web Services ブログの記事より転載させていただきました)

https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2019/08/12/irp-eks-setup-1024x1015.png

設定

では実際の設定を見ていきながらそれぞれ確認していきましょう。

AWSでOIDCプロバイダーを作成

まず、IAMのOIDC providerというエンティティを作成します。これを作成することで、EKSクラスタから発行されたトークンを信頼するようになり、AssumeRoleWithWebIdentityによるWebフェデレーションが行えるようになります。

eksctlでは以下のようなコマンドで実行しますが、

eksctl utils associate-iam-oidc-provider \
            --name floral-mongoose-1574427060 \
            --approve

これは以下のようなコマンドと同等です。

EKSクラスタから発行されるIDトークンのISSUERのURLを取得し、IAMにOIDCのプロバイダとして設定することで、EKSクラスタが発行したIDトークンを信頼させています。

ISSUER_URL=$(aws eks describe-cluster \
                    --name irptest \
                    --query cluster.identity.oidc.issuer \
                    --output text)

aws iam create-open-id-connect-provider \
        --url $ISSUER_URL \
        --thumbprint-list $ROOT_CA_FINGERPRINT \
        --client-id-list sts.amazonaws.com

ServiceAccountとIAMRoleの作成

次にServiceAccountおよびそこからAsssumeRoleできるIAM Roleを作成していきます。eksctlを使用すると以下のようなコマンドで実行できます。

eksctl create iamserviceaccount --cluster floral-mongoose-1574427060 --name serviceaccount-iamrole-test --attach-policy-arn arn:aws:iam::aws:policy/PowerUserAccess --approve

このコマンドは、実際には以下のような信頼ポリシーを持つIAMロールを作成し、

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "$PROVIDER_ARN"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${ISSUER_HOSTPATH}:sub": "system:serviceaccount:default:<service account>"
        }
      }
    }
  ]
}

以下のようなアノテーションがついたServiceAccountを作成しています。

eks.amazonaws.com/role-arn=<IAMロールのArn>

信頼ポリシーを見ると、Service Accountから発行されたトークンを使用してAssumeRoleできるように設定されていることがわかります。

PodでServiceAccountを指定

最後にPodでこのServiceAccountを指定し、Pod内のプロセスがIAMロールを引き受けられるようにします。

AssumeRole先のIAM Roleに関するアノテーションがついたServiceAccountを指定してPodを作成すると、 MutatingAdmissionWebhookで処理が委譲されたamazon-eks-pod-identity-webhookにより、Podにいくつか設定が追加されます。

まず、KubernetesのService Account Token Volume projectionという仕組みでaudsts.amazonaws.comとなっているIDトークンが発行され、/var/run/secrets/eks.amazonaws.com/serviceaccount/tokenに埋め込むように設定が追加されます。

https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#service-account-token-volume-projection

    volumeMounts:
    # 省略
    - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
      name: aws-iam-token
      readOnly: true
  volumes:
  - name: aws-iam-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token

そして、トークンの場所及び引き受けるIAMロールを表す環境変数が追加されます。

  containers:
  - env:
    - name: AWS_ROLE_ARN
      value: arn:aws:iam::795113267886:role/eksctl-floral-mongoose-1574427060-addon-iams-Role1-1BHQ40Q5V2FWF
    - name: AWS_WEB_IDENTITY_TOKEN_FILE
      value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token

このように環境変数が設定されトークンが埋め込まれている場合、ある一定のバージョン以上のAWS SDKであれば勝手にトークンを使用してAssumeRoleWithWebIdentityでIAMロールを引き受けてくれます。

このように、IRSAは、Kubernetesの外部audience向けにService AccountのIDトークンを発行する仕組み(Service Account Token Volume Projection)とAWSのウェブ ID フェデレーションの仕組みがうまく噛み合うことで実現されています。

まとめ

aws-iam-authenticatorおよびIRSAの仕組みを解説しました。

aws-iam-authenticatorは署名付きURLを用いてクライアントが実際にIAMで認証されていることを検証する巧妙な方法で実現されていました。またIRSAの仕組みはOIDCというオープンな仕様の上でKubernetesAWSの実装がうまく噛み合って実現されていました。

個人的に気になりつつも調べきれていなかったところではあったのですが、アドベントカレンダーという機会で半強制的に自分にプレッシャーを掛けて勉強できたので良かったなと感じています。

これからもEKSやっていくぞ!

参考資料

全体

aws-iam-authenticator

IRSA

CKA受験ログ

f:id:katainaka0503:20191114124257p:plain
CKA合格証

ねんがんのCKAに88%で合格(合格ライン74%)したので、事前に行った勉強内容等を紹介する。

TL;DR

試験概要

3時間で24問の問題を解き、74%以上得点できれば合格。得点は問題ごとに異なり、受験時には現在表示している問題の配点が画面上に表示されている。

問題とターミナルが表示されるタブに加え、1つだけ以下の3つのサイトを参照するためタブを開くことが許されている。

そのため、基本的には kubernetes.io/docs/ を開いているタブを参照しながら問題が表示されているタブ内のターミナルで解答していくことになる。

準備が必要なもの

  • 試験を受けるのに使用するPCやWebカメラ
    • MBPで問題なかった
  • 試験会場の確保
    • 私の場合は貸し会議室を試験時間3時間に前後30分余裕をもたせて4時間確保した
  • 身分証明書2種類
    • パスポート等の顔写真と署名の入ったもの
    • クレジットカード等の署名の入ったもの(私が受けた際には提示を求められなかった)

学習内容

勉強開始時点の知識(試験本番 2週間前)

  • EKSを使用したインフラの構築経験(技術検証程度)
  • Kubernetes 完全ガイドを半年前に1周読んだ状態
  • Amazon ECSを使用したインフラの構築・運用経験

試験概要・範囲の確認

何よりも先に公式の資料を読んで試験の概要や範囲を確認した。

Kubernetes 完全ガイド

https://www.amazon.co.jp/dp/B07HFS7TDT/

読みながらひたすら手を動かした。

  • 各リソースがどのような役割を持っていてどのような設定値があるか理解した
  • kubectl cordonkubectl rollout 等、馴染みの低かったコマンドを手を動かしながら意識して頭に入れるようにした
  • Helm等の周辺のプロダクトの章は試験対策としてはやらなかった

Kubernetes The Hard Way

Kubernetes The Hard Wayというリポジトリで紹介されている手順で何度かクラスタを組んだ。Kubernetesを構成するコンポーネントを一つ一つ手動で立てていくHardな手順であるため、Kubernetesの各コンポーネントの理解につながった。また、後述する演習問題をやる際にもここで作成したリポジトリを使用した。

この手順の中ではkubeletkube-apiserver等をsystemdを使用して立てていくため、systemdの復習も軽くしておいた。

kubectl の練習

スムーズに回答できるようにkubectlの機能を復習しておいた。

練習問題で手を動かす

一通り試験に出そうな内容が頭に入った状態にしたところで、手を動かす練習に移行した。

具体的にはHard Wayで作成したクラスタ上で、以下の2つのリポジトリを使って演習を行った。

公式ドキュメントのTasksをななめ読み

範囲に入ってそうなところをサラッと流し読みした。一通りの内容がドキュメントを参照すれば実行できる状態にしておいた。

Tasks - Kubernetes

その他

  • 試験会場として貸し会議室を借りた。試験時間が3時間のため前後30分余裕をもたせて4時間確保した。
  • 身分証明書としてパスポートとクレジットカードを準備した

やらなかったこと

  • Linux FoundationやUdemyのCKA対策コース

当日

  • 試験官とのやり取りはすべて英語でのチャット
  • カメラでの会場の様子の確認と身分証明書の確認が終わり次第試験開始
  • 試験中、通信が切れて再接続したりトイレに行きたくなったりしたが、チャット上で英語で説明すれば問題なく対応してもらえた
  • 後半明らかに面倒そうな問題が出てきたが、すぐに捨てる判断をして正答できそうな問題の見直しに時間を割いた

感想

用意された環境に対して3時間ひたすら手を動かす試験であり、問題を解いていて楽しかったが体力をかなり消耗した。時間勝負の試験でありいかにスムーズに設定できるかが重要となるため、事前に手を動かして練習しておく重要性を感じた。

追記: CKADも合格した

CKA受験から3日後に特に追加の勉強をすることなくCKADを受験したが、91%(合格ライン66%)で合格できた。

範囲はCKAからクラスタの管理の話題を除いたサブセットである印象だったが、CKAよりずっとスピードを求められ、受験した際はかなり時間不足を意識させられた。そのため、不安な方は以下のリポジトリ等で手を動かす練習をしてから受験することをおすすめする。