AWSの薄い本 IAMのマニアックな話 その3 IAMグループのデザインパターン

前回まで

前回はIAMポリシーとそのデザインパターンについて学びました。
今回はIAMグループのデザインパターンについて理解したいと思います。

IAMグループのデザインパターン

IAMグループのデザインパターンは大きく2つの方法があります。

  • 個々のIAMグループには、グループの責務にあったIAMポリシーのみを付与し、IAMユーザーは複数のIAMグループに所属する方法
  • 1つのIAMグループに必要な権限を全て付与し、IAMユーザーはそのIAMグループにのみ所属する方法

それぞれのメリット、デメリットをみていきましょう

複数のグループに所属するバターン

ユーザーが複数のグループに所属することを前提とします。

メリット

ポリシーが複数のグループから利用されることがほとんどない(ポリシー:グループ = 1: 1)ので、変更の際の影響範囲がわかりやすくなります。
ポリシーから見ると、グループは1つに特定されるように設計すべきだということです。

また、必須の権限を全ユーザーが所属するグループに付与することで、抜け漏れを防ぐことができます。

デメリット

ユーザーがどのグループに所属しているのか、どのグループに所属すべきなのかの管理が煩雑になりそうが気がしています。本来ポリシーを付与すべきでないユーザーに付与してしまう事故が起こりかねないと思います。

グループ内に複数のポリシー

ユーザーが1つのグループに所属することを前提とします。

メリット

ユーザーは基本的に1つのグループにしか所属しないため、ユーザーから見るとシンプルな構造になります。また、ポリシーも複数のグループから利用されることが前提になるため、自然とシンプルで使いやすいポリシー設計になります。

デメリット

権限を細かくわけたい場合は、そのユーザーのためのグループのような設計になってしまうかもしれません。1ユーザーあたり1グループ作成しないといけなくなる可能性もあり、グループの数が増えて管理が煩雑になるかもしれません。

まとめ

IAMグループのデザインパターンとして、複数グループに所属するパターンと、グループ内に複数ポリシーを配置するパターンの2つを見てきました。
筆者はこの2つの方法に、機能的な優劣はないので、どちらを選択するかは好みの問題であると言っています。しかし、筆者はグループ内に複数ポリシーを配置するデザインパターンを利用することが多いとのことです。特に好みがなければグループ内に複数ポリシーを配置するパターンを利用するのがよいのではないでしょうか。

わたしは、この2つのデザインパターンの違いは責務(権限)をどこに凝縮するかによるのかなと思います。ユーザーが複数のグループに所属するパターンだと、グループが責務の単位となり、グループがそれぞれ疎になると思います。設計としてはこちらの方がきれいかもしれません。グループ内に複数のポリシーをもつパターンだと、ポリシーが疎になります。グループ自体はポリシーを複数持っており重複する部分もあるため、設計はそれほどきれいではないかもしれませんが、ユーザーから見た時にとてもシンプルになると思います。

一旦はグループ内に複数のポリシーを持つパターンで設計を考えてみるという指針にしようと思います。

次回はIAMのセキュリティーについて読んでいきたいと思います。

クリーンアーキテクチャ

動機

前回、ヘキサゴナルアーキテクチャについて調べました。日本語訳で、似たようなアーキテクチャであると紹介されていたクリーンアーキテクチャを知ることでより深くヘキサゴナルアーキテクチャを知ろうと思います。

書籍 Clean Architectureとブログの内容について

原文日本語訳(はもちろん一緒)と書籍でクリーンアーキテクチャに言及している章をみてみましたが、内容はすべて一緒でした。なので、ここからは書籍の22章をもとに内容を理解していきたいと思います。

クリーンアーキテクチャ

アーキテクチャの特徴

ヘキサゴナルアーキテクチャの紹介のなかで、実践テスト駆動開発で採用したものと記載がありました。この書籍の中では、17章のMainクラスを分解するで、Mainクラスからさまざまな責務を抽出した結果、「ポートとアダプタ」アーキテクチャになったという形で利用されていました。こちらの書籍についてはまた別の機会で詳しくみていきます。

いろんな類似のアーキテクチャがありますが、共通する点は「関心ごとの分離」という目的を持っている点です。外部との依存関係がなくなるため、外部の環境(UI,DBなど)は交換可能になります。

クリーンアーキテクチャ

この図はブログでも紹介されています。正直言って、六角形が円になっただけのような気がしなくもないです。層がすこし増えているかなというのと、ビジネスロジックがEnterprise Business RulesApplication Business Rulesにわけられているところが変わったかなというくらいです。

このアーキテクチャを動作させるもっとも重要なルールは、依存性のルールであると言っています。そのルールは

ソースコードの依存性は、内側(上位レベルの方針)だけにむかっていなければいけない。

ということです。外部に依存してはいけないということです。次にこのアーキテクチャを構成する各要素を書籍を引用して紹介します。

エンティティ

エンティティは最重要ビジネスルールをカプセル化したもの。

ユースケース

ユースケースはアプリケーション固有のビジネスルールが含まれている。ユースケースは、エンティティに入出力するデータの流れを調整し、ユースケースの目標を達成できるように、エンティティに最重要ビジネスルールを使用するように指示を出す。

インターフェースアダブター

インターフェースアダプターはユースケースやエンティティに便利なフォーマットから、データベースやウェブなどの外部エージェントに便利なフォーマットにデータを変換するアダプター。

この層のインターフェースに依存するように実装することで、外部エージェントを交換可能にしているのだと思います。

フレームワークとドライバ

図のもっとも外側の縁は、フレームワークやツールで構成されています。たとえば、データベースやウェブフレームワークなどです。フレームワークとドライバの層には詳細が詰まっています。ウェブも詳細、データベースも詳細。被害が抑えられるようにこれらは外側に置いておきます。

境界を越える

