Edited at

AWS初心者だけど、EKSのクラスタを作って、NodePort と ELBアクセス、EBSのPVを確認したよ

自己研鑽で学んだことのメモです。


準備事項


  1. kubectlをインストールする

  2. AWS CLIをインストールする

  3. aws-iam-authenticator をインストールする

  4. キーペアを作成する

  5. サービスロールを作成する

  6. クラスタVPCを作成する


インストールするものから、先に進めていきます。EKSは、日本から一番近いオレゴンのリージョンを利用しました。


1.kubectlコマンドのインストール

筆者が試したところ、CNCFからダウンロードした kubectl コマンドでも、利用できたので、特別にビルドされたものではないようです。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/configure-kubectl.html

ホームディレクトリに、ディレクトリ aws-eks を作成して、ダウンロードした kubectl を保存します。


2.AWS CLIをイントール

awsコマンドは、IaaS部分の操作のために必要なので、インストールしておきます。

$ aws configure

AWS Access Key ID []: ****************ADMA
AWS Secret Access Key []: ****************pXoq
Default region name []: us-west-2
Default output format []: text

AWS Access Key ID と Secret Access ID の取得は、https://console.aws.amazon.com/iam/home#/security_credential で、「新しいアクセスキーの作成」をクリックする。

アクセスキーを表示して、コピーして、上記の asw configure コマンドのプロンプトへペーストする。


3.aws-iam-authenticator をインストール

このaws-iam-authenticator kubectl コマンドの中から呼び出して利用します。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started.html Amazon EKS の 「aws-iam-authenticator をインストールするには」に従ってインストールする。

ホームディレクトリに、ディレクトリ aws-eks を作成して、ダウンロードした このファイルを保存します。


4.キーペアを作成する

後に、ワーカーノードを作成する時に、必要となるので、キーペアを作成しておきます。

コンソールのリンク

https://us-west-2.console.aws.amazon.com/ec2/v2/home?region=us-west-2#KeyPairs:sort=keyName


5.サービスロールの作成

EKSクラスタのために、サービスロールを作成します。

https://console.aws.amazon.com/iam/home#/home をクリックして、Web画面を開いてロールを選択する。そして、「ロールの作成」ボタンをクリックする。次に遷移した画面で、"EKS" のリンクをクリックする。 「次のステップ:アクセス権限」をクリック、「次のステップ:確認」をクリックする。次の画面のロール名*にロール名を入れて、「ロールの作成」ボタンをクリックする。

クリックにより、ロールのリストが表示されたら、今作った「eksRole」をクリックする。そして、「ポリシーをアタッチします」をクリックする。

ロール名のリストの中から、「AmazonEC2FullAccess」を探して、アタッチする。


6.クラスタVPCを作成する

EKSクラスタのために、VPCを作成します。

CloudFormationマネジメント https://us-west-2.console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks?filter=active をクリックして開くいて、「新しいスタックの作成」をクリック

テンプレートが登録されたURLをペーストして、「次へ」をクリックする。

https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-08-30/amazon-eks-vpc-sample.yaml

以下は、S3のURLをペーストしたところ

Amazon S3テンプレートによって、次の画面の表示が変わる。 スタックの名前に eks-vpc をセットして、「次へ」をクリックする。

オプション画面は入力なしで、「次へ」をクリック。確認画面が表示されるので「作成」をクリックする。

スタック作成の進行中画面が表示されるので、「状況」に「CREATE_COMPLETE」が表示されたら、作成成功です。

以上で、EKSクラスタを作成するための準備が整いました。これから、EKSクラスタのマスターノードとワーカーノードを作成していきます。



EKS (Kubernetes) クラスタの構築

EKSでは、クラスタを一歩づつ構成していく必要があるので、GKE/IKSと同じような環境をつくるために、次の 1〜7 の作業をおこないます。


  1. k8sクラスタの作成

  2. KUBECONFIGの設定

  3. アクセス資格情報の取得

  4. ワーカーノードの起動

  5. ワーカーノードとクラスタ結合

  6. Calicoのデーモンセット起動

  7. ストレージクラスの設定



