このシリーズは、入社1年目の新人がEC2上にKubernetes環境構築を色々試行錯誤してやってみて、上手くいった手順をまとめたものです。
#はじめに
前の記事では、Amazon EC2上にKubernetesクラスターを構築しました。
Kubernetesをデプロイするだけでは意味がないので、今回はKubernetesクラスターに色んなリソースを作成してみます。
Kubernetes on Amazon EC2 環境構築編 ~新人がやってみた(1)~の続きになります。
この記事の前後の記事は以下です。
- Kubernetes on Amazon EC2 環境構築編
- Kubernetes on Amazon EC2 リソース作成編 (本記事)
- Kubernetes on Amazon EC2 運用監視編(今後公開予定)
※この記事は手順に焦点を当てているので、Kubernetesに関する用語の詳細な説明は省略しています。
目次
0.本記事で構築する環境について
1.Namespaceの作成
2.Deploymentの作成
3.Serviceの作成
4.PersistentVolumeの作成
5.Role(ユーザー)の作成
#0. 本記事で構築する環境について
前回の記事で作成したKubernetes on EC2環境上に以下5つのリソースを作成します。
- Namespace
- Deployment
- Service
- PersistentVolume
- Role
作成する流れは、以下のようになっています。
まずNamespaceを1つ作成し、Deploymentを使ってpodをデプロイします。
podの中にはそれぞれNGINXコンテナをデプロイし、アクセスできるようにServiceを設定します。
次に、MasterノードにEBSをアタッチし、NFSサーバとして設定し、PersistentVolumeを作成します。
EBSボリュームの中に自作のhtmlファイルを格納し、PVをマウントするようなPodをデプロイして自作htmlにアクセスできるようにします。
最後にClusterRoleやRoleBindingを使用して、Namespace1におけるReadOnly権限を持つユーザーを作成します。
本記事で紹介している手順を全て行うと、以下のようになると思います。
※本記事では、各リソースをyamlで定義して作成しています。
どのリソースも、作成するまでの流れは基本的に同じで、
yamlを作成して、kubectl create
コマンドでリソースをデプロイするという感じです。
#1. Namespaceの作成
本章では、Namespaceを1つ作成する手順を紹介します。
Namespaceとは、Kubernetesクラスターの中に仮想クラスターを作成するものです。
Namespaceを作成することで、各Namespace上に作成されたリソースを独立させることができます。
Namespaceを作成したい場合、以下のコマンド1つで作成できます。
本記事では、namespace1
という名前のNamespaceを作成しています。
$ kubectl create namespace namespace1
#2. Deploymentの作成
本章では、NGINXのpodを2起動させるDeploymentを作成する手順を紹介します。
Deploymentとは、Podのロールバックやローリングアップデート等を管理することができるものです。
Deploymentを作成すると、コンテナイメージがアップデートされた場合などに
アップデートしたコンテナイメージを使用して、自動でPodを再起動してくれます。
本記事では、NGINXコンテナを1台起動するpodをレプリカ数2でデプロイしています。
(1)yamlを作成します。
$ sudo vi nginx-deployment.yaml
apiVersion: apps/v1 #APIのバージョン
kind: Deployment #リソースの種類
metadata:
name: test-nginx #podの名前
namespace: namespace1 #デプロイするNamespaceを指定
spec:
selector: #どのPodを起動するか
matchLabels:
app: nginx #テンプレートを指定
replicas: 2 #レプリカ数(起動するPodの数)
template: #作成されるPodのテンプレート
metadata:
labels:
app: nginx #Labelを付ける
spec:
containers:
- name: nginx # コンテナに名前を付ける
image: nginx:latest # イメージを指定する
ports:
- containerPort: 80 #コンテナが開くポートを指定
(2)作成したyamlを使用して、podをデプロイします。
$ kubectl create -f nginx-deployment.yaml
#3. Serviceの作成
本章では、2.Deploymentの作成で起動させたPodを外部に公開するためのServiceを作成する手順を紹介します。
Serviceとは、デプロイされたPodの公開ポリシーや接続方法を定義するものです。
Serviceには、以下のように4つの公開タイプがあります。
- ClusterIP : Kubernetesクラスター内でのみ有効なタイプです。外部からアクセスできません。
- NodePort : Workerノードのポートを指定して、外部に公開します。
- LoadBalancer : 外部からのリクエストを複数のPodへ負荷分散するタイプです。
- ExtarnalName : 任意のドメインをServiceに紐づけ、Podをドメインで外部に公開します。
本記事では、NodePortタイプのServiceを作成し、Podを公開します。
(1)yamlを作成します。外部に公開するポート番号は、30000から32767の間で自由に指定できます。
ポート番号を指定しない場合は、30000から32767の間で自動で割り当たります。
$ sudo vi nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx # Serviceの名前
labels:
app: nginx # Serviceのラベル
spec:
type: NodePort #Serviceのタイプ
ports:
- port: 80 # Serviceが受け取るポート
protocol: TCP
targetPort: 80 # コンテナが開いているポート
nodePort: 30001 # 外部に公開するWorkerノードのポート
selector:
app: nginx # Serviceを紐づけるPodのラベルを指定します
(2)作成したyamlを使用して、Serviceをデプロイします。
$ kubectl create -f nginx-service.yaml
(3)以下のコマンドを使用して、PodがどのWorkerノードで起動しているかを調べます。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
test-nginx 2/2 Running 0 6m 10.244.1.10 worker1
(4)「http://NGINXのPodが起動しているWorkerノードのIPアドレス:30001」にアクセスして、以下のように表示されることを確認します。
#4. PersistentVolumeの作成
本章では、EBSを使用してPersistentVolumeを作成する手順を紹介します。
PersistentVolume(PV)とは、Kubernetesクラスターから利用可能なボリュームのことです。
しかしPVだけではPodにマウントできないため、
PersistnetVolumeClaim(PVC)というボリュームの使用要求リソースと一緒に使用します。
PVはPVCから呼び出されることによって、Podにマウントできるようになります。
MasterノードにアタッチしたEBSをNFSサーバーとして設定し、それをPersistentVolumeとしてPodからアクセスできるようにします。
本記事では、EBSの作成からPVをマウントするPodの公開まで、以下のような流れで作成します。
- EBSの作成とアタッチ
- NFSサーバの設定
- NFSサーバの動作確認
- PersistentVolumeの作成
- PersistentVolumeClaimの作成
- PVをマウントするpodの作成
- podを外部に公開するServiceの作成
##4-1. EBSの作成とアタッチ
GUIを使用してEBSを作成することもできますが、本記事ではAWS CLIを使用して作成しています。
Masterノードにて、以下の手順を行います。(Workerノードでも可能です。)
(1)aws configureを設定します。使用しているIAMユーザーのアクセスキーとシークレットキーを入力してください。
$ aws configure
AWS Access Key ID [None]: アクセスキー
AWS Secret Access Key [None]: シークレットキー
Default region name [None]: ap-northeast-1
Default output format [None]: json
※IAMユーザーのアクセスキーは、AWSコンソールの「IAMサービス > ユーザー > 認証情報」で確認できます。
しかし、シークレットキーはアクセスキーを作成したときにしか表示、保存できません。
シークレットキーが見つからないという場合は、新規にアクセスキーを作成し、使用してください。
(2)EBSを作成します。
--availability-zoneはNFSサーバーとして設定する予定のEC2インスタンスと同様のアベイラビリティゾーンを入力してください。(本記事では、Masterノードです。)
実行結果のVolumeId:
の後ろに表示されているvol-XXXXXXXXX
をコピーしておいてください。
$ aws ec2 create-volume --size=10 --volume-type=gp2 --availability-zone ap-northeast-1d
{
"AvailabilityZone": "ap-northeast-1c",
"CreateTime": "2020-12-15T10:59:55.000Z",
"Encrypted": false,
"Size": 10,
"SnapshotId": "",
"State": "creating",
"VolumeId": " vol-07ebc41e508b23485",★この部分★
"Iops": 100,
"Tags": [],
"VolumeType": "gp2"
}
(3)EBSをMasterノードにアタッチします。MasterノードのEC2インスタンスIDと上記ボリュームIDを入力してください。
実行結果のState
がattaching
になっていることを確認します。
$ aws ec2 attach-volume --instance-id MasterノードのEC2インスタンスID --device /dev/xvdf --volume-id vol-07ebc41e508b23485 --region ap-northeast-1
{
"AttachTime": "2020-12-15T11:08:26.251Z",
"InstanceId": "MasterノードのインスタンスID",
"VolumeId": "vol-07ebc41e508b23485",
"State": "attaching",★
"Device": "/dev/xvdf"
}
(4)EBSがアタッチされている(xvdf
が認識されている)ことを確認します。
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda 202:0 0 8G 0 disk
└─xvda1 202:1 0 8G 0 part /
xvdf 202:80 0 10G 0 disk★
##4-2. NFSサーバの設定
MasterノードにアタッチしたEBSをNFSサーバとしてKubernetesクラスター間で共有できるように設定します。
(1)/dev/xvdf
パーティションをファイルシステムext4でフォーマットします。
$ sudo mkfs -t ext4 /dev/xvdf
(2)マウントポイントを作成します。
$ sudo mkdir -p /export/nfs
(3)/etc/fstabの最後の行にマウント情報を追加します。
$ sudo vi /etc/fstab
/dev/xvdf /export/nfs ext4 defaults,nofail 1 2
(4)EBSを/export/nfs
にマウントします。
$ sudo mount /export/nfs
(5)/etc/exportsの最後の行にexportポイント情報を追加します。本記事では、/export/nfs
をVPC内で共有できるように設定します。
$ sudo vi /etc/exports
/export/nfs VPCのCIDER(rw,no_root_squash)
(6)NFSを起動します。
$ sudo systemctl start nfs
※NFSがすでに起動済みの場合は以下のコマンドで設定を反映できます。
$ sudo exportfs -ar
(7)ディレクトリ(/export/nfs
)が共有されているか確認します。
$ showmount -e
Export list for master:
/export/nfs VPCのCIDER
(8)EBSがマウントされている(xvdfのMOUNTPOINT欄に/export/nfs
が表示されている)ことを確認します。
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda 202:0 0 8G 0 disk
└─xvda1 202:1 0 8G 0 part /
xvdf 202:80 0 10G 0 disk /export/nfs
^^^^^^^^^^^
(9)表示させるhtmlを作成し、共有ディレクトリ(/export/nfs
)に配置します。
$ sudo vi /export/nfs/index.html
<html>
<head>
<title>Volume Test</title>
</head>
<body>
<h1>Hello Persistent Volume!</h1>
</body>
</html>
##4-3. NFSサーバの動作確認
(1)全Workerノードにnfsがインストールされていることを確認してください。インストールされていない場合、インストールを行ってください。
$ yum list | grep nfs
(省略)
nfs-utils.x86_64 1:1.3.0-0.54.amzn2.0.2 installed
nfs4-acl-tools.x86_64 0.3.3-17.amzn2 amzn2-core
(省略)
(2)Workerノードで、NFSサーバから共有されているディレクトリをマウントできることを確認します。
NFSサーバーのIPアドレス
には、NFSサーバとして設定したEC2インスタンス(本記事では、Masterノード)のプライベートIPアドレスを入力します。
$ sudo mount -t nfs NFSサーバのIPアドレス:/export/nfs /mnt/nfs
$ df
Filesystem 1K-blocks Used Available Use% Mounted on
NFSサーバのIPアドレス:/export/nfs 503839744 128 503839616 1% /mnt/nfs
※マウントを解除するには、下記コマンドを実行してください。
$ umount /mnt/nfs
##4-4. PersistentVolumeの作成
本節では、前々節で作成したNFSサーバーをPersistentVolumeとして、Kubernetesクラスターに作成します。
(1)PersistentVolumeのyamlを作成します。
server
欄にNFSサーバのIPアドレスを入力し、path
欄に設定したマウントポイントを入力します。
$ sudo vi nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv # PVの名前
spec:
capacity:
storage: 8Gi # ストレージの容量指定
accessModes:
- ReadWriteOnce #ボリュームをアタッチできるノード数の指定
persistentVolumeReclaimPolicy: Recycle
nfs:
server: NFSサーバのIPアドレス
path: /export/nfs #マウントポイント
(2)作成したyamlを使用して、PVをデプロイします。
$ kubectl create -f nfs-pv.yaml
##4-5. PersistentVolumeClaimの作成
4-4.で作成したPVをPodからマウントできるように、PVCを作成します。
(1)yamlを作成します。
$ sudo vi nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc # PVCの名前
spec:
accessModes:
- ReadWriteOnce #ボリュームをアタッチできるノード数の指定
resources:
requests:
storage: 2Gi
(2)作成したyamlを使用して、PVCをデプロイします。
$ kubectl create -f nfs-pvc.yaml
##4-6. PVをマウントするpodの作成
podのyamlを作成します。
Pod内のNGINXコンテナの/usr/share/nginx/html ディレクトリにPVをマウントさせるyamlを作成します。
4-5.で作成したPVCを指定することで、PVをマウントできるようになります。
(1)yamlを作成します。
$ sudo vi nginx-pv.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pv # Podの名前
namespace: namespace1 #デプロイするNamespaceを指定
labels:
app: nginx-pv # Podのラベル
spec:
containers:
- name: nginx-container # コンテナの名前
image: nginx # コンテナイメージ
ports:
- containerPort: 80 # コンテナが開くポート
name: "http-server" # ポートの名前
volumeMounts:
- mountPath: "/usr/share/nginx/html" # コンテナ側のマウントポイント
name: nginx-vm #ボリューム名
volumes:
- name: nginx-vm # PVCで呼び出したボリューム名
persistentVolumeClaim:
claimName: nfs-pvc # PVCを指定
(2)作成したyamlを使用して、podをデプロイします。
$ kubectl create -f nginx-pv.yaml
##4-7. podを外部に公開するServiceの作成
本節では、NodePortタイプのServiceを作成して、30002ポートを外部に公開します。
(1)yamlを作成します。
$ sudo vi nginx-svc-pv.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-pv # Serviceの名前
labels:
app: nginx-svc-pv # Serviceのラベル
spec:
type: NodePort # NodePortタイプを指定
ports:
- port: 80 # Serviceが受け取るポート
protocol: TCP
targetPort: 80 # コンテナ側のポート
nodePort: 30002 # 外部に公開用のポート
selector:
app: nginx-pv # 公開するpodのラベルを指定
(2)作成したyamlを使用して、Serviceをデプロイします。
$ kubectl create -f nginx-svc-pv.yaml
(3)以下のコマンドを使用して、podがどのWorkerノードで起動しているかを調べます。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-pv 1/1 Running 0 3m 10.244.1.11 worker2
(4)「http://NGINXのpodがデプロイされているノードのIPアドレス:30002」にアクセスして、作成したhtmlが表示されていることを確認します。
#5. Role(ユーザー)の作成
本章では、Kubernetesクラスター上のリソースに対して、ReadOnly権限のみを付与したRoleを作成する手順を紹介します。
Kubernetesには、RBAC(Role-Based Access Control)というアクセス制御機能があり、以下の4つのリソースがあります。
- Role
- ClusterRole
- RoleBinding
- ClusterRoleBinding
RoleとClusterRoleは、どのリソースに対するどんな操作を許可するかを定義するもので、
RoleBindingとClusterRoleBindingは、RoleやClusterRoleをどのユーザー等に紐づけるかを定義するものです。
そして、それぞれClusterが付いていないリソース(Role,RoleBinding)と付いているリソース(ClusterRole,ClusterRoleBinding)の違いは、前者が特定のNamespaceに属するリソースで、後者がNamespaceに属さずクラスター内で使用できることです。
本記事では、ClusterRoleとRoleBindingを使用して、Namespace1におけるReadOnly権限を持つユーザーを作成します。
以下のような流れで、ユーザーを作成します。
##5-1. ユーザー認証情報の作成
※本記事で作成している認証情報は、自己署名証明書です。
(1)秘密鍵を作成します。
$ sudo openssl genrsa -out ns1user.key 2018
Generating RSA private key, 2018 bit long modulus
.......+++
...............+++
e is 65537 (0x10001)
(2)作成した秘密鍵を元に、証明書発行リクエストファイルを作成します。Organization Name
に所属グループ名、Common Name
にユーザー名を入力し、それ以外は空欄で大丈夫です。
$ sudo openssl req -new -key ns1user.key -out ns1user.csr
(略)
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:test
Organizational Unit Name (eg, section) []: ^^^^
Common Name (eg, your name or your server's hostname) []:ns1user
Email Address []: ^^^^^^^
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
(3)作成した証明書発行リクエストファイルとPKI証明書を使って、SSL証明書を作成します。
$ sudo openssl x509 -req -in ns1user.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ns1user.crt -days 10000
Signature ok
subject=/C=XX/L=Default City/O=test/CN=ns1user
Getting CA Private Key
(4)ns1user
というユーザー名で、(1)から(3)で作成した証明書情報をKubernetesクラスターに登録します。
$ kubectl config set-credentials ns1user --client-certificate=ns1user.crt --client-key=ns1user.key --embed-certs=true
##5-2. コンテキストの作成
コンテキストを作成し、Namespaceとユーザー、クラスターを紐づけます。
本手順書では例として、ns1user
というコンテキスト名で、各項目を紐づけています。
$ kubectl config set-context ns1user --user=ns1user --cluster=Kubernetes --namespace=namespace1
##5-3. ClusterRoleとRoleBinding作成
ユーザーの権限を作成します。Namespace1におけるReadOnly権限(get, watch, list)を持つns1userを作成します。
(1)ClusterRoleとRoleBindingを定義するyamlを作成します。
$ sudo vi ns1user.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: readonly-for-all # ClusterRoleの名前
rules:
- apiGroups: ["*"] #
resources: ["*"] # 操作を許可するリソースを指定
verbs: ["get", "list", "watch"] # 許可する操作を指定
- nonResourceURLs: ["*"]
verbs: ["get", "list", "watch"] # 許可する操作を指定
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: readonly-ns1user # RoleBindingの名前
namespace: namespace1 # RoleBindingを作成するNamespaceを指定
subjects:
- kind: User
name: ns1user # ユーザー名を指定
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: readonly-for-all # ClusterRoleを指定
apiGroup: rbac.authorization.k8s.io
(2)作成したyamlを使用して、ClusterRoleとRoleBindingをデプロイします。
$ kubectl create -f ns1user.yaml
##5-4. 動作確認
(1)作成したコンテキストに切り替えます。
$ kubectl config use-context ns1user
Switched to context "ns1user"
(2)Namespace1内のPodが見られることを確認します。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-pv 1/1 Running 0 90m
(3)podの作成はできないことを確認します。
(使用しているyamlファイルは、2.章で作成したものです。)
$ kubectl create -f nginx-deployment.yaml
Error from server (Forbidden): pods is forbidden: User "ns1user" cannot create resource "pods" in API group "" in the namespace "namespace1"
#あとがき
最初は、NamespaceやDeployment、Pod作成だけをまとめていたのですが、せっかく勉強する機会があるのに、これだけでは勿体ないと思い、PersistentVolumeとRoleの作成手順を追加しました。
手順を検証していく中で、EC2上のKubernetes環境でPVを作るのに大変苦労しました。
AWS CLIでEBSを作成してアタッチする方法やEBSをPVとして認識させる方法など、分からないことだらけでした。
先輩方や色んなWebサイトに助けられて、何とか上手くいきましたが、AWS CLIやNFSの勉強もできたので、大変いい経験でした。
※商標類について:
- Amazon Web Services、“Powered by Amazon Web Services”ロゴ、[およびかかる資料で使用されるその他のAWS商標]は、米国その他の諸国における、Amazon.com, Inc.またはその関連会社の商標です。
- DockerおよびDockerロゴは、Docker Inc. の米国およびその他の国における登録商標もしくは商標です。
- NGINXはNGINX, Inc.の登録商標です。
- Kubernetesは、The Linux Foundationの米国およびその他の国における登録商標または商標です。
- その他記載されている会社名、製品名はそれぞれ各社の商標および登録商標です。