図の右下に、円の境界線をどのように越えるべきかの例が記載されています。コントローラーからプレゼンターへの制御の流れがあるが、ユースケースを経由しています。この際に、依存関係逆転の法則を用いてコントローラー、プレゼンター共通のインターフェースを提供します。
制御の流れは外側から内側であるが、ソースコードの依存関係は内側から外側へ発生します。

まとめ

こうした単純なルールに従うのは、それほど難しいことではなさそうです。ルールを守っていればいずれ多くの苦痛から解放してくれると言っています。

全体のまとめ

クリーンアーキテクチャも関心ごとの分離が目的のアーキテクチャです。外部を交換可能にするためには依存関係を守ること、しっかりと関心ごとを分離することが重要です。ここでもオブジェクト指向の基本原則であるSOLIDが重要になってきます。特にD(依存関係逆転の法則)は重要だと思いました。

マイクロサービスにおけるサービスはオブジェクト指向におけるオブジェクトと同義だと思います。責務を明確にし、インターフェースを正しく定義し利用しやすいマイクロサービスを設計したいものです。

ヘキサゴナルアーキテクチャ

動機

わたしが担当しているWebアプリケーションがいろんなサービスを扱っていて、変更が予期せぬところに影響を及ぼすようになってしまっています。そこで、Webアプリケーションを分割しようと思い、マイクロサービスについて調べようと思いました。
まずはじめにマイクロサービスアーキテクチャを読み始めました。すると、すぐにヘキサゴナルアーキテクチャについて記されていました。

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

レイヤ化アーキテクチャが好ましくないような記述に疑問がわいたので、しっかり理解しようと思います。

書籍マイクロサービスアーキテクチャにあったヘキサゴナルアーキテクチャについてのURLは2020年5月23日現在、改装中でした…こちらに日本語訳がありました。

PoEAAの中でのヘキサゴナルアーキテクチャ

翻訳者の方のコメントにもあるように、PoEAAに記載があるということで、早速読んでみました。

ヘキサゴナルアーキテクチャについてはかなり序盤でふれられていました。以下がその引用になります。

(中略) プレゼンテーションレイヤとデータソースレイヤには多くの類似点があるように見える。どちらも外部との接続に関するレイヤだからだ。これは、Alistair Cockburnのヘキサゴナルアーキテクチャーパターンの背後にあるロジックである。ヘキサゴナルアーキテクチャは、外部システムへのインターフェースで囲まれた核としてシステムを視覚化したものである。ヘキサゴナルアーキテクチャでは、外部にあるものは基本的にすべて外側のインターフェースであり、したがってこれは対照的なビューであって、私の言う非対称のレイヤ化スキーマではない。

さらに、以下のように続きます。

しかし、私はこの非対称性こそ有用だと思っている。他へのサービスとして提供するインターフェースと、他のサービスを使用することとの間には、歴然とした違いがあるからだ。核心に触れていえば、これこぞが私の言うプレゼンテーションとデータソースとの違いなのである。(中略)これらを分けて考えることは有用であると私は考える。

両者の考え方はわかれていてちょっと対立しているようにも捉えられます。
プレゼンテーションとデータソースは外側のインターフェースであるという共通点はあるものの、利用用途を考えると別のものと認識するのがレイヤ化、どちらも外側のインターフェースであるという共通点を持っているので同じものと考えるのがヘキサゴナルアーキテクチャということでしょうか。

ヘキサゴナルアーキテクチャ

翻訳いただいた内容をもとにまとめいきます。意図や動機、構造など書かれているので、GoFのデザインパターンの説明みたいな感じです。

ヘキサゴナルアーキテクチャは別名Ports and Adapter*Ports and Adaptersパターンといいます。
Portsは外部との接点という感じでしょうか(プレゼンテーション、データソースなど)。TCPのポート番号と同じようなイメージです。
Adaptersはその具体的な外部(HTTPなど)とのインターフェースを統一するためのアダプタです。

意図

アプリケーションを、ユーザー、プログラム、自動テストあるいはバッチスクリプトから、同じように駆動できるようにする。そして、実際のランタイムデバイスとデータベースから隔離して、開発とテストをできるようにする。

外部のインターフェースに依存しないようにアプリケーションを構築するということだととらえました。すなわち、アプリケーションの外側に対して同じインターフェースを提供し、ビジネスロジック自体はそのインターフェースの外には実装しないということだと思います。

動機

数年来、ソフトウェアアプリケーションで一番怖いことのひとつは、ビジネスロジックがユーザーインターフェイスコードに侵入することだった。これが引き起す問題は、3つある:
・はじめに、システムを自動テストスイートで綺麗にテストすることができない。なぜなら、テストを必要とするロジックの部分が、フィールドサイズやボタン配置など、頻繁に変わるビジュアルの詳細に依存するからだ。
・同じ理由により、人間駆動のシステム使用から、バッチ処理システムに移行することが不可能になる。
・これも同じ理由から、他のプログムからプログラムを駆動したくなったときに、そうすることが難しいか、または不可能になる。

ビジネスロジックがユーザーインターフェースコードに侵入するのは確かに問題ですね。ユーザーインターフェースが交換可能ではなくなってしまいます。

(多くの組織によって繰り返し)試みられた解法は、アーキテクチャに新しい層を足すことだ。そのときには、今度は、本当に絶対に、ビジネスロジックが新しいレイヤーに置かれることはないという取り決めをする。しかしながら、取り決めへの違反が起きたときに検出する仕組みはなく、組織は、数年後、新しいレイヤーがビジネスロジックでとっちらかっており、同じ問題が起きたことに気付く。

ロジック・責務を持たせるクラスに迷った時、層を追加することはありますね。RailsでいうService層やDecorator層がまさにそれかなと思いました。層を足す=間に挟み込むようなイメージで実装しています。ControllerとModelの間にロジックを詰め込みたいみたいな感じですね。これがよくないと解釈しました。