1.k8sクラスタの作成

EKSではマスターノードとワーカーノードは別々に作成します。 ここでは、まず、マスターノードのデプロイです。

マスターノードだけの作成時間

開始 14:52 完了 15:02


2.KUBECONFIGの設定

macOSのケースですが、ホームディレクトリにaws-eksに作っておき、以下のファイルを置いておきます。 

export KUBECONFIG=/Users/maho/aws-eks/.kube/config.yml:$KUBECONFIG

export PATH=/Users/maho/aws-eks/bin:/Users/maho/Library/Python/2.7/bin:$PATH

aws-eksにディレクトリとコマンドを、専用のディレクトリに置いて、上のパス設定で利用することにしました。

$ tree aws-eks

aws-eks
├── bin
│   ├── aws-iam-authenticator
│   └── kubectl
├── env-setup

EKSを利用する前に、source して、環境変数を設定します。

$ . env-setup


3.アクセス資格情報の取得

新しく提供されたコマンド https://aws.amazon.com/jp/about-aws/whats-new/2018/09/amazon-eks-simplifies-cluster-setup-with-update-kubeconfig-cli-command/ を利用して、前述で設定した 環境変数 KUBECONFIG のパスに設定されたコンフィグファイルに、EKSクラスタの設定を追加します。

$ aws eks update-kubeconfig --region us-west-2 --name eks1

Added new context arn:aws:eks:us-west-2:102321567306:cluster/eks1 to /Users/maho/aws-eks/.kube/config.yml
imac:aws-eks maho$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* arn:aws:eks:us-west-2:102321567306:cluster/eks1 arn:aws:eks:us-west-2:102321567306:cluster/eks1 arn:aws:eks:us-west-2:102321567306:cluster/eks1

上記のコマンドが成功すると、次のように、マスターノード上で動作するサービスが表示されます。しかし、この時点でワーカーノードが無いので、これ以上のことができません。

imac:aws-eks maho$ kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 5m


4.ワーカーノードの起動

ワーカーノードは、EC2インスタンスとして起動して、マスターと結合します。 CloudFormation ( https://us-west-2.console.aws.amazon.com/cloudformation/) を開いて、「スタックの作成」をクリックして、作成画面を表示します。そして、次のリンクをAmazon S3 テンプレートURLの入力フィールドにコピペします。

https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/amazon-eks-nodegroup.yaml

次の画面は、テンプレートURLをペーストしたところです。

これで「次へ」をクリックして、入力画面を表示します。スタックの名称をインプットします。

クラスタの作成パラメータをセットしていきます。この設定が正しくないと、ワーカーノードの作成に失敗したり、ネットワーク関連の動作がうまくいかないケースが発生するので、注意が必要です。


  • スタックの名前: CloudFormation上の名前

  • ClusterName: EKSクラスタの名前で、前述で作成した名前と一致させます。

  • ClusterControlPlaneSecurityGroup: 前述のCloudFormationで作成したVPCの名前で始まる eks-pvc をセットします。

  • NodeGroupName: ノード名に付与される目印です。

  • NodeAutoScalingGroupMinSize: オートスケール利用時の最小ノード数

  • NodeAutoScalingGroupMaxSize: オートスケール利用時の最大ノード数

  • NodeInstanceType: EC2インスタンスのタイプ

  • NodeImageId: イメージID データセンターによってセットするべきIdが決まっています。

  • KeyName: 前述で作成したキーペアの名前です。

  • Vpcid: 前述で作成したVPCのIDです。

  • Subnets: サブネットはVPCのもとに作られたサブネットを全て選択します。

以下は、入力画面です。

入力後に「作成」ボタンをクリックした後に、EC2インスタンスのリストを表示したところです。 インスタンスが作成されていきます。


5.ワーカーノードとクラスタ結合

次のYAMLファイルを作成して、キー rolearn の値に、NodeInstanceRole の値をセットします。


aws-auth-cm.yaml

apiVersion: v1

kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: (ここに CloudFormation の NodeInstanceRole の値を入れる)
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes

この NodeInstanceRole は、CloudFormationの画面から参照できます。

YAMLを適用して、ノードがクラスタに追加される様子です。約40秒で追加が完了しています。

$ kubectl apply -f aws-auth-cm.yaml

configmap "aws-auth" created

$ kubectl get no --watch
NAME STATUS ROLES AGE VERSION
ip-192-168-112-136.us-west-2.compute.internal NotReady <none> 3s v1.10.3
ip-192-168-142-69.us-west-2.compute.internal NotReady <none> 3s v1.10.3
ip-192-168-248-229.us-west-2.compute.internal NotReady <none> 5s v1.10.3
ip-192-168-248-229.us-west-2.compute.internal NotReady <none> 11s v1.10.3
ip-192-168-142-69.us-west-2.compute.internal NotReady <none> 11s v1.10.3
ip-192-168-112-136.us-west-2.compute.internal NotReady <none> 11s v1.10.3
ip-192-168-248-229.us-west-2.compute.internal Ready <none> 21s v1.10.3
ip-192-168-142-69.us-west-2.compute.internal Ready <none> 21s v1.10.3
ip-192-168-112-136.us-west-2.compute.internal NotReady <none> 21s v1.10.3
ip-192-168-248-229.us-west-2.compute.internal Ready <none> 31s v1.10.3
ip-192-168-142-69.us-west-2.compute.internal Ready <none> 31s v1.10.3
ip-192-168-112-136.us-west-2.compute.internal Ready <none> 31s v1.10.3
ip-192-168-248-229.us-west-2.compute.internal Ready <none> 41s v1.10.3
ip-192-168-142-69.us-west-2.compute.internal Ready <none> 41s v1.10.3

次は追加されたノードのリストです。

$ kubectl get no

NAME STATUS ROLES AGE VERSION
ip-192-168-112-136.us-west-2.compute.internal Ready <none> 5m v1.10.3
ip-192-168-142-69.us-west-2.compute.internal Ready <none> 5m v1.10.3
ip-192-168-248-229.us-west-2.compute.internal Ready <none> 5m v1.10.3


6.Calicoの設定

次のネットワークのポリシー設定が有効となるように、Calicoを導入します。

$ kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/v1.2/calico.yaml

daemonset.extensions "calico-node" created
customresourcedefinition.apiextensions.k8s.io "felixconfigurations.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "bgpconfigurations.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "ippools.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "hostendpoints.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "clusterinformations.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "globalnetworkpolicies.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "globalnetworksets.crd.projectcalico.org" created
customresourcedefinition.apiextensions.k8s.io "networkpolicies.crd.projectcalico.org" created
serviceaccount "calico-node" created
clusterrole.rbac.authorization.k8s.io "calico-node" created
clusterrolebinding.rbac.authorization.k8s.io "calico-node" created
deployment.extensions "calico-typha" created
clusterrolebinding.rbac.authorization.k8s.io "typha-cpha" created
clusterrole.rbac.authorization.k8s.io "typha-cpha" created
configmap "calico-typha-horizontal-autoscaler" created
deployment.extensions "calico-typha-horizontal-autoscaler" created
role.rbac.authorization.k8s.io "typha-cpha" created
serviceaccount "typha-cpha" created
rolebinding.rbac.authorization.k8s.io "typha-cpha" created
service "calico-typha" created

calicoの導入と稼働は、デーモンセットによって行われますから、ノードを追加した場合でも、自動的にインストールされます。 calico-nodeがノードで動作することで、機能が働くようになります。

$ kubectl get daemonset calico-node --namespace=kube-system

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
calico-node 3 3 3 3 3 <none> 1m

$ kubectl get po --namespace=kube-system
NAME READY STATUS RESTARTS AGE
aws-node-lktrj 1/1 Running 0 12m
aws-node-m745d 1/1 Running 0 12m
aws-node-x2vr2 1/1 Running 1 12m
calico-node-hcw6s 1/1 Running 0 1m
calico-node-nchg5 1/1 Running 0 1m
calico-node-p8d2l 1/1 Running 0 1m
calico-typha-75667d89cb-ftvbf 1/1 Running 0 1m
calico-typha-horizontal-autoscaler-78f747b679-8k2jm 1/1 Running 0 1m
kube-dns-7cc87d595-zfmf5 3/3 Running 0 6h
kube-proxy-9vc2m 1/1 Running 0 12m
kube-proxy-m584p 1/1 Running 0 12m
kube-proxy-xlp7r 1/1 Running 0 12m


7.ストレージクラスの設定

EKSでは、デフォルトでストレージクラスが入っていないので、AWSのブロックストレージ EBS が利用できるように、ストレージクラスを設定します。


ebs-storage-class.yml

kind: StorageClass

apiVersion: storage.k8s.io/v1
metadata:
name: ebs-gp2
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
mountOptions:
- debug

上記のストレージクラスのマニフェストを設定する様子が次の実行結果です。

$ kubectl apply -f ebs-storage-class.yml

storageclass.storage.k8s.io "ebs-gp2" created

$ kubectl get sc
NAME PROVISIONER AGE
ebs-gp2 (default) kubernetes.io/aws-ebs 7s

以上で、EKSのセットアップが完了しました。



アプリケーションのデプロイ

EKSの中でも、ネットワークとストレージの基本的な部分を以下の3つのケースで確認しました。


  1. ノードポート EC2インスタンスに対応づけたパブリックIPアドレスでアクセスします。

  2. ロードバランサー ELBを起動してパブリックIPでアクセスします。

  3. 永続ボリューム EBSをマウントします。ブロックストレージなので、1PVは1ポッド接続になります。


1.ノードポート

マニフェストを適用した結果です。

$ kubectl apply -f apl-1.yml

deployment.apps "web-apl1" created
service "web-apl1" created

$ kubectl get -f apl-1.yml
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/web-apl1 1 1 1 0 7s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/web-apl1 NodePort 10.100.97.17 <none> 80:31467/TCP 7s

EC2インスタンスのリストを表示したところです。 このIPアドレスに対して、curlでアクセスして、動作を確認します。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].[PublicIpAddress,Tags[?Key==`Name`].Value|[0]]'

