/EKSPoC_For_SecureEnvironment

セキュアな環境でEKSを利用するための検証用環境を作成するCloudFormationテンプレート

Apache License 2.0Apache-2.0

EKS Fully-Private Cluster without eksctl

インターネット接続のないVPC(VPC閉塞環境、プロキシ接続もなし)環境で、EKSクラスターを利用するためのセットアップの手順(ハンズオン)です。

eksctlコマンドを利用すれば比較的容易にEKSのプライベートクラスターが構築可能ですが(EKS Fully-Private Cluster参照)、EKSクラスターが、どのようなAWSサービスを活用しているのか、どのようなIAM権限や、通信経路が必要になるのかを学習することも目的としているため、スクラッチで順を追って構築する手順にしています。

作成環境

Overall Architecture

このハンズオンで、以下の環境を構築できます。

  • シンプルなEKSプライベートクラスター(ワーカーノードは、EC2タイプ)を用意し、シンプルなhttpdのpodを稼働させる
  • Autoscalerを導入し、ワーカーノードをスケールイン/アウトさせる。
  • AWS Load Balancer Controllerを導入し、ELBによるロードバランシングを実装する

EKSの構築の手順が複雑なため、手順の多くはCloudFormation化していますが、一部CLIで設定する箇所もあります。 またGUI(マネージメントコンソール)はUIが頻繁に変わるため、CloudFormationのスタック作成も含め全てAWS CLI(LinuxやMacのシェル環境を前提)での実行を前提としています。

ハンズオン(その1): シンプルなEKSプライベートクラスター作成

シンプルなEKSプライベートクラスターを作成し、動作テストでpodを動かします。 Simple EKS Private Cluster Architecture

(1)事前設定

(1)-(a) 作業環境の準備

下記を準備します。

  • bashが利用可能な環境(LinuxやMacの環境)
  • aws-cliのセットアップ
  • AdministratorAccessポリシーが付与され実行可能な、aws-cliのProfileの設定

(1)-(b) gitのclone

git clone https://github.com/Noppy/EKSPoC_For_SecureEnvironment.git
cd EKSPoC_For_SecureEnvironment

(1)-(c) CLI実行用の事前準備

これ以降のAWS-CLIで共通で利用するパラメータを環境変数で設定しておきます。

export PROFILE=<PoC環境のAdministratorAccess権限が実行可能なプロファイル>
export REGION="ap-northeast-1"

# プロファイルの動作テスト
# COMPUTE_PROFILE
aws --profile ${PROFILE} sts get-caller-identity

(2)Network準備

(2)-(a) VPC作成

aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-VPC \
        --template-file "./src/vpc-2az-4subnets.yaml" \
        --parameter-overrides "file://./src/vpc.conf"

(2)-(b) SecurityGroup作成

aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-SG \
        --template-file "./src/sg.yaml"

(3)-(c) VPCエンドポイント作成

aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-VpceSimple \
        --template-file "./src/vpce_simple.yaml"

(3)IAMロール&KMSキー作成

(3)-(a) IAMロール作成

必要なIAMロールを準備します。

  • AWS管理ポリシーを付与する場合おはこのタイミングで付与します。
  • またカスタマー管理ポリシーまたはインラインポリシーでリソースの特定が不要な場合もこのタイミングでポリシーを付与します。
  • リソースの特定が必要な場合(例えばECRのリポジトリのARNが必要など)は、リソース作成時に個別にポリシーを付与します。
aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-IAM \
        --template-file "./src/iam.yaml" \
        --capabilities CAPABILITY_IAM

(3)-(b) KMS CMKキー作成

aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-KMS \
        --template-file "./src/kms.yaml"

(4)インスタンス準備

# Bastion & DockerSG & kubectl
aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-Instances \
        --template-file "./src/instances.yaml"

(5)dockerイメージ作成とECRへの格納

(5)-(a) ECRリポジトリ作成

aws --profile ${PROFILE} --region ${REGION} \
    cloudformation deploy \
        --stack-name EksPoc-Ecr \
        --template-file "./src/ecr.yaml"

(5)-(b) docker環境準備

(i) DockerDevインスタンスへSSMでOSログイン

# DockerDevインスタンスのインスタンスID取得
DockerDevID=$(aws --profile ${PROFILE} --region ${REGION} --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-Instances \
        --query 'Stacks[].Outputs[?OutputKey==`DockerDevId`].[OutputValue]')
echo "DockerDevID = $DockerDevID"

# SSMによるOSログイン
aws --profile ${PROFILE} --region ${REGION} \
    ssm start-session \
        --target "${DockerDevID}"

(ii) docker環境のセットアップ

# ec2-userにスイッチ
sudo -u ec2-user -i
# Setup AWS CLI
REGION=$( \
    TOKEN=`curl -s \
        -X PUT \
        -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
        "http://169.254.169.254/latest/api/token"` \
    && curl \
        -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')
aws configure set region ${REGION}
aws configure set output json

# 動作テスト(作成したECRレポジトリがリストに表示されることを確認)
aws ecr describe-repositories
# dockerのセットアップ
sudo yum install -y docker
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -a -G docker ec2-user
# usermod設定をセッションに反映するためsudoし直す
exit

# ec2-userにスイッチ
sudo -u ec2-user -i

# ec2-userユーザのセカンドグループにdockerが含まれていることを確認する
id

# dockerテスト(下記コマンドでサーバ情報が参照できることを確認)
docker info

(iii)dockerイメージ作成

# コンテナイメージ用のディレクトリを作成し移動
mkdir httpd-container
cd httpd-container

# データ用フォルダを作成
mkdir src

# dockerコンテナの定義ファイルを作成
cat > Dockerfile << EOL
# setting base image
FROM php:8.1-apache

RUN set -x && \
    apt-get update && \
    apt-get upgrade && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

COPY src/ /var/www/html/
EOL

# アプリケーションのトップページを作成
cat > src/index.php << EOL
<html>
  <head>
    <title>PHP Sample</title>
  </head>
  <body>
    <?php echo gethostname(); ?>
  </body>
</html>
EOL

# Docker build
docker build -t httpd-sample:ver01 .
docker images

# コンテナの動作確認
docker run -d -p 8080:80 httpd-sample:ver01
docker ps # コンテナが稼働していることを確認

# 接続確認
# <title>PHP Sample</title>という文字が表示されたら成功!!
curl http://localhost:8080

(iv)dockerイメージ作成とECRリポジトリへの登録

REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names ekspoc-repo \
    --query 'repositories[].repositoryUri' ) ;
echo "
REPO_URL = ${REPO_URL}
"
# ECR登録用のタグを作成
docker tag httpd-sample:ver01 ${REPO_URL}:latest
docker images # 作成したtagが表示されていることを確認

# ECRログイン
# "Login Succeeded"と表示されることを確認
aws ecr get-login-password | docker login --username AWS --password-stdin ${REPO_URL}