解決法の本質

利用すべき非対称性は、アプリケーションの「左側」と「右側」ではなく、アプリケーションの「内側」と「外側」だ。従うべきルールは、「内側」の部分にあるコードが「外側」の部分に漏れ出さないようにすべき、ということだ。

プレゼンテーション(フロント)、ビジネスロジック、データソースと左からリクエストを受け付けてレスポンスを返すまでの絵を思い浮かべたりしますが、そうではなく、すべて内側と外側のやりとりであると考えるということですね。プレゼンテーションとデータソースは同じ外側であるという考え方をしましょうということです。
内側であるビジネスロジックはAdapterのインターフェースに依存し、外側もAdapterのインターフェースに依存するように実装すべきです。

ポート用のプロトコルは、2つのデバイスの会話を目的として、与えられる。
このプロトコルは、アプリケーションプログラムインターフェイス(API)の形を取る。

やっとマイクロサービスの本で紹介されていた理由がわかってきました。まさに外側と内側のやりとりをサービス間で行うべきということですね。

また、なぜ六角形なのかの説明も記載されていました。

六角形は、視覚的に、
1.内側と外側の非対称性と、ポートの似たような特性(1次元のレイヤーの絵と、それが想起させるものから完全に離れるために)と、
2.定義された数の異なるポートの存在 ー 2,3,あるいは4つの(4が、わたしがこれまで遭遇した中では一番多かった)
に焦点を当てるよう意図されている。

構造

アプリケーションは各ポートの責務を実装し、ポートは具体的な外部とやり取りするためにAdapterを実装します。
ここでの例はポートがuser-side APIdata-side APIで、user-side APIの具体的な外部には、http adapterGUI adapterなどが記載されていて、data-side APIの具体的な外部はDB access servicemock in-memory databaseとなっています。余談ですがデータベースへのインターフェースを考えるときに必ずSOLID原則のD、依存関係逆転の法則を思い出します。

構造については特に真新しいものはないですね。ですが、応用ノートにおもしろい内容が記載されていました。

応用ノート

ports and adaptersパターンは、意図的に、すべてのポートが基本的に類似しているふりをしながら書かれている。このようなふりをすることは、アーキテクチャレベルで有益だ。実装においては、ポートとアダプターには2種類のものがあることがわかる。すぐに明らかになる理由から、わたしが、「プライマリ」と「セカンダリ」と呼ぶものだ。これらは、「駆動する」アダプターと「駆動される」アダプターと呼ばれることもある。

構造の例でいうと、駆動するアダプタはuser-side APIのことで、駆動されるアダプタはdata-side APIのことでしょう。結局は外部を全て同等には扱えないということでしょうか。レイヤ化アーキテクチャとの大きな違いだと思っていた外部は全て同じように扱うという考え方ではなくなっている気がします。

まとめ

ヘキサゴナルアーキテクチャはシステムをビジネスロジックがある内側と、ビジネスロジックと相互作用する外側におおきくわけるという考え方。その意図はビジネスロジックが外部に侵入しないようにするため。

元々の引用

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

ビジネスロジックが階層化によって本来の場所ではないところに侵入する(から見えなくなる)ことをいっているのだと思います。マイクロサービスではビジネスロジック自体が一つのサービスとして稼働すると思うので、外部との境界をしっかりと認識することが重要かと思います。

ヘキサゴナルアーキテクチャはレイヤ化アーキテクチャをより抽象化したような考え方だという印象を持ちました。マイクロサービスを構築する際のサービス間の責務を考える際には有用かなと思いました。その場合も駆動する側、駆動される側という考え方はどうしても必要になるかと思います。駆動する、駆動されるサービスが多数になるので、レイヤ化よりヘキサゴナルアーキテクチャの方が視覚的にわかりやすく記述できるという利点があると思います。

次はヘキサゴナルアーキテクチャに似ていると言われているクリーンアーキテクチャについて考えたいと思います。

AWSの薄い本 IAMのマニアックな話 その2

前回まで

前回はIAMについてと、IAMの基本機能5つの説明のところまですすみました。
今回はIAMポリシーの具体的な設定方法、デザインパターンについて理解したいと思います。
(書籍の中では具体的なカスタマー管理ポリシーの作成のチュートリアルに入っていくのですが、ここでは重要だと思うポイントにしぼって記します。)

IAMポリシー

IAMポリシーを構成する要素(エレメント)は大きく以下の2つです。

  • Version
  • Statement

Version

Versionは2008-10-172012-10-17があります。指定しない場合は2008-10-17になるので、必ず明示的に2012-10-17を指定しましょう。

Statement

Statementは大きくEffect, Action, Resourceの3つがあります。
EffectはAllowDenyを指定します。
ActionはAWSサービスを指定します。全てを指定するアスタリスクも利用できます。
Resourceは利用するリソース(リージョン、IAMユーザー名、S3バケットなど)を指定します。

チュートリアルで紹介されていた特定のIPアドレスを許可するポリシーはこんな感じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"8.8.8.8/32"
]
}
}
}
]
}

ここで新しくConditionというStatementが出てきています。制限を追加する場合に利用します。
この例は送信元IPが8.8.8.8/32であれば全て許可されるということです。aws:SourceIpで指定するIPアドレスはグローバルIPでなければなりません。VPC内のリソースを制限したい場合は、VPCのプライベートIPを指定するのではなく、VPC IDもしくはVPC Endpoint IDを指定します。
6章で紹介されているVPC Endpoint IDが指定されている例を記します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"Version": "2012-10-17",
"Id": "ListrictAccess",
"Statement": [
{
"Sid": "Allow-from-specific-VPC-only",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::kindle-iam-test",
"arn:aws:s3:::kindle-iam-test/*"
],
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-id1234"
}
}
}
]
}