18.***.***.*** eks1-ng1-Node
35.***.***.** eks1-ng1-Node
34.***.***.*** eks1-ng1-Node

セキュリティ・グループへのNodePortをアクセスするためのルールの追加します。

次は curlのテスト結果です。 ポッドが1個なので、どのノード(EC2インスタンス)から、同じポッドにアクセスしていることがわかります。

$ curl http://18.***.***.***:31467/

Hostname: web-apl1-74cb4d5959-tk6qp

$ curl http://35.***.***.**:31467/
Hostname: web-apl1-74cb4d5959-tk6qp

$ curl http://34.***.***.***:31467/
Hostname: web-apl1-74cb4d5959-tk6qp

ここで利用したマニフェストです。


apl-1.yml

apiVersion: apps/v1beta1

kind: Deployment
metadata:
name: web-apl1
spec:
replicas: 1
template:
metadata:
labels:
web: web-apl1
spec:
containers:
- image: maho/webapl3
name: web-server-c
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-apl1
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
selector:
web: web-apl1


2.ロードバランサー

EKSからELBを利用して、外部からアクセスするケースです。

$ kubectl apply -f apl-3.yml

deployment.apps "web-apl3" created
service "web-apl3" created

$ kubectl get -f apl-3.yml
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/web-apl3 3 3 3 0 8s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/web-apl3 LoadBalancer 10.100.162.235 a4538c834d465... 80:32641/TCP 8s

起動状態の確認です。

$ kubectl get svc web-apl3 -o wide

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
web-apl3 LoadBalancer 10.100.248.65 acfbaa466d46611e8baaa02a2ba37abf-1173102834.us-west-2.elb.amazonaws.com 80:31152/TCP 4m apl=web-apl3

