AWSの無料枠といえばt2.microです。
ということで、EKSをWorkerがt2.micro 1台という構成で構築してみました。1
(2018/06/12) CloudFormationテンプレートのMaxPodsの設定が影響している可能性を考慮していなかったため、追記しました。
結論
EKSのWorkerは、t2.microでも特に問題なく構築でき、Podの起動も可能でした。
ただし、IPアドレス数の制限により、Podは2つ以上起動できませんでした。
IPアドレスが枯渇するとWorkerもPodもスケールできなくなると思われるので、IPアドレス数の制限には注意が必要そうです。
インスタンスタイプごとに、IPアドレス数の制限と、MaxPodsによる制限と、他にも何らかの制限があり、Podの起動数が制限されているようです。
スケールを考えるうえで、Podの起動数の制限には注意が必要そうです。
やったこと
Workerがt2.micro 1台構成なEKSの構築
Workerの構築の手前まで
Amazon EKS の使用開始 に従い、「ステップ 3: Amazon EKS ワーカーノードを起動して設定する」の手前まで構築を進めます。
CloudFormationテンプレートの修正
Amazon EKS の使用開始 に掲載されているテンプレートを、以下のように2箇所書き換えます。
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Amazon EKS - Node Group'
Parameters:
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instances
Type: AWS::EC2::KeyPair::KeyName
:
:
:
NodeInstanceType:
Description: EC2 instance type for the node instances
Type: String
Default: t2.medium
AllowedValues:
# t2.microを追加
- t2.micro
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t2.2xlarge
:
:
:
MaxPods: 234
r4.8xlarge:
MaxPods: 234
r4.16xlarge:
MaxPods: 737
# t2.microを追加
t2.micro:
# MaxPodsは適当に設定
MaxPods: 4
t2.small:
MaxPods: 8
t2.medium:
MaxPods: 17
t2.large:
:
:
:
修正したテンプレートでWorkerを構築
変更したテンプレートを使ってWorkerを構築します。
NodeAutoScalingGroupMaxSizeは1、NodeInstanceTypeはt2.microとします。
ConfigMapの作成
Amazon EKS の使用開始 に記載されている「ワーカーノードをクラスターと結合するには」に従って、ConfigMapを作成します。
Worker構築完了の確認
kubectlでワーカーが1台表示されれば構築完了です。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-157-38.us-west-2.compute.internal Ready <none> 1m v1.10.3
Podの起動
まずはPodを1つ起動してみる
NginxのPodを1つ起動してみます。
$ kubectl run my-nginx --image=nginx:alpine
deployment.apps "my-nginx" created
無事起動しました。
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-6947c57698-tjt6p 1/1 Running 0 25s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 24m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 1 1 1 1 25s
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-6947c57698 1 1 1 25s
ポートフォワードして動作確認します。
$ kubectl port-forward deployment.apps/my-nginx 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
ブラウザから http://localhost:8080 に接続すると、画面が表示されました。
t2.microでもPodを起動できることが確認できました。
Podを増やしてみる
Podを2つに増やしてみます。
$ kubectl scale deployment.apps/my-nginx --replicas=2
deployment.apps "my-nginx" scaled
以下の通り、2つ目のPodが起動していません。
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-6947c57698-5lnxj 0/1 Pending 0 16s
pod/my-nginx-6947c57698-tjt6p 1/1 Running 0 6m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 29m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 2 2 2 1 6m
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-6947c57698 2 2 1 6m
詳細を確認します。
$ kubectl describe pod/my-nginx-6947c57698-5lnxj
Name: my-nginx-6947c57698-5lnxj
Namespace: default
Node: <none>
Labels: pod-template-hash=2503713254
run=my-nginx
Annotations: <none>
Status: Pending
IP:
Controlled By: ReplicaSet/my-nginx-6947c57698
Containers:
my-nginx:
Image: nginx:alpine
Port: <none>
Host Port: <none>
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8xb9r (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
default-token-8xb9r:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-8xb9r
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 19s (x8 over 1m) default-scheduler 0/1 nodes are available: 1 Insufficient pods.
何かの不足でPodが起動できていないようです。
考察
2つ目のPodが起動できなかった理由
ポッドネットワーキング によると...
Amazon EKS は、Kubernetes の Amazon VPC CNI プラグインを使用した従来の VPC ネットワーキングをサポートしています。この CNI プラグインを使用すると、Kubernetes ポッドは VPC ネットワーク上と同じ IP アドレスをポッド内に持つことができます。この CNI プラグインは、GitHub で管理されているオープンソースのプロジェクトです。
:
:
:
Elastic Network Interface と、Amazon EC2 インスタンスタイプによるセカンダリ IP アドレス制限が適用されます。一般的に、インスタンスが大きいほど、より多くの IP アドレスをサポートできます。詳細については、Linux インスタンス用 Amazon EC2 ユーザーガイドの「各インスタンスタイプのネットワークインターフェイスごとの IP アドレス」を参照してください。
各インスタンスタイプのネットワークインターフェイスごとの IP アドレス を参照すると...
インスタンスタイプ ネットワークインターフェイスの最大数 インターフェイスあたりの IPv4 アドレス インターフェイスあたりの IPv6 アドレス t2.micro 2 2 2 t2.small 2 4 4 t2.midium 3 6 6
ということで、t2.microは 2 × 2 = 4 つまでしかIPアドレスを持てないようです。
他のNamespaceでどれだけIPアドレスを使っているのか確認すると...
$ kubectl get pod --namespace kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE
aws-node-2tqc2 1/1 Running 0 30m 192.168.157.38 ip-192-168-157-38.us-west-2.compute.internal
kube-dns-7cc87d595-bqdjk 3/3 Running 0 52m 192.168.170.125 ip-192-168-157-38.us-west-2.compute.internal
kube-proxy-zkd2n 1/1 Running 0 30m 192.168.157.38 ip-192-168-157-38.us-west-2.compute.internal
上記のように、kube-systemでIPアドレスを2つ使っています。
インスタンスがそもそも1つIPアドレスを使っているので、各ノードに対して自動的に3個のIPアドレスが消費されてしまうようです。
その結果、合計で4つまでしかIPアドレスを持てないt2.microは、Podを1つしか起動できなかったようです。
t2.smallでも試してみる
t2.smallでも実験してみました。
t2.smallはIPアドレスを 2 × 4 = 8 個持てるはずです。
そのうち3個が消費されてしまうはずなので、5個だけPodが起動して、6個目は起動できないはずです。
実際にPodを6個起動しようとすると...
$ kubectl scale deployment.apps/my-nginx --replicas=6
deployment.apps "my-nginx" scaled
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-6947c57698-2cq6s 1/1 Running 0 34s
pod/my-nginx-6947c57698-6kdmb 1/1 Running 0 34s
pod/my-nginx-6947c57698-6xnfc 0/1 Pending 0 34s
pod/my-nginx-6947c57698-gl29s 1/1 Running 0 34s
pod/my-nginx-6947c57698-jfk58 1/1 Running 0 34s
pod/my-nginx-6947c57698-z5fh4 1/1 Running 0 34s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 1h
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 6 6 6 5 50m
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-6947c57698 6 6 5 50m
たしかに5つまでしか起動できませんでした。
(2018/06/12) 追加調査
t2.mediumでも試してみる
実は、ここまでの確認方法では、t2.micro、t2.smallのPod起動制限がCloudFormationテンプレートで指定したMaxPodsに依存している可能性を排除できていませんでした。
そこで、t2.mediumでも試してみました。
t2.mediumはMaxPodsが17なので、この設定の影響があるならNginxのPodは14個まで起動できるはずです。
ENIの面では、 3 × 6 = 18 なので、こちらの設定が影響するならNginxのPodは15個まで起動できるはずです。
では、Podを16個起動しようとしてみます。
$ kubectl scale deployment.apps/my-nginx --replicas=16
deployment.apps "my-nginx" scaled
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-6947c57698-2dm68 1/1 Running 0 1m
pod/my-nginx-6947c57698-5zdkr 1/1 Running 0 1m
pod/my-nginx-6947c57698-6kx6c 1/1 Running 0 2m
pod/my-nginx-6947c57698-8mt2x 0/1 Pending 0 1m
pod/my-nginx-6947c57698-9lqmk 1/1 Running 0 1m
pod/my-nginx-6947c57698-dwpcz 1/1 Running 0 1m
pod/my-nginx-6947c57698-gxzft 1/1 Running 0 1m
pod/my-nginx-6947c57698-jf94r 1/1 Running 0 1m
pod/my-nginx-6947c57698-jnzd9 1/1 Running 0 1m
pod/my-nginx-6947c57698-k69fp 1/1 Running 0 1m
pod/my-nginx-6947c57698-nntk4 1/1 Running 0 1m
pod/my-nginx-6947c57698-rhdn6 1/1 Running 0 1m
pod/my-nginx-6947c57698-s47mq 1/1 Running 0 1m
pod/my-nginx-6947c57698-thc85 0/1 Pending 0 1m
pod/my-nginx-6947c57698-vkdpb 1/1 Running 0 1m
pod/my-nginx-6947c57698-vwvd6 1/1 Running 0 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 14m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 16 16 16 14 2m
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-6947c57698 16 16 14 2m
念のため詳細を見ておくと...
$ kubectl describe pod/my-nginx-6947c57698-8mt2x
Name: my-nginx-6947c57698-8mt2x
Namespace: default
Node: <none>
Labels: pod-template-hash=2503713254
run=my-nginx
Annotations: <none>
Status: Pending
IP:
Controlled By: ReplicaSet/my-nginx-6947c57698
Containers:
my-nginx:
Image: nginx:alpine
Port: <none>
Host Port: <none>
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-t664j (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
default-token-t664j:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-t664j
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 48s (x8 over 1m) default-scheduler 0/1 nodes are available: 1 Insufficient pods.
ということで、Podは14個までしか起動できませんでした。
したがって、Podの起動数の制限はMaxPodsにも依存していたように思えます。
MaxPodsを変更して試してみる
ENIによる制限とMaxPodsによる制限のうち小さいほうに依存している可能性があるので、さらに検証します。
t2.mediumのMaxPodsを19に書き換えます。
MaxPods: 737
t2.micro:
MaxPods: 4
t2.small:
MaxPods: 8
t2.medium:
# 17から19に書き換える
MaxPods: 19
t2.large:
MaxPods: 35
t2.xlarge:
MaxPods: 44
t2.2xlarge:
これでもMaxPodsが影響するなら 19 - 3 = 16 個のPodが起動するはずです。
ENIが影響するなら 18 - 3 = 15 個のPodが起動するはずです。
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-6947c57698-2k9kz 1/1 Running 0 6m
pod/my-nginx-6947c57698-4q8j7 0/1 ContainerCreating 0 6m
pod/my-nginx-6947c57698-5n4hn 1/1 Running 0 6m
pod/my-nginx-6947c57698-7ntlc 1/1 Running 0 6m
pod/my-nginx-6947c57698-96p94 1/1 Running 0 6m
pod/my-nginx-6947c57698-bxqfz 0/1 Pending 0 6m
pod/my-nginx-6947c57698-d4rt8 1/1 Running 0 6m
pod/my-nginx-6947c57698-f2bv7 1/1 Running 0 6m
pod/my-nginx-6947c57698-g2krs 0/1 ContainerCreating 0 6m
pod/my-nginx-6947c57698-kw2dq 1/1 Running 0 6m
pod/my-nginx-6947c57698-kzc4k 1/1 Running 0 6m
pod/my-nginx-6947c57698-mrv8m 1/1 Running 0 6m
pod/my-nginx-6947c57698-sq9td 1/1 Running 0 6m
pod/my-nginx-6947c57698-t9kfq 1/1 Running 0 6m
pod/my-nginx-6947c57698-wnvjf 1/1 Running 0 6m
pod/my-nginx-6947c57698-x8lkg 1/1 Running 0 6m
pod/my-nginx-6947c57698-zbkt7 1/1 Running 0 6m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 44m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 17 17 17 14 31m
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-6947c57698 17 17 14 31m
14個という、予想外の結果になりました。。。
PendingになっているPodの詳細は...
$ kubectl describe pod/my-nginx-6947c57698-bxqfz
Name: my-nginx-6947c57698-bxqfz
Namespace: default
Node: <none>
Labels: pod-template-hash=2503713254
run=my-nginx
Annotations: <none>
Status: Pending
IP:
Controlled By: ReplicaSet/my-nginx-6947c57698
Containers:
my-nginx:
Image: nginx:alpine
Port: <none>
Host Port: <none>
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-t664j (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
default-token-t664j:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-t664j
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m (x26 over 8m) default-scheduler 0/1 nodes are available: 1 Insufficient pods.
今まで表示されていたのと同様のエラーです。
ContainerCreatingになっているPodの詳細は...
$ kubectl describe pod/my-nginx-6947c57698-4q8j7
Name: my-nginx-6947c57698-4q8j7
Namespace: default
Node: ip-192-168-144-73.us-west-2.compute.internal/192.168.144.73
Start Time: Tue, 12 Jun 2018 11:25:42 +0900
Labels: pod-template-hash=2503713254
run=my-nginx
Annotations: <none>
Status: Pending
IP:
Controlled By: ReplicaSet/my-nginx-6947c57698
Containers:
my-nginx:
Container ID:
Image: nginx:alpine
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-t664j (ro)
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-t664j:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-t664j
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9m default-scheduler Successfully assigned my-nginx-6947c57698-4q8j7 to ip-192-168-144-73.us-west-2.compute.internal
Normal SuccessfulMountVolume 9m kubelet, ip-192-168-144-73.us-west-2.compute.internal MountVolume.SetUp succeeded for volume "default-token-t664j"
Warning FailedCreatePodSandBox 8m (x12 over 9m) kubelet, ip-192-168-144-73.us-west-2.compute.internal Failed create pod sandbox: rpc error: code = Unknown desc = NetworkPlugin cni failed to set up pod "my-nginx-6947c57698-4q8j7_default" network: add cmd: failed to assign an IP address to container
Normal SandboxChanged 4m (x271 over 9m) kubelet, ip-192-168-144-73.us-west-2.compute.internal Pod sandbox changed, it will be killed and re-created.
IPアドレスを与えることに失敗しています。
どうやら、MaxPodsとENIの制限と、他にも何らかの制限があるようです。。。
これ以上は未調査です。
結論 (再掲)
EKSのWorkerは、t2.microでも特に問題なく構築でき、Podの起動も可能でした。
ただし、IPアドレス数の制限により、Podは2つ以上起動できませんでした。
IPアドレスが枯渇するとWorkerもPodもスケールできなくなると思われるので、IPアドレス数の制限には注意が必要そうです。
インスタンスタイプごとに、IPアドレス数の制限と、MaxPodsによる制限と、他にも何らかの制限があり、Podの起動数が制限されているようです。
スケールを考えるうえで、Podの起動数の制限には注意が必要そうです。
-
GKEやAKSと違い、EKSはMasterノードが有料 ($0.20/hr。t2.xlargeよりも高額) なので、Workerを無料枠に入れても仕方ないというのは別のお話です。 ↩