Conditionのところに、VPC Endpointが指定されていることがわかります。

IAMの許可・拒否ポリシーの挙動

権限の指定の優先度は以下の順序になっています。

明示的なDeny > 明示的なAllow > 暗黙的なDeny(デフォルト)

設定しなければ暗黙的なDenyとなります。こう言った優先度になるので、明示的なAllowをAWS管理ポリシーで設定し、明示的なDenyをカスタマー管理ポリシーで設定するのがよさそうです。この設定方法は後にハイブリッドパターンとして紹介します。

IAMポリシーのデザインパターン

大きく3つのパターンに分けられます。

  • ホワイトリストパターン
  • ブラックリストパターン
  • ハイブリッドパターン

一つずつみていきましょう。

ホワイトリストパターン

許可する権限のみ付与していくパターン。
サービス単位で指定する場合は、AWS管理ポリシーを利用します。

メリット

必要最小限の権限のみ付与するので、セキュリティ面での信頼性が高くなります。

デメリット

事前に役割が決まっていないと権限を付与できない。
アクション単位で指定する場合、AWSサービスが拡大したときなど、都度それに対応しないといけない。

ユースケース

業務、運用、設計が確立している本番環境に適用すべきです。
AWS管理ポリシーもほぼホワイトリストパターンの実装になっています。

ブラックリストパターン

許可してはいけない権限のみを剥奪するパターン

メリット

禁止事項のみを定義すれば良いので、IAMポリシーの設計、設定が最小ですみます。

デメリット

予期せぬ機能が突然使えるようになる点。

ユースケース

  • 一般的なIAMの運用としては、ブラックリストパターンの利用が多くなる。
  • AWSの権限のデフォルトは暗黙的拒否。
    そのため、どこかで許可のステートメントを作った上でブラックリストで拒否するというタイミングになります。

ハイブリッドパターン

AWS管理ポリシーによる許可と、カスタマー管理ポリシーによる拒否の組み合わせ。

メリット

AWSの定義済ポリシーと自分で作ったブラックリストを組み合わせて利用することにより、最小の労力で実用的なポリシーを作ることもできる。個々のポリシーもシンプルにできる。

デメリット

特になし

ユースケース

1ポリシーで管理すべきか、グループで組み合わせて1ポリシー管理するか、どちらが良いのでしょうか。

1ポリシでーで全て書くことのメリット

視認性が高い
そのポリシーを付与するだけで良い

デメリット

再利用性(モジュラリティ)が低い

グループでの組み合わせで書くことのメリット

各ポリシーの再利用性が高い=管理するポリシーが少なくて済みます。
各ポリシーは独立していて、疎な関係を持ちます。

まとめ

IAMロールを付与するパターンはホワイトリストかブラックリスト
どちらかだけで良いと言うわけではなくどちらも重要なのでこれらの組み合わせで権限を制御します。
〇〇以外という反転のパターンを考えられるようになると記載できるルールの幅が広がりそうです。

次回はIAMグループのデザインパターンをみていきます。

AWSの薄い本 IAMのマニアックな話

動機

IAMのことを今までちゃんと考えたことはありませんでした(よくない)。
サービスを利用するときに、そのサービスの既存のポリシーをReadOnlyで割り当てようか、FullAccessで割り当てようかを考えたくらいでした…
でもそれではよくない!ということで、この本を読んだのを機に、IAMについてしっかりとりかいしたいと思いました。

IAMとは

AWS Identity and Management (以下、IAM)は、AWS 利用に関する認証と認可を司るサービスです。

認証と認可

認証と認可はOAuthに関わるときにもよく出てきますね。
認証は本人性のの確認(Authentication)で、
認可はリソースに対する利用権限の付与(Authorization)です。
わかりづらいですね…ログインは認証で、その対象者はなにができるのか、なにができないのかが認可です。
OAuthの場合だと、認証はそのサービスへのログインであり、認可はサードパーティのアプリケーションになにをどこまで許可するのかということです。
例えばfacebookの認可だと、フィードへの投稿を許可するなどがあります。

AWSアカウントとIAMユーザー

AWSアカウントはルートアカウントとも呼ばれるアカウントで、絶対的な権限を持ちます。
通常利用してはいけません。IAMユーザーを作成し、IAMユーザーでログイン、管理など行いましょう。

IAMの機能

IAMには以下の5つの機能があります。

  • IAMユーザー
  • IAMグループ
  • IAMポリシー
  • IAMロール
  • パーミッションバウンダリー

ひとつずつみていきます。

IAMユーザー

共有アカウントは作成せずに、必ず個々でユーザーを作成しましょう(MFA利用推奨)。
プログラム、ツールから利用の際もそれぞれに作成します。

IAMユーザーに直接権限を付与することも可能ですが、管理コストが高くなるのでやめましょう。
次に紹介するIAMグループで管理し、ユーザーの役割に応じてグループに所属させる方法が良いです。

IAMグループ

IAMグループは同一の役割を持つIAMユーザーをグループ化する機能です。IAMユーザーは複数のグループに所属することもできます。
IAMグループに権限を付与することにより、権限を容易に、かつ正確に管理することができます。
権限の付与方法は管理ポリシーとインラインポリシーの2つです。

IAMポリシー

IAMポリシーはAWSリソースへのアクセス権限をまとめたものです。
以下の3つの大きなルールに基づいて権限を設定します。

  • Action(どのサー ビスの)
  • Resource(どういう機能や範囲を)
  • Effect(許可 or 拒否)

IAMポリシーの種類

IAMポリシーには2種類あります。

  • AWSが最初から設定しているAWS管理ポリシー
  • ユーザーが作成したカスタマー管理ポリシー

ポリシーはIAMユーザー、IAMグループ、IAMロールに付与できます。

IAMポリシーの使い分け