# イメージのpush
docker push ${REPO_URL}:latest

# ECR上のレポジトリ確認
aws ecr list-images --repository-name ekspoc-repo

(v)ログアウト

exit  # ec2-userから戻る
exit  # SSMからのログアウト

(5)EKSコントロールプレーン&ノードグループ作成

以下の作業は、Bastion兼高権限用インスタンスで作業します。 これは作成したEKSクラスターの初期状態でkubectlで操作可能なIAMは、EKSクラスターを作成した権限のみのためである。

(5)-(a) 高権限(Bastion)インスタンス環境準備

(i) 高権限インスタンスへSSMでOSログイン

# 高権限インスタンスのインスタンスID取得
HighAuthID=$(aws --profile ${PROFILE} --region ${REGION} --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-Instances \
        --query 'Stacks[].Outputs[?OutputKey==`BastionAndHighAuthorityId`].[OutputValue]')
echo "HighAuthID = $HighAuthID"

# SSMによるOSログイン
aws --profile ${PROFILE} --region ${REGION} \
    ssm start-session \
        --target "${HighAuthID}"

(ii) AWS CLIセットアップ

# ec2-userにスイッチ
sudo -u ec2-user -i
# Setup AWS CLI
REGION=$( \
    TOKEN=`curl -s \
        -X PUT \
        -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
        "http://169.254.169.254/latest/api/token"` \
    && curl \
        -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')
aws configure set region ${REGION}
aws configure set output json

(iii)高権限環境へのkubectlセットアップ

EksAdmin環境でkubectl操作を可能にするためには、まずHightAuth環境でkubeconfigの初期設定の初期設定を行う必要がある。そのためにまずHighAuth環境でkubectlをセットアップする。

# kubectlのダウンロード
curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.22.6/2022-03-09/bin/linux/amd64/kubectl

curl -o kubectl.sha256 https://s3.us-west-2.amazonaws.com/amazon-eks/1.22.6/2022-03-09/bin/linux/amd64/kubectl.sha256

# チェックサム確認
if [ $(openssl sha1 -sha256 kubectl|awk '{print $2}') = $(cat kubectl.sha256 | awk '{print $1}') ]; then echo OK; else echo NG; fi
# kubectlのパーミッション付与と移動
chmod +x ./kubectl
mkdir -p $HOME/bin && mv ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc

# 動作テスト
kubectl version --short --client

(iv) ソースコードのclone

sudo yum -y install git
git clone https://github.com/Noppy/EKSPoC_For_SecureEnvironment.git
cd EKSPoC_For_SecureEnvironment

(5)-(b) EKSクラスター作成(k8sコントロールプレーン作成)

(i) EKSクラスター作成

EKSクラスター作成は15分程度かかります。

aws cloudformation deploy \
        --stack-name EksPoc-EksControlPlane \
        --template-file "./src/eks_control_plane.yaml"

(ii)高権限環境のkubectlをコントロールプレーンに接続

kubectlからクラスターが参照できるように設定を行います。

# EKSクラスター情報取得
EKS_CLUSTER_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-EksControlPlane \
    --query 'Stacks[].Outputs[?OutputKey==`ClusterName`].[OutputValue]' )
echo "EKS_CLUSTER_NAME = ${EKS_CLUSTER_NAME}"
# kubectl用のconfig取得
aws eks update-kubeconfig --name ${EKS_CLUSTER_NAME}

# kubectlコマンドからのk8sマスターノード接続確認
kubectl get svc

(5)-(c) EKSワーカーグループ作成

(i)aws-auth ConfigMapのクラスターへの適用

(この手順はセルフマネージド型ノードの場合は必要ですが、マネージド型ノードグループでは不要です) ワーカーノードに適用するインスタンスロールをk8sのコントロールプレーンで認識し有効化するために、aws-authでマッピングを行います。

aws-auth ConfigMap が適用済みであるかどうかを確認します。

kubectl describe configmap -n kube-system aws-auth

Error from server (NotFound): configmaps "aws-auth" not foundというエラーが表示された場合は、以下のステップを実行してストック ConfigMap を適用します。

curl -o aws-auth-cm.yaml https://amazon-eks.s3.us-west-2.amazonaws.com/cloudformation/2020-10-29/aws-auth-cm.yaml

CloudFormationからWorkerNodeインスタンス用のIAMロールのARNを取得します。

aws --output text cloudformation describe-stacks \
    --stack-name EksPoc-IAM \
    --query 'Stacks[].Outputs[?OutputKey==`EC2k8sWorkerRoleArn`].[OutputValue]'

aws-auth-cm.yaml編集 <ARN of instance role (not instance profile)>をWorkerNodeのインスタンスロールARNに修正します。

vi aws-auth-cm.yaml

中略
data:
  mapRoles: |
    - rolearn: <ARN of instance role (not instance profile)>
以下略

aws-authを適用します。

# aws-auth-cm.yamlの適用
kubectl apply -f aws-auth-cm.yaml

(ii)ノードグループ作成前の情報取得

(セルフマネージド型ノードの場合や、マネージド型ノードグループで起動テンプレートのユーザーデータを使用してブートストラップスクリプトに引数を渡す必要がある場合は、Kubernetes API サーバーの URL と証明書の情報が必要です)

# WorkerへのSSH接続設定
KEY_NAME="CHANGE_KEY_PAIR_NAME" #SSH接続する場合
# KEY_NAME=""                    #SSH接続しない場合はブランクを設定する

EKS_CLUSTER_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-EksControlPlane \
    --query 'Stacks[].Outputs[?OutputKey==`ClusterName`].[OutputValue]' )
# EKS_B64_CLUSTER_CA=$(aws --output text cloudformation \
#     describe-stacks --stack-name EksPoc-EksControlPlane \
#     --query 'Stacks[].Outputs[?OutputKey==`CertificateAuthorityData`].[OutputValue]' )
# EKS_API_SERVER_URL=$(aws --output text cloudformation \
#     describe-stacks --stack-name EksPoc-EksControlPlane \
#     --query 'Stacks[].Outputs[?OutputKey==`ControlPlaneEndpoint`].[OutputValue]' )
echo "
KEY_NAME           = ${KEY_NAME}
EKS_CLUSTER_NAME   = ${EKS_CLUSTER_NAME}
# EKS_B64_CLUSTER_CA = ${EKS_B64_CLUSTER_CA}
# EKS_API_SERVER_URL = ${EKS_API_SERVER_URL}
"

(iii)EKSノードグループ作成

(セルフマネージド型ノードの場合や、マネージド型ノードグループで起動テンプレートのユーザーデータを使用してブートストラップスクリプトに引数を渡す必要がある場合は、Kubernetes API サーバーの URL と証明書の情報が必要です。なお、マネージド型ノードグループでブートストラックスクリプトに引数を渡す場合、AMI ID の指定も必須となります)

