はじめに
こんにちは、イノベーションセンターの鈴ヶ嶺です。
本記事では、自社データセンター等でAWSサービスを利用可能なAWS OutpostsにおけるElastic Kubernetes Service(EKS)で新たに追加されたLocal clusterの概要や通信切断検証の結果について紹介します。
以前記事にした2022年3月17日時点では、ワーカーノードはAWS Outposts上で実行し、KubernetesコントロールプレーンはAWS Cloud上で実行する構成でした。この構成がLocal clusterによってKubernetesコントロールプレーンもAWS Outposts上で実行可能になりました。これによりAWS CloudとAWS Outposts間の通信切断などによるアプリケーションのダウンタイムのリスクを軽減することが可能となりました。
今までのEKS on Outpostsの問題点
上図に、今までのAWS Outposts上でEKSを利用する構成を示しています。現在ではExtended clusterと命名されています。 この構成では、KubernetesコントロールプレーンがAWS Cloud上に存在しています。 このことからAWS CloudとAWS Outpostsのファイバー切断などの通信切断やAWS Cloud上で障害が起きた場合にKubernetesの操作が不可能となる問題がありました。 データセンターに設置するAWS Outpostsの性質を考慮するとEKS on Outpostsには、自律的に動作をして外部の障害に対して頑健であることが求められます。
EKS Local cluster on Outposts
上図にAWS Outposts上でKubernetesコントロールプレーンを実行可能となったLocal clusterの構成を示しています。 この構成ではAWS CloudとAWS Outposts間で通信を必要としていません。 これにより先に述べた外部の障害に対してKubernetesの操作のダウンタイムを抑えた頑健なシステムが構築可能となります。
Extended clusterとLocal clusterの違い
ここでは従来のExtended clusterとLocal clusterの主な違いを次の表にまとめました。詳細はこちらのデプロイオプションの比較を参照してください。
Extended cluster | Local cluster | |
---|---|---|
Kubernetes version | 1.23, 1.22, 1.21, 1.20から選択可能(2022/10/31時点) | 1.21のみ |
Amazon EKS 最適化 AMI | Amazon Linux, Windows, Bottlerocket | Amazon Linux |
Kubernetes API サーバー認証 | IAM, OIDC | IAM, X.509証明書 |
シークレットエンベロープ暗号化 | 対応 | 非対応 |
サービスアカウントの IAM ロール | 対応 | 非対応 |
Local clusterはKubernetesのversionやAMIが固定化されています。また、通信障害時にも動作可能とするためのX.509証明書によるAPIサーバの認証があります。こちらの認証方法については後述する通信切断の検証で説明します。
構築方法
AWS Consoleでの構築は次のように設定します。Kubernetesコントロールプレーンの場所をAWS Outpostsに選択することでLocal clusterを構築できます。 現時点では、レプリカ数は3に固定されています。
Terraformでは、次のように outpost_config を設定することでLocal clusterを構築できます。
resource "aws_eks_cluster" "outposts_local_cluster" { name = "outposts-local-cluster" role_arn = aws_iam_role.local_cluster_role.arn enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"] vpc_config { security_group_ids = [aws_security_group.cluster.id] # Amazon EKS セキュリティグループの要件および考慮事項を参照 https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/sec-group-reqs.html subnet_ids = [aws_subnet.outposts_subnet01.id] # AWS Outposts上のsubnetを指定 endpoint_public_access = false endpoint_private_access = true } outpost_config { control_plane_instance_type = "m5.large" # Clusterのインスタンスタイプ outpost_arns = [local.outpost_arn] # AWS OutpostsのARN } depends_on = [ aws_iam_role_policy_attachment.eks_local_cluster_policy, ] } resource "aws_iam_role" "local_cluster_role" { name = "outposts-local-cluster" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } resource "aws_iam_role_policy_attachment" "eks_local_cluster_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLocalOutpostClusterPolicy" role = aws_iam_role.local_cluster_role.name }
実際に構築したLocal clusterのEKSは、次のようになります。クラスタのダッシュボードには、KubernetesコントロールプレーンにAWS OutpostsのARNが表示されています。
次のEC2一覧には、Kubernetesコントロールプレーン用のEC2([EKSの名前]-controle-plane-XXXXXXX)が立てられていることが分かります。このEC2はAWS Outposts上のリソースになります。
また、kubectlでnode情報を見ると以下のようにcontrol-planeとワーカーノードが確認できます。
おそらくcontrol-planeがNot Readyなのは以下のようにTaintsで汚染してワークロードがスケジュールされることを防ぐためだと思われます。
各インスタンスは node-role.eks-local.amazonaws.com/control-plane で汚染されているため、コントロールプレーンインスタンスでワークロードがスケジュールされることはありません。 https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-outposts-local-cluster-create.html
❯ kubectl get node NAME STATUS ROLES AGE VERSION ip-10-2-1-174.ap-northeast-1.compute.internal NotReady control-plane,master 46h v1.21.13 ip-10-2-1-185.ap-northeast-1.compute.internal NotReady control-plane,master 46h v1.21.13 ip-10-2-1-61.ap-northeast-1.compute.internal NotReady control-plane,master 46h v1.21.13 ip-10-2-2-15.ap-northeast-1.compute.internal Ready <none> 46h v1.21.14-eks-ba74326 ip-10-2-2-198.ap-northeast-1.compute.internal Ready <none> 46h v1.21.14-eks-ba74326 ip-10-2-2-23.ap-northeast-1.compute.internal Ready <none> 46h v1.21.14-eks-ba74326
通信切断検証
ここでは通信切断時にもダウンタイムなくKubernetesを動作可能かを検証します。まずAWS Outpostsに接続されたルータのBGPを切断して以下のようにサービスリンクの接続ステータスが0となっていることを確認します。
ここから次の3つのケースに分けて検証します。
- Extended clusterの場合
- Local cluster(AWS IAM認証)の場合
- Local cluster(X.509証明書)の場合
1. Extended clusterの場合
従来のKubernetesコントロールプレーンがAWS Cloud上にある構成の場合は次のようにサーバに接続できないというエラーが表示されます。
❯ aws eks --region [Region] update-kubeconfig --name [EKSクラスタの名前] ❯ kubectl get svc Unable to connect to the server: net/http: TLS handshake timeout
通信切断時にExtended clusterの場合、Kubernetesの操作が不可能となります。
2. Local cluster(AWS IAM認証)の場合
KubernetesコントロールプレーンがAWS Outposts上に存在する場合でも、通信切断時にIAM認証で操作した場合は次のようにUnauthorizedというエラーが表示されます。 この事象はネットワーク切断中にAWS Cloud上のIAMを使用できないことが原因でおきます。
❯ aws eks --region [Region] update-kubeconfig --name [EKSクラスタの名前] ❯ kubectl get svc error: You must be logged in to the server (Unauthorized)
1. Extended clusterの場合と同様に、通信切断時にLocal cluster(AWS IAM認証)の場合、Kubernetesの操作が不可能となります。
このためKubernetesコントロールプレーンをAWS Outposts上で実行するだけでは、AWS CloudとAWS Outposts間の通信切断によるKubernetesの操作のダウンタイムのリスクを軽減できません。 対策として次に記述したX.509証明書を事前に設定する必要があります。
3. Local cluster(X.509証明書)の場合
AWS CloudとAWS Outposts間の通信障害時に、アクセスするためには次のようにX.509証明書を通信障害以前に事前準備する必要があります。 詳細はこちらのネットワーク切断中のローカルクラスターへの認証を参照してください。 以下にコマンドを記述します。
openssl req -new -newkey rsa:4096 -nodes -days 365 -keyout admin.key -out admin.csr -subj "/CN=admin" BASE64_CSR=$(cat admin.csr | base64 -w 0) # macの場合 # BASE64_CSR=$(cat admin.csr | base64) cat << EOF > admin-csr.yaml apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: admin-csr spec: signerName: kubernetes.io/kube-apiserver-client request: ${BASE64_CSR} usages: - client auth EOF kubectl create -f admin-csr.yaml kubectl certificate approve admin-csr kubectl get csr admin-csr -o jsonpath='{.status.certificate}' | base64 --decode > admin.crt kubectl create clusterrolebinding admin --clusterrole=cluster-admin --user=admin --group=system:masters aws eks describe-cluster --name [EKSクラスタの名前] --query "cluster.certificateAuthority" --output text | base64 --decode > ca.crt kubectl config --kubeconfig admin.kubeconfig set-cluster [EKSクラスタの名前] --certificate-authority=ca.crt --server [EKSクラスタのAPIエンドポイント] --embed-certs kubectl config --kubeconfig admin.kubeconfig set-credentials admin --client-certificate=admin.crt --client-key=admin.key --embed-certs kubectl config --kubeconfig admin.kubeconfig set-context admin@[EKSクラスタの名前] --cluster [EKSクラスタの名前] --user admin kubectl config --kubeconfig admin.kubeconfig use-context admin@[EKSクラスタの名前] kubectl get svc --kubeconfig admin.kubeconfig # 確認
上記により --kubeconfig admin.kubeconfig
でX.509証明書によるアクセスが可能となりました。
これにより次のように通信障害時にアクセスした場合も問題なくアクセス可能となります。
❯ kubectl get svc --kubeconfig admin.kubeconfig NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 5h13m
まとめ
本記事では、新たに追加されたAWS OutpostsのEKS Local clusterの概要や従来のExtended clusterとの違い、構築方法について紹介しました。 また、AWS CloudとAWS Outposts間の通信切断検証からダウンタイムなくKubernetesをローカル環境で実行可能であることを確認しました。 外部の障害に対して頑健なシステムを構築する場合には非常に効果的な機能であると思います。