筆者のオススメは足し算と引き算。
AWS管理ポリシーで基本的な権限を付与、カスタマー管理ポリシーで権限を制限するのがよいと言っています。

IAMロール

IAMロールはAWSサービスやアプリケーションに対してAWSの操作権限を与える仕組みです。
LambdaやECSなど、実行している個々のタスクに対してIAMユーザーを割振れないようなサービスでIAMロールを利用します。
IAMロールは使わなくてもなんとかなりますが、IAMロールを正しく使うことによって、AWSの安全性も利便性も格段に高まります。積極的に使っていくのが良さそうです。

パーミションバウンダリー

IAMの移譲権限を制限する機能です。
IAMユーザー、IAMロールに対してアクセス制限を行います。
付与した権限とパーミションバウンダリーで許可した権限の重なり合うところのみ有効な権限として動作します。
あまり利用しなさそうな機能なのですが、一旦どういうものかは理解しておきたいです。

まとめ

パーミッションバウンダリーを除いた4つのIAMについてしっかりと理解することで、9割方マスターできます。
IAMユーザーはユーザーごとに作成します、また、共有アカウントは禁止です。
IAMグループはグループ化する機能で、グループにたいしてポリシーを付与します。
IAMポリシーは権限をまとめたものです。
IAMロールはAWSの操作権限を与えます。
IAMロールをうまく使うとアクセスキーがほぼ不要になります。

次回からはIAMポリシーについて詳しく掘り下げます。またIAMポリシーのデザインパターンについても理解していこうと思います。

systemdの起動でハマった

systemdのエラー

Let’s Encryptの導入でsystemdを利用してHexoをdaemonとして起動しようとしました。
その際に解決に時間がかかるハマりどころがあったので忘れないように記載しておきます。

systemdの導入

はじめに/etc/systemd/system/hexo.serviceを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Unit]
Description=hexo
After=syslog.target network.target

[Service]
Type=simple
ExecStart=sudo /home/ec2-user/.anyenv/envs/nodenv/shims/hexo server -p 8080
WorkingDirectory=/home/ec2-user/blog
StandardOutput=syslog
StandardError=syslog
KillMode=process
Restart=always
User=ec2-user
Group=ec2-user
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

書き方はこちらを参考にしてください。

登録されたかどうかを確認します。

1
2
$ sudo systemctl list-unit-files --type=service | grep hexo
hexo.service disabled

大丈夫でした。

enableしてstartします。

1
2
3
4
5
6
$ sudo systemctl enable hexo
Created symlink from /etc/systemd/system/multi-user.target.wants/hexo.service to /etc/systemd/system/hexo.service.
$
$ sudo systemctl start hexo
Failed to start hexo.service: Unit is not loaded properly: Invalid argument.
See system logs and 'systemctl status hexo.service' for details.

起動に失敗しました。See system logs and 'systemctl status hexo.service' for details.と書いてあるので言われた通りにやってみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo systemctl status hexo.service
● hexo.service - hexo
Loaded: error (Reason: Invalid argument)
Active: failed (Result: start-limit) since 水 2019-06-26 20:40:03 JST; 10 months 10 days ago
Main PID: 13043 (code=exited, status=2)

5月 07 01:04:35 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:04:35 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:06:36 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:06:36 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:07:03 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:07:03 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:10:02 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:10:02 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:10:18 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:10:18 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
Hint: Some lines were ellipsized, use -l to show in full.

全然わからない…

1
2
Loaded: error (Reason: Invalid argument)
Active: failed (Result: start-limit) since 水 2019-06-26 20:40:03 JST; 10 months 10 days ago

この辺がヒントといえばヒントなんだと思いますが、結果的にここに惑わされた形になりました。

全くヒントも掴めずに調べていると/var/log/messagesを見るとよいみたいなコメントを見つけました。なのでみてみると

1
May  7 01:04:35 ip-172-31-43-237 systemd: [/etc/systemd/system/hexo.service:7] Executable path is not absolute, ignoring: sudo /home/ec2-user/.anyenv/envs/nodenv/shims/hexo server -p 8080

めちゃくちゃわかりやすいメッセージが書かれています。
起動コマンドがsudoで始まっていて、それがが絶対パスではないので起動できてなかったようです。
なのでsudo/usr/bin/sudoに変更して問題なく起動しました。

まとめ

systemdのエラーは/var/log/messagesを見ること。

Let's Encryptを使ったHTTPS化

HTTPS化

このブログはhexoを使って表示しています。
以前HTTPSにしないとサイトの評価が上がらないと言われていたので、HTTPSにしようと思います。
できるだけ管理に手間をかけたくないので、Let’s Encryptを利用しようと思います。

Let’s Encryptについて

恥ずかしながらLet’s Encryptを利用するのは今回が初めてです。なので、本家のサイトをまず見てみます。
ドキュメントを上から読んでいくと、以下のことがわかります。

  • ACMEプロトコルを利用している
  • 証明書を設置するサーバにSSHログインできる場合、CertbotというACMEクライアントを利用する
  • ドメイン検証 (Domain Validation; DV) 型の証明書
  • 無料で利用できる

想定としてはリバースプロキシとしてnginxを動かして、フォワード先をhexoとします。
では早速進めていきたいと思います。

Certbot

Let’s EncryptのACMEクライアント実装というページでもCertbotをおすすめしています。とりあえずこれをインストールしてみようと思います。
Certbotのページにいくと、My HTTP Website is runningという表示があります。そのセレクトボックスに自分の環境のHTTPサーバ、OSを指定します。

AmazonLinux2のベースはなに?

OSを選ぼうとしたらAmazonLinux2の文字はありませんでした。そう言われるとAmazonLinux2のベースのOSはなんだろう?と思いました。
ググってみるとCentOS/RHEL 7のようです。yumが利用できるのでRedHat系かとは思っていましたが、RHEL7ベースのようなのでそれを選択しました。