aws cloudformation deploy \
        --stack-name EksPoc-EksNodeGroup\
        --template-file "./src/eks_worker_nodegrp.yaml" \
        --parameter-overrides \
            ClusterName="${EKS_CLUSTER_NAME}" \
            KeyName="${KEY_NAME}"
            # B64ClusterCa="${EKS_B64_CLUSTER_CA}" \
            # ApiServerUrl="${EKS_API_SERVER_URL}"

(iv) k8sでの状態確認

# WorkerNode状態確認
kubectl get nodes --watch

(6) k8s RBAC設定: IAMユーザ/ロールの追加

aws-authにk8sのRBAC認証に対応させたいIAMユーザ/ロールを追加します。 手順の概要は以下のとおりです。

  • kubectlコマンドでaws-auth ConfigMapを開き編集する
  • 設定はmapRolesにリスト形式で追加する。追加する場合の設定はそれぞれ以下の通り
    • rolearn:またはuserarn: IAMロールを追加する場合はrolearn、IAMユーザを追加する場合はuserarnで、対象のARNを指定する。
    • username: kubernetes内のユーザー名
    • groups : k8s内でのマッピング先のグループをリストで指定する。
  • エディタで保存&終了(viエディタなので、:のあとwq)すると反映してくれる。
  • 参考情報

(6)-(a) kubectl実行用EC2のインスタンスロール登録

  • 事前の情報取得
# kubectl実行用EC2のインスタンスロールのARN取得
KUBECTL_ROL_ARN=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-IAM \
    --query 'Stacks[].Outputs[?OutputKey==`EC2kubectlRoleArn`].[OutputValue]' )

echo "
KUBECTL_ROL_ARN = ${KUBECTL_ROL_ARN}
"
  • aws-auth ConfigMapの編集
# aws-auth ConfigMapを開く
kubectl edit -n kube-system configmap/aws-auth
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  mapRoles: |
    - rolearn: arn:aws:iam::616605178605:role/EksPoc-IAM-EC2k8sWorkerRole-8BI00X63GF2P
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
# ↓ココから下を追加
    - rolearn: "$KUBECTL_ROL_ARN のARN値を指定"
      username: kubectladmin
      groups:
        - system:masters
# ここまで
# 以下略

(6)-(b) コンソールユーザの追加

# aws-auth ConfigMapを開く
kubectl edit -n kube-system configmap/aws-auth
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  mapRoles: |
    - rolearn: arn:aws:iam::616605178605:role/EksPoc-IAM-EC2k8sWorkerRole-8BI00X63GF2P
      username: system:node:{{EC2PrivateDNSName}}
     groups:
        - system:bootstrappers
        - system:nodes
    - rolearn: "$KUBECTL_ROL_ARN のARN値を指定"
      username: kubectladmin
      groups:
        - system:masters
# ↓ココから下を追加
    - rolearn: "コンソール操作時の権限のARNを指定"
      username: consoleadmin
      groups:
        - system:masters
# ここまで
# 以下略

(7) 動作テスト(podの起動)

作成したEKSのkubernetes環境の動作確認のために事前にECRに登録したhttpdのDockerイメージを利用し以下のようなサービスを作成して、端末からアクセスできるかテストします。 kubernetesのテスト環境

参考情報

(7)-(a) ECRリポジトリのURL取得

REPO_URL=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-Ecr \
    --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]' )
echo "
REPO_URL = ${REPO_URL}
"

(7)-(b) kubernetesのDeploymentとService作成

(i) 定義ファイルの準備

# Deployment定義ファイルの作成
# 環境固有となるECRレポジトリURL情報をDeploymentに設定します。
sed -e "s;REPO_URL;${REPO_URL};" k8s_define/httpd-deployment.yaml.template > httpd-deployment.yaml
cat httpd-deployment.yaml

# Service定義ファイルの確認
cat k8s_define/httpd-service.yaml

(ii) DeploymentとServiceの適用

kubectlコマンドを利用して定義を適用します。

# Deploymentの適用
kubectl apply -f httpd-deployment.yaml

# Serviceの適用
kubectl apply -f k8s_define/httpd-service.yaml

(iii) 状態を確認します。

  • Deploymentの状態確認
kubectl get deployments -o wide httpd-deployment

NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                                                 SELECTOR
httpd-deployment   0/2     2            0           9s    httpd        141247782993.dkr.ecr.ap-northeast-1.amazonaws.com/ekspoc-repo:latest   app=httpd-pod
  • Podの状態確認
kubectl get pods -o wide

NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE                                             NOMINATED NODE   READINESS GATES
httpd-deployment-65f68b9dfc-2bx8n   1/1     Running   0          29s   10.1.39.243    ip-10-1-42-54.ap-northeast-1.compute.internal     <none>           <none>
httpd-deployment-65f68b9dfc-9svlr   1/1     Running   0          29s   10.1.154.189   ip-10-1-147-247.ap-northeast-1.compute.internal   <none>           <none>
  • Service状態確認
kubectl get svc -o wide httpd-service

NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     SELECTOR
httpd-service   ClusterIP   172.20.170.144   <none>        8080/TCP   9m31s   app=httpd-pod

(iv) クライアントからの接続確認

ClusterIPは、通常kubernetesのクラスター内からのみからのアクセスとなりますが、kubectlコマンドでフォワードさせることでクラスター外の端末からアクセスが可能となります。

  • ポートフォワーディング起動(この状態でwaitになります。終了する場合はCTRL+Cで終了)
kubectl port-forward service/httpd-service 9999:8080
Forwarding from 127.0.0.1:9999 -> 80
Forwarding from [::1]:9999 -> 80
  • 別端末からkubectl port-forwardを実行しているOS上にログインします
  • 別端末で下記コマンドでhttpサーバの情報が参照できたら成功です
curl http://localhost:9999

<html>
  <head>
    <title>PHP Sample</title>
  </head>
  <body>
    httpd-deployment-dbb8b7f8c-nbkg2  </body>
</html>

(7)-(c) ServiceとDeploymentの削除

# Serviceの削除
kubectl delete -f k8s_define/httpd-service.yaml

# Deploymentの削除
kubectl delete -f httpd-deployment.yaml

ハンズオン(その2): ClusterAutoscalerを追加しk8sでスケールイン/アウトをコントロールする

以下の作業は、Bastion兼高権限用インスタンスで作業します。 作業のカレントディレクトリは、githubからcloneしたEKSPoC_For_SecureEnvironmentのリポジトリ直下を前提としています。 Add Autoscaler Architecture

(1) OIDCプロバイダ

(1)-(a) jqのインストール

コマンドの中でJSONデータを処理するjqコマンドを利用するため、予めjqをインストールします。

sudo yum -y install jq

