AWS EC2でkubeadmを用いたKubernetesクラスターを作ってみたのでメモ
2024-05-27
azblob://2024/05/27/eyecatch/2024-05-27-aws-ec2-kubernetes-cluster-000.jpg
この記事はなむゆの個人ブログにもマルチポストしています。
 

はじめに

Kubernetesって動かすと楽しいじゃないですか。
でも、Kubernetesで遊ぼうと思ったら普段はローカルでRancher Desktopからシングルノードのクラスターをワンボタンで作ったりEKSやAKSでマネージドなクラスターを作ったりするのですが、それではちょっと物足りないこともあります。
例えば最新のバージョンのKubernetesを使ってみようとしたら、前述の方法だとどれもすぐには対応していなくて、最新バージョンに対応するのを待つ必要があります。
そのためいつでも最新のバージョンのKubernetesを試せるように、ついでにマルチノードの構成で立ち上げるようにするためにAWS EC2の中にkubeadmでKubernetesを立ち上げ、クラスターを構成する方法を確立しておこうと試みたので今のところ確立できている方法をメモしておきます。
そのうちもっといい方法が確立できるかもしれないのでその時はその時で別途記事にしようと思います。
 

今回の構成

今回作成した構成は以下のような形です。
Control Plane Nodeが1台、Worker Nodeの数は2台にしましたが実際はお好みで。
コンテナランタイム: runc
CNI: Cilium

作成したリソース

EC2
- name: kubernetestest-dev-app-controlplane
  image: Canonical, Ubuntu, 24.04 LTS, amd64 noble image build on 2024-04-23
  instanceType: t3.small
  keyPair: 新規作成
  VPC: kubernetestest-dev-pvc
  サブネット: kubernetes-dev-subnet
  NSG: kubernetestest-dev-nsg
  パブリックIPの自動割り当て: 有効化
- name: kubernetestest-dev-app-worker
  image: Canonical, Ubuntu, 24.04 LTS, amd64 noble image build on 2024-04-23
  instanceType: t3.micro
  keyPair: 新規作成
  VPC: kubernetestest-dev-pvc
  サブネット: kubernetes-dev-subnet
  NSG: kubernetestest-dev-nsg
  パブリックIPの自動割り当て: 有効化
 
インスタンスサイズは、Control Plane用のインスタンスではメモリとCPUがそれぞれ2GiBと2v必要なためt3.smallとしています。
Worker Node用では最低限で構わないのでt3.microにしています。
また、今回は学習用リソースとして作成しているため、インスタンスにローカルから直接sshするためにパブリックIPの自動割り当てを有効にいています。
 
VPC
- name: kubernetestest-dev-vpc
  IPv4 CIDR: 10.0.0.0/16
 
Subnet
- name:
  VPC: kubernetestest-dev-vpc
  IPv4 Subnet CIDR: 10.0.0.0/16
 
Route Table
- name: kubernetes-dev-rtb
  VPC: kubernetestest-dev-vpc
  routes:
  - to: 10.0.0.0/16
    target: local
  - to: 0.0.0.0/16
    target: kubernetestest-dev-igw
 
IGW
- name: kubernetestest-dev-igw
  VPC: kubernetestest-dev-vpc
 
NSG
- type: ssh
  source: 0.0.0.0/0
- type: customTCP
  source: 0.0.0.0/0
  port: 6443
- type: customTCP
  source: 10.0.0.0/16
  port: 10250
 
NSGではこちらを参考に許可する通信を規定しています。
本当はControl PlaneとWorker Nodeで要件は異なりますが、今回はひとまとめにしています。
ssh用の22番、API Serverへのアクセス用の6443番、Kubernetes Nodeのkubelet間のやりとりのための10250番ポートを開放してあります。
特に10250番はクラスター内部の通信であるため、通信元は同じVPC内部に限定しています。
 

実行したコマンド

リソースが一通り作成できれば、EC2 Instance Connect等を用いてインスタンスにssh接続します。
Control Plane NodeとなるEC2インスタンスでは起動後に以下のコマンドを実行してコンテナランタイム、Kubernetes、CNIをインストールしています。
実行時は先にControl Plane Nodeのコマンドから実行してください。
 
# Dockerのインストール
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
    sudo apt-get update
    sudo apt-get install -y docker.io
    
    # Dockerの開始
    sudo systemctl start docker
    sudo systemctl enable docker
    
    # Kubernetesのインストール
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl
    
    # Kubernetesの起動
    sudo kubeadm init --pod-network-cidr=10.0.0.0/16
    
    # kubeconfigのコピー
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    # CNIのインストール
    CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
    CLI_ARCH=amd64
    if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
    curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
    sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
    sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
    rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
    cilium install
 
Worker NodeとなるEC2インスタンスでは以下のコマンドを実行しています。KubernetesのインストールコマンドまではControl Plane Nodeと同様です。
クラスターに加入するコマンドは、Control Plane Nodeの立ち上げ時に最後のほうでkubeadm join ~~~といった形で表示されるのでそれをそのままWorker Nodeで打ち込んでください。
# Dockerのインストール
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
    sudo apt-get update
    sudo apt-get install -y docker.io
    
    # Dockerの開始
    sudo systemctl start docker
    sudo systemctl enable docker
    
    # Kubernetesのインストール
    
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl
    
    # Kubernetesクラスターに加入
    sudo kubeadm join <Control PlaneノードのプライベートIP>:6443 --token <トークン> --discovery-token-ca-cert-hash sha256:<hash値>
 
 
# 動作確認
各ノードでコマンドを実行し、成功していれば以下のような出力が得られるかと思います。
Control Plane Nodeでkubectl get nodeを実行
どこのノードでもsudo docker infoコマンドを実行すると現在使用しているDockerのバージョンやコンテナランタイムが表示されるかと思います。

Todo

このクラスターではまだメトリクスサーバーがインストールされていません。
そのため`kubectl top`コマンドやHPAが使えません。
スケーリングの動きを確かめようと思ったらこのあたりの機能が使える必要があるので、また今度インストールも試してみます。
今回動作確認が取れたコンテナランタイムはruncで、しかもそのためにインストールしたパッケージは少し古めのdocker.ioでした。
推奨されるコンテナランタイムはcotainerdかcri-oなのですが、今回は動作確認が取れなかったので今度動作することを確認したいと思います。
また、今回はEC2やネットワーク系のリソース、Kubernetesのインストール等を手動で行っていますが、1コマンドでできたほうが楽なので今度Terraform化を試してみます。
 

おわりに

今回は勉強がてらEC2でKubernetesクラスターをkubeadmベースで作成してみました。
この方法が確立できていれば後でいろいろ検証するのに役立ちそうに思います。
ただ、今回はそれなりに苦労した割に妥協した点も多くあるので、これからもっと構成を洗練させていければと考えています。
自分と同様にKubernetesクラスターをkubeadmベースで作ってみたいという方の助けになれば幸いです。