AWS構築[Cloudfront+ELB+WEB+DB+S3]
AWSなれるために2018年ごろに手でポチポチ構築したときのメモ なので今は設定画面とか変わっているものがありそう [Cloudfront+ELB+WEB+DB+S3] 構成。 ほとんどの場合、Terraformで構築すると思うけど、 その前のAWS入門として一応残しておきます。
仕様と構成
サブネット構成
名前タグ | VPC | AZ | IPv4 CIDR ブロック |
---|---|---|---|
subnet-hogehoge-training-ssh | hog | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hogehoge-training-web01 | training | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hogehoge-training-web02 | training | ap-northeast-c | 172.31.hoge.0/24 |
subnet-hogehoge-training-db01 | training | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hogehoge-training-db02 | training | ap-northeast-c | 172.31.hoge.0/24 |
IAMロール
- IAMロール名
- hoge-training
- 権限
- EBSスナップショット
- S3ファイルアップロード権限
S3
サーバ構成
踏み台
- OS
- CentOS7(AWS Marketplaceから)
- インスタンス対応
- t2.micro
- サブネット
- subnet_ssh
- 自動割当パブリックIP
- 有効化
- プライベートIPアドレス
- 172.31.hoge.10
- ディスク
- 初期値を利用
- ボリュームタイプは汎用SSD(GP2)
- タグ
- セキュリティグループ
- キーペア
- 新規作成
- EIP
- 必要
- ホスト名
web
- OS
- CentOS7(AWS Marketplaceから)
- インスタンス対応
- t2.micro
- サブネット
- 自動割当パブリックIP
- 有効化
- プライベートIPアドレス
- ディスク
- 初期値を利用
- ボリュームタイプは汎用SSD(GP2)
- タグ
- セキュリティグループ
- キーペア
- 新規作成
- EIP
- 不要
- ホスト名
- ミドルウェア
ELB(ALB)
- 名前
- hoge-training-elb
- セキュリティグループ
- セキュリティグループ名:hoge-training-elb
- ルーティングの設定
- ターゲットグループ名:hoge-training-elb
- ターゲットの登録
- webサーバ2台を登録
RDS(MySQL)
- サブネットグループの作成
- hoge-training-db
- 開発/テストを洗濯
- DBエンジンのバージョン
- 最新版を選択
- DBインスタンスの選択
- db.t2.micro
- マルチAZ配置
- はい
- DBインスタンス識別子
- hoge-training-db
- マスターユーザの名前
- root
- パスワード
- VPC
- training
- サブネットグループ
- パブリックアクセス可能
- いいえ
- VPCセキュリティグループ
- タグ名: hoge-training-db
- インバウンドルールの編集: webサーバのsubnetからのみ3306のアクセス許可
- データベース名
- hoge_training_db
- バックアップウィンドウ
- 開始時間20:00UTF
- マイナーバージョン自動アップグレード
- いいえ
- メンテナンスウィンドウ
- 開始日時:日曜日の21:00UTF
CloudFront
S3参照
- logoの画像
/image/
配下は300秒キャッシュ(http://hoge-training.<ドメイン>/image/)
- logo以外
/js/
,/css/
配下は600秒キャッシュ(http://hoge-training.<ドメイン>/js/),(http://hoge-training.<ドメイン>/css/)
- それ以外はキャッシュさせない
- 他のパラメータ値は気にしない
Route53
hoge-trainigをサブドメインとして<ドメイン>に登録
流れ
- hoge-training.<ドメイン> にアクセスするとサイト表示閲覧可能にする。
- ELB から 2 台に振り分けられている状態
- index.html を設置
- RDS 作成
- web サーバから mysql コマンドで接続可能
- CloudFront の設定
- プログラムの作成
手順
IAMロールの作成
ロールは永続的な権限(アクセスキー、シークレットアクセスキー)を保持するユーザーとは異なり、 一時的にAWSリソースへアクセス権限を付与する場合に使用します。
- AWSリソースへの権限付与
- EC2上で稼働するアプリに一時的にAWSのリソースへアクセスする権限を与えたい場合
- EC2作成時にロールを付与することで可能
- [AWS]IAMロールをEC2インスタンスに設定(アタッチ)してみたで、既存のインスタンスにもアタッチ可能
- クロスアカウントアクセス
- 複数のAWSアカウント間のリソースを1つのIAMユーザアカウントで操作したい
- IDフェデレーション
- WEB IDフェデレーション
AWSコンソールのIAM→ロール→ロールの作成
EC2インスタンスだけがそのロールを取得することができるポリシーを選択
次のステップ:アクセス権限
をクリック
ポリシーの作成
をクリック
後述の IAMポリシーの付与
に飛びます。
IAMユーザとグループ
今回は使わないがロールではなくユーザとグループを作成してポリシーを付与するのは以下手順
AWSコンソールのIAM→ユーザ→ユーザを追加
IAMユーザにアクセス権限を設定する場合、ユーザーに直接ポリシー付与する方法と、ポリシー付与したグループを作成して、ユーザーをグループに所属させる方法がある。
基本的にはIAMグループに対して、アクセス権限を設定するようにする。
グループの名前も管理者であることが想像できるものにするのがよい。
- ユーザ名
- hoge-training
- AWSアクセスの種類を選択
- アクセスの種類:プログラムによるアクセス、AWSコンソールへのアクセス
- カスタムパスワード:*********
- パスワードのリセットが必要
- ユーザをグループに追加で
グループの作成
をクリック - グループ名
hoge-training
入力してグループの作成
をクリック - ポリシーの付与はのちほど行うので
次のステップ:確認
をクリック ユーザーの作成
をクリック
これでIAMユーザーが作成されました。
作成結果の画面にアクセスキーIDとシークレットアクセスキーが表示されていますので、
忘れずに控えておきましょう。
.csvのダウンロード
をクリックすると、アクセスキー情報が記載されたCSVファイルをダウンロードできます、
後からアクセスキーの作成は可能だが、同じアクセスキーは二度とダウンロードできないので注意。
アクセスキーを不特定多数が閲覧可能な場所には置かないこと。Githubとか...
アクセスキーを入手したら 閉じる
をクリックしてIAMのユーザー画面に戻る。
IAMポリシーの付与
作成したIAMユーザにアクセス権限を設定 アクセス権限はIAMポリシーで管理されます。 ポリシーには管理ポリシーとインラインポリシーの2種類があります。
- 管理ポリシー
- インラインポリシー
- 特定のIAMユーザ、IAMグループ、IAMロールに直接付与されるポリシー
- 基本的には管理ポリシーを使うので、インラインポリシーが付与されることはあまりない。
- 管理ポリシーはそのポリシーを適用している全ユーザ、グループ、ロールに影響があるので、特定のユーザのみに付与したい場合などはインラインポリシーを使う
ポリシーはJSON形式で記述します。
権限を以下のみにしたいので参考記事を参照しつつ設定してください。
- EBSスナップショット
- S3ファイルアップロード権限
参考記事
Review policy
をクリックし、ポリシー名と説明を記入し、 Create policy
をクリック
次にアクセス権限ポリシーをロールにアタッチさせます。
対象のポリシーを選択し、 次のステップ:確認
をクリック
ロール名とロールの説明を入力し、 ロールの作成
をクリック
EC2で対象のインスタンスを選択し、 アクション→インスタンスの設定→IAMロールの割り当て/置換
をクリックし,アタッチしたいポリシーを選択。
サブネットの作成
サブネットは大きなネットワークを複数の小さなネットワークに分割して管理する歳の、管理単位となるネットワーク ELBを作成する予定があるサブネットは余裕を持って、「/24」(256IPアドレス以上)のネットワーク範囲で作成することが推奨 なぜなら、ELB作成時でELBを作成するサブネットに20IPアドレス以上の空きが必要になるため、「/28」(16IPアドレス)で作成したサブネットにはELBを作成することができないため。
AWSコンソールで VPC→サブネット→サブネットの作成
から以下の条件でサブネットを作成する
名前タグ | VPC | AZ | IPv4 CIDR ブロック |
---|---|---|---|
subnet-hoge-training-ssh | training | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hoge-training-web01 | training | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hoge-training-web02 | training | ap-northeast-c | 172.31.hoge.0/24 |
subnet-hoge-training-db01 | training | ap-northeast-b | 172.31.hoge.0/24 |
subnet-hoge-training-db02 | training | ap-northeast-c | 172.31.hoge.0/24 |
踏み台とWEBは- 自動割当パブリックIPを有効化にしたいので、
サブネットのアクション
タブの自動割り当てIP設定の変更
から有効化します。
EC2作成
AWS操作用の公開鍵・秘密鍵の作成
EC2では公開鍵暗号方式でろログインをします。
EC2→キーペア→キーペアの作成
でキーペアを作成します。
作成したキーペアは作成したタイミングでしかダウンロードできないので注意。
- AWSコンソールからEC2を選択
- EC2ダッシュボードからキーペアを選択
- キーペアの作成をクリック
- キーペア名に作成するキーペアの名前を入力
- 作成をクリック
- pem形式のファイルをダウンロードします。
権限は600
にします。
$ chmod 600 hoge.pem
セキュリティグループを作成
セキュリティグループはホワイトリスト方式なので「何を許可するのか」のみ指定可能 また、セキュリティグループはVPCごとの設定になります。
AWSコンソールのEC2→セキュリティグループ→セキュリティグループの作成
からインバウンド(内部への通信)
で以下の条件で作成
- 踏み台
- WEB
- ELB
- DB
EC2作成・起動
AWSコンソールのEC2→インスタンス→インスタンスの作成
から作成していく
- AMIの選択
AWS Marketplace からCentOS7を選択
- インスタンスタイプの選択
t2.micro
- 詳細設定
ネットワークで対象のVPCを選択 サブネットはそれぞれのものを選択 自動割り当てパブリック IPは有効化 ネットワークインターフェイスのプライマリIPで以下のを指定 - ssh - 172.31.hoge.10 - web01 - 172.31.hoge.10 - web02 - 172.31.hoge.10
ストレージの追加
初期値を利用
ボリュームタイプは汎用SSD(GP2)
タグの追加
Name:hoge-training-ssh Name:hoge-training-web01 Name:hoge-training-web02
- セキュリティグループの設定
既存のセキュリティグループを選択
EIP
AWSコンソールのEC2→Elastic IP→新しいアドレスの割り当て
でElasticIPを作成
次にアクション→アドレスの関連付け
で踏み台のインスタンスとプライベートIPを選択を選択し関連付けをおす。
ELBの作成
AWSコンソールのEC2→ロードバランサー→ロードバランサーの作成
をクリック。
ALBのHTTP(S) で作成。
名前:hoge-training-elb リソースはHTTPのみ アベイラビリティーゾーン:VPCと登録するEC2インスタンスを含むAZを選択 タグ:Name,hoge-training-elb
次の手順:セキュリティ設定の構成
を選択
以下のエラーが出るが気にせず、進む。
ロードバランサーのセキュリティを向上させましょう。ロードバランサーは、いずれのセキュアリスナーも使用していません。 ロードバランサーへのトラフィックを保護する必要がある場合は、フロントエンド接続に HTTPS プロトコルをお使いください。 最初のステップに戻り、基本的な設定 セクションでセキュアなリスナーを追加 / 設定することができます。または現在の設定のまま続行することもできます。
ステップ 3: セキュリティグループの設定
では既存のセキュリティグループを選択する
で既に作成したセキュリティグループを選択
ステップ 4: ルーティングの設定
のターゲットグループ
では名前だけ入力
名前:ELBTARGET
ステップ 5: ターゲットの登録
で追加したいEC2インスタンスを選択して、登録済みに追加
をクリック
登録済みに追加
されたら次の手順:確認
を選択
ステップ 6: 確認
で問題なければ作成
ELBの動作確認
webサーバにcentosをインストール
# yum -y install httpd # systemctl list-unit-files -t service |grep httpd httpd.service disabled # systemctl enable httpd.service Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service. # systemctl list-unit-files -t service |grep httpd httpd.service enabled # systemctl start httpd.service
ELBのDNS名をブラウザに入力してindex.html
の中身が表示されることを確認
ターゲットグループのターゲットから両インスタンスがhealthy
になることを確認
Route53の設定
ホストゾーンドメイン
は既にあるものなどを使い、
hoge-trainigをサブドメインとして ドメイン
に登録する。
ホストゾーンはそのドメインのリソースレコードセットの集合です。
Route53→Hosted zones
からドメイン
を選択
Create Record Set
を選択
Name:hoge-training
Type:Aレコード(IPv4)
Value:Alias:Yes
Alias Target:ELBのDNS名
Routing Policy:Simple
のちにAliasをCloudFrontに変更します。
RDS 作成
VPC上にRDSインスタンスを起動する場合、DBサブネットグループを作成する必要があるので まずはサブネットグループを作成します。
RDS→サブネットグループ→DBサブネットグループの作成
を選択
サブネットグループの詳細
名前:hoge-training
説明:middle engineer training ozawa subnet
VPC:trainingのVPCを選択
サブネットの追加でアベイラビリティーゾーン
とサブネット
RDS→インスタンス→DBインスタンスの起動→MySQL
を選択
DB詳細の指定
- 開発/テストを選択
- DBエンジンのバージョン
- 最新のバージョン
- DBインスタンスの選択
- db.t2.micro
- マルチAZ配置
- 別のゾーンにレプリカを作成します
- DBインスタンス識別子
- hoge-training-db
- マスターユーザの名前
- root
- パスワード
[詳細設定]の設定 ネットワーク&セキュリティ
- VPC
- training
- サブネットグループ
- hoge_training
- パブリックアクセシビリティ
- いいえ
- アベイラビリティーゾーン
- 指定なし
- VPCセキュリティグループ
- タグ名: hoge-training-db
データベースの設定
- データベースの名前
- hoge_training_db
- データベースのポート
- 3306
- DBパラメータグループ
- デフォルト
- オプショングループ
- デフォルト
- IAM DB 認証
- 無効化
暗号化
- 無効化(無料利用枠ではデフォルトで無効)
バックアップ
- バックアップの保存期間
- 1日
- バックアップウィンドウ
- 開始時間20:00UTF期間0.5時間
- タグをスナップショットへコピー - チェック
モニタリング
- 拡張モニタリング
- 有効
- モニタリングロール:デフォルト
- 60秒
ログのエクスポート
- 監査ログ
- 有効
- エラーログ
- 無効
- 全般ログ
- 有効
- スロークエリログ
- 有効
メンテナンス
- マイナーバージョン自動アップグレード
- 無効化
- メンテナンスウィンドウ
- 開始日時:日曜日の21:00UTF期間0.5時間
DBインスタンスの作成
で作成完了
webサーバにmysqlクライアントをインスタンス RDSインスタンスからエンドポイントを確認
# yum install mysql -y # mysql -u root -h エンドポイント名 -p
S3
hoge-training.<ドメイン>
でバケットを作成します。
S3→バケットを作成する
で作成します。
{ "Version": "2012-10-17", "Id": "PublicRead", "Statement": [ { "Sid": "ReadAccess", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::hoge-training.<ドメイン/*" } ] }
プロパティの設定およびアクセス許可の設定はデフォルトのまま進めます。
CloudFrontの設定
CloudFrontはAWSのCDNサービスです。 CDNとはコンテンツを配信するために最適化されたネットワークのことです。 分散して配置されたサーバからコンテンツを配布することで効率的にコンテンツを配信する仕組み。
CloudFrontはAWSが世界中に配置したエッジサーバを利用して効率的にコンテンツを配信します。 エッジサーバはCloudFrontのコンテンツの配布ポイントでユーザーのアクセスを最も近くにあるエッジサーバに誘導します。 「xxx.cloudfront.net」というドメインにアクセスすると、最も近いエッジサーバのIPアドレスが返されます。 CloudFrontではコンテンツの配信元のサーバをオリジンサーバと呼びます。 CloudFrontを利用していない場合は、全てのアクセスがオリジンサーバにいくが、 利用するとオリジンサーバに到達する前に、エッジサーバがコンテンツを返す。 そのため、オリジンサーバの負荷を下げることができ負荷分散としても大きな意味があります。 なのでEC2やS3等コンテンツを配信するサーバの前には、なるべくCloudFrontを配置するべき。
エッジロケーションはエッジサーバが存在する地域で、日本では東京と大阪にある。
CloudFront→Create Distribution
をクリック
- コンテンツの配信方法の選択
HTTP[S]で表示するWEBコンテンツの配信なのでWEBを選択します。
- Distributionの設定
OriginSettingでオリジンサーバの設定をします。
今回CloudFrontはS3とALBの前に設置するので、
Origin Domain Name
にS3とALBを選択して入力することになります。
- Origin Domain Name
- Behaviors
- /image/* 300 秒キャッシュ
- Origin Domain Name
- hoge-training-elb-1353485913.ap-northeast-1.elb.amazonaws.com
Behaviors
- /js/* 600 秒キャッシュ
- /css/* 600 秒キャッシュ
- Default (*)
Distributionの設定(Origin Settings)
オリジンサーバの設定をする
設定項目 | 値 | 説明 |
---|---|---|
Origin Domain Name | S3バケットのエンドポイント | オリジンサーバのドメインを入力 |
Origin Path | 値なし | CloudFrontへのリクエストをオリジンサーバの特定のパスにルーティングしたい場合に設定。 |
Origin ID | 任意の名前 | このDistributionを区別するための名前を設定 |
Restrict Bucket Access | No | オリジンがS3の場合のみ有効。S3バケットのコンテンるへのアクセスをCloudFrontからのみに制限する場合はYes。直接エンドポイントにアクセスできるようにするならNo |
Origin Custom Headers | 値なし | リクエストをオリジンサーバに転送する際のヘッダーを指定 |
- Default Cache Behavior Setting
キャッシュの動作の設定をする
設定項目 | 値 | 説明 |
---|---|---|
Path Pattern | Default(*) | キャッシュを有効にするパスのパターンを指定。 |
Viewer Priticol Policy | HTTP and HTTPS | コンテンツにアクセスする際にどのプロトコルを使用するか選択 |
Allowed HTTP Methods | GET,HEAD | エンドユーザーに許可するHTTPメソッドを選択 |
Field-level Encryption Config | 値なし | 特定のデータフィールドにフィードレベル暗号化を適用する場合に指定 |
Cached HTTP Methods | GET,HEAD | CloudFrontでのキャッシュが有効になるHTTPメソッドを選択 |
Cached Based on Selected Request Headers | None | CloudFrontがオリジンサーバに転送するリクエストヘッダーの指定とヘッダー値に基づいてオブジェクトをキャッシュするかの設定を行う。 |
Object Caching | Use Origin Cache Headers | CloudFrontがキャッシュを保持する時間の設定。オリジンサーバで追加したCache-COntorolの時間に応じてキャッシュを保持する場合は、今回の値を設定する。 |
Minimum TTL | 0 | キャッシュの最小保持期間 |
Maximum TTL | 31536000 | キャッシュの最大保持期間 |
Default TTL | 86400 | キャッシュのデフォルトの保持期間 |
Foward Cookied | None | CloudFrontからオリジンサーバに転送するCookieを指定。オリジンがS3のときは無効。 |
Query String Fowarding and Caching | None | クエリ文字列に基づいてキャッシュを行う |
Smooth Streaming | No | Microsoftスムーズストリーミング形式のメディアファイルを配信する場合はYES |
Restrict Viewer Access | No | 署名付きURLを利用するかの選択 |
Compress Objects Automatically | No | ファイルを自動的に圧縮する |
Lambda Function Assopciations | 値なし | トリガーを追加するLambda関数のARNを指定 |
- Distribution Setting
Distributionの詳細を設定
設定項目 | 値 | 説明 |
---|---|---|
Price Class | Use ALL Edge Locations | 価格クラスを選択。 |
AWS WAF Web ACL | None | AWS WAFを使用する場合にウェブACLを選択する・ |
Alternate Domain Names | 値なし | 独自ドメインを利用する場合に設定 |
SSL Certificate | Default CloudFrint Cerificate | DefaultではCloudFrontにデフォルトで用意されている証明書を利用する。 |
Supported HTTP Versions | HTTP/2,HTTP/1.1,HTTP/1.0 | CloudFrontとの通信に使用するHTTPバージョンを指定 |
Default Root Object | index.html | デフォルトのルートオブジェクトを設定 |
Logging | OFF | ログを取得するか設定 |
Bucket for Logs | 値なし | ログを配置するS3のバケットを選択 |
Log Prefix | 値なし | ログファイル名の戦闘につける文字列を指定 |
Cookie Logging | off | ログにCookieも記録するか選択 |
Enable IPv6 | 有効 | IPv6を有効にするか選択 |
Comment | 値なし | 入力は任意。 |
Distribution State | Enabled | Distributionの使用準備が整ったあと、自動的にこのDistributionを有効にするか選択 |
Deployedになったら、Domain Nameに表示されている「****.cloudfront.net」にアクセスすればS3のコンテンツが表示されます。
- Route53との連系
Route53にCLoudFrontのエンドポイントを設定することで、独自ドメインでCloudFrontを利用することができます。 作成したDistributionを選択し、Distribution Settingをクリック。 GeneralタブのEditで編集画面に行き、Alternate Domain Namesに設定したい独自ドメインを入力する。
次にRoute5→Hotsted Zonesから使用する独自ドメインのホストゾーンを選択し、Aliasレコードを追加する。
確認項目
セキュリティ
RDS
- 手動フェイルオーバを行なう
- AZ が切り替わっていることを確認
- サービスが閲覧できることを確認
S3
- web サーバから aws コマンドを利用してS3 のバケットにテストファイルをアップロードする
- S3 のバケットから aws コマンドを利用してテストファイルをダウンロードする
- 踏み台からは S3 操作が不可であることを確認する
EBS
- web サーバから aws コマンドを利用して、EBS スナップショットを取得する
- 踏み台からは EBS スナップショット取得が出来ないことを確認
サイト表示
- yourname-training.<ドメイン> 画面表示が正常であることを確認
- web01, web02 に分散されていることを確認
- web01 を ELB から切り離しても正常に閲覧できることを確認
- image 配下へのアクセス
- S3 へアクセスが行っていることを確認
- js, css 配下へのアクセス ELB を経由していることを確認
- キャッシュ時間に応じてキャッシュされていることを確認
上記以外
- ELB を経由していることを確認
- キャッシュされていないことを確認
podのCrashLoopBackOff原因およびNodeのNot Readyフラッピング問題調査
これは何?
とあるPodがCrashLoopBackOffのステータスになりあがってくれず、 それにあわせてNodeのstatusがNot Readyでフラッピングしている。 調査しつつ周辺技術(kubelet, CRI,CNIとか)についても調べて自信ニキになりたい。
事象
fluentdのpodがCrashLoopBackOffのステータスになり起動しない、 それに伴いNodeのstatusもNot Readyにフラッピングしている。
- 各nodeの状態
# kubectl get pods |grep fluentd node1 0/1 CrashLoopBackOff 2029 28d node2 0/1 CrashLoopBackOff 1075 28d node3 0/1 CrashLoopBackOff 1052 28d node4 0/1 CrashLoopBackOff 1036 28d node5 0/1 CrashLoopBackOff 2994 28d
どんなとき
fluentdにログが流れてなかった時期
原因
CNIのbug fluentd PodのPodSandboxのコンテナがないためkubeletでPodの起動に失敗している。
根本対応
bugfixされたlibcniをpullする。
暫定対応
PodSandboxのコンテナ起動もしくはfluentd Podの再作成(DeamonSetなので消せば再起動するため)もしくはkubelet再起動
調査した流れとログ
pod起動していないのでlogsは不可。
kubeletかdescribeでまずは調べる。
台数あるのでまずは fluentd
を中心に調べていく。
その次にNode NotreadyについてPLEG周りを調べていく。
- node server
kubeletが fluentd-
podへの動機に失敗している模様
# journalctl -u kubelet -- Logs begin at 月 2018-11-19 12:14:46 JST, end at 月 2019-02-04 16:29:22 JST. -- 1月 24 01:49:36 node kubelet[10796]: E0124 01:49:36.768314 10796 pod_workers.go:190] Error syncing pod a094d5a4-125b-11e9-8374-fa163e76fc98 ("fluentd(a094d5a4-125b-11e9-8374-fa163e76fc98)"), skipping: rpc err 1月 24 01:49:42 node kubelet[10796]: I0124 01:49:42.507809 10796 setters.go:72] Using node IP: "10.64.152.1" 1月 24 01:49:51 node kubelet[10796]: E0124 01:49:51.768283 10796 pod_workers.go:190] Error syncing pod a094d5a4-125b-11e9-8374-fa163e76fc98 ("fluentd(a094d5a4-125b-11e9-8374-fa163e76fc98)"), skipping: rpc err 1月 24 01:49:52 node kubelet[10796]: I0124 01:49:52.523387 10796 setters.go:72] Using node IP: "10.64.152.1"
- Master側
CrashLoopBackOffはどうやら以下の内容
fluentd
は Daemonset
だった。なので自動起動を何度も試みていると考えられる。
# kubectl get pods fluentd -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES fluentd 0/1 CrashLoopBackOff 1075 28d 172.16.69.8 node <none> <none>
- master側
OCIruntimeがコンテナ起動作成失敗している模様
Eventsに status: rpc error
とあるので、kubeletからCRIへのgrpcプロトコルの命令が処理されずエラーになっていると考えられる。
# kubectl describe pods fluentd (略) State: Waiting Reason: CrashLoopBackOff Last State: Terminated Reason: ContainerCannotRun Message: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"\"": unknown Exit Code: 128 Started: Fri, 11 Jan 2019 16:26:40 +0900 Finished: Fri, 11 Jan 2019 16:26:40 +0900 (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedSync 60m (x85 over 19d) kubelet, node error determining status: rpc error: code = Unknown desc = operation timeout: context deadline exceeded Warning FailedSync 8s (x123314 over 23d) kubelet, node error determining status: rpc error: code = DeadlineExceeded desc = context deadline exceeded
PodSandboxStatus of sandbox for pod "fluentd" error: rpc error: code = Unknown desc = Error: No such container:
とあるので
fluentd
podのための PodSandbox
がないメッセージが出力されている。
- node
# less /var/log/messages-20190113 (略) Jan 7 09:07:16 node004 kubelet: E0107 18:07:16.254903 10796 kuberuntime_manager.go:857] PodSandboxStatus of sandbox "5983c305299bada0906df670eba18f8be1e5192d75b825f1a01075dd5595c5f3" for pod "fluentd(a094d5a4-125b-11e9-8374-fa163e76fc98)" error: rpc error: code = Unknown desc = Error: No such container: 5983c305299bada0906df670eba18f8be1e5192d75b825f1a01075dd5595c5f3 Jan 7 09:07:16 node004 kubelet: E0107 18:07:16.254959 10796 generic.go:247] PLEG: Ignoring events for pod fluentd/default: rpc error: code = Unknown desc = Error: No such container: 5983c305299bada0906df670eba18f8be1e5192d75b825f1a01075dd5595c5f3
- node
fluentd
コンテナは起動しきってない。
gcr.io/google_containers/pause-amd64
もk8s_POD_fluentd_default_a094d5a4-125b-11e9-8374-fa163e76fc98_1
をみにいっている。
google_containers/pause-amd64 pause-amdd64はimage周りで使うコンテナの模様
image_gc_manager_test.goでもpauseコンテナについて書いてある。
pauseコンテナの説明はここがわかりやすい
# docker ps -a [85/1657] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 000016b6000 asia.gcr.io/hoge/fluentd "/bin/sh -c '/run.sh…" 3 weeks ago Created k8s_fluentd_fluentd_default_a094d5a4-125b-11e9-8374-fa163e76fc98_1076 0004301c000 asia.gcr.io/hoge/fluentd "/bin/sh -c '/run.sh…" 3 weeks ago Removal In Progress k8s_fluentd_fluentd_default_a094d5a4-125b-11e9-8374-fa163e76fc98_1075 0002e7bc000 gcr.io/google_containers/pause-amd64:3.1 "/pause" 3 weeks ago Up 3 weeks k8s_POD_fluentd_default_a094d5a4-125b-11e9-8374-fa163e76fc98_1
以上をまとめると fluentd
コンテナは作成され起動しようとしているけど、OCIruntimeがコンテナ起動作成失敗していると考えられる。
fluentd_default
podのための PodSandbox
がないメッセージが出力されているので、 PodSandbox
に調べてみる。
PodSandbox は以下。
流れとして kubelet→CRI(docker)→podsandbox→pod
となる。
Before starting a pod, kubelet calls RuntimeService.RunPodSandbox to create the environment. This includes setting up networking for a pod (e.g., allocating an IP). Once the PodSandbox is active, individual containers can be created/started/stopped/removed independently. To delete the pod, kubelet will stop and remove containers before stopping and removing the PodSandbox. Kubelet is responsible for managing the lifecycles of the containers through the RPCs, exercising the container lifecycles hooks and liveness/readiness checks, while adhering to the restart policy of the pod.
つまりkubeletはポッドを開始する前に、RuntimeServiceを呼ぶ。そしてRunPodSandboxを呼び出して環境を作成する。(ポッド用のネットワーク設定(IP割当て)などもする。) PodSandboxがアクティブになると、個々のコンテナを個別に作成/開始/停止/削除することができる。 ポッドを削除するには、kubeletはPodSandboxを停止して削除する前にコンテナを停止して削除する。 Kubeletは、ポッドの再起動ポリシーを守りながら、RPCを通じてコンテナのライフサイクルを管理して、 コンテナーのライフサイクルフックを実行し、liveness/readiness のチェックを行う。
とあるのでkubeletがCRIにgRPCでコンテナ起動させようとしても PodSandboxのコンテナがないため、コンテナの起動に失敗している。 そしてDeamonSetが起動させようとして、Woeker NodeのStatusもフラッピングしていると考えられる。
Not ReadyのNodeでは PLEG
でFalseしている。
PLEGはここ参照。
PLEGはkubeletの内部モジュールで、
Pod Lifecycle Event Generatorという名前の通り、kubeletがPodの管理およびコンテナの状態を管理するためのもの。
# kubectl describe nodes node Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- MemoryPressure False Tue, 05 Feb 2019 14:36:43 +0900 Fri, 21 Dec 2018 20:19:20 +0900 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Tue, 05 Feb 2019 14:36:43 +0900 Fri, 21 Dec 2018 20:19:20 +0900 KubeletHasNoDiskPressure kubelet has no disk pressure PIDPressure False Tue, 05 Feb 2019 14:36:43 +0900 Fri, 21 Dec 2018 20:19:20 +0900 KubeletHasSufficientPID kubelet has sufficient PID available Ready False Tue, 05 Feb 2019 14:36:43 +0900 Tue, 05 Feb 2019 14:36:33 +0900 KubeletNotReady ≈is not healthy: pleg was last seen active 3m11.707539232s ago; threshold is 3m0s (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal NodeReady 19m (x8929 over 45d) kubelet, node004 Node node004 status is now: NodeReady Normal NodeNotReady 4m15s (x8932 over 24d) kubelet, node004 Node node004 status is now: NodeNotReady
PLEGのhealth checkは3分毎。docker ps
でコンテナの状態変化を検出し、docker ps
とinspect
でこれらのコンテナの詳細を取得する。
これらが終了した後にタイムスタンプを更新するのだけれども、タイムスタンプが更新されていない場合(3分)、ヘルスチェックは失敗する。
https://github.com/kubernetes/kubernetes/blob/a1539d8e52c7ca5f6a590eebc66a5b33acc9c036/pkg/kubelet/pleg/generic.go#L134-L146
Master側はNodeのkubeletのPLEGからpodが落ちていると受け取って、Not Readyとしている。 そしてPLEGがpodが落ちていると判断しているのはPodSandboxがおらずコンテナが起動していないから。 そしてCNIのbugでpodsandboxの起動時失敗でtimeoutのままlockを要求して、podsandboxが再起動されず起動していない模様。 https://github.com/containernetworking/cni/issues/567
# kubectl describe pods fluentd (略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedSync 60m (x85 over 19d) kubelet, node004 error determining status: rpc error: code = Unknown desc = operation timeout: context deadline exceeded Warning FailedSync 8s (x123314 over 23d) kubelet, node004 error determining status: rpc error: code = DeadlineExceeded desc = context deadline exceeded
コンテナがどうやって起動しているのか、コンテナランタイムの実装などをみて、 理解が必要だと思ったので、理解を深めてからまた、kubernatesのpod起動周りについて調べ直したい。
kubeadmでHA構成のetcdクラスタ構築
Kubeadmは、コントロールプレーンノード上のkubeletによって管理される静的ポッドで単一メンバーのetcdクラスタをデフォルトで実行する。 etcdクラスターに含まれるメンバーは1つだけで、メンバーが使用不可になっても持続できないため、これはHA設定ではない。 このタスクでは、kubeadmを使用してkubernetesクラスタを設定するときに外部etcdとして使用できる3つのメンバからなる高可用性etcdクラスタを作成する手順をみていく。
始める前に
- ポート2379および2380を介して互いに通信できる3つのホスト。(今回はこれらをデフォルトポートと想定。kubeadmの設定ファイルで設定可能)
- 各ホストにはdocker、kubelet、およびkubeadmがインストールされている必要がある。
- ホスト間でファイルをコピーするためのssh, scpなどが可能であること。
クラスタを設定
一般的な方法は、1つのノードですべての証明書を生成し、必要なファイルだけを他のノードに配布すること。
※kubeadmには、以下に説明する証明書を生成するために必要なすべての暗号化機構が含まれているので他の暗号化ツールは必要ない
- etcのサービスマネージャになるようにkubeletを設定
etcdが最初に作成されたので、kubeadm提供のkubeletユニットファイルよりも高い優先順位を持つ新しいユニットファイルを作成することによって サービスの優先順位を上書きする必要がある。
cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf [Service] ExecStart= ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true Restart=always EOF systemctl daemon-reload systemctl restart kubelet
- kubeadm用の設定ファイルを作成
以下のスクリプトを使用して、etcdメンバーが実行されるホストごとに1つのkubeadm構成ファイルを生成する。
# Update HOST0, HOST1, and HOST2 with the IPs or resolvable names of your hosts export HOST0=10.64.20.1 export HOST1=10.64.20.2 export HOST2=10.64.20.3 # Create temp directories to store files that will end up on other hosts. mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/ ETCDHOSTS=(${HOST0} ${HOST1} ${HOST2}) NAMES=("infra0" "infra1" "infra2") for i in "${!ETCDHOSTS[@]}"; do HOST=${ETCDHOSTS[$i]} NAME=${NAMES[$i]} cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml apiVersion: "kubeadm.k8s.io/v1beta1" kind: ClusterConfiguration etcd: local: serverCertSANs: - "${HOST}" peerCertSANs: - "${HOST}" extraArgs: initial-cluster: ${NAMES[0]}=https://${ETCDHOSTS[0]}:2380,${NAMES[1]}=https://${ETCDHOSTS[1]}:2380,${NAMES[2]}=https://${ETCDHOSTS[2]}:2380 initial-cluster-state: new name: ${NAME} listen-peer-urls: https://${HOST}:2380 listen-client-urls: https://${HOST}:2379 advertise-client-urls: https://${HOST}:2379 initial-advertise-peer-urls: https://${HOST}:2380 EOF done
- 認証局を生成する
すでにCAを持っているなら、 crt
と key
ファイルを /etc/kubernetes/pki/etcd/ca.crt
と /etc/kubernetes/pki/etcd/ca.key
にコピーするだけがアクションです
これらのファイルをコピーしたら、次の手順「各メンバーの証明書を作成する」に進む。ない場合は作成する。
- 各メンバーの証明書を作成する
kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml cp -R /etc/kubernetes/pki /tmp/${HOST2}/ # cleanup non-reusable certificates find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml cp -R /etc/kubernetes/pki /tmp/${HOST1}/ find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml # No need to move the certs because they are for HOST0 # clean up certs that should not be copied off this host find /tmp/${HOST2} -name ca.key -type f -delete find /tmp/${HOST1} -name ca.key -type f -delete
- 証明書とkubeadm設定をコピーする
証明書が生成されたので、今度はそれらをそれぞれのホストに移動する必要がある。
USER=hogeuser HOST=${HOST1} scp -r /tmp/${HOST}/* ${USER}@${HOST}: ssh ${USER}@${HOST} USER@HOST $ sudo -Es root@HOST $ chown -R root:root pki root@HOST $ mv pki /etc/kubernetes/
- 必要なファイルがすべて存在することを確認。
$HOST0
に必要なファイルの完全なリストは以下。
/tmp/${HOST0} └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── ca.key ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
$HOST1
$HOME └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
$HOST2
$HOME └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
- 静的ポッドマニフェストを作成
証明書と設定が整ったので、次にマニフェストを作成。 各ホストで、kubeadmコマンドを実行してetcdの静的マニフェストを生成する。
root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml root@HOST1 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml root@HOST2 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml
- オプション:クラスターの正常性を確認
docker run --rm -it \ --net host \ -v /etc/kubernetes:/etc/kubernetes quay.io/coreos/etcd:${ETCD_TAG} etcdctl \ --cert-file /etc/kubernetes/pki/etcd/peer.crt \ --key-file /etc/kubernetes/pki/etcd/peer.key \ --ca-file /etc/kubernetes/pki/etcd/ca.crt \ --endpoints https://${HOST0}:2379 cluster-health ... cluster is healthy
${ETCD_TAG}
:あなたのetcd画像のバージョンタグを設定。例えばv3.2.24。
${HOST0}
:テストしているホストのIPアドレスを設定。
Creating multi master cluster with kubeadm(ver1.13以下)
document
https://kubernetes.io/docs/setup/independent/install-kubeadm/ https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/ kubeadmのトラブルシューティング
始める前に
- 以下のいずれかを実行している1台以上のマシンを用意
- Ubuntu 16.04+
- CentOS 7
- マシンごとに2 GB以上のRAM(それ以下にすると、アプリケーション用のスペースが狭まる)
- 2 CPU以上
- クラスタ内のすべてのマシン間の完全なネットワーク接続(パブリックまたはプライベートネットワークは問題なし)
- ノードごとに固有のホスト名、MACアドレス、およびproduct_uuid。
- マシンでは特定のポートを開けとく
- スワップ無効(kubeletを正しく動作させるためにスワップを無効にする。)
今回の構成
ホスト名 | 役割 |
---|---|
haproxy01 | ロードバランサー(HAProxy) |
master-node01 | MasterNode |
master-node02 | MasterNode |
master-node03 | MasterNode |
worker-node01 | WorkerNode |
worker-node02 | WorkerNode |
worker-node03 | WorkerNode |
クライアントに必要なもの
cfsslとkubectlをインストールする
HAProxyロードバランサーのインストール
3つのKubernetesマスターノードを配置するので、 トラフィックを分散させるためにそれらの前にHAPRoxyロードバランサーを配置する必要がある。
- LBにするサーバにSSHで接続します。
- OS update
$ sudo yum update -y
- HAProxyをインストール
$ sudo yum install haproxy
- 3つのKubernetesマスターノード間でトラフィックを負荷分散するようにHAProxyを設定。
$ sudo vim /etc/haproxy/haproxy.cfg global ... default ... #--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend kubernetes bind 10.64.21.35:6443 option tcplog mode tcp default_backend kubernetes-master-nodes #--------------------------------------------------------------------- # static backend for serving up images, stylesheets and such #--------------------------------------------------------------------- backend static balance roundrobin server static 127.0.0.1:4331 check #--------------------------------------------------------------------- # round robin balancing between the various backends #--------------------------------------------------------------------- backend kubernetes-master-nodes mode tcp balance roundrobin option tcp-check server master-node01 10.64.20.01:6443 check server master-node02 10.64.20.02:6443 check server master-node03 10.64.20.03 :6443 check
- HAProxyを再起動。
$ sudo systemctl restart haproxy
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg exclude=kube* EOF # Set SELinux in permissive mode (effectively disabling it) setenforce 0 sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes systemctl enable kubelet && systemctl start kubelet
以下は各kubeノードで実行
sudo visudo
で一般ユーザにroot権限を付与
sudo yum -y install vim
Dockerのインストール
$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 $ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo $ sudo yum -y install docker-ce-18.06.1.ce-3.el7 $ sudo systemctl start docker & sudo systemctl enable docker
kubeadmのインストール
まず事前準備として、全ノードで Docker、CLI 等の関連パッケージのインストールと、 クラスタ内で利用するオーバーレイネットワーク用にカーネルパラメータを変更しておきます。
# 必要な依存パッケージのインストール $ sudo yum -y update # リポジトリの登録と更新 $ sudo su - $ cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg exclude=kube* EOF # SELinux disabling it) setenforce 0 sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config # Kubernetes 関連パッケージのインストール yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes systemctl enable --now kubelet # オーバーレイネットワーク用にカーネルパラメータを変更 # RHEL / CentOS 7の一部のユーザーは、iptablesがバイパスされているために # トラフィックが誤ってルーティングされるという問題を報告しています。 # あなたのnet.bridge.bridge-nf-call-iptables設定で1に設定されていることを確認する必要がある cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
kubeadmを使ったHAクラスタの作成
TLS証明書を生成する
これらの手順は、cfsslツールをインストールした場所に応じて、 LinuxデスクトップまたはHAProxyマシン上にあれば実行できる。
認証局を作成する
- 認証局設定ファイルを作成します。
$ vim ca-config.json { "signing": { "default": { "expiry": "8760h" }, "profiles": { "kubernetes": { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "8760h" } } } }
- 認証局署名要求設定ファイルを作成します。
$ vim ca-csr.json { "CN": "Kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "IE", "L": "Cork", "O": "Kubernetes", "OU": "CA", "ST": "Cork Co." } ] }
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
- ca-key.pemとca.pemが生成されたことを確認します。
$ ls -la
Etcdクラスター用の証明書を作成する
- 証明書署名要求設定ファイルを作成します。
$ vim kubernetes-csr.json { "CN": "kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "IE", "L": "Cork", "O": "Kubernetes", "OU": "Kubernetes", "ST": "Cork Co." } ] }
- 証明書と秘密鍵を生成します。
cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -hostname=10.64.20.1,10.64.20.2,10.64.20.3,10.64.21.35,127.0.0.1,kubernetes.default \ -profile=kubernetes kubernetes-csr.json | \ cfssljson -bare kubernetes
- kubernetes-key.pemファイルとkubernetes.pemファイルが生成されたことを確認
ls -la
- 証明書を各ノードにコピー
$ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.1~ $ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.2:~ $ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.3:~ $ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.4:~ $ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.5:~ $ scp ca.pem kubernetes.pem kubernetes-key.pem hogeuser@10.64.20.6:~
最初のコントロールプレーンノードの手順
最初のコントロールプレーンノードで、次の設定ファイルを作成
kubeadm-config.yaml
kubernetesVersion
使用するKubernetesバージョンに設定する必要があります。この例ではstable
を使用。controlPlaneEndpoint
ロードバランサのアドレスまたはDNSとポートを一致させる必要があり。kubeadm、kubelet、kubectl
およびKubernetesのバージョンを一致させることがお勧め。
apiVersion: kubeadm.k8s.io/v1beta1 kind: ClusterConfiguration kubernetesVersion: stable apiServer: certSANs: - "10.64.21.35" controlPlaneEndpoint: "10.64.21.35:6443"
- ノードがクリーンな状態にあることを確認
sudo kubeadm init --config=kubeadm-config.yaml
次のようなものが見えるはず
To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 10.64.21.35:6443 --token c6c3id.bba2b5hih8ka9jx3 --discovery-token-ca-cert-hash sha256:b078841bd826050e1461341835ffc5a5b0cf2e32365a33794eb77512ca0c016a
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
kubectl を kubelet に利用可能にするために以下のコマンドを実行しておくこと
$ mkdir -p $HOME/.kube $ cp -f /etc/kubernetes/admin.conf $HOME/.kube/config $ chown $(id -u):$(id -g) $HOME/.kube/config
実行しない場合は次のようになる。
# kubectl get pod --all-namespaces Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")
- 次のように入力して、コンポーネントのPodを見始める。
kubectl get pod -n kube-system -w
- 最初のノードの初期化が完了した後にのみ、新しいコントロールプレーンノードを結合させる。
次の例でCONTROL_PLANE_IPSは、他のコントロールプレーンノードのIPアドレスに置き換えます。
USER=hogeuser CONTROL_PLANE_IPS="10.64.20.190 10.64.20.186" for host in ${CONTROL_PLANE_IPS}; do scp /etc/kubernetes/pki/ca.crt "${USER}"@$host: scp /etc/kubernetes/pki/ca.key "${USER}"@$host: scp /etc/kubernetes/pki/sa.key "${USER}"@$host: scp /etc/kubernetes/pki/sa.pub "${USER}"@$host: scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host: scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host: scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key scp /etc/kubernetes/admin.conf "${USER}"@$host: done
注意:上記のリストの証明書だけをコピーしてください。kubeadmは、参加しているコントロールプレーンインスタンスに必要なSANを使用して、残りの証明書を生成します。すべての証明書を誤ってコピーした場合、必要なSANが不足しているために追加のノードを作成できない可能性があります。
残りのコントロールプレーンノードの手順
ノード一つずつ、クラスタに組み込んでから次のノードに進むこと
- 前の手順で作成したファイルを
scp
を使用した場所に移動させる
USER=hogeuser sudo mkdir -p /etc/kubernetes/pki/etcd sudo mv /home/${USER}/ca.crt /etc/kubernetes/pki/ sudo mv /home/${USER}/ca.key /etc/kubernetes/pki/ sudo mv /home/${USER}/sa.pub /etc/kubernetes/pki/ sudo mv /home/${USER}/sa.key /etc/kubernetes/pki/ sudo mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/ sudo mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/ sudo mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt sudo mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key sudo mv /home/${USER}/admin.conf /etc/kubernetes/admin.conf
- 最初のノードで以前に渡されたjoinコマンドを使用して、このノードで起動(
kubeadm init
)します。これは次のようになります。
sudo kubeadm join 10.64.21.35:6443 --token c6c3id.bba2b5hih8ka9jx3 --discovery-token-ca-cert-hash sha256:b078841bd826050e1461341835ffc5a5b0cf2e32365a33794eb77512ca0c016a --experimental-control-plane
--experimental-control-plane
フラグの追加に注意してください。このフラグは、このコントロールプレーンノードをクラスタに参加させることを自動化します。
コントロールプレーンノードをクラスタ追加失敗時は kubeadm reset
して kubeadm init
する。
- 次のように入力して、コンポーネントのポッドを見始めます。
kubectl get pod -n kube-system -w
- 残りのコントロールプレーンノードに対してこれらの手順を繰り返します。
workerノードのクラスタ組み込み
さきほどの kubeadm join
のコマンドを --experimental-control-plane
をつけないで 実行。
1台ずつpodが組み込まれて完了したことを確認してから実行していくこと。
unshareコマンドでLinuxのNamespaceに入門
Namespaceはコンテナで使われている技術の一つで、コンテナを理解深めるために知っておくとよいので調べてみた。 どんな使われ方をしているかというと、 例えばPID namespaceはPIDの number spaceを隔離する。 これは同じホスト上で実行されている2つのプロセスが同じPIDを持つことができるということになる。
namespaceがなくて隔離されてないとコンテナAがコンテナB、C、Dなどに filesystemのunmountやホスト名の変更、NWインターフェースの削除など できたりしてしまうので、必ず他のコンテナのプロセスがみれないようにする。
Namespace
Kernel/OSのリソースで、物理リソースは制限しない(cgroupsでする)が、 以下の項目についてNamespaceを分離する。 namespaceを分離した環境では、許可されたリソースしか見えなくなるので コンテナ内の要素だけ見えるように制限できる。
- Mount Namespace(ファイルシステムのマウントポイントを分離: Namespace 内の mount / umount が他の Namespace に影響を与えないようにする)
- UTS Namespace(ホスト名,ドメイン名の分離)
- PID Namespace(PID 空間の分離、新しい PID Namespace では PID 1 から始まる)
- IPC Namespace(セマフォ、MQ、共有メモリなどのプロセス間通信の分離)
- User Namespace(UID、GID Namespaceの分離)
- Network Namespace(インターフェース、ルーティングテーブル、ソケットなど)
- cgroup Namespace(cgroupのルートディレクトリを分離)
cgroups
cpuやmemory、ディスクなどの物理リソース制限は cgroupsと呼ばれるカーネル機能で計測されアクセス制限される。 cgroupsではタスクをグループ化したり、そのグループ内のタスクに対して 以下のような物理リソースを制限できる。使用量やアクセスを制限する。
unshareコマンドでNamespaceについて確認
unshare
コマンドはparentから unshared
されている namespaceを使用してプログラムを実行できるらしい。 unshare
が新しいnamespace でどんなプログラムでも走らせることができるということ。実際にUTS Namespaceを例に unshare
コマンドの動きを確認してみる。
$ unshare -h Usage: unshare [options] <program> [<argument>...] Run a program with some namespaces unshared from the parent. オプション: -m, --mount unshare mounts namespace -u, --uts unshare UTS namespace (hostname etc) -i, --ipc unshare System V IPC namespace -n, --net unshare network namespace -p, --pid unshare pid namespace -U, --user unshare user namespace -f, --fork fork before launching <program> --mount-proc[=<dir>] mount proc filesystem first (implies --mount) -r, --map-root-user map current user to root (implies --user) --propagation <slave|shared|private|unchanged> modify mount propagation in mount namespace -s, --setgroups allow|deny control the setgroups syscall in user namespaces -h, --help display this help and exit -V, --version output version information and exit For more details see unshare(1).
UTS Namespaceは名前空間ごとにホスト名やドメイン名を独自に持つことができる。
以下で UTS Namespace を unshare
コマンドで操作してみる。
unshare -u /bin/sh
はUTS名前空間を指定してunshare実行
している
これでホスト名、ドメイン名が分離されたので、
もとのホスト名は test-ozawa-dev01.amb-infra-dev.incvb.io
だが、
unshare で切り替え後、 my-new-hostname
に変更している。
もちろんこのホスト名は新たな namespace だけで有効なので、 unshareで起動したシェルを終了すると、ホスト名はもとに戻る。
$ sudo su # root userになる # uname -n # 現在のhostnameを確認 test01 # unshare -u /bin/sh # 新しいUTS namespaceでshellを作成 sh-4.2# hostname my-new-hostname # hostnameを設定 sh-4.2# uname -n # 新しいhostnameを確認 my-new-hostname sh-4.2# exit # 新しいUTS namespaceから出る exit # uname -n # 元のhostnameが変更されていないことを確認 test01
2018年読んだ本
2018年の読書メーター
読んだ本の数:15
読んだページ数:4818
ナイス数:70
アシュリーの戦争 -米軍特殊部隊を最前線で支えた、知られざる「女性部隊」の記録の感想
15時間ほどで読めた。CST(文化支援部隊)という女性メンバーだけの特殊部隊を追ったノンフィクション。CSTの役割はアフガニスタンでの戦闘でアフガニスタン人の女性や子供たちから情報を聞き出すことが彼女たちの任務で地上戦の最前線でレンジャーの任務を支えていました。主人公のアシュリーが英雄視されているようで、プロパガンダ的作品と感じとってしまいました。2016年にアメリカの女性兵士も地上戦闘に参加することが法的に認められたのも、このCSTがあってのことのようで米軍にとっても大きな影響を与えた部隊だと思います。
読了日:12月30日 著者:ゲイル・スマク・レモン
シベリアの掟の感想
15時間ほどで読めた。かなりの力作だけど面白かった。筆者の幼少期の自伝的小説。これはntddkさんが面白いとツイートしていたので読んだ。この本については多くは語るのは不要だと思いますので、この本についての感想は本の中で語られているシベリアの掟の引用で締めくくる。『私たちシベリアの民は、子供の頃から「言葉にフィルターをかける」、すなわちたとえ故意でなくとも決して過ちを犯さないよう、口から出る言葉に気をつけることを教えられてきた。シベリアの掟によれば、「一度口から飛び去った言葉は二度と戻ってこない」からだ。』
読了日:12月30日 著者:ニコライ・リリン
五色の虹 満州建国大学卒業生たちの戦後の感想
8時間ほどで読めた。日本が満州国を建国した時の理念である五族協和。満州国を引っ張っていくリーダーを育成するための学校である満州建国大学についての話。日・漢・朝・満・蒙から集められた超エリートの卒業生たちを取材することで少ない資料の中、どんな学校だったのか、どんなことを考えて授業を受けたのか、戦後どうなったのか話をきいて浮き彫りになっていく建国大学。日本の敗戦とともにエリートだった学生たちが不遇の待遇を受けていたりと、国がその優秀な人材を生かさず中には忙殺する亡国もあったりと、貴重な歴史的資料のような一冊。
読了日:12月30日 著者:三浦 英之
悪童日記 (ハヤカワepi文庫)の感想
5時間ほどで読めた。薄い小説だけどrebuild.fmで紹介されていたように凄まじい本。打ちのめされるような本。双子の男の子の日記の体でストーリーが進んでいきます。男の子たちの行動原理みたいなものが読み取れてるので、その行動が加速するにつれてページを捲るスピードも上がっていきました。全部で第3部らしいのですが、素晴らしい作品のようですのでほかも読んでみたいです。子供だから視点は狭いようで、大人とは別の視点を持ち戦争下の描写が書かれています。筆者の幼少期の体験を双子の男の子を通して追体験するような感覚です。
読了日:12月30日 著者:アゴタ クリストフ
UNIXという考え方―その設計思想と哲学の感想
20時間ぐらいで読めたと思う。途中何年も積んだりしたので、正確な時間がわかないけど、薄いけど一気に読めるような文章ではないので読むのが大変だった。名著ということでとりあえず読んでみたのが良くないのか、あんまり理解できなかった。これだけみんな名著と思って読まれているのにUNIXという考え方で実装していないのは何故だと思うぐらい複雑だったり謎の処理つけたりしているので気をつけたいですね。Linuxコマンドは強力でそれを使うスクリプトも強力ですね。こんな内容の現代の本が読みたいのでオススメあったら教えて下さい。
読了日:11月30日 著者:Mike Gancarz
スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)の感想
6時間ほどで読めた。タイトルの通りスラスラ読めました。ES6でJavaScriptを説明していますので、これからJavaScriptを勉強したい人や、プログラミングを覚えたい人が読む最初の一冊には良いと思いました。ふりがなが全てに振ってあるので、これがどんな意味なのかを、おまじないなどでごまかしていないので納得して読み進めることができると思います。監修も及川卓也さんなので内容も安心して読むことができました。次のステップはどう進めていけばいいのかは書いてないので、どうステップを進めるかが難しいと思いました。
読了日:08月20日 著者:リブロワークス
Linuxサーバーセキュリティ徹底入門 オープンソースによるサーバー防衛の基本の感想
8時間ほどで読めました。CentOS6で内容は少し古いですが、現在動いているシステムを運用している人は読んでおくとよいと思いました。LinuxのOS全般とApacheやメールなどの設定でセキュアな設定について細かく書かれており、わかりやすく書かれています。どのような運用が望ましいのかなども自分で調べるには難しいですが、このような本が増えてほしいと思いました。MySQLなどのDBやPHPなどについては記載ありませんが、それらはどのような本を読めばいいかなどの動線があればよいなと思います。おすすめの一冊です。
読了日:08月16日 著者:中島 能和
インフラエンジニアの教科書2 スキルアップに効く技術と知識の感想
10時間ほどで読めた。インフラエンジニア教科書とのことなのでインフラエンジニアとして読んでみた。1は立ち読みしたことありますが、個人的には2の方が読んでいて面白かったです。オペレーションシステムの基礎知識をわりと実用的なレベルで紹介されていて、インフラエンジニアになった人のまさに教科書的な存在だと思います。個人的にはなるほどUnixなどで、手で動かしてから読んでから読んだ方が理解が深まると思います。OSの動作の理屈をいきなり本を読んで理解できる人は頭がいいと思うので、普通の人は手を動かすといいと思います。
読了日:07月31日 著者:佐野 裕
絵で見てわかるOS/ストレージ/ネットワーク~データベースはこう使っている (DB Magazine Selection)の感想
読むのに30時間ぐらいかかったと思う。新人の時(6年前)から何度も途中で諦めたりした本。OSやストレージ、DBMS、ネットーワークとシステム周り全般のボトルネックがどこか、リソースをどう使っているのかなどをコマンド実行レイヤ、絵を通して詳細に解説してくれている。個人的には詳解システムパフォーマンスの前に読んでおくと良いのではないかと思った。内容はオンプレミスのシステム前提で少し古いので、今のクラウド時代での内容に即した内容ではどうなるか気になるし、どんな本がそれにあたるのか気になる。このような本読みたい。
読了日:07月31日 著者:小田 圭二
オブジェクト指向でなぜつくるのか 第2版の感想
15時間ほどで読めた。Pythonでクラスをどういう時に書くべきなのか、オブジェクト指向でプログラミングするとはどういうことなのかよくわかっていないのでオブジェクト指向とは何なのかじっくり調べたいと思って読みました。この本は1冊まるまる書いているので説明が豊富でわかりやすかったです。Pythonの入門本とかだと犬とか人間とかを例にしたりして解説するのが余計に混乱させられていたのでオブジェクト指向の歴史と意義やクラス(カプセル化)・継承・ポリモーフィズムがどう意味なのかわかりやすく説明してありよかったです。
読了日:07月31日 著者:平澤 章
アカマイ―知られざるインターネットの巨人 (角川EPUB選書)の感想
6時間ほどで読めた。インターネットのトラフィックがどう流れているのか、CDNのアカマイがどういう成り立ちでできたのか。どのようにサービスを成り立たせているのか、どのような仕組みなのかなどをわかりやすく説明されているので読んでいて楽しかったです。CDNを利用すればオリジンサーバへの負荷分散にもなり、ユーザも高速にアクセスができ本当に良いものです。ネットワークの基本のようなものと併せて本書を読むことでインターネットの大枠を掴むことができるのではないでしょうか。誰にでも読むことができるので、オススメの一冊です。
読了日:06月21日 著者:小川 晃通
MySQL徹底入門 第3版 ~5.5新機能対応~の感想
10時間ほどで読めた。4年ほど積んでいましたが、そろそろMySQLに入門したい気持ちになり読みました。内容としては設定から運用までわかりやすくまとめっていて良いと思います。内容も5.5なのでそこまで古くはないので今読んでも参考になりました。昨今MySQL8がリリースされましたが、ほとんどの運用されているMySQLのバージョンはおいくつでしょうか?そうですね。おわかりのように、この本の内容は古くはないのです。次は実践ハイパフォーマンスMySQLをよんでMySQLの内部にもう少し踏み込んでいきたいと思います。
読了日:05月30日 著者:遠藤 俊裕,坂井 恵,館山 聖司,鶴長 鎮一,とみた まさひろ,班石 悦夫,松信 嘉範
忘れられた巨人の感想
40時間ぐらいかけて読んだ。カズオ・イシグロは初めて読みます。牧歌的なファンタジー小説という印象で、THE・ビッグオーのような世界観です。記憶を奪う霧のせいで過去が曖昧な老夫婦がある日息子の存在を思い出して、どこに住んでいるかも顔も思い出せない息子に会いに行こうと行くあてのない旅を初めます。舞台はイングランドで時代はアーサー王伝説なので、この物語には騎士王伝説の知識があるとより楽しめるのかもしれません。読んでいて、ついさっきの記憶も危うい人達の会話を延々と読むことになるので、かなりの混乱が起こりました。
読了日:05月02日 著者:カズオ イシグロ
データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]の感想
8時間ほどで読めた。EFKで可視化したい人向けの本。
td-agentとElasticStackはバージョンが上がってしまったので、この本の内容は古いが、十分参考になる内容です。Qiitaぐらいしか日本語での情報がないEFKの可視化について上手くまとまっています。また、運用Tipsについても詳しく書かれていますので、運用や監視の勘所やチューニングの勘所についても参考になります。これからEFKで可視化をしたいと思っている人にはお勧めの一冊です。データ分析基盤の本で代表的な一冊になると思います。おすすめです。
読了日:04月22日 著者:鈴木 健太,吉田 健太郎,大谷 純,道井 俊介
Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版の感想
6時間ほどで読めた。AWSでWEB/DB構成をインスタンス1台ずつたてて、Wordpressを構築するLessonとなっています。新改訂版でコンソールが日本語対応となっているので、わかりやすくなっています。一部コンソール表示は変わっていましたが。他にもネットワークの説明、VPNやサブネットなどAWS特有の説明もされているのでAWSはじめに読む本には良いと思います。TCP/IP周りの説明もされていますので、サーバやネットワークの勉強がしたい人にもおすすめです。内容は薄いのでサクサクすすめてよいと思います。
読了日:01月11日 著者:玉川憲,片山暁雄,今井雄太,大澤文孝
読書メーター
Kubernetes Application Update
303-app-updateの内容
Kubernetes Application Update
今回では、Kubernetesクラスタにデプロイされたアプリケーションを使用して更新する方法について説明しデプロイします。 また、アプリケーションのCanary Deploymentについても見ていきます。
Deploymentは、Podを管理するためのレプリカセットを作成します。 レプリカセット内のレプリカの数は、アプリケーションの要求に合わせて拡大縮小できます。 Deploymentを使用してdeployされたアプリケーションを更新するには、 Deploymentの構成を更新する必要があります。
この変更により、新しいレプリカセットが作成されます。 これは、以前のレプリカセットが縮小されている間にスケールアップされます。 これにより、アプリケーションのダウンタイムが発生しません。
kubectl rolling-update
コマンドが ありますが、レプリカセットにのみ適用されます。
このコマンドからの更新は、クライアント側で行われました。
更新がサーバー側にあるので、Deploymentを使用してrolling-updateを行うことを強くお勧めします。
我々のユースケースでは、アプリケーションは最初に画像を使用します arungupta/app-upgrade:v1
。
次に、イメージを使用するようにDeploymentが更新されます arungupta/app-upgrade:v2
。
v1イメージは "Hello World!"を出力します。
v2イメージは「Howdy World!」を印刷します。
これらのイメージのソースコードはimagesディレクトリにあります。
前提条件
この章の演習を行うには、Kubernetesクラスタ構成を展開する必要があります。 EKSベースのKubernetesクラスタを作成するには、AWS CLIを使用します。 EKSを使用せずにKubernetesクラスタを作成する場合は、代わりにkopsを使用できます。 この章の設定ファイルはすべてapp-updateディレクトリにあります。 この章のコマンドを実行する前に、そのディレクトリに移動してください。 Cloud9で作業している場合は、次のコマンドを実行します。
cd ~/environment/aws-workshop-for-kubernetes/03-path-application-development/303-app-update/
rolling-update
新しいリビジョンへのアップデート
アプリケーションを更新するには、既存のすべてのポッドを、別のバージョンのイメージを使用する新しいポッドに置き換える必要があります。
.spec.strategy
デプロイメント設定で、古いポッドを新しいポッドに置き換えるための戦略を定義することができます。
このキーには次の2つの値があります。
- Recreate
- RollingUpdate (デフォルト)
この2つのデプロイ戦略を見てみましょう。
strategy を再作成する
既存のPodはすべて、新しいものが作成される前に強制終了されます。 設定ファイルは以下のようになります
apiVersion: apps/v1 kind: Deployment metadata: name: app-recreate spec: replicas: 5 selector: matchLabels: name: app-recreate strategy: type: Recreate template: metadata: labels: name: app-recreate spec: containers: - name: app-recreate image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
- deploymentを作成
$ kubectl create -f templates/app-recreate.yaml --record deployment "app-recreate" created
--recordこのdeploymentを開始するコマンドが確実に記録されます。 これは、アプリケーションがいくつかの更新を経て、バージョンとコマンドを関連付ける必要がある場合に便利です。
- deploymentsの履歴を取得
$ kubectl rollout history deployment/app-recreate deployments "app-recreate" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-recreate.yaml --record=true
- サービスを公開する
$ kubectl expose deployment/app-recreate --port=80 --target-port=8080 --name=app-recreate --type=LoadBalancer service "app-recreate" exposed
- サービスの詳細を取得する
$ kubectl describe svc/app-recreate Name: app-recreate Namespace: default Labels: name=app-recreate Annotations: <none> Selector: name=app-recreate Type: LoadBalancer IP: 100.65.43.233 LoadBalancer Ingress: af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 30158/TCP Endpoints: 100.96.1.14:80,100.96.2.13:80,100.96.3.13:80 + 2 more... Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CreatingLoadBalancer 24s service-controller Creating load balancer Normal CreatedLoadBalancer 23s service-controller Created load balancer
- serviceにアクセス
$ curl http://af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Hello World!
- 別の端末では、Podの状態を確認
$ kubectl get -w pods app-v1-recreate-486400321-4rwzb 1/1 Running 0 9m app-v1-recreate-486400321-fqh5l 1/1 Running 0 9m app-v1-recreate-486400321-jm02h 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Running 0 9m app-v1-recreate-486400321-z89nm 1/1 Running 0 9m
- deploymentのイメージを更新します。
$ kubectl set image deployment/app-recreate app-recreate=arungupta/app-upgrade:v2 deployment "app-recreate" image updated
- Podのステータスが更新されます。すべてのPodが最初に終了し、新しいPodが作成されたことを示します。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-v1-recreate-486400321-4rwzb 1/1 Running 0 9m app-v1-recreate-486400321-fqh5l 1/1 Running 0 9m app-v1-recreate-486400321-jm02h 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Running 0 9m app-v1-recreate-486400321-z89nm 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 1/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 1/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 1/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 1/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-2362379170-fp3j2 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 Pending 0 0s app-v1-recreate-2362379170-hkpt7 0/1 Pending 0 0s app-v1-recreate-2362379170-jzh5d 0/1 Pending 0 0s app-v1-recreate-2362379170-k26sf 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 Pending 0 0s app-v1-recreate-2362379170-fp3j2 0/1 Pending 0 0s app-v1-recreate-2362379170-hkpt7 0/1 Pending 0 0s app-v1-recreate-2362379170-jzh5d 0/1 Pending 0 0s app-v1-recreate-2362379170-k26sf 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 ContainerCreating 0 0s app-v1-recreate-2362379170-fp3j2 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-hkpt7 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-jzh5d 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-k26sf 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-fp3j2 1/1 Running 0 3s app-v1-recreate-2362379170-k26sf 1/1 Running 0 3s app-v1-recreate-2362379170-xxqqw 1/1 Running 0 3s app-v1-recreate-2362379170-hkpt7 1/1 Running 0 4s app-v1-recreate-2362379170-jzh5d 1/1 Running 0 4s
出力は、すべてのPodが最初に終了した後、新しいPodが作成されたことを示します。
- deploymentsの履歴を手に入れる
$ kubectl rollout history deployment/app-recreate deployments "app-recreate" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-recreate.yaml --record=true 2 kubectl set image deployment/app-recreate app-recreate=arungupta/app-upgrade:v2
- 再度アプリケーションにアクセスする
$ curl http://af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Howdy World!
出力にv2は、使用されているイメージのバージョンが表示されるようになりました。
Rolling update戦略
Podはローリングアップデートの方法で更新されます。 Rolling updateの実行方法を定義するには、次の2つのオプションのプロパティを使用できます。
.spec.strategy.rollingUpdate.maxSurge
必要な数のポッドに作成できるポッドの最大数を指定します。値には、絶対数またはパーセンテージを使用できます。デフォルト値は25%です。.spec.strategy.rollingUpdate.maxUnavailable
更新処理中に使用できないポッドの最大数を指定します。
設定ファイルは以下のようになります
apiVersion: apps/v1 kind: Deployment metadata: name: app-rolling spec: replicas: 5 selector: matchLabels: name: app-rolling strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1 template: metadata: labels: name: app-rolling spec: containers: - name: app-rolling image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
この場合、最大数のポッド上に1つ以上のポッドを作成することができ、更新プロセス中には1つのポッドしか利用できなくなります。
- deploymentを作成
$ kubectl create -f templates/app-rolling.yaml --record deployment "app-rolling" created
再度、--recordこの展開を開始するコマンドが確実に記録されます。 これは、アプリケーションがいくつかの更新を経て、バージョンとコマンドを関連付ける必要がある場合に便利です。
- デプロイの履歴を取得する
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true
- サービスを公開する
$ kubectl expose deployment/app-rolling --port=80 --target-port=8080 --name=app-rolling --type=LoadBalancer service "app-rolling" exposed
- サービスの詳細を取得する
$ kubectl describe svc/app-rolling Name: app-rolling Namespace: default Labels: name=app-rolling Annotations: <none> Selector: name=app-rolling Type: LoadBalancer IP: 100.71.164.130 LoadBalancer Ingress: abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 31521/TCP Endpoints: 100.96.1.16:80,100.96.2.15:80,100.96.3.15:80 + 2 more... Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CreatingLoadBalancer 1m service-controller Creating load balancer Normal CreatedLoadBalancer 1m service-controller Created load balancer
- サービスへアクセス
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Hello World!
出力はv1、イメージのバージョンが使用されていることを示します。
- 別の端末では、Podの状態を確認します。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-rolling-1683885671-d7vpf 1/1 Running 0 2m app-rolling-1683885671-dt31h 1/1 Running 0 2m app-rolling-1683885671-k8xn9 1/1 Running 0 2m app-rolling-1683885671-sdjk3 1/1 Running 0 2m app-rolling-1683885671-x1npp 1/1 Running 0 2m
- deploymentのイメージを更新します。
$ kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2 deployment "app-rolling" image updated
- Podのステータスが更新されます。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-rolling-1683885671-d7vpf 1/1 Running 0 2m app-rolling-1683885671-dt31h 1/1 Running 0 2m app-rolling-1683885671-k8xn9 1/1 Running 0 2m app-rolling-1683885671-sdjk3 1/1 Running 0 2m app-rolling-1683885671-x1npp 1/1 Running 0 2m app-rolling-4154020364-ddn16 0/1 Pending 0 0s app-rolling-4154020364-ddn16 0/1 Pending 0 1s app-rolling-4154020364-ddn16 0/1 ContainerCreating 0 1s app-rolling-1683885671-sdjk3 1/1 Terminating 0 5m app-rolling-4154020364-j0nnk 0/1 Pending 0 1s app-rolling-4154020364-j0nnk 0/1 Pending 0 1s app-rolling-4154020364-j0nnk 0/1 ContainerCreating 0 1s app-rolling-1683885671-sdjk3 0/1 Terminating 0 5m app-rolling-4154020364-ddn16 1/1 Running 0 2s app-rolling-1683885671-dt31h 1/1 Terminating 0 5m app-rolling-4154020364-j0nnk 1/1 Running 0 3s app-rolling-4154020364-wlvfz 0/1 Pending 0 1s app-rolling-4154020364-wlvfz 0/1 Pending 0 1s app-rolling-1683885671-x1npp 1/1 Terminating 0 5m app-rolling-4154020364-wlvfz 0/1 ContainerCreating 0 1s app-rolling-4154020364-qr1lz 0/1 Pending 0 1s app-rolling-4154020364-qr1lz 0/1 Pending 0 1s app-rolling-1683885671-dt31h 0/1 Terminating 0 5m app-rolling-4154020364-qr1lz 0/1 ContainerCreating 0 1s app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-4154020364-wlvfz 1/1 Running 0 2s app-rolling-1683885671-d7vpf 1/1 Terminating 0 5m app-rolling-4154020364-vlb4b 0/1 Pending 0 2s app-rolling-4154020364-vlb4b 0/1 Pending 0 2s app-rolling-4154020364-vlb4b 0/1 ContainerCreating 0 2s app-rolling-1683885671-d7vpf 0/1 Terminating 0 5m app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-4154020364-qr1lz 1/1 Running 0 3s app-rolling-1683885671-k8xn9 1/1 Terminating 0 5m app-rolling-1683885671-k8xn9 0/1 Terminating 0 5m app-rolling-4154020364-vlb4b 1/1 Running 0 2s
出力は、新しいPodが作成された後、古いPodが作成された後、新しいPodが作成されたことを示します。
- デプロイの履歴を取得する
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true 2 kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2
- アプリケーションに再度アクセスする
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Howdy World!
出力にv2は、使用されているイメージのバージョンが表示されるようになりました。
以前のリビジョンへのロールバック
上記で説明したように、Deploymentをどのように展開したかの詳細は、
kubectl rollout history
コマンドを使用して取得できます。
ロールバックするには、Deploymentの完全な履歴を取得できます。
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true 2 kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2
次のコマンドを使用して以前のバージョンにロールバックします。
$ kubectl rollout undo deployment/app-rolling --to-revision=1 deployment "app-rolling" rolled back
サービスに再度アクセスしてください
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Hello World!
出力はv1、イメージのバージョンが現在使用されていることを示します。
リソースの削除
kubectl delete deployment/app-recreate svc/app-recreate deployment/app-rolling svc/app-rolling
Canary deployment
Canaryデプロイメントを使用すると、少数のユーザーに変更を徐々に反映させることで、すべてのユーザーに展開する前に、新しいバージョンのアプリケーションを本番環境に展開することができます。 Kubernetesでこれを達成するにはいくつかの方法があります。
- Service、DeploymentおよびLabelの使用
- 入力コントローラの使用
- DNSコントローラの使用
- IstioまたはLinkerdの使用
今回はService、DeploymentおよびLabelの方法を見ていきます
Deployment, ServiceとLabels
異なるバージョンのイメージを使用した2つのデプロイメントが使用されます。 どちらの配置も同じポッドラベルを持ちますが、少なくとも1つのラベルが異なります。 一般的なポッドラベルは、サービスのセレクタとして表示されます。 レプリカの数を調整するために、異なるポッドラベルが使用されます。 新しいバージョンのDeploymentの1つのレプリカが古いバージョンとともにリリースされます。 しばらくの間エラーが検出されない場合、新しいバージョンのレプリカの数がスケールアップされ、古いバージョンのレプリカの数が縮小されます。 最終的に、古いバージョンは削除されます。
Deploymentとサービス定義
v1展開のバージョンを見てみましょう
apiVersion: apps/v1 kind: Deployment metadata: name: app-v1 spec: replicas: 2 selector: matchLabels: name: app version: v1 template: metadata: labels: name: app version: v1 spec: containers: - name: app image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
それは arungupta/app-upgrade:v1
イメージを使用します。
それは2つのラベル name: app
と version: v1
v2展開のバージョンを見てみましょう
apiVersion: apps/v1 kind: Deployment metadata: name: app-v2 spec: replicas: 2 selector: matchLabels: name: app version: v2 template: metadata: labels: name: app version: v2 spec: containers: - name: app image: arungupta/app-upgrade:v2 ports: - containerPort: 8080
それは別のイメージ arungupta/app-upgrade:v2
を使用します。
これには、Deploymentのバージョン v1
と一致する1つのラベル name: app
があります。
これは、他のラベル v2
と似ていますが、異なる値 version: v2
を使用しています。
このラベルを使用するv1と、Deploymentの v1
バージョンをオーバーライドすることなく、このDeploymentを独自に拡張できます。
最後に、これらのデプロイメントを使用するサービス定義を見てみましょう。
apiVersion: v1 kind: Service metadata: name: app-service spec: selector: name: app ports: - name: app port: 80 type: LoadBalancer
サービスは、アプリケーションの両方のバージョンに共通のラベルを使用します。これにより、両方のデプロイメントのポッドをサービスの一部にすることができます。
確認しましょう。
Canary Deploymentを作成
- Deploymentのv1バージョンをデプロイする
$ kubectl apply -f templates/app-v1.yaml deployment "app-v1" created
- Deploymentのv2バージョンをデプロイする
$ kubectl apply -f templates/app-v2.yaml deployment "app-v2" created
3. サービスをデプロイする
$ kubectl apply -f templates/app-service.yaml service "app-service" created
- このサービスのPod listを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v1-3101668686-4mhcj 1/1 Running 0 2m app-v1-3101668686-ncbfv 1/1 Running 0 2m app-v2-2627414310-89j1v 1/1 Running 0 2m app-v2-2627414310-bgg1t 1/1 Running 0 2m
templates/app-service.yaml
のサービス定義で指定されているポッドのみを選択するように、クエリーのname=app
ラベルを明示的に指定していることに注意してください。
v1バージョンからは2つのポッド、 v2バージョンからは2つのポッドがあります。
このサービスにアクセスすると、v1バージョンから50%、2vバージョンから50%の応答が得られます。
Canary Deploymentをスケール
v1バージョンとv2バージョンから含まれるポッドの数は、2つのデプロイメントを使用して個別に拡張できます。
- v2 deployment のレプリカ数を増やす
$ kubectl scale deploy/app-v2 --replicas=4 deployment "app-v2" scaled
- サービスの一部であるポッドを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v1-3101668686-4mhcj 1/1 Running 0 6m app-v1-3101668686-ncbfv 1/1 Running 0 6m app-v2-2627414310-89j1v 1/1 Running 0 6m app-v2-2627414310-8jpzd 1/1 Running 0 7s app-v2-2627414310-b17v8 1/1 Running 0 7s app-v2-2627414310-bgg1t 1/1 Running 0 6m
現在、4つのポッドはアプリケーションのバージョンv2
から来ており、2つのポッドはアプリケーションのバージョンv1
から来ていることがわかります。
したがって、ユーザーからのトラフィックの3分の2が新しいアプリケーションから提供されるようになります。
- v1バージョンのレプリカ数を0に減らす
$ kubectl scale deploy/app-v1 --replicas=0 deployment "app-v1" scaled
- サービスの一部であるPodを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v2-2627414310-89j1v 1/1 Running 0 8m app-v2-2627414310-8jpzd 1/1 Running 0 1m app-v2-2627414310-b17v8 1/1 Running 0 1m app-v2-2627414310-bgg1t 1/1 Running 0 8m
現在、すべてのポッドがDeploymentのv2
バージョンを提供しています。
Canary Deploymentを削除する
上記で作成したすべてのリソースを削除するには、このコマンドを実行します。
$ kubectl delete svc/app-service deployment/app-v1 deployment/app-v2
Ingress Controller (まだ未実装)
デプロイメントとサービスを使用してトラフィックの適切なパーセンテージを達成するには、必要な数のポッドをスピンアップする必要があります。 たとえば、バージョンにv1ポッドのレプリカが4つある場合などです。 次に、バージョンに5%のトラフィックを向けるためにv2、1ポッドのv2バージョンのレプリカには16個のv1バージョンのレプリカがさらに必要になります。 これはリソースの最適な使用ではありません。 この問題を解決するには、Kubernetes Ingressによる重み付けトラフィックの切り替えが使用できます。
Zalandoによると Kubernetes Ingress Controller for AWS はKubernetesのIngressコントローラ
$ kubectl apply -f templates/ingress-controller.yaml deployment "app-ingress-controller" created