(1)-(b) VPCエンドポイント作成

OIDCの認証情報取得のためにstsへのアクセスを行うため、STSのVPCエンドポイントを追加します。

aws cloudformation deploy \
        --stack-name EksPoc-Vpce-oidc \
        --template-file "./src/vpce_for_oidc.yaml"

(1)-(c) OIDCプロバイダのサムプリント取得

サムプリントは、証明書の暗号化ハッシュです。

(i) EKSクラスターからOICD用のURLを取得(CloudFormationのスタック出力結果からの取得)

OpenIdConnectIssuerUrl=$(aws --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-EksControlPlane \
        --query 'Stacks[].Outputs[?OutputKey==`OpenIdConnectIssuerUrl`].[OutputValue]')

(ii) OICDプロバイダーのから証明書を取得

# IdP の設定ドキュメント取得のURL生成
URL="${OpenIdConnectIssuerUrl}/.well-known/openid-configuration"
echo $URL

# ドメイン取得
FQDN=$(curl $URL 2>/dev/null | jq -r '.jwks_uri' | sed -E 's/^.*(http|https):\/\/([^/]+).*/\2/g')
echo $FQDN

#サーバー証明書の取得
echo | openssl s_client -connect $FQDN:443 -servername $FQDN -showcerts

opensslコマンドを実行すると、次のような証明書が複数表示されます。 複数の証明書のうち表示される最後 (コマンド出力の最後) の証明書を特定します。

-----BEGIN CERTIFICATE-----
MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE=
-----END CERTIFICATE-----

証明書 (-----BEGIN CERTIFICATE----- および -----END CERTIFICATE----- 行を含む) をコピーして、テキストファイルに貼り付けます。次に、certificate.crt という名前でファイルを保存します。

cat > certificate.crt
# コピーした証明書を貼り付けて、最後にCTRL+Dで終了する

# ファイルの確認
cat certificate.crt

(iii) サムプリントの取得

THUMBPRINT=$(openssl x509 -in certificate.crt -fingerprint -noout | sed -E 's/SHA1 Fingerprint=(.*)/\1/g' | sed -E 's/://g')
echo $THUMBPRINT

(1)-(d) OIDCプロバイダ作成

aws iam create-open-id-connect-provider \
    --url "${OpenIdConnectIssuerUrl}" \
    --thumbprint-list "${THUMBPRINT}" \
    --client-id-list "sts.amazonaws.com"

(2) Cluster Autoscalerのセットアップ

Cluster Autoscalerを導入して、kubernetesからAutoScalingを調整してスケールアップ/スケールインをコントローするようにします。

(2)-(a) Cluster Autoscaler用にVPCエンドポイントを追加

Cluster Autoscalerは、ワーカーノードのリソース利用状況に合わせて、EC2 Autoscalingのインスタンス数設定を変更することで、キャパシティーの調整を行います。 Cluster AutoscalerからEC2 Autoscalingを操作できるようにするために、EC2 AutoscalingのVPCエンドポイントを追加します。

aws cloudformation deploy \
        --stack-name EksPoc-Vpce-Autoscaler \
        --template-file "./src/vpce_for_autoscaler.yaml"

(2)-(b) AutoscalerのdockerイメージをECRに格納

本検証環境は、kubernetesのワーカーノードから外部にはアクセスができないため、そのままではCluster Autoscalerのdockerイメージが取得できません。 そのためECRリポジトリを用意し、Cluster Autoscalerのdockerイメージを格納しておきます。

(i) Autoscalerイメージ保管用ECRリポジトリ作成

aws cloudformation deploy \
        --stack-name EksPoc-AutoscalerEcr \
        --template-file "./src/Autoscaler/ecr_for_autoscaler.yaml"

(ii) (Dockerインスタンス)Autoscalerイメージの取得と保管

以下の作業は、別端末を開いてDockerインスタンスにログインして作業します。

  • Dockerインスタンスへのログイン
export PROFILE=<PoC環境のAdministratorAccess権限が実行可能なプロファイル>
export REGION="ap-northeast-1"

# プロファイルの動作テスト
aws --profile ${PROFILE} sts get-caller-identity
# DockerDevインスタンスのインスタンスID取得
DockerDevID=$(aws --profile ${PROFILE} --region ${REGION} --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-Instances \
        --query 'Stacks[].Outputs[?OutputKey==`DockerDevId`].[OutputValue]')
echo "DockerDevID = $DockerDevID"

# SSMによるOSログイン
aws --profile ${PROFILE} --region ${REGION} \
    ssm start-session \
        --target "${DockerDevID}"
  • ec2-userへの変更
sudo -u ec2-user -i
  • dockerイメージの情報取得 下記で表示されるイメージ情報のURI(k8s.gcr.io/autoscaling/cluster-autoscalerなど)を控えておきます。
curl https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml 2> /dev/null | grep 'image:'

タグ情報は、ウェブブラウザで、GitHub の Cluster Autoscaler リリースページを開き、最新の (クラスターの Kubernetes のメジャーおよびマイナーバージョンに一致する) Cluster Autoscaler バージョンを見つけます。ととえば、クラスターの Kubernetes バージョンが 1.21 の場合、1.21 で始まる Cluster Autoscaler リリースを見つけます。次のステップで使用するので、そのリリースのセマンティックバージョン番号 (1.21.n) を書き留めておきます。

上記のimage情報を変数に入れておきます。

AUTOSCALER_PATH="<上記で控えておいたAutoscalerのイメージのuri:タグ情報>"

AutoscalerのDockerイメージをローカルにpullします。

docker pull "${AUTOSCALER_PATH}"
# 取得した情報の確認
docker images
  • dockerイメージをECRに格納 Autoscaler用ECRのURI取得
REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names autoscaler-repo \
    --query 'repositories[].repositoryUri' ) ;
echo "
REPO_URL = ${REPO_URL}
"

ECRへのpush

# ECR登録用のタグを作成
docker tag ${AUTOSCALER_PATH} ${REPO_URL}:latest
docker images # 作成したtagが表示されていることを確認

# ECRログイン
# "Login Succeeded"と表示されることを確認
aws ecr get-login-password | docker login --username AWS --password-stdin ${REPO_URL}

# イメージのpush
docker push ${REPO_URL}:latest

# ECR上のレポジトリ確認
aws ecr list-images --repository-name autoscaler-repo

(iii)ログアウト

作業が完了したので、Dockerインスタンスからログアウトします

exit
exit

以後の作業は、Bastion兼高権限用インスタンスに戻って行います。

(2)-(c) Cluster Autoscaler用IAMロール追加

(i)IAMロールの信頼関係(Trust relationship)設定用の情報取得

# EKSクラスターのOIDC情報取得
OIDCProviderId=$(aws --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-EksControlPlane \
        --query 'Stacks[].Outputs[?OutputKey==`OpenIdConnectIssuerUrl`].[OutputValue]' | cut -d "/" -f 5)
