この間UdemyでMac上にminikubeの環境を構築してkubenetesを学ぶ講座を受けたが、その続きでローカルではなくAWS EKS上で本番運用っぽく動かしてみる講座があったので受講してみた。
米シリコンバレーエンジニア監修!AWS EKS KubernetesハンズオンBest Practices (2022) | Udemy
講座聴きながら一通り動かしてみたけど結構複雑で正直理解しきれてない感がある。。ので、講座についてた資料を見返し理解が曖昧な点を掘り下げながら整理してみる。
コマンドは大体講座の添付資料の通りだけど元はregionがus-west-2だったのでap-northeast-1に変更している。
EKSのセットアップ
前回minikubeの時にも使ったkubectlに加えてEKS操作用のeksctlとAWS CLI(awscli)を使ってターミナルからコマンドでEKS Clusterを立ち上げる。ただこれは学習目的で「本番環境ではTerraformやCloudFormationといったIaCを推奨」とある。
AWSの設定とかCLIのローカルへのインストールを済ませた後以下コマンド実行するとEKSのクラスタが作成される。
eksctl create cluster \ --name eks-from-eksctl \ --version 1.16 \ --region ap-northeast-1 \ --nodegroup-name workers \ --node-type t3.medium \ --nodes 2 \ --nodes-min 1 \ --nodes-max 4 \ --ssh-access \ --ssh-public-key ~/.ssh/eks_worker_nodes_demo.pem.pub \ --managed
ここでいうnodeっていうのは前回の講座でも出たけどKubenetesの中のサーバの実態を表す概念みたいなものでAWS上で言うとEC2 or Fagateのホストに当たる。そういえば今回の講座ではworker nodeはEC2を使ったのでFagateの場合はどうするのかは別途調べないとかもな。。
nodeの他はname spaceとかversion指定とかsshの認証周りのオプションつけてる感じ。
このコマンド打った後にAWS管理画面開くとEKSやそのワーカノードのEC2がちゃんと作られていた。
あとクラスタ立ち上げっぱなしだとworker nodeのEC2の料金に加えてEKSを使うための料金も取られるので使わない時はマメにクラスタ落とした。
eksctl delete cluster --name eks-from-eksctl --region us-west-2
Helm Chartについて
Kubenetesは結構な量のyamlファイルの作成が必要なんだけど全部手で書くのは辛いのでHelmというツールで作成する。まあ、Kubenetesのパッケージマネージャだと思っておけば良さそうで調べた感じ現在のデファクトスタンダードみたい。
nginx用のyamlを作りたければこんな感じ。
helm search repo nginx helm search repo bitnami/nginx helm install nginx bitnami/nginx
このコマンドでConfigMap、Service、Deploymentとnginx環境構築に必要なリソースのyamlが用意される。 helmはstatausとかhistoryとかいろんな便利コマンドが用意されている。
Kuberenetesダッシュボードについて
Kubenetesクラスタの状態を監視するダッシュボードが紹介されている。 GitHub - kubernetes/dashboard: General-purpose web UI for Kubernetes clusters
kubectlでdashboardのリソースを作る →ダッシュボードにログインするためのトークン(パスワードみたいなもの)をSecretリソースから取得 →kubenetesクラスタへのプロキシを作ってブラウザからlocalhost:8001にアクセスするとクラスタの状態を監視できる。
- kubectlでdashboardのリソースを作るコマンド
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml
namespace、serviceaccount、service、secret、configmap、role、clusterrole、rolebindingなどができきてたけどぶっちゃけまだそれぞれのリソースの役割を理解できておらず講座でもそこまでそこは深追いはしてないのでここは別途調べないとかな。。
- トークン取得
kubectlでsecretを取得→結果がbase64エンコードされてるのでデコードする。これをダッシュボードのログイン画面に貼るとログインできる。
kubectl get secrets kubernetes-dashboard-token-t9z22 -n kubernetes-dashboard --output yaml echo "{出てきたパスワード}" | base64 -D
- プロキシ作成
kubectl proxy
サンプルアプリのデプロイ
「guestbook」と言うPHP+Redisでできたサンプルアプリをkubenetesで動かすためのjsonが公開されているのでそれをEKS上で動かした。
guestbookはkubenetes本体のgithubレポジトリの中で管理されている。
examples/guestbook-go/README.md at master · kubernetes/examples · GitHub
web上で公開されているjsonをkubectlで直接読んでクラスタ構築する感じ。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook-go/redis-master-controller.json kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook-go/redis-master-service.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook-go/guestbook-controller.json kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook-go/guestbook-service.json
指定しているリソースはservice(Podのラッパー)とReplicationController(レプリカ数指定するやつ)
以下のコマンドで公開したサービスのAWS上のロードバランサを取得できる
kubectl get svc guestbook
Networking: Ingress ControllerでPodを外部に公開
kubectl get service guestbook
と打つとレイヤ4のロードバランサが使われていることを確認できる。ただ本当はレイヤ7を使いたい。
helmでレイヤ7のロードバランサをinstall
kubectl create namespace nginx-ingress-controller
helm install nginx-ingress-controller stable/nginx-ingress -n nginx-ingress-controller
これを使うとnginxがレイヤ7のロードバランスをしてくれる。
ただこのやり方は問題があって本番環境で動かすならIstioを別途学んだ方がいいらしい。クラスタ内の認証が面倒でサービス間の認証のたびにサーバに負担がかかるって感じ?↓
NginxやAWS ALB Ingress Controllerは共にSSL terminationに対応しているが、バックエンドのアプリ間のTLSはアプリ次第となっています。つまり 1) アプリ間でTLS certを提供し、2) CPUリソースを消費するSSL handshakesを行う必要があります。 もしIstioを使うと、アプリのコードを一切変更せずに、クラスター内でデフォルトでSSLを可能にし、且つService Mesh機能であるCanaryリリースやFault Injectionなどもできるようになります。
Security: AWS Userの認証 (aws-iam-authenticator) と 認可(RBAC: Role Based Access Control)
AWS上でKubenetesを動かしているわけなのでAWSのIAMで認証されたAWSユーザーがK8sユーザーとして存在するか認可する(ややこしい)
kubectl get configmap aws-auth -n kube-system -o yaml
とコマンドを打つとAWSのユーザがkubenetesのユーザ、ユーザグループにマップされていることを確認できる。
IAMユーザに権限を与える場合(ルートユーザとして追加)Kubenetesのconfigmapに新しいAWS IAM userのARN(Amazonリソースネーム)を追加する。
kubectl edit -n kube-system configmap/aws-auth
mapUsers: | - userarn: arn:aws:iam::111122223333:user/eks-viewer # AWS IAM user username: this-aws-iam-user-name-will-have-root-access groups: - system:masters # K8s User Group
このAWS IAM userはsystem:masters
というK8sユーザーグループにバインドされている
ClusterRoleBinding
これはkebenetesの世界の話でkubenetesユーザにRoleを割り当てる。リソースの1種なのでyamlで定義してkubectlでapplyできる。
kubectl create clusterrolebinding system:viewer \ --clusterrole=view \ --group=system:viewer \ --dry-run -o yaml > clusterrolebinding_system_viewer.yaml
Monitoring: PrometheusとGrafana
監視ツールの話。Prometheusはサーバインフラ監視ツール、Grafanaはログ・データの可視化ツールでどっちも別にkubenetes専用のものではないがkubenetes環境でも使えるって感じ。
どっちもHelmからinstallできる。Helmって監視ツールもインストールできるのか。。
# まずはnamespaceを作成 kubectl create namespace prometheus helm install prometheus stable/prometheus \ --namespace prometheus \ --set alertmanager.persistentVolume.storageClass="gp2" \ --set server.persistentVolume.storageClass="gp2"
kubectl create namespace grafana helm install grafana stable/grafana \ --namespace grafana \ --set persistence.storageClassName="gp2" \ --set persistence.enabled=true \ --set adminPassword='EKS!sAWSome' \ --set datasources."datasources\.yaml".apiVersion=1 \ --set datasources."datasources\.yaml".datasources[0].name=Prometheus \ --set datasources."datasources\.yaml".datasources[0].type=prometheus \ --set datasources."datasources\.yaml".datasources[0].url=http://prometheus-server.prometheus.svc.cluster.local \ --set datasources."datasources\.yaml".datasources[0].access=proxy \ --set datasources."datasources\.yaml".datasources[0].isDefault=true \ --set service.type=ClusterIP
(ベストプラクティス) Security: IRSA(IAM Role for Service Account)を使い、PodレベルのAWSへの認可を設定
PodにService Accountを指定してPodにトークンを持たせてそこからAWSのapiサーバにつないでPod単位の認証かけられる。その流れざっくり噛み砕くとこんな感じ↓一つ一つは普段触ってるWebアプリの認証の仕組みと変わらないんだけど手順が多くて複雑だな。
Podを起動する時にAWSのAPIサーバにyamlを送る →APIサーバのwebhookがk8sのService AccountとそのService AccountにIAM Role ARNがあることを確認する →webhookがService Accountのannotationを元にpodに環境変数を設定 →Service AccountがOIDC(OpenID Connect)経由でAWS IAMから認証 →JWT トークンをOIDCから受け取ってPodの環境変数(AWS_WEB_IDENTITY_TOKEN_FILE)に保存 →以降PodでAWS CLIコマンドを使うと環境変数のトークンを使ってAWS IAM roleをAssumeする。
実際の構築コマンド
AWSでIODCを作成する必要あり(このハンズオンではeksctl create clusterを使ってclusterを作った際に作られているので未実施) 確認コマンドは略
aws iam create-open-id-connect-provider \ --url $ISSUER_URL \ --thumbprint-list $ROOT_CA_FINGERPRINT \ --client-id-list sts.amazonaws.com
OIDC providerをEKSクラスターにリンク
eksctl utils associate-iam-oidc-provider \ --region=us-west-2 \ --cluster=eks-from-eksctl \ --approve
管理画面からIAMを作成してから以下コマンド実行 Service accountを作成 →IAM role ARNをAnnotationに追加
eksctl create iamserviceaccount \ --name irsa-service-account \ --namespace default \ --cluster eks-from-eksctl \ --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \ --approve \ --region ap-northeast-1
EC2 instance profileにアクセスが可能なのでブロック
podからEC2のインスタンスメタデータにアクセスできてしまうのでそこも塞がないとダメらしい
以下講義資料のコマンド。ec2に入ってiptablesコマンド打ってファイヤウォール設定するのか。これよく気づくな。
EKSワーカーノードにSSH
eval $(ssh-agent) ssh-add -k ~/.ssh/ ssh -A ec2-user@192.168.20.213
iptablesコマンドを実行
yum install -y iptables-services iptables --insert FORWARD 1 --in-interface eni+ --destination 169.254.169.254/32 --jump DROP iptables-save | tee /etc/sysconfig/iptables systemctl enable --now iptables
11. (ベストプラクティス) Scaling: Cluster Autoscaler (CA)
Clusterのスケーリングの話
1.AWS ASGのタグを追加(AWGはAuto Scaling Groupのこと) →AWS管理画面からEC2→Auto Scaling Groupを開いてそこで設定する(クラスタ作成時に勝手に作られているので実際は作成不要。管理画面開くと確認できる)
2.cluster autoscalerへ認可(Authorization)のIAM パミッションをIRSA (Podレベル)かEC2 Instance Profile(ノードレベル)で追加
手順としてはIAMポリシーを管理画面から作成→eksctlでService AccountとIAMロールを作成の流れ
eksctl create iamserviceaccount \ --name cluster-autoscaler-aws-cluster-autoscaler \ --namespace kube-system \ --cluster eks-from-eksctl \ --attach-policy-arn arn:aws:iam::266981300450:policy/EKSFromEksctlClusterAutoscaler \ --approve \ --region ap-northeast-1
3.cluster-autoscalerをHelm ChartとしてEKS clusterにインストール
Region、ServiceAccount名、クラスタ名を記載したyamlを元にしてHelmでcluster-autoscalerをインストールする。これでAuto Scalingの設定が完了する。
awsRegion: ap-northeast-1 rbac: create: true # ref: https://github.com/kubernetes/autoscaler/issues/1507 serviceAccount: create: false # because Service account and IAM role already created by `eksctl create iamserviceaccount` s name: cluster-autoscaler-aws-cluster-autoscaler autoDiscovery: clusterName: eks-from-eksctl enabled: true
(ベストプラクティス) Scaling: Horizontal Pod Autoscaler (HPA、水平オートスケーリング)
Podの数を水平にスケールする
cluster-autoscalerはHelmで入れないといけなかったけどこっちはKubenetesのネイティブで入っているのでインストールは不要。
Metrics Serverは必要(ダッシュボード作る時に入れたやつ)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml
HPAリソースのyamlを作成してkubectlでapplyすればいいらしい。まあ見たまんまでCPUの状態見て最大数までPodを増やしてくれる。
$ kubectl autoscale deployment test-hpa \ --min 1 \ --max 7 \ --cpu-percent=80 \ --namespace default \ --dry-run \ -o yaml > hpa.yaml $ kubectl apply -f hpa.yaml $ kubectl get hpa
感想
認証とかAutoScalingとかAWSのサービスとKubenetesの機能が複雑につながってる感じがしてなかなか辛そうだな。今回は学習用にコマンド打って一つ一つ設定してったけど、実際に使う時には一度KubenetesのマニフェストファイルとTerraformかCloudFormationを作りきってしまえばインフラの状態コードで把握できるし勝手にスケーリングもしてくれるんで今回みたいにいちいちコマンド打つのとは違った快適な感じになるのかな?
しかし学習コスト高いな。。昔Oracle触ってた時にこれOS学ぶのと同じくらい大変じゃね。。って思ってたけど同じような巨大さを感じる。
この講座だけではまだ本番で使うには不十分でIstioやインフラのコード化の知識やCI/CDも学ばないといけないみたい。しかもまだ開発活発みたいなんで新しいAPIのキャッチアップも必要なんだろうな。