Certbotのインストール

SoftwareNginxSystemCentOS/RHEL 7を選択すると、ページ下にインストール方法が表示されれます。
その手順通りに進めていきます。

サーバーにログインします

ログインします

EPELリポジトリを有効にします

今有効になっているリポジトリ一覧を見てみます。

1
2
3
4
5
6
7
8
9
10
$ sudo yum repolist all
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
リポジトリー ID リポジトリー名 状態
!amzn2-core/2/x86_64 Amazon Linux 2 core repository 有効: 19,545
amzn2-core-debuginfo/2/x86_64 Amazon Linux 2 core repository - debugin 無効
amzn2-core-source/2 Amazon Linux 2 core repository - source 無効
!amzn2extra-docker/2/x86_64 Amazon Extras repo for docker 有効: 24
amzn2extra-docker-debuginfo/2/x86_64 Amazon Extras debuginfo repo for docker 無効
amzn2extra-docker-source/2 Amazon Extras source repo for docker 無効
repolist: 19,569

有効になっていないようなので有効にします。
有効にする方法はこちらに記載されていました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
epel-release-latest-7.noarch.rpm | 15 kB 00:00:00
/var/tmp/yum-root-HHwmTy/epel-release-latest-7.noarch.rpm を調べています: epel-release-7-12.noarch
/var/tmp/yum-root-HHwmTy/epel-release-latest-7.noarch.rpm をインストール済みとして設定しています
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ epel-release.noarch 0:7-12 を インストール
--> 依存性解決を終了しました。
amzn2-core/2/x86_64 | 2.4 kB 00:00:00
amzn2extra-docker/2/x86_64 | 1.8 kB 00:00:00

依存性を解決しました

==========================================================================================
Package アーキテクチャー
バージョン リポジトリー 容量
==========================================================================================
インストール中:
epel-release noarch 7-12 /epel-release-latest-7.noarch 24 k

トランザクションの要約
==========================================================================================
インストール 1 パッケージ

合計容量: 24 k
インストール容量: 24 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
インストール中 : epel-release-7-12.noarch 1/1
検証中 : epel-release-7-12.noarch 1/1

インストール:
epel-release.noarch 0:7-12

完了しました!

次にepelを有効にします。

1
2
3
4
5
6
$ sudo yum-config-manager --enable epel
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
======================================= repo: epel =======================================
[epel]
async = True
(省略)

有効になったかを確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo yum repolist all
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
192 packages excluded due to repository priority protections
リポジトリー ID リポジトリー名 状態
!amzn2-core/2/x86_64 Amazon Linux 2 core repository 有効: 19,545
amzn2-core-debuginfo/2/x86_64 Amazon Linux 2 core repository - deb 無効
amzn2-core-source/2 Amazon Linux 2 core repository - sou 無効
amzn2extra-docker/2/x86_64 Amazon Extras repo for docker 有効: 24
amzn2extra-docker-debuginfo/2/x86_64 Amazon Extras debuginfo repo for doc 無効
amzn2extra-docker-source/2 Amazon Extras source repo for docker 無効
epel/x86_64 Extra Packages for Enterprise Linux 有効: 13,061+192
epel-debuginfo/x86_64 Extra Packages for Enterprise Linux 無効
epel-source/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing-debuginfo/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing-source/x86_64 Extra Packages for Enterprise Linux 無効
repolist: 32,630

有効になっていますね。epelのその他のリポジトリも有効にすれば利用できるようになっていました。

optional channelを有効にする

パッケージyum-utilsはインストール済だったので、有効にするコマンドのみ実行します。
記載のコマンドのREGIONはap-northeast-1に置き換えて実行してみます。

1
2
$ sudo yum-config-manager --enable rhui-ap-northeast-1-rhel-server-extras rhui-ap-northeast-1-rhel-server-optional
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd

特に変化はなさそうですが、一旦次に進んでみます。

Certbotをインストール

次のコマンドを実行します。

1
2
3
$ sudo yum install certbot python2-certbot-nginx
(省略)
完了しました!

Certbotの実行

CertbotがNginxの設定を書き換えると書いてあります。
まだNginxの準備ができていないので、そちらを行います。

1
2
3
$ sudo yum install nginx.x86_64
(省略)
完了しました!

Nginxのインストールが完了したので、hexoへリバースプロキシをする設定を追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi /etc/nginx/conf.d/hexo.conf
server {
server_name book-reviews.blog;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location / {
proxy_pass http://localhost:8080/;
}
}

hexoのポートも80から8080に変更しています。

Nginxを起動しておかないとCertbotの実行でエラーが出るので起動しておきます。

1
$ sudo systemctl start nginx

準備が整ったのでCertbotを実行します。

1
2
3
4
5
6
7
8
9
10
$ sudo certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

設定ファイルから自動的にドメインを認識してくれるので該当するドメインを選択します。

1
2
3
4
5
6
7
8
9
10
11
(中略)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
server {
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/hexo.conf

HTTPのアクセスをHTTPSへリダイレクトするかどうか聞かれるので、リダイレクトするを選びました。nginxの設定に301redirectが追記されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://book-reviews.blog

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
(中略)
Your cert will expire on 2020-08-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

ということで無事インストールが終わりました。

1
2
3
Your cert will expire on 2020-08-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option.

ということなので、2020年8月4日には有効期限が切れてしまうようです。またその際にcertonlyオプションをつけて実行します。

HTTPSアクセスを試す

今このページもHTTPSで表示されていると思いますが、無事表示されました!
HTTPアクセスもちゃんとリダイレクトされます!

まとめ

初めてLet’s EncryptでHTTPS化しましたが、とても楽でした!Certbotのおかげだと思います!
ここには記載しなかったですが、Hexoのsystemdでの起動でちょっとつまずきました。
この点については近いうちに記載したいと思います。

※追記 こちらに記載しました。

15Stepで習得 Dockerから入るKubernetes その5

ロールアウト・ロールバック

ロールアウト機能

ロールアウトとは、アプリケーションコンテナの更新
サービスが止まらないよう、古いPodと新しいPodを入れ替えることが可能

例)nginxの設定を変更する
手順

  1. nginxの設定を変更
  2. 新しいコンテナイメージとしてビルド
  3. コンテナイメージをリポジトリへ登録する
  4. マニフェストで指定されているコンテナイメージ新しいコンテナイメージに変更する
  5. ロールアウト