echo "OIDCProviderId = ${OIDCProviderId}"

# 該当OIDCプロバイダーのARN取得
OIDCProviderARN=$(aws --output json iam list-open-id-connect-providers | jq -r '.OpenIDConnectProviderList[].Arn | select( . | contains("'${OIDCProviderId}'") )')
echo "OIDCProviderARN = ${OIDCProviderARN}"

# 該当OIDCプロバイダーのURI取得
OIDCProviderURI=$(aws --output text iam get-open-id-connect-provider --open-id-connect-provider-arn ${OIDCProviderARN} --query 'Url')
echo "OIDCProviderURI = ${OIDCProviderURI}"

(ii)IAMロールの信頼関係用ポリシー生成

sed -e "s;OIDCProviderARN;${OIDCProviderARN};g" \
    -e "s;OIDCProviderURI;${OIDCProviderURI};g" \
    src/Autoscaler/cluster_autoscaler_iam_role_trust_policy.json_template > cluster_autoscaler_iam_role_trust_policy.json

(iii)Cluster Autoscaler用のIAMロール作成

# EKSクラスター情報取得
EKS_CLUSTER_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-EksControlPlane \
    --query 'Stacks[].Outputs[?OutputKey==`ClusterName`].[OutputValue]' )
echo "EKS_CLUSTER_NAME = ${EKS_CLUSTER_NAME}"

IAM_ROLE_NAME=${EKS_CLUSTER_NAME}-Autoscaler_Role
# IAMロール作成
aws iam create-role \
    --role-name "${IAM_ROLE_NAME}" \
    --assume-role-policy-document "file://cluster_autoscaler_iam_role_trust_policy.json"

# IAMポリシー(インラインポリシー)のアタッチ
aws iam put-role-policy \
    --role-name "${IAM_ROLE_NAME}" \
    --policy-name Autoscaler \
    --policy-document "file://./src/Autoscaler/cluster_autoscaler_iam_policy.json"

(2)-(d) ワーカーノードのインスタンスロールへの権限付与

下記ドキュメントにAttach the above created policy to the instance role that's attached to your Amazon EKS worker nodes.とあるので、同じIAMポリシーをワーカーノードのインスタンスロールにも付与します。

# ワーカーノードのインスタンスロールのロール名を取得
WORKER_ROLE_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-IAM \
    --query 'Stacks[].Outputs[?OutputKey==`EC2k8sWorkerRoleName`].[OutputValue]' )
echo "WORKER_ROLE_NAME = ${WORKER_ROLE_NAME}"
# IAMポリシー(インラインポリシー)のアタッチ
aws iam put-role-policy \
    --role-name "${WORKER_ROLE_NAME}" \
    --policy-name Autoscaler \
    --policy-document "file://./src/Autoscaler/cluster_autoscaler_iam_policy.json"

(2)-(e) Autoscalerの定義サンプル取得と編集

(ii) ロールのARN確認

# ロールのARNをメモ帳などに控えておきます。
aws --output text iam get-role --role-name "${IAM_ROLE_NAME}" --query 'Role.Arn'

(i) AutoscalerのGitHubから定義ファイルを取得

curl -o cluster-autoscaler-autodiscover.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

(ii) 定義ファイルの変更

エディタで開いて定義ファイルを編集します。

  • クラスター名の変更
    • <YOUR CLUSTER NAME>の部分を実際のEKSクラスター名に変更します。
    • k8s.gcr.io/autoscaling/cluster-autoscaler:v1.22.2の部分を、(2)-(b)で保管したECRに変更します。URIは(2)-(b)で取得したものでタグはlatestにします
      • 変更後のimageパスの例: 999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/autoscaler-repo:latest
    • 起動オプションの変更
      • --aws-use-static-instance-list=trueを追加。(デフォルトではEC2インスタンスの最新リスト取得のためにapi.pricing.us-east-1.amazonaws.comにアクセスするが、インターネット接続がない環境ではエラーになりAutoscalerが起動失敗するため無効化する)
      serviceAccountName: cluster-autoscaler
      containers:
        - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.22.2  <<== 変更する
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 600Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<YOUR CLUSTER NAME> <<== 変更する
            - --aws-use-static-instance-list=true <<==追加する
  • Autoscaler用IAMロールの追加
    • Autoscalerで利用するOIDC認証を行うIAMロールを定義に追加します
    • 追加場所と追加方法は、定義ファイル先頭のmetadataセクションにannotationsで追加します。
    • arn:aws:iam::xxxxx:role/Amazon_CA_roleの部分を、(2)-(b)の(iii)で作成したIAMロールのARNに置き換えます。
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  annotations:   <==行追加
    eks.amazonaws.com/role-arn: arn:aws:iam::xxxxx:role/Amazon_CA_role   # Add the IAM role created in the above C section.  <==行追加
  name: cluster-autoscaler
  namespace: kube-system

(2)-(f) Autoscalerの適用

(i) Autoscalerの適用

kubectl apply -f cluster-autoscaler-autodiscover.yaml

(ii) 状態確認

kubectl get deployment/cluster-autoscaler -o wide -n kube-system


NAME                 READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS           IMAGES                                                                     SELECTOR
cluster-autoscaler   1/1     1            1           16s   cluster-autoscaler   616605178605.dkr.ecr.ap-northeast-1.amazonaws.com/autoscaler-repo:latest   app=cluster-autoscaler

READY1/1になり、AVAILABLEが1であれば成功です。

  • ログを参照する場合は下記コマンドで確認できます。
kubectl -n kube-system logs -f deployment.apps/cluster-autoscaler

(2)-(f) Autoscalerの検証

ハンズオン(その1)の(7)で動作確認で利用したdeploymentを利用して、autoscalingの動作確認を行います。

(i)pod数の変更

httpd-deployment.yamlreplicas:の数を2から20に変更します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-deployment
  labels:
    app: httpd-dep
spec:
  replicas: 2 <<= ここを2から20に変更する
  selector:
    matchLabels:
      app: httpd-pod
<以下略>

(ii)適用

kubectl apply -f httpd-deployment.yaml

(iii)確認

# deploymentの状態確認
kubectl get deployments httpd-deployment

# ワーカーノードの確認
kubectl get nodes

また、AutoscalingのDesired capacityが変更されているかを確認する。

ハンズオン(その3): AWS Load Balancer ControllerによるELB構成

Add AWS Load Balancer Controller

(1) PrivateクラスターのためのVPCE作成とECRイメージの格納

(1)-(a) AWS Load Balancer Controller用にVPCエンドポイントを追加

AWS Load Balancer Controllerから、ELBを操作できるようにするために、Elastic Load BalancingのVPCエンドポイントを追加します。