ELBのDNS名でアクセスした結果です。 同様にポッドが一個なので、一つのポッドへしかアクセスしていません。

imac:yaml maho$ curl http://acfbaa466d46611e8baaa02a2ba37abf-1173102834.us-west-2.elb.amazonaws.com/

Hostname: web-apl3-dc7dcbfdf-rmkz9

imac:yaml maho$ curl http://acfbaa466d46611e8baaa02a2ba37abf-1173102834.us-west-2.elb.amazonaws.com/
Hostname: web-apl3-dc7dcbfdf-rmkz9

imac:yaml maho$ curl http://acfbaa466d46611e8baaa02a2ba37abf-1173102834.us-west-2.elb.amazonaws.com/
Hostname: web-apl3-dc7dcbfdf-rmkz9

ここで利用したマニフェストです。 この設定でELBが起動して外部公開されます。


apl-3.yml

apiVersion: apps/v1

kind: Deployment
metadata:
name: web-apl3
spec:
replicas: 1
selector:
matchLabels:
apl: web-apl3
template:
metadata:
labels:
apl: web-apl3
spec:
containers:
- image: maho/webapl3
name: web-server-c
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-apl3
spec:
selector:
apl: web-apl3
ports:
- name: http
protocol: TCP
port: 80
type: LoadBalancer


3.永続ボリューム

EBSを利用するケースです。

最初に、PVC(永続ボリューム要求)を作成しておきます。 EBSはブロックストレージなので、1ボリュームは、1ポッドからのみアクセスできます。


pvc.yml

apiVersion: v1

kind: PersistentVolumeClaim
metadata:
name: data1
spec:
accessModes:
#- ReadWriteMany
- ReadWriteOnce
# storageClassName: standard
resources:
requests:
storage: 2Gi

永続ボリュームにマウントするポッドのマニフェストです。


pod.yml

apiVersion: v1

kind: Pod
metadata:
name: pod1
spec:
volumes:
- name: pvc1
persistentVolumeClaim:
claimName: data1
containers:
- name: ubuntu
image: ubuntu:16.04
volumeMounts:
- name: pvc1
mountPath: /mnt
#command: [”tail”, “-f”, “/d
command: [ 'tail' ]
args:
- -f
- /dev/null

デプロイと結果です。

$ kubectl apply -f pvc.yml

persistentvolumeclaim "data1" created

$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data1 Bound pvc-4ce26c73-d476-11e8-baaa-02a2ba37abf8 2Gi RWO ebs-gp2 20s

$ kubectl apply -f pod.yml
pod "pod1" created

$ kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 15s

デプロイしたポッドに入って、永続ボリュームをマウントしている状態を確認したものです。

$ kubectl exec -it pod1 -- bash

root@pod1:/# df -h
Filesystem Size Used Avail Use% Mounted on
overlay 20G 2.3G 18G 12% /
tmpfs 997M 0 997M 0% /dev
tmpfs 997M 0 997M 0% /sys/fs/cgroup
/dev/xvdbj 2.0G 6.0M 1.8G 1% /mnt
/dev/xvda1 20G 2.3G 18G 12% /etc/hosts
shm 64M 0 64M 0% /dev/shm
tmpfs 997M 12K 997M 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 997M 0 997M 0% /sys/firmware



クリーンアップ

EKSクラスタを削除しただけでは、ワーカーノードのEC2インスタンスなどを削除しないので、注意が必要です。想定外の課金が発生しないように、それぞれ削除しなければなりません。


  • EKSクラスタの削除

  • Cloud Formation のワーカーノードのスタックを削除

  • ELBの削除 k8sから作成したPVを消去する必要がある。

  • EBSの削除 k8sから作成したLoadBalancerは削除されないケースがあった。



感想

EKSは、GKEやIKSとは違った設定方法だけど、解ってしまえば、同じように使えるということが解った。



参考資料

[1] Amazon EKS の使用開始、https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started.html