マニフェストファイルの作成

変更前のマニフェストをnginx-deployment2.yml、変更後のマニフェストをnignx-deployment3.ymlとする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat nginx-deployment2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.16

nginxのバージョンは1.16

変更後

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat nginx-deployment3.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.17

違いは

1
2
3
4
5
6
7
8
9
$ diff -u nginx-deployment2.yml nginx-deployment3.yml
--- nginx-deployment2.yml 2020-03-04 21:39:06.000000000 +0900
+++ nginx-deployment3.yml 2020-03-04 21:40:14.000000000 +0900
@@ -14,4 +14,4 @@
spec:
containers:
- name: nginx
- image: nginx:1.16
+ image: nginx:1.17

のようにバージョンのみ

マニフェストの適用

まずはnginx-deployment2.ymlから

1
2
3
4
5
6
7
8
9
$ kubectl apply -f nginx-deployment2.yml
deployment.apps/web-deploy created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
web-deploy-866f97c649-788hf 1/1 Running 0 6s
web-deploy-866f97c649-8hsr8 1/1 Running 0 6s
web-deploy-866f97c649-kfxmg 1/1 Running 0 6s
web-deploy-866f97c649-pqrbf 1/1 Running 0 6s
web-deploy-866f97c649-vrm6r 1/1 Running 0 6s