aws cloudformation deploy \
        --stack-name EksPoc-Vpce-AwsLoadBalancerController \
        --template-file "./src/vpce_for_aws-load-balancer-controller.yaml"

(1)-(b) AWS Load Balancer ControllerとCert-ManagerのDockerイメージの保管

本検証環境はkubernetesのワーカーノードから外部にはアクセスができないため、ECRリポジトリを用意しAWS Load Balancer Controllerのdockerイメージを格納しておきます。

(i) ECRリポジトリ作成

  • AWS Load Balancer Controller
aws cloudformation deploy \
        --stack-name EksPoc-AwsLoadBalancerControllerEcr \
        --template-file "./src/AWSLoadBalancerController/ecr_for_aws-load-balancer-controller.yaml"
  • CERT-Manager
aws cloudformation deploy \
        --stack-name EksPoc-CertManagerControllerEcr \
        --template-file "./src/AWSLoadBalancerController/ecr_for_cert-manager-controller.yaml"
aws cloudformation deploy \
        --stack-name EksPoc-CertManagerCainjectorEcr \
        --template-file "./src/AWSLoadBalancerController/ecr_for_cert-manager-cainjector.yaml"
aws cloudformation deploy \
        --stack-name EksPoc-CertManagerWebhookEcr \
        --template-file "./src/AWSLoadBalancerController/ecr_for_cert-manager-webhook.yaml"

(ii) AWS Load Balancer Controllerの最新バージョンを確認

下記AWS Load Balancer ControllerのGitHubのリリース情報から、最新バージョンを確認する。 https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases

最新バージョンを確認したら下記情報を控えておく

  • バージョン名: 例えばv.2.4.4など
  • Assetsの定義ファイルのURI: Assetsのリストでファイル名がv2_4_4_full.yamlなどとあるYAML定義のURLを控える
  • DockerイメージのURI: リリース情報の冒頭にImage: docker.io/amazon/aws-alb-ingress-controller:v2.4.4という形で表示されているのでそこから取得するか、上記のYAML定義の中から情報を取得する。

(iii) (Dockerインスタンス)AWS Load Balancer Controllerイメージの取得と保管

以下の作業は、別端末を開いてDockerインスタンスにログインして作業します。

  • Dockerインスタンスへのログイン
export PROFILE=<PoC環境のAdministratorAccess権限が実行可能なプロファイル>
export REGION="ap-northeast-1"

# プロファイルの動作テスト
aws --profile ${PROFILE} sts get-caller-identity
# DockerDevインスタンスのインスタンスID取得
DockerDevID=$(aws --profile ${PROFILE} --region ${REGION} --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-Instances \
        --query 'Stacks[].Outputs[?OutputKey==`DockerDevId`].[OutputValue]')
echo "DockerDevID = $DockerDevID"

# SSMによるOSログイン
aws --profile ${PROFILE} --region ${REGION} \
    ssm start-session \
        --target "${DockerDevID}"
  • ec2-userへの変更
sudo -u ec2-user -i
  • DockerイメージのPull
AWSLBCTL_PATH="<(ii)で控えておいたAWS Load Balancer Controllerのイメージのuri:タグ情報>"

AWS Load Balancer ControllerのDockerイメージをローカルにpullします。

docker pull "${AWSLBCTL_PATH}"
# 取得した情報の確認
docker images
  • dockerイメージをECRに格納 AWS Load Balancer Controller用ECRのURI取得
REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names aws-load-balancer-controller-repo \
    --query 'repositories[].repositoryUri' ) ;
echo "
REPO_URL = ${REPO_URL}
"

ECRへのpush

# ECR登録用のタグを作成
docker tag ${AWSLBCTL_PATH} ${REPO_URL}:latest
docker images # 作成したtagが表示されていることを確認

# ECRログイン
# "Login Succeeded"と表示されることを確認
aws ecr get-login-password | docker login --username AWS --password-stdin ${REPO_URL}

# イメージのpush
docker push ${REPO_URL}:latest

# ECR上のレポジトリ確認
aws ecr list-images --repository-name autoscaler-repo

(iv) (Dockerインスタンス)CertManagerイメージの取得と保管

同様にCertManagerのイメージをECRに保管します。最新情報は以下のデプロイ手順のCERT-Managerのノードが quay.io コンテナレジストリにアクセスできない場合の説明を参照下さい。

curl -Lo cert-manager.yaml https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
  • イメージURIの取得
grep -e 'image:' cert-manager.yaml

          image: "quay.io/jetstack/cert-manager-cainjector:v1.5.4"
          image: "quay.io/jetstack/cert-manager-controller:v1.5.4"
          image: "quay.io/jetstack/cert-manager-webhook:v1.5.4"

手動で以下を設定します

CERT_MGR_CAIN="<cert-manager-cainjectorのパスを設定>"
CERT_MGR_CONT="<cert-manager-controllerのパスを設定>"
CERT_MGR_WEBH="<cert-manager-webhookのパスを設定>"
  • ECRレポジトリのURI取得
CERT_MGR_CAIN_REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names cert-manager-cainjector-repo \
    --query 'repositories[].repositoryUri' ) ;
CERT_MGR_CONT_REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names cert-manager-controller-repo \
    --query 'repositories[].repositoryUri' ) ;
CERT_MGR_WEBH_REPO_URL=$( aws --output text \
    ecr describe-repositories \
        --repository-names cert-manager-webhook-repo \
    --query 'repositories[].repositoryUri' ) ;

echo "
CERT_MGR_CAIN_REPO_URL = ${CERT_MGR_CAIN_REPO_URL}
CERT_MGR_CONT_REPO_URL = ${CERT_MGR_CONT_REPO_URL}
CERT_MGR_WEBH_REPO_URL = ${CERT_MGR_WEBH_REPO_URL}
"
  • イメージPull
docker pull "${CERT_MGR_CAIN}"
docker pull "${CERT_MGR_CONT}"
docker pull "${CERT_MGR_WEBH}"

確認します。

docker images
  • ECRへのPush(cert-manager-cainjector)
docker tag ${CERT_MGR_CAIN} ${CERT_MGR_CAIN_REPO_URL}:latest
aws ecr get-login-password | docker login --username AWS --password-stdin ${CERT_MGR_CAIN_REPO_URL}
docker push ${CERT_MGR_CAIN_REPO_URL}:latest
aws ecr list-images --repository-name cert-manager-cainjector-repo
  • ECRへのPush(cert-manager-controller)
docker tag ${CERT_MGR_CONT} ${CERT_MGR_CONT_REPO_URL}:latest
aws ecr get-login-password | docker login --username AWS --password-stdin ${CERT_MGR_CONT_REPO_URL}
docker push ${CERT_MGR_CONT_REPO_URL}:latest
aws ecr list-images --repository-name cert-manager-controller-repo
  • ECRへのPush(cert-manager-webhook)
docker tag ${CERT_MGR_WEBH} ${CERT_MGR_WEBH_REPO_URL}:latest
aws ecr get-login-password | docker login --username AWS --password-stdin ${CERT_MGR_WEBH_REPO_URL}
docker push ${CERT_MGR_WEBH_REPO_URL}:latest
aws ecr list-images --repository-name cert-manager-webhook-repo

(v)ログアウト

作業が完了したので、Dockerインスタンスからログアウトします

exit
exit

(2) AWS Load Balancer Controller用のIAMロール作成

以後の作業は、Bastion兼高権限用インスタンスに戻って行います。

(2)-(a) IAMポリシー取得

curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json

(2)-(b) IAMロールの信頼関係(Trust relationship)設定用の情報取得

# EKSクラスターのOIDC情報取得
OIDCProviderId=$(aws --output text \
    cloudformation describe-stacks \
        --stack-name EksPoc-EksControlPlane \
        --query 'Stacks[].Outputs[?OutputKey==`OpenIdConnectIssuerUrl`].[OutputValue]' | cut -d "/" -f 5)
echo "OIDCProviderId = ${OIDCProviderId}"

# 該当OIDCプロバイダーのARN取得
OIDCProviderARN=$(aws --output json iam list-open-id-connect-providers | jq -r '.OpenIDConnectProviderList[].Arn | select( . | contains("'${OIDCProviderId}'") )')
echo "OIDCProviderARN = ${OIDCProviderARN}"

# 該当OIDCプロバイダーのURI取得
OIDCProviderURI=$(aws --output text iam get-open-id-connect-provider --open-id-connect-provider-arn ${OIDCProviderARN} --query 'Url')
echo "OIDCProviderURI = ${OIDCProviderURI}"

(2)-(c) IAMロールの信頼関係用ポリシー生成

sed -e "s;OIDCProviderARN;${OIDCProviderARN};g" \
    -e "s;OIDCProviderURI;${OIDCProviderURI};g" \
    src/AWSLoadBalancerController/aws-load-balancer-controller_iam_role_trust_policy.json_template > aws-load-balancer-controller_iam_role_trust_policy.json

生成した信頼関係用ポリシーの確認をします。

cat aws-load-balancer-controller_iam_role_trust_policy.json

(2)-(d) IAMロールの作成

IAMロール名を設定します。

# EKSクラスター情報取得
EKS_CLUSTER_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-EksControlPlane \
    --query 'Stacks[].Outputs[?OutputKey==`ClusterName`].[OutputValue]' )
echo "EKS_CLUSTER_NAME = ${EKS_CLUSTER_NAME}"

LB_CTL_IAM_ROLE_NAME=${EKS_CLUSTER_NAME}-AWS-Loadbalancer-Controler-Role

IAMロールを作成します。

# IAMロール作成
aws iam create-role \
    --role-name "${LB_CTL_IAM_ROLE_NAME}" \
    --assume-role-policy-document "file://aws-load-balancer-controller_iam_role_trust_policy.json"

# IAMポリシー(インラインポリシー)のアタッチ
aws iam put-role-policy \
    --role-name "${LB_CTL_IAM_ROLE_NAME}" \
    --policy-name loadbalancer \
    --policy-document "file://iam_policy.json"

(2)-(e) AWS Load Balancer Controller用のIAMロールをk8sにサービスアカウントとして登録

(i) 作成したIAMロールのARN取得

AWS_LOAD_BALANCER_CONTROLLER_IAM_ROLL_ARN=$(aws --output text \
    iam get-role --role-name "${LB_CTL_IAM_ROLE_NAME}" --query 'Role.Arn')

echo "
AWS_LOAD_BALANCER_CONTROLLER_IAM_ROLL_ARN = ${AWS_LOAD_BALANCER_CONTROLLER_IAM_ROLL_ARN}
"

(ii) k8sのサービスアカウント定義ファイルの作成

テンプレートにIAMロールのARNを設定します。

sed -e "s;AmazonEKSLoadBalancerControllerRoleARN;${AWS_LOAD_BALANCER_CONTROLLER_IAM_ROLL_ARN};g" \
    src/AWSLoadBalancerController/aws-load-balancer-controller-service-account.yaml_template > aws-load-balancer-controller-service-account.yaml

#確認します
cat aws-load-balancer-controller-service-account.yaml

(iii) k8sのクラスターへの登録

kubectl apply -f aws-load-balancer-controller-service-account.yaml

下記コマンドで登録されていることを確認します。

kubectl -n kube-system get serviceaccount aws-load-balancer-controller

NAME                           SECRETS   AGE
aws-load-balancer-controller   1         74s

(3)CERT-Managerのインストール

(i)マニフェストの取得

curl -Lo cert-manager.yaml https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml

(ii)マニフェストの編集

ダウンロードしたマニフェストのDockerイメージのURI(下記部分)をECRに格納したイメージのURIへ書き換えます。

    image: "quay.io/jetstack/cert-manager-cainjector:v1.5.4"
    image: "quay.io/jetstack/cert-manager-controller:v1.5.4"
    image: "quay.io/jetstack/cert-manager-webhook:v1.5.4"
  • ECRレポジトリのURI取得 取得したURIをメモ帳などに控えておきます。
CERT_MGR_CAIN_REPO_URL=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-CertManagerCainjectorEcr \
        --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]')
CERT_MGR_CONT_REPO_URL=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-CertManagerControllerEcr \
        --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]')
CERT_MGR_WEBH_REPO_URL=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-CertManagerWebhookEcr \
        --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]')

echo "
CERT_MGR_CAIN_REPO_URL = ${CERT_MGR_CAIN_REPO_URL}
CERT_MGR_CONT_REPO_URL = ${CERT_MGR_CONT_REPO_URL}
CERT_MGR_WEBH_REPO_URL = ${CERT_MGR_WEBH_REPO_URL}
"
  • マニフェストの編集 Dockerイメージを指定している3箇所(image: "quay.io/jetstack/cert-manager-xxxxxx部分)をECRに格納したイメージのURI:latestに変更する。
 vi cert-manager.yaml

編集後のimage:部分の例。

    image: "999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/cert-manager-cainjector-repo:latest"
    image: "999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/cert-manager-controller-repo:latest"
    image: "999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/cert-manager-webhook-repo:latest"

(iii)マニフェストの適用

kubectl apply \
    --validate=false \
    -f ./cert-manager.yaml

状態を確認します。READYが1/1ならpodが正常に起動しておりOKです。

kubectl -n cert-manager get deployments

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
cert-manager              1/1     1            1           55s
cert-manager-cainjector   1/1     1            1           55s
cert-manager-webhook      1/1     1            1           55s

(4) AWS Load Balancer Controllerのインストール

(4)-(a) Controllerのマニフェスト取得

(1)-(b)で確認したAWS Load Balancer ControllerバージョンのYAML定義ファイルを取得します。

# v2_4_4_full.yamlの場合
curl -Lo v2_4_4_full.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.4/v2_4_4_full.yaml
curl -Lo v2_4_4_ingclass.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.4/v2_4_4_ingclass.yaml

Controllerのマニフェストの編集

  • Cluster
  • image変更
  • arg変更

(i)情報の取得

取得したクラスター名とLoadBalancerのECRのURIを控えておきます。

# EKSクラスター情報取得
EKS_CLUSTER_NAME=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-EksControlPlane \
    --query 'Stacks[].Outputs[?OutputKey==`ClusterName`].[OutputValue]' )

