2024年02月08日
連載 第2回
Terraformを利用したEKSインストールとローカル管理環境の構築
1. コードを利用したクバネティス インストールのメリット
読者がクバネティス運用担当者になってEKSのインストール業務を進めると想定した場合、EKSをどのようにインストールすることが良いでしょうか?これまではどのように進めてきたかを確認して、今後どのように進めることが良いかその方法を考えます。
EKSのインストールはamazonコンソールでGUI(Graph User Interface)を利用するかeksctlコマンドででき、比較的簡単にインストールできます。しかし、次にインストールをするときも毎回同じ操作を進めるため、再利用の面では不便です。何よりヒューマンミスの可能性が高いです。
同じEKSを開発環境と運用環境或は他のサービスの用途でも構築する必要がありますが、その度に一連のGUIメニューの選択、コマンド操作を繰り返す必要があります。最初の作業に10分掛かるとすると、次回も同じく10分掛かります。また、作業に必要な全てのコマンドを事前に検討できないため、チームメンバ内でのレビューが難しいです。
前回、説明したコードでクバネティスを管理するとメリットがあったように、EKS即ち、インフラもコードで管理するとメリットが大きいです。
最近はTerraformなどのツールを活用してインフラをコードで管理するIaC(Infra as Code)をしています。特にTerraformをパブリッククラウド環境で多く利用します。Terraformはインフラ自動化ツールで、コードを利用してクラウドとオンプレミス環境でインフラをプロビジョニングして管理します。Terraformではインフラをコードで定義して管理できるので、繰り返し作業を自動化して、変更事項を追跡でき、インフラ環境の一貫した維持ができます。Terraformは宣言文的な言語を用いリソースを定義して、求める状態のインフラを構成できます。
EKSのインストールでもTerraformを利用でき、Terraformを利用してEKSをインストールすると次のようなメリットがあります。
① コードを利用したインフラ管理
コードを利用するため、事前にコードをレビューして問題点を発見するなどの共同作業で有利です。GitHubなどでバージョン管理をして変更事項を簡単に追跡できます。
② 再利用と維持保守が容易
現場では開発、ステージング、運用などで複数のクラスタを利用します。同じクラスタを再度作成するときに既存コードをそのまま利用できるため、生産性が向上します。
Terraformを利用してEKSを構築する方法も多様です。TerraformはEKSと関連するVPC、Security Group、Subnetなど多様な関連リソースコードを重複して利用することなく、一回で簡単にインストールできます。Terraformのモジュールは特定機能やリソースを抽象化しキャップシェル化して、複雑なインフラ構成をシンプルにしてモジュール化できるようにします。これによりコードの再利用とメンテナンス性を向上できます。
Terraformモジュールを利用すると、一般的なシナリオまたはパターンをカプセル化して様々なプロジェクト、環境で同じ構成を簡単に繰り返し構築できます。つまり、Terraformモジュールを利用すれば、EKSを簡単にインストールできます。
2. Terraformを利用したEKSのインストール
実際の環境で利用しているTerraform EKSのインストールコードを確認します。コードは GitHubコードで確認できます。EKSを十分理解していない状態でEKS Terraformコードを見ると理解できない部分もあると思います。最初は用語を理解するだけで問題ないですが、少しずつ利用することで難しかった概念を理解できるようになります。初めから完全に理解して進めるとかなりの時間が必要で、なかなかインストールを進めることが難しいので、最初は全体を実習して難しい部分や必要な部分は再度繰り返し復習することがより効果的です。
EKSのインストールでは、最初にコードを‘git clone’を利用してローカル環境にダウンロードします。
1. Lvi-Jerry-LX2Y49939H:k8s jerry$ git clone https://github.com/junghoon2/k8s-class.git
2. Cloning into 'k8s-class'...
3. remote: Enumerating objects: 5021, done.
4. remote: Counting objects: 100% (66/66), done.
5. remote: Compressing objects: 100% (8/8), done.
6. remote: Total 5021 (delta 60), reused 58 (delta 58), pack-reused 4955
7. Receiving objects: 100% (5021/5021), 4.78 MiB | 12.89 MiB/s, done.
8. Resolving deltas: 100% (2232/2232), done.
下記の‘tf-eks’ディレクトリを確認するとEKSのインストールに関連するTerraformコードを確認できます。
1. Lvi-Jerry-LX2Y49939H:k8s jerry$ cd k8s-class/tf-eks/
2. Lvi-Jerry-LX2Y49939H:tf-eks jerry$ ls
3. eks-addon.tf eks-cluster.tf irsa-role.tf karpenter.tf main.tf outputs.tf vpc.tf
次に、ローカル変数(local variables)に関連する設定です。ローカル変数はTerraformでローカルブロックを利用してローカル変数を定義します。ローカルブロックを利用して変数を定義すると、変数は該当モジュールまたは設定ファイル内だけで利用可能で外部では利用できません。主に重複する値、複雑な式を変数で保存してコードを管理し易くするために利用します。
任意のローカル変数ファイルを保存することもできます。main.tfファイルにローカルブロックを登録しても問題ありません。
1. locals {
2. name = "singapore-test"
3. cluster_version = "1.26"
4. region = "ap-southeast-1"
5.
6. vpc_cidr = "10.110.0.0/16"
7. azs = slice(data.aws_availability_zones.available.names, 0, 3)
8.
9. tags = {
10. env = "dev"
11. user = "jerry"
12. }
13. }
. name
EKSの名前です。一度作成すると修正できないため、最初にクラスタの名前を慎重に決める必要があります。会社にネーミングルールがあれば、それに従って作成します。無ければ明確な意味があり、今後の拡張性を考慮して一貫して適用できる規則を決める必要があります。説明可能な名前を定義しましょう。 例えば、{Product Name} – {Region} – {Env(test/stage/prod)} などの規則は必要です。必ず事前に決めることをお勧めします。
. region
一般的にap-northeast-2、Seoulを使用するとき、該当リージョン(Region)に他のeksがインストールされて区分のためにap-southeast-1、Singaporeリージョンを選択しました。勿論、同じリージョンもVPCで区分できますが、利便性のためにリージョンを分けることも良いです。以上のような特別な理由が無ければap-northeast-2を選択します。
. vpc_cidr
重要な設定です。CIDR(Classless Inter-Domain Routing)はIPアドレスの空間を効率的に管理して分けるために利用するネットワークアドレス体系です。既存のクラス基盤のアドレス体系(Classful Network)を補完して発展させた概念で、より柔軟なIPアドレスの割り当てができます。既存の利用中の他VPCのIP帯域と重ならないユニークなIP帯域を選択します。もし、オンプレミスとAWSクラウドを同時に利用する場合、オンプレミスIP帯域と異なるIP帯域を使用することがPeering構成時に良いと思います。
IP帯域も明確な規則があることが望ましいです。例えば、Prod環境は10.1.0.0/16, 10.2.0.0/16、 Stageは 10.11.0.0/16, 10.12.0.0/16に分けて、リージョン別にSeoul 10.0.0.0/16 ~ 10.50.0.0/16、Tokyo 10.51.0.0/16 ~ 10.100.0.0/16などに分離できます(又は172.16.0.0/16, 192.168.0.0/16などに)。最初に規則を決めなかったため、異なるVPCに同じ帯域を使用する場合も多くあります。
. azs
可用性を考慮して3つのAZ(Availability Zone)に分けて割り当てます。テストクラスタはコスト削減のため、一つのAZを利用します。実際の運用環境ではクラスタ内のノード間のトラフィックが多数発生してData Transferコストが高額になる可能性もあります。
次は、 EKSモジュール の設定です。
1. module "eks" {
2. cluster_endpoint_public_access = true
3.
4. cluster_addons = {
5. coredns = {
6. preserve = true
7. most_recent = true
8.
9. timeouts = {
10. create = "25m"
11. delete = "10m"
12. }
13. }
14. kube-proxy = {
15. most_recent = true
16. }
17. vpc-cni = {
18. most_recent = true
19. }
20. }
21.
22. vpc_id = module.vpc.vpc_id
23. subnet_ids = module.vpc.private_subnets
24. control_plane_subnet_ids = module.vpc.intra_subnets
25.
26. # Extend cluster security group rules
27. cluster_security_group_additional_rules = {
28. ingress_nodes_ephemeral_ports_tcp = {
29. description = "Nodes on ephemeral ports"
30. protocol = "tcp"
31. from_port = 1025
32. to_port = 65535
33. type = "ingress"
34. source_node_security_group = true
35. }
36. }
37.
38. # Extend node-to-node security group rules
39. node_security_group_additional_rules = {
40. ingress_self_all = {
41. description = "Node to node all ports/protocols"
42. protocol = "-1"
43. from_port = 0
44. to_port = 0
45. type = "ingress"
46. self = true
47. }
48. }
49. }
. cluster_endpoint_public_access
Testクラスタ環境のため、EKSAPIサービスの外部アプローチ(public access)を許容しました。しかし、実運用環境ではセキュリティ上、外部接続ができないようにすることをお勧めします。
1. endpoint_private_access = "true"
2. endpoint_public_access = "false"
上記の様に設定するとEKSのようなVPC内部だけで接続できます。EKS APIサーバを通じてクバネティスの全ての作業、例えば、Podとノードの削除又はクラスタ全体の削除まで進めることができるため、慎重に行う必要があります。VPNを利用してローカルIP帯域に接続できます。もし、VPNを利用しない場合、APIに接続できるPublic IP帯域を制限する方法も可能です。
. cluster_addons
EKS AddonはAmazon EKSクラスタで特定機能とサービスを簡単に活性化して管理するための拡張機能です。ネットワーク、DNSなどEKS構成に必須な要素を管理し易いです。Coredns、Kube-proxy、Vpc-cniなどを事前にadd-onで管理すると、今後EKSのアップグレード作業の時に、新規バージョン情報のみの提示で簡単にアップグレードできます。
. vpc_id
EKSの用途では、既存VPCとは区分して専用のVPCを使用することをお勧めします。クバネティスネットワークを管理するCNI(Container Network Interface)でEKSは基本的にVPC_CNIを利用します。VPC_CNIはPodやノードと同じIP帯域を利用するので多くのIPが必要です。Podの数が1,000個を超えることも頻繫に発生してIPが不足する可能性があるため、別途で専用のVPCを使用することをお勧めします。
. subnet_ids
EKS Podが割り当てられるサブネット(Subnet)帯域を指定します。外部とPodのパブリックIPで通信する特別な環境ではなければ、セキュリティ上でサブネット帯域はPrivate IP帯域を指定します。
. control_plane_subnet_ids
コントロールプレーン(Control plane)のPodが割り当てられるsubnet帯域です。コントロールプレーンはクバネティスクラスタの核心コンポーネントで、クラスタ内の全ての作業を管理して制御を行うシステムです。詳細は今後の実習と同時に提供する予定です。
コントロールプレーンのネットワーク帯域をPublic、Privateではない、より安全なIntra帯域で指定します。コントロールプレーンはインターネットゲートウェイ、NATゲートウェイを介した外部アプローチがなく、VPC内部のみで利用するリソースです。
ノードグループ(nodegroup)の設定です。クバネティスは実際コンテナーアプリケーションを実行するVMインスタンスが必要です。EKSはこれをノードグループを利用して効率的にグループで管理し、拡張できます。最近は既存のノードグループを利用せず、karpenterを利用してEKSのEC2ノードを管理します。KarpenterはノードとPodのリソースサイズを管理して、クラスタ内のリソースの効率性を最適化します。これによりリソースサイズの調整を自動化してクラスタ性能と可用性を向上できます。詳細は「連載第8回 ノードオートスケール ‘Karpenter’」で説明します。
Karpenterが実行するノードはkarpenter自身が指定できないため、karpenterが実行するノードグループを下記のように定義します。 (eks-cluster.tf)
1. eks_managed_node_group_defaults = {
2. ami_type = "AL2_x86_64"
3.
4. attach_cluster_primary_security_group = true
5. iam_role_additional_policies = {
6. additional = aws_iam_policy.additional.arn
7. }
8.
9. ebs_optimized = true
10. block_device_mappings = {
11. xvda = {
12. device_name = "/dev/xvda"
13. ebs = {
14. volume_size = 100
15. volume_type = "gp3"
16. iops = 3000
17. throughput = 150
18. # encrypted = true
19. # kms_key_id = aws_kms_key.ebs.arn
20. delete_on_termination = true
21. }
22. }
23. }
24. tags = local.tags
25. }
26.
27. eks_managed_node_groups = {
28. base = {
29. name = "karpenter"
30. use_name_prefix = false
31.
32. instance_types = ["t3.small"]
33. capacity_type = "SPOT"
34.
35. min_size = 1
36. max_size = 5
37. desired_size = 1
38.
39. subnet_ids = module.vpc.private_subnets
40. }
41. }
. eks_managed_node_group_defaults
ノードグループのデフォルト設定を指定します。security group、iam_role設定はTerraformのデフォルト設定をしました。ディスク容量の設定は、デフォルト設定で障害を考慮して余裕を持ってgp3基盤の100Giに変更しました。
. eks_managed_node_groups.capacity_type, instance_types
運用環境ではOn-demandのインスタンスタイプを指定して、Dev/Stage環境ではSpot Instanceを利用するとコスト削減できるので(on-demandとの比較で約30%のコスト削減)、テストEKSとSpot Instanceを指定しました。
参考までに、Spot環境で‘instance_types’を複数指定するとSpotで指定するリソースが不足する状況を防ぐことができます。状況により[“t3.small“, “t3.large”, “m6i.large”] など複数の指定ができます。
最後にvpcの設定です。
(vpc.tf)
1. module "vpc" {
2. source = "terraform-aws-modules/vpc/aws"
3. version = "~>3.12"
4.
5. name = local.name
6. cidr = local.vpc_cidr
7.
8. azs = local.azs
9. private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
10. public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
11. intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)]
12.
13. enable_nat_gateway = true
14. enable_dns_hostnames = true
15.
16. enable_flow_log = true
17. create_flow_log_cloudwatch_iam_role = true
18. create_flow_log_cloudwatch_log_group = true
19.
20. public_subnet_tags = {
21. "kubernetes.io/role/elb" = 1
22. }
23.
24. private_subnet_tags = {
25. "kubernetes.io/role/internal-elb" = 1
26. }
27.
28. tags = local.tags
29. }
. module “vpc”.source
Terraformはeksと同様に別途のvpcモジュールを提供します。
. private_subnets, [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
vpc_cidr = “10.110.0.0/16″のCIDRに4を追加して、/20bitのCIDRを3つのAZ(可用ゾーン)、例えば、ap-northeast-2a、ap-northeast-2b、ap-northeast-2cに割り当てられます。
. public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)]
/16 + 8 で/24 bitのCIDRを3つのAZに割り当てます。割り当てられたIPは以前のPrivateネットワーク帯域の後です。
実際適用されたIP帯域をAWSコンソールで確認すると下記のようになります。
/20 bit 3つ、/24 bit 6つが割り当てられます。
設定が完了すると、Terraformを利用してEKSをインストールできます。前に‘git clone’でダウンロードしたTerraformコードが保存されたディレクトリへ移動します。
1. Lvi-Jerry-LX2Y49939H:k8s jerry$ cd k8s-class/terraform-eks/
2. Lvi-Jerry-LX2Y49939H:terraform-eks jerry$ ls
3. eks-addon.tf eks-cluster.tf irsa-role.tf karpenter.tf main.tf outputs.tf vpc.tf
TerraformコマンドでEKSをインストールします。
1. tf init
2. tf plan -out planfile
3. tf apply planfile
20分程、経過すると正常にインストールが完了します。完了するとAWS EKSコンソールで下記のように確認できます。EKSメニューはAWSサービスメニューで‘eks’を検索します。
すると上記のようにコンソール画面でEKS情報を確認できます。これで、正常にEKSがインストールされました。
3. ローカルKubectl運用環境の設定 – クバネティス環境ファイル(~/.kube/config)構成とKrewプラグインの活用
クバネティスを管理するためには‘kubectl’コマンドツールが必要です。Kubectlはクバネティスクラスタと相互作用するために使用するコマンドラインインターフェース(CLI)です。ユーザがクラスタのリソースを管理し、モニタリングする場合に必須なツールです。Mac環境ではhomebrewを利用して簡単にインストールできます。
1. brew install kubectl
2. kubectl version --client
参考までに、Ubuntu環境でもhomebrewを利用できます。例ではwsl ubuntuを使用しますがhomebrewをインストール(インストール方法)して利用します。上記の同じコマンドで‘kubectl’インストールできます。
1. sudo apt-get update
2. sudo apt-get install -y apt-transport-https ca-certificates curl
3. sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
4. echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
5. sudo apt-get update
6. sudo apt-get install -y kubectl
勿論、aptパッケージマネージャーを利用できます。詳細なインストール方法はクバネティス公式ホームページで確認できます。インストール後、クバネティス 公式ホームページのガイドにより自動完成およびAlias設定を完了します。
1. apt-get install bash-completion
1. echo 'source <(kubectl completion bash)' >>~/.bashrc
2. echo 'alias k=kubectl' >>~/.bashrc
3. echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
追加で下記のAliasを登録するとkubectlコマンドをより早く実行できます。
1. alias kgp='kubectl get pods -o wide'
2. alias kgn='kubectl get nodes -o wide'
3. alias kgs='kubectl get svc -o wide'
4. alias kgv='kubectl get pvc -o wide'
kubectlツールのインストールが完了しました。次は遠隔EKSクラスタをローカルで管理するためには個人PCのKubernetes Configファイル(~/.kube/config)の変更が必要です。クバネティスの‘~/.kube/config’ファイルは遠隔クバネティスクラスタのアドレス情報やユーザ認証情報などが含まれています。設定ファイルのタイプはYAMLで、直接編集するか‘kubectl config’コマンドを利用します。下記はPCに登録したクバネティスConfigファイルの例です。設定すると遠隔クバネティス接続に必要な情報が登録されます。
Kubernetes Configファイルの構成は下記の3つのフィールドで構成されています。
- クラスタ(Clusters): クラスタのサーバアドレスは基本TLS認証情報が含まれています。クラスタにコネクションするための必須情報です。
- コンテキスト(Contexts): クラスタとユーザのネームスペース情報が含まれています。コンテキストを利用すると複数のクラスタとユーザを素早く転換できます。
- ユーザ(Users): クライアントの認証情報で、クラスタと通信するための認証手段を定義します。これは認証トークン、クライアント認定証、ユーザ名や、パスワードなどです。参考にEKSとオンプレミスクバネティスは互いに異なる認証方法を利用します。
では今度は、~/.kube/configファイルの‘Clusters’と‘Users’情報を直接変更して遠隔のクバネティスクラスタを個人PCで管理します。EKSクバネティスConfigファイルに対する 詳細な追加情報は AWS公式文書で確認できます。
先ず、‘clusters’フィールドのサーバアドレスと認定証情報はAWS EKS管理コンソールの‘概要’メニューで確認できます。
必要な情報をコピーして上記の画面を参照してローカル~/.kube/configファイルに登録します。アドレスに該当する‘APIサーバエンドポイント’を‘server’に入力し、認定証情報の「認証機関」を‘certificate-authotiry-data’に入力します。
次に、cluster、context、userの名前を指定します。Nameは任意に決めることができるため、各自適切な名前を指定します。例では3つ全てに同名のswitch-singapore-testを入力します。
最後に‘user’フィールド入力です。下記の‘–cluster-name’にはインストール時、利用したクラスタ名(ex: singapore-test)を入力します。env:name、valueには各自AWS Credential情報を入力します。AWS Credential情報は ~/.aws/credentialsファイルで確認できます。EKSインストールに利用したCredential情報を入力します。‘env:-name’にAWS_PROFILEを‘env:value’にAWS CredentialsファイルのProfile名を入力します。
上記の設定を完了すると、ローカルでkubectlコマンドを実行できます。
1. $ (⎈ |switch-singapore-test:default) kubectl get nodes
2. NAME STATUS ROLES AGE VERSION
3. ip-10-110-9-40.ap-southeast-1.compute.internal Ready <none> 39d v1.26.4-eks-0a21954
コマンドが正常に実行されると、ローカルで遠隔クラスタを管理する全ての準備が完了しました。テストPodを作成するとPodが正常に実行されます。
1. $ (⎈ |switch-singapore-test:default) k run nginx --image=nginx
2. pod/nginx created
3.
4. $ (⎈ |switch-singapore-test:default) k get pod
5. NAME READY STATUS RESTARTS AGE
6. nginx 1/1 Running 0 29s
AWSコンソールで確認すると、VPC、Subnet、NATゲートウェイなどが自動的に含まれていることを確認できます。Terraformが便利なモジュールでEKSインストールに必要なリソースを一括でインストールしました。
ここでは3つのNATゲートウェイが登録されました。
以上がTerraformを利用してEKSをインストールする方法です。
Terraformを利用するとEKSのみならずEKS実行に必要な多様なリソースまで同時に簡単にインストールされます。Terraformは抽象化されているため、多数のリソースの詳細設定を完全に把握しなくてもインストールと運用に大きな支障はありません。会社毎の状況に合わせて少しずつ変更して最適化できます。