起動したことがわかる
詳細に見る場合はkubectl describeを利用する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.16
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-866f97c649 (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6s deployment-controller Scaled up replica set web-deploy-866f97c649 to 5

nginxのimageは1.16

次にnginx-deployment3.ymlを適用する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ kubectl apply -f nginx-deployment3.yml
deployment.apps/web-deploy configured
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 0/1 ContainerCreating 0 4s
web-deploy-85477dddcd-4z7bw 0/1 ContainerCreating 0 4s
web-deploy-85477dddcd-crs96 0/1 ContainerCreating 0 4s
web-deploy-866f97c649-5z7r9 0/1 Terminating 0 2m48s
web-deploy-866f97c649-65fpv 1/1 Running 0 2m48s
web-deploy-866f97c649-7j7m6 1/1 Running 0 2m48s
web-deploy-866f97c649-nsw5d 1/1 Running 0 2m48s
web-deploy-866f97c649-vkwxd 1/1 Running 0 2m48s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 1/1 Running 0 34s
web-deploy-85477dddcd-4z7bw 1/1 Running 0 34s
web-deploy-85477dddcd-5plrj 1/1 Running 0 23s
web-deploy-85477dddcd-848ww 1/1 Running 0 24s
web-deploy-85477dddcd-crs96 1/1 Running 0 34s

数十秒で入れ替わったことがわかる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 2
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.17
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-85477dddcd (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 4m24s deployment-controller Scaled up replica set web-deploy-866f97c649 to 5
Normal ScalingReplicaSet 100s deployment-controller Scaled up replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 100s deployment-controller Scaled down replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 100s deployment-controller Scaled up replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 90s deployment-controller Scaled down replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 90s deployment-controller Scaled up replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 89s deployment-controller Scaled down replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 89s deployment-controller Scaled up replica set web-deploy-85477dddcd to 5
Normal ScalingReplicaSet 88s deployment-controller Scaled down replica set web-deploy-866f97c649 to 1
Normal ScalingReplicaSet 85s deployment-controller (combined from similar events): Scaled down replica set web-deploy-866f97c649 to 0

nginxのimageが1.17になっているのがわかる。またEventsにロールアウトの履歴が残っていることがわかる

ロールバック機能

Kubernetesにおけるロールバック機能は「ロールアウト前の古いコンテナへ戻すためにPodを入れ替えること」をさす

ロールバックコマンド

以下の1行で実行できる

1
kubectl rollout undo deployment デプロイメント名

実際に実行してみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ kubectl rollout undo deployment web-deploy
deployment.apps/web-deploy rolled back
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 0/1 Terminating 0 11m
web-deploy-85477dddcd-4z7bw 1/1 Running 0 11m
web-deploy-85477dddcd-5plrj 1/1 Terminating 0 11m
web-deploy-85477dddcd-848ww 1/1 Terminating 0 11m
web-deploy-85477dddcd-crs96 1/1 Terminating 0 11m
web-deploy-866f97c649-2sfv5 0/1 ContainerCreating 0 2s
web-deploy-866f97c649-nwv7d 0/1 ContainerCreating 0 2s
web-deploy-866f97c649-qhvdr 1/1 Running 0 4s
web-deploy-866f97c649-xskvq 1/1 Running 0 5s
web-deploy-866f97c649-xw4zq 1/1 Running 0 5s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4z7bw 1/1 Terminating 0 11m
web-deploy-866f97c649-2sfv5 1/1 Running 0 7s
web-deploy-866f97c649-nwv7d 1/1 Running 0 7s
web-deploy-866f97c649-qhvdr 1/1 Running 0 9s
web-deploy-866f97c649-xskvq 1/1 Running 0 10s
web-deploy-866f97c649-xw4zq 1/1 Running 0 10s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-866f97c649-2sfv5 1/1 Running 0 12s
web-deploy-866f97c649-nwv7d 1/1 Running 0 12s
web-deploy-866f97c649-qhvdr 1/1 Running 0 14s
web-deploy-866f97c649-xskvq 1/1 Running 0 15s
web-deploy-866f97c649-xw4zq 1/1 Running 0 15s

実際に動いているバージョンを確認する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 3
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.16
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-866f97c649 (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 12m deployment-controller Scaled down replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 12m deployment-controller Scaled down replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set web-deploy-85477dddcd to 5
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set web-deploy-866f97c649 to 1
Normal ScalingReplicaSet 11m deployment-controller (combined from similar events): Scaled down replica set web-deploy-866f97c649 to 0
Normal ScalingReplicaSet 32s deployment-controller Scaled up replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 32s deployment-controller Scaled down replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 31s deployment-controller Scaled up replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 29s (x2 over 14m) deployment-controller Scaled up replica set web-deploy-866f97c649 to 5
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 29s deployment-controller Scaled up replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 1
Normal ScalingReplicaSet 23s deployment-controller Scaled down replica set web-deploy-85477dddcd to 0

1.16に戻っていることがわかる

ロールアウト、ロールバック機能はサービスを停止することなくリリースを行うことができる
実際にアクセスできるサービスを立ち上げないと実感がわかないので、次はServiceについて調べてみる

15Stepで習得 Dockerから入るKubernetes その4

Deploymentの概要

DeploymentはReplicaSetを管理する仕組み
ReplicaSetはPodを管理し、Pod内にコンテナが存在する

Deploymentのマニフェストファイル

シンプルな例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest

ポイント

  • Podの稼働数が3 replicas: 3
  • matchLabelsapp: web を指定
    • templatelabelsは先ほどselector内で指定したapp: webと同じにする
  • specに関してはPodのspecと同じ

Deploymentのマニフェストファイルの実行

実行する

1
2
$ kubectl apply -f nginx-deployment.yml
deployment.apps/web-deploy created

各情報をみてみる

1
2
3
4
5
6
7
8
9
10
11
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
web-deploy 3/3 3 3 24m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
web-deploy-654cd6d4d8 3 3 3 27m
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 28m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 28m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 28m 172.17.0.4 minikube <none> <none>

replicasetを増やしてみる

マニフェストファイルのreplicasの値を増減することでReplicaSetの数を調整でき、スケールすることができる
これとは別でCPU使用率と連動して動的にReplicaSetを数を増やすことができるオートスケール機能がある

スタティックな変更

マニフェストをreplicas: 5にしてみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest

適用する

1
2
$ kubectl apply -f nginx-deployment.yml
deployment.apps/web-deploy configured

実行時の表示はconfigured
起動したPodを確認してみる

1
2
3
4
5
6
7
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 11s 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 37m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 37m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 11s 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 37m 172.17.0.4 minikube <none> <none>

既存の3つのPodに加えて、新しく2つのPodが起動しているのがわかる

コマンドラインでの変更

kubectl scaleを実行することでPodの数を調整できる
現状確認

1
2
3
4
5
6
7
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 9m53s 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 47m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 47m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 9m53s 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 47m 172.17.0.4 minikube <none> <none>

5コ
10コにする

1
2
$ kubectl scale --replicas=10 deployment.apps/web-deploy
deployment.apps/web-deploy scaled

メッセージはscaled
確認する

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 13m 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 50m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-jw5z4 1/1 Running 0 35s 172.17.0.11 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 50m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-nwv8f 1/1 Running 0 35s 172.17.0.10 minikube <none> <none>
web-deploy-654cd6d4d8-pfp5n 1/1 Running 0 35s 172.17.0.9 minikube <none> <none>
web-deploy-654cd6d4d8-rnfpw 1/1 Running 0 35s 172.17.0.13 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 13m 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 50m 172.17.0.4 minikube <none> <none>
web-deploy-654cd6d4d8-wgltb 1/1 Running 0 35s 172.17.0.12 minikube <none> <none>

既存の5コに加えて新規5コが追加されたことがわかる

次回はPodの入替を行なってみる

15Stepで習得 Dockerから入るKubernetes その3

マニフェストファイル

今回はマニフェストファイルを作成してアプリケーションを記述し、実行する

マニフェストファイルの作成

Podのマニフェストファイル(nginxのサンプル)を作成

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest

マニフェストファイルの記述方法は
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/
にあるがよくわからない
kindPodにすると、Podのマニフェストファイルとなる。

マニフェストファイルの適用

以下のコマンドで適用する

1
$ kubectl apply -f 作成したマニフェストファイル

実際に作成したファイルはkubernetes/nginx-pod.ymlなので以下を実行する

1
2
3
4
5
$ kubectl apply -f kubernetes/nginx-pod.yml
pod/nginx created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 7s

クラスタネットワーク上のPodのIPアドレスを表示するには、-o wide オプションを追加する

1
2
3
$ kubectl get pod nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 52s 172.17.0.4 minikube <none> <none>

表示されているIPアドレスに80番でアクセスしてみると、ERR_SOCKET_NOT_CONNECTEDが返ってくる
クラスタネットワーク上のPodにクラスタネットワーク外からアクセスするためにはServiceを利用する必要がある
Serviceはクラスタネットワークのロードバランサ的な存在
今回はServiceなしで動作確認するために、クラスタネットワーク内にPodを作成してテストする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ kubectl run busybox --image=busybox --restart=Never --rm -it sh
If you don't see a command prompt, try pressing enter.

/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:05
inet addr:172.17.0.5 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

/ # wget http://172.17.0.4
Connecting to 172.17.0.4 (172.17.0.4:80)
saving to 'index.html'
index.html 100% |********************************| 612 0:00:00 ETA
'index.html' saved
/ # more index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
/ #

nginxが動作していることが確認できた

次はDeploymentの作成をマニフェストファイルで行う