Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

準備事項

  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 で、「新しいアクセスキーの作成」をクリックする。

スクリーンショット 2018-10-20 9.32.34.png

アクセスキーを表示して、コピーして、上記の asw configure コマンドのプロンプトへペーストする。
スクリーンショット 2018-10-20 9.33.46.png

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" のリンクをクリックする。 「次のステップ:アクセス権限」をクリック、「次のステップ:確認」をクリックする。次の画面のロール名*にロール名を入れて、「ロールの作成」ボタンをクリックする。

スクリーンショット 2018-10-20 13.30.58.png

クリックにより、ロールのリストが表示されたら、今作った「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をペーストしたところ

スクリーンショット 2018-10-20 13.46.31.png

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

スクリーンショット 2018-10-20 13.49.11.png

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

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

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


EKS (Kubernetes) クラスタの構築

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

  1. k8sクラスタの作成
  2. KUBECONFIGの設定
  3. アクセス資格情報の取得
  4. ワーカーノードの起動
  5. ワーカーノードとクラスタ結合
  6. Calicoのデーモンセット起動
  7. ストレージクラスの設定

1.k8sクラスタの作成

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

スクリーンショット 2018-10-20 14.51.13.png

マスターノードだけの作成時間
開始 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をペーストしたところです。

スクリーンショット 2018-10-20 20.41.50.png

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

スクリーンショット 2018-10-20 20.45.20.png

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

  • スタックの名前: CloudFormation上の名前
  • ClusterName: EKSクラスタの名前で、前述で作成した名前と一致させます。
  • ClusterControlPlaneSecurityGroup: 前述のCloudFormationで作成したVPCの名前で始まる eks-pvc をセットします。
  • NodeGroupName: ノード名に付与される目印です。
  • NodeAutoScalingGroupMinSize: オートスケール利用時の最小ノード数
  • NodeAutoScalingGroupMaxSize: オートスケール利用時の最大ノード数
  • NodeInstanceType: EC2インスタンスのタイプ
  • NodeImageId: イメージID データセンターによってセットするべきIdが決まっています。
  • KeyName: 前述で作成したキーペアの名前です。
  • Vpcid: 前述で作成したVPCのIDです。
  • Subnets: サブネットはVPCのもとに作られたサブネットを全て選択します。

以下は、入力画面です。

スクリーンショット 2018-10-20 20.45.29.png

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

スクリーンショット 2018-10-20 20.52.34.png

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の画面から参照できます。

スクリーンショット 2018-10-20 21.06.30.png

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をアクセスするためのルールの追加します。

スクリーンショット 2018-10-20 21.30.56.png

次は 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

MahoTakara
Docker/Kuberneresの学習本を書きました。15ステップあるのですが、1ステップ完結型なので好きな所から学習できます。https://amzn.to/2mgCRya
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした