0.前提
ROSA HCP クラスターは、こちらの Qiita記事にある方法で作成済みの環境を使用します。
作成された ROSA HCP クラスターを使って、Red Hat の Black Belt チームで作成されたこちらの手順と、KB でリリースされている こちらの情報を参照しながら作成しました。
1.環境変数の準備
ROSA Cluster に oc login
後、
oc login <API Server Endpoint> --username cluster-admin --password <password>
と
rosa login
は済ましておいてください。
以下を実行してセットアップに必要な環境変数を準備します。
AWS_REGION
をセットします。ap-northeast-1
(東京リージョン) にしてますが、環境に合わせて変更してください。
export AWS_REGION="ap-northeast-1"
ClUSTER_NAME
は rosa cluster が環境内に一つの時だけ正しく値が取得できるようになっています。
export CLUSTER_NAME=$(rosa list clusters -o json | jq '.[0].name' | sed 's/"//g')
export OIDC_PROVIDER=$(oc get authentication.config.openshift.io cluster -o json \
| jq -r .spec.serviceAccountIssuer| sed -e "s/^https:\/\///")
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export SCRATCH_DIR=/tmp/scratch
export AWS_PAGER=""
mkdir -p $SCRATCH_DIR
2. IAM Policy の準備
(1) IAM Policy
の元ネタになる json
ファイルを作成します。
cat << EOF > $SCRATCH_DIR/efs-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticfilesystem:DescribeAccessPoints",
"elasticfilesystem:DescribeFileSystems",
"elasticfilesystem:DescribeMountTargets",
"elasticfilesystem:TagResource",
"ec2:DescribeAvailabilityZones"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"elasticfilesystem:CreateAccessPoint"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:RequestTag/efs.csi.aws.com/cluster": "true"
}
}
},
{
"Effect": "Allow",
"Action": "elasticfilesystem:DeleteAccessPoint",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/efs.csi.aws.com/cluster": "true"
}
}
}
]
}
EOF
(2) json
ファイルから IAM Policy
を作成します。
POLICY=$(aws iam create-policy --policy-name "${CLUSTER_NAME}-rosa-efs-csi" \
--policy-document file://$SCRATCH_DIR/efs-policy.json \
--query 'Policy.Arn' --output text) || \
POLICY=$(aws iam list-policies \
--query 'Policies[?PolicyName==`rosa-efs-csi`].Arn' \
--output text)
echo $POLICY
(3) Trust Policy を作成します。
この Policy
は、この後作成する IAM Role
の中で使用します。
cat <<EOF > $SCRATCH_DIR/TrustPolicy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": [
"system:serviceaccount:openshift-cluster-csi-drivers:aws-efs-csi-driver-operator",
"system:serviceaccount:openshift-cluster-csi-drivers:aws-efs-csi-driver-controller-sa"
]
}
}
}
]
}
EOF
(4) EFS CSI Driver Operator
に使う IAM Role
を (3)で作成した Trust Policy
を使って作成します。
ROLE=$(aws iam create-role \
--role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
--assume-role-policy-document file://$SCRATCH_DIR/TrustPolicy.json \
--query "Role.Arn" --output text)
echo $ROLE
(5) 上記で作成した IAM Role
に IAM Policy
をアタッチします。
aws iam attach-role-policy \
--role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
--policy-arn $POLICY
3. AWS EFS CSI Driver Operator の インストール
EFS CSI Driver Operator
をインストールします。
Operator Hub
の GUIからインストールしても良いのですが、この手順では CLI
で EFS CSI Driver Operator
をインストールしてしまいます。(GUIインストールでも一部、CLI作業が発生します)
(1) AWS EFS CSI Driver Operator
で使用する IAM Role
の ARN
を入れた Secret
を作成します。
cat << EOF | oc apply -f -
apiVersion: v1
kind: Secret
metadata:
name: aws-efs-cloud-credentials
namespace: openshift-cluster-csi-drivers
stringData:
credentials: |-
[default]
role_arn = $ROLE
web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
EOF
(2) AWS EFS CSI Driver Operator
をインストールします。
cat <<EOF | oc create -f -
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
generateName: openshift-cluster-csi-drivers-
namespace: openshift-cluster-csi-drivers
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
labels:
operators.coreos.com/aws-efs-csi-driver-operator.openshift-cluster-csi-drivers: ""
name: aws-efs-csi-driver-operator
namespace: openshift-cluster-csi-drivers
spec:
channel: stable
installPlanApproval: Automatic
name: aws-efs-csi-driver-operator
source: redhat-operators
sourceNamespace: openshift-marketplace
EOF
(3) Operator
のインストールが完了するまで待ちます。
watch oc get deployment aws-efs-csi-driver-operator -n openshift-cluster-csi-drivers
以下でも確認できます。
oc get pods -n openshift-cluster-csi-drivers | grep efs
(4) ClusterCSIDriver
CRD を作成します。
これで各 Node
に CSI Driver
の Pod
が作成されます。
cat <<EOF | oc apply -f -
apiVersion: operator.openshift.io/v1
kind: ClusterCSIDriver
metadata:
name: efs.csi.aws.com
spec:
managementState: Managed
EOF
(5) CSI Driver
のインストールの完了を待ちます。
watch oc get daemonset aws-efs-csi-driver-node -n openshift-cluster-csi-drivers
4. EFS の作成の準備
(1) 以下のコマンドを実行して環境変数を準備します。
NODE=$(oc get nodes --selector=node-role.kubernetes.io/worker \
-o jsonpath='{.items[0].metadata.name}')
VPC=$(aws ec2 describe-instances \
--filters "Name=private-dns-name,Values=$NODE" \
--query 'Reservations[*].Instances[*].{VpcId:VpcId}' \
--region $AWS_REGION \
| jq -r '.[0][0].VpcId')
CIDR=$(aws ec2 describe-vpcs \
--filters "Name=vpc-id,Values=$VPC" \
--query 'Vpcs[*].CidrBlock' \
--region $AWS_REGION \
| jq -r '.[0]')
SG=$(aws ec2 describe-instances --filters \
"Name=private-dns-name,Values=$NODE" \
--query 'Reservations[*].Instances[*].{SecurityGroups:SecurityGroups}' \
--region $AWS_REGION \
| jq -r '.[0][0].SecurityGroups[0].GroupId')
echo "CIDR - $CIDR, SG - $SG"
(2) EFS
volume をマウントできるように、Security Group
を Update します。
この Security Group
は ROSA
の Worker Node
用の Security Group
で、ROSA
の VPC
に割り当てたアドレスレンジ($CIDR
) から、EFS
の TCP Port
2049
へのアクセスを可能にするものです。
aws ec2 authorize-security-group-ingress \
--group-id $SG \
--protocol tcp \
--port 2049 \
--cidr $CIDR | jq .
5. EFS を作成する。
EFS
には、Regional
と Single AZ
の2種類の EFS
があります。
Regional
は、AZ
障害に対応できます。一方、Single AZ
は、AZ
障害に対応できませんが、コストを安く済ます事ができます。テスト環境やデータアナリシスなどで一時的なデータを吐き出すのはこちらが良いでしょう。
この手順では、EFS
を使用するStorageClass
は一つしか作らないので、どちらか一つだけを選択して作成してください。
この手順では Cluster がインストールされている Private Subnet を
A) Regional の EFS を作成する場合
(1) EFS
を作成します。
EFS=$(aws efs create-file-system --creation-token efs-token-1 \
--region ${AWS_REGION} \
--encrypted | jq -r '.FileSystemId')
echo $EFS
AWS Console の EFS の項目には以下のような FileSystem が作成されます。(Availability Zone
がRegional
になっている事に注目します)
(2) EFS
の Mount Targetを作成します。Mount Target Id
を取得して、$MOUNT_TARGET
に格納します。
for SUBNET in $(rosa list machinepools -c $CLUSTER_NAME -o json | jq -r '.[].subnet'); do \
MOUNT_TARGET=$(aws efs create-mount-target --file-system-id $EFS \
--subnet-id $SUBNET --security-groups $SG \
--region $AWS_REGION \
| jq -r '.MountTargetId'); \
echo $MOUNT_TARGET; \
done
この例では、各 Zone 毎に一つの Mount Target
を作成しています。こちらによると、各AZ
毎に作成できる Mount Target
は最大一つです)
B) Single AZ の EFS を作成する場合
(1) EFS
をマウントするための AZ を一つ選びます。
ここでは、サブネットを適当に一つ取り出して、そのサブネットの AZ
を EFS
に接続する AZ
とする事にします。
SUBNET=$(rosa list machinepools -c $CLUSTER_NAME -o json | jq -r '.[0].subnet')
AWS_ZONE=$(aws ec2 describe-subnets --filters Name=subnet-id,Values=$SUBNET \
--region $AWS_REGION | jq -r '.Subnets[0].AvailabilityZone')
(2) EFS
を作成します。
AWS Console の EFS
の項目には以下のような FileSystem が作成されます。(Availability Zone
がこの例ではap-northeast-1c
で、一つの AZ
だけになっている事に注目します)
EFS=$(aws efs create-file-system --creation-token efs-token-1 \
--availability-zone-name $AWS_ZONE \
--region $AWS_REGION \
--encrypted | jq -r '.FileSystemId')
echo $EFS
(3) EFS
の Mount Targetを作成します。 Mount Target Id
を取得して、$MOUNT_TARGET
に格納します。
MOUNT_TARGET=$(aws efs create-mount-target --file-system-id $EFS \
--subnet-id $SUBNET --security-groups $SG \
--region $AWS_REGION \
| jq -r '.MountTargetId')
echo $MOUNT_TARGET
6. EFS 用の Storage Class の作成
EFS
Volume 用の StorageClass
を作成します。
この StorageClass
を使って EFS
Volume が作成できるようになります。
cat <<EOF | oc apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: $EFS
directoryPerms: "700"
gidRangeStart: "1000"
gidRangeEnd: "2000"
basePath: "/dynamic_provisioning"
EOF
7. 実際に Pod をデプロイして EFS Volume の動作を確認
(1) 実験用の namespace
を作成します。
oc new-project efs-demo
(2) PVC
を作成します。
中では、先ほど作成した EFS
Volume 用の StorageClass
を使用しています。
cat <<EOF | oc apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-efs-volume
spec:
storageClassName: efs-sc
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
EOF
(3) PVCが作成されるのを待ちます。2分程度で、 RWX
の PVC のデプロイが完了するはずです。
watch oc get pvc
(4) EFS
Volume にメッセージを書き込むテスト用の Pod
を作成します。
5秒起きに、作成した EFS
Volume 上のファイルに hello efs
と書き出します。
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-efs
spec:
volumes:
- name: efs-storage-vol
persistentVolumeClaim:
claimName: pvc-efs-volume
containers:
- name: test-efs
image: centos:latest
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do echo 'hello efs' | tee -a /mnt/efs-data/verify-efs && sleep 5; done;" ]
volumeMounts:
- mountPath: "/mnt/efs-data"
name: efs-storage-vol
EOF
(5) Test 用の Pod
がデプロイされるのを待ちます。
watch oc get pod test-efs
(6) 次に、EFS
Volume 上のファイルを読み込む別のPodを作成します。
先ほど作成した EFS
Volume 上のファイルを tail
します。
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-efs-read
spec:
volumes:
- name: efs-storage-vol
persistentVolumeClaim:
claimName: pvc-efs-volume
containers:
- name: test-efs-read
image: centos:latest
command: [ "/bin/bash", "-c", "--" ]
args: [ "tail -f /mnt/efs-data/verify-efs" ]
volumeMounts:
- mountPath: "/mnt/efs-data"
name: efs-storage-vol
EOF
(7) ファイルをtail
している Pod
のログを確認します。
tail
は標準出力に吐かれているので、oc logs
で tail
の結果が確認できます。
oc logs test-efs-read
以下のような出力が確認できるはずです。
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
8. 環境の削除
(1) デプロイした Test 用の Podを削除します。
oc delete pod -n efs-demo test-efs test-efs-read
(2) デプロイした EFS Volume を削除します。
oc delete -n efs-demo pvc pvc-efs-volume
(3) 作成した Namespace を削除します。
oc delete project efs-demo
(4) 作成した Storage Class を削除します。
oc delete storageclass efs-sc
(5) EFS File System を削除します。
Mount Target を削除します。
for MOUNT_TARGET in $(aws efs describe-mount-targets --file-system-id $EFS \
--region $AWS_REGION \
| jq -r '.MountTargets[].MountTargetId'); do \
echo $MOUNT_TARGET; \
aws efs delete-mount-target --mount-target-id $MOUNT_TARGET --region $AWS_REGION; \
done
FileSystem を削除します。(Mount Target を削除してから数十秒時間を置く必要があります)
aws efs delete-file-system --file-system-id $EFS --region $AWS_REGION
(6) IAM Policy と IAM Role をデタッチします。
アタッチしたままだと削除できないので、デタッチします。
aws iam detach-role-policy \
--role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
--policy-arn $POLICY
(7) 作成したIAM Role を削除します。
aws iam delete-role --role-name \
${CLUSTER_NAME}-aws-efs-csi-operator
(8) 作成した IAM Policy を削除します。
aws iam delete-policy --policy-arn \
$POLICY
9.[おまけ] NodeからEFSへのアクセス経路を少し深掘り
Regional の EFS を使用した場合に、各 Node から EFS がどのように見えるのか確認してみます。
各AZ の Compute Node 上から EFS の DNS 名を解決するとどのような IPが返ってくるか確認してみます。
環境の EFS の DNS 名は、AWS Console から確認するとfs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
となっていました。これを各 Node 上で名前解決してみます。
尚、この手順の5番で作成した各 AZ (の Private Subnet) の Mount Target
は以下の通りで、各AZ内の Private IP が割り振られています。
各 AZに配置された、Node で debug pod を起動して EFS の DNS名fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
を解決してみます。
$ oc get nodes
NAME STATUS ROLES AGE VERSION
ip-10-0-1-244.ap-northeast-1.compute.internal Ready worker 13m v1.29.6+aba1e8d
ip-10-0-2-214.ap-northeast-1.compute.internal Ready worker 23m v1.29.6+aba1e8d
ip-10-0-3-103.ap-northeast-1.compute.internal Ready worker 22m v1.29.6+aba1e8d
$
$ oc debug node/ip-10-0-2-214.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-47hcg is created for debugging node...
Starting pod/ip-10-0-2-214ap-northeast-1computeinternal-debug-ddjdm ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.2.214
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.2.133
sh-5.1#
$ oc debug node/ip-10-0-1-244.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-94mp9 is created for debugging node...
Starting pod/ip-10-0-1-244ap-northeast-1computeinternal-debug-r5gft ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.1.244
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.1.154
sh-5.1#
$ oc debug node/ip-10-0-3-103.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-mnzsh is created for debugging node...
Starting pod/ip-10-0-3-103ap-northeast-1computeinternal-debug-l4n7p ...
To use host binaries, run `chroot /host`
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.3.72
sh-5.1#
同じDNS名が、それぞれのAZにある Mount Target のIP に解決されていました。
各 Nodeからの EFS へのアクセスは、各 Node が存在する AZ 内の Mount Target (ENI)のIP経由でアクセスが行われるようです。
環境の構成を図にまとめると以下の通りです。