LBCTL_REPO_URL=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-AwsLoadBalancerControllerEcr \
        --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]')

VPCID=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-VPC \
        --query 'Stacks[].Outputs[?OutputKey==`VpcId`].[OutputValue]')

REGION=$(aws configure get region)

echo "
EKS_CLUSTER_NAME = ${EKS_CLUSTER_NAME}
LBCTL_REPO_URL   = ${LBCTL_REPO_URL}
VPCID            = ${VPCID}
REGION           = ${REGION}
"

(ii)マニフェストの編集

取得したマニフェストの以下の部分を修正します

  • 必須項目
    • クラスター名変更: --cluster-name=your-cluster-nameyour-cluster-nameを変更します
  • EC2インスタンスのIMDSへのアクセスが制限されているまたはFargate利用時
    • 引数にVPC ID追加: --aws-vpc-id=vpc-xxx
    • リージョン追加: --aws-region=region-code
  • Privateクラスター固有の追加(NATGW等によるインターネット接続不可時)
    • shield/waf無効化の追加: --enable-shield=false,--enable-waf=false,--enable-wafv2=false
    • Dockeイメージパス変更: image:をECRにPUSHしたイメージに変更

以下に変更例を示します。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/name: aws-load-balancer-controller
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/name: aws-load-balancer-controller
    spec:
      containers:
      - args:
        - --cluster-name=your-cluster-name #<<== クラスター名を変更
        - --ingress-class=alb
        - --aws-vpc-id=vpc-xxxxxxxx        #<== 取得したVPC IDを入れて追加
        - --aws-region=region-code         #<== 取得したリージョンコードを入れて追加
        - --enable-shield=false            #<== 追加
        - --enable-waf=false               #<== 追加
        - --enable-wafv2=false             #<== 追加
        image: amazon/aws-alb-ingress-controller:v2.4.4 #<<== ECRのイメージのパス "ECRURI:latest"に変更する
        livenessProbe:
          failureThreshold: 2

また以下の部分を削除します。(前のステップで追加された IAM ロールを持つアノテーションが、コントローラーがデプロイされる際に上書きされるのを防ぐため)

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system
---

(iii)マニフェストの適用

# マニフェストの適用
# kubectl apply -f ファイル名
# 以下はv2_4_4_full.yamlファイルの場合
kubectl apply -f v2_4_4_full.yaml
kubectl apply -f v2_4_4_ingclass.yaml

状態を確認します。

kubectl get deployment -n kube-system aws-load-balancer-controller


NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   1/1     1            1           3m11s

(5) サブネットを検知できるようにする

ALBを配置するPublic SubnetをAWS Load Balancer Controllerが検知できるようにするため、Public Subnetに以下のタグを追加します。

  • 追加するタグ
    • key: kubernetes.io/role/elb
    • value: 1

(5)-(a)情報の取得

PUBSUB1ID=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-VPC \
        --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet1Id`].[OutputValue]')

PUBSUB2ID=$(aws --output text cloudformation describe-stacks \
        --stack-name EksPoc-VPC \
        --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet2Id`].[OutputValue]')

echo "
PUBSUB1ID = ${PUBSUB1ID}
PUBSUB2ID = ${PUBSUB2ID}
"

(5)-(b)タグの追加

aws ec2 create-tags --resources ${PUBSUB1ID} ${PUBSUB2ID} --tags 'Key=kubernetes.io/role/elb,Value=1'

(6)テスト

以下のようにIngress(ALB)、NodePortのサービス、とhttpdのPodで構成するサンプルを稼働させます。 ingress arch

(6)-(a) 既存サービスの削除

ハンズオン(その2)までの定義がある場合はまず削除します。

kubectl delete -f k8s_define/httpd-service.yaml
kubectl delete -f httpd-deployment.yaml

(6)-(b) 定義ファイルの生成

(i)リポジトリ情報の取得

REPO_URL=$(aws --output text cloudformation \
    describe-stacks --stack-name EksPoc-Ecr \
    --query 'Stacks[].Outputs[?OutputKey==`EcrRepositoryUri`].[OutputValue]' )
echo "
REPO_URL = ${REPO_URL}
"

(i) 定義ファイルの準備

# Deployment定義ファイルの作成
# 環境固有となるECRレポジトリURL情報をDeploymentに設定します。
sed -e "s;REPO_URL;${REPO_URL};" k8s_define/httpd-ingress.yaml.template > httpd-ingress.yaml
cat httpd-ingress.yaml

(6)-(c) DeploymentとServiceの適用

(i) 適用

kubectl apply -f httpd-ingress.yaml

状態を確認します。

kubectl get cm,deployment,pod,svc,ing -o wide


NAME                         DATA   AGE
configmap/kube-root-ca.crt   1      2d3h

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                                                 SELECTOR
deployment.apps/httpd-deployment   2/2     2            2           10m   httpd        616605178605.dkr.ecr.ap-northeast-1.amazonaws.com/ekspoc-repo:latest   app.kubernetes.io/name=httpd-pod

NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE                                              NOMINATED NODE   READINESS GATES
pod/httpd-deployment-ff96f4749-7fgcl   1/1     Running   0          10m   10.1.154.230   ip-10-1-147-224.ap-northeast-1.compute.internal   <none>           <none>
pod/httpd-deployment-ff96f4749-m5b6r   1/1     Running   0          10m   10.1.46.57     ip-10-1-60-36.ap-northeast-1.compute.internal     <none>           <none>

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE    SELECTOR
service/httpd-service   NodePort    172.20.192.129   <none>        80:32679/TCP   10m    app.kubernetes.io/name=httpd-pod
service/kubernetes      ClusterIP   172.20.0.1       <none>        443/TCP        2d3h   <none>

NAME                                      CLASS   HOSTS   ADDRESS   PORTS   AGE
ingress.networking.k8s.io/httpd-ingress   alb     *                 80      83s

(ii) 確認

マネージメントコンソールなどで、ALBのURLを確認し、ブラウザやcurlコマンドでhttp://ALBのDNSでアクセス可能か確認します。

接続できない場合は以下で原因を特定します。

  • AWS Load Balancer Controllerを調査する
kubectl logs -n kube-system deployment.apps/aws-load-balancer-controller