LoginSignup
1
0

AWSのEC2インスタンスでKubernetesを作ってみる

Last updated at Posted at 2024-01-08

概要

AWSのEC2インスタンスで、kubeadmとAnsible Playbookを使ってKubernetesを作ってみたので、手順を本記事にまとめます。

本記事の対象者

  • マネージドなKubernetesサービス(EKS,AKS,GKE等)以外でK8sを作ってみたい
  • KubernetesをMinikubeやkindではなく、物理マシンでcontrol planeとworker nodeで分けて自力で作ってみたい
  • しかしながら自宅にKubernetesの構築を手軽に試せるような物理マシンがない

Kubernetes全般の環境情報

  • OS : Ubuntu 22.04
  • コンテナランタイム : containerd
  • Kubernetesのバージョンは以下
$ kubectl version
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.5

$ kubelet --version
Kubernetes v1.28.2

$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", GitCommit:"89a4ea3e1e4ddd7f7572286090359983e0387b2f", GitTreeState:"clean", BuildDate:"2023-09-13T09:34:32Z", GoVersion:"go1.20.8", Compiler:"gc", Platform:"linux/amd64"}

Kubernetes構築手順

(1) EC2インスタンスの作成

あくまでお試し用なので、control planeとworker node用のインスタンスをそれぞれ1台作ることにします。

インスタンス情報

AMI

  • ID
    • ami-07c589821f2b353aa
  • name
    • amazon/ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20231207

インスタンスタイプ

  • control plane
    • t3a.small : 2vCPU, 2GiBメモリ
  • worker node
    • t3.micro : 2vCPU, 1GiBメモリ

kubeadmのインストールにも記載があるように、control planeを構築するEC2インスタンスには2GiBのメモリが必要でした。試しにそれよりもメモリが小さいt3.nanot3.microでやってみましたが、kubeadm initの実行途中にメモリ不足とみなされてエラーになってしまうようです。
一方でワーカーノードだと2GiB未満のメモリのマシンでもkubeadm joinに成功しました。(作れはしても、すぐにリソースが枯渇してしまうはずですが...)

(2) セキュリティグループ設定

Kubernetes公式の以下のドキュメントに従って設定します。

本来はcontrol planeとworker nodeとは別々でセキュリティグループルールを設定する必要がありますが、筆者は横着して両方のインスタンスに共通で以下を設定しました(6443は本当はworker nodeでは開ける必要はないです...)

通信の方向 プロトコル ポート番号 用途 通信許可するIP範囲
inbound TCP 6443 kube-apiserverで利用 全てのノード
inbound TCP 10250 kubeletで利用 全てのノード
inbound TCP 30000-32767 NodePortのServiceリソースで利用 全てのノード
outbound 全て 全て インスタンスから外部にアクセス 0.0.0.0/0

※ 上記はKubernetesのシステムで最低限開ける必要があるポートです。最終的にはCNI(Container Network Interface)のインストールも必要になりますが、使うCNIによって適宜開けるプロトコルとポートの追加が必要です。

(3) Kubernetesの構築

kubeadmのインストールを参考にして、Ansibleでスクリプトを作りました。詳しくは筆者作成の下記GitHubをご覧ください。

こちらのツールを使うにはAnsible Playbookを実行するマシンが別途必要となります。実行するマシンが(ネットワーク的な意味での)存在する場所によって、それに応じたSSHのセキュリティルールの追加やインターネットゲートウェイの作成等が必要となります。

README.mdに従い事前準備ができたら、Ansible Playbookでcontrol planeとworker nodeを構築します。

control planeの構築

ansible-playbook site_control-plane.yml

worker nodeの構築

ansible-playbook site_worker.yml

構築完了後、control planeノードにSSH等で接続すると、以下のようにKubernetesが出来上がっているのを確認できます。今回ケースでは、control planeのホスト名はip-10-0-0-5です。

(control planeで実行)
$ kubectl get pod -A
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   coredns-5dd5756b68-r9gdq              0/1     Pending   0          41m
kube-system   coredns-5dd5756b68-zhksc              0/1     Pending   0          41m
kube-system   etcd-ip-10-0-0-5                      1/1     Running   0          42m
kube-system   kube-apiserver-ip-10-0-0-5            1/1     Running   0          42m
kube-system   kube-controller-manager-ip-10-0-0-5   1/1     Running   0          42m
kube-system   kube-proxy-96bcm                      1/1     Running   0          41m
kube-system   kube-proxy-ghl74                      1/1     Running   0          39m
kube-system   kube-scheduler-ip-10-0-0-5            1/1     Running   0          42m

(4) CNIのインストール

Kubernetes内のネットワークを設定するためのツールをインストールします。今回はFlannelを使ってみます。(後述しますがCalicoだとうまくいかずに断念しました...)

セキュリティグループにFlannel関連のルールを追加

こちらを参考に、Flannelがノード間で通信を行えるようにするため、以下のルールを追加します。

通信の方向 プロトコル ポート番号 用途 通信許可するIP範囲
inbound UDP 8472 flannel overlay network - vxlan backend 全てのノード

※ Flannelの設定によっては8472ではなく、8285を開ける必要があるかもしれません

Flannelのデプロイ

Flannelのマニフェストkube-flannel.ymlで編集が必要な部分があるため、一旦control planeにマニフェストをダウンロードします。

(control planeで実行)
sudo apt -y install wget
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

ダウンロードしたkube-flannel.ymlで、PodのCIRDの値をkubeadm initコマンドで設定したものに変更します。

vi kube-flannel.yml
kube-flannel.yml
...
  net-conf.json: |
    {
      "Network": "10.244.0.0/16", # 設定したPodのCIDRに変更
      "Backend": {
        "Type": "vxlan"
      }
    }
...

修正したFlannelのマニフェストをapplyします。

$ kubectl apply -f kube-flannel.yml
(実行結果)
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

Flannelのリソースが新たにデプロイされているのを確認できれば成功です。

$ kubectl get pod -n kube-flannel
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-c2d6d   1/1     Running   0          37s
kube-flannel-ds-cntpk   1/1     Running   0          37s

以上でEC2インスタンス上にKubernetesを構築できました🙌

構築で行き詰まった点

ほぼ筆者の備忘メモなので読み飛ばしていただいてもいいです。

containerdの設定不備でkube-apiserverが立ち上がらない...

今回はコンテナランタイムでcontainerdを使いましたが、aptでcontainerdをインストールしただけのデフォルトの状態だと、kube-systemのPodが以下のようにリスタートを繰り返してKubernetesが正常稼働しない事態になりました。

$ kubectl get po -A
NAMESPACE     NAME                                  READY   STATUS    RESTARTS       AGE
kube-system   coredns-5dd5756b68-8jgt4              0/1     Pending   0              3m25s
kube-system   coredns-5dd5756b68-9wq97              0/1     Pending   0              3m25s
kube-system   etcd-ip-10-0-0-5                      0/1     Running   106 (9s ago)   2m25s
kube-system   kube-apiserver-ip-10-0-0-5            0/1     Running   80 (25s ago)   4m40s
kube-system   kube-controller-manager-ip-10-0-0-5   0/1     Running   96 (9s ago)    2m43s
kube-system   kube-proxy-8bwp7                      1/1     Running   3 (3s ago)     3m25s
kube-system   kube-scheduler-ip-10-0-0-5            0/1     Running   108 (9s ago)   5m15s

調査と試行錯誤した結果、「今回使ったAMIのデフォルト設定だとsystemdがcgroupドライバーを使うようにする必要があるのに、containerdの設定はそうなっていない」ことがわかりました。そこで以下の対応を行い解決できました。

containerdの設定ファイルを作成

$ sudo su -
# containerd config dump > /etc/containerd/config.toml
# logout

作成した設定ファイルで、SystemdCgroupの値がfalseになっているのをtrueに変更する

sudo vi /etc/containerd/config.toml

以下のように変更

/etc/containerd/config.toml
...
            SystemdCgroup = true
...

containerdおよびkubeleteのサービスをrestart

sudo systemctl restart containerd
sudo systemctl restart kubelet

参考情報 

CNIがCalicoだと異なるノードのPodが通信できない(未解決)

Quickstart for Calico on Kubernetes筆者記事にしたがってCNIをCalicoで作ろうとしましたが、どうやっても異なるノードのPod同士が通信できなくて断念しました...

試してみたことは以下です。

  • Calicoバージョンを以下のように変えてみる
    • v3.27.0(現時点の最新), v3.26.4, v3.24.6
  • Installationリソースのパラメータ spec.calicoNetwork.ipPools[].encapsulationVXLANCrossSubnetからIPIPに変えてみる

怪しいと思っている部分はネットワークのルーティングに関する設定で、以下に具体的に説明します。

既にCalicoの構築に成功しているK8sクラスター上では、vxlan.calicoというネットワークインターフェースがあり、ここを経由するネットワーク経路が以下のように定義されていました。

$ sudo ip route | grep vxlan
10.128.75.0/26 via 10.128.75.1 dev vxlan.calico onlink
...

一列目のCIDR(10.128.75.0/26等)は、PodのCIDRの範囲に含まれています。

このルートがEC2インスタンスで構築した場合だと存在せず、代わりに以下のように ens5というAWSサブネットのインターフェースに紐づけられています。

$ sudo ip route | grep onlink
192.168.91.64/26 via 10.0.0.5 dev ens5 proto 80 onlink

ちなみにEC2インスタンスのノード上にもvxlan.calicoのインターフェースは作られているのですが、それを使うルートは一つも定義されていません。

ヤマ勘なので間違っている可能性が高いのですが「本当はこのルートはens5ではなくて、vxlan.calicoに作られるべきなのでは?」というのが現状の考えです。

これに関連しそうな内容をGitHubのissueで見つけました。まだあまりやり取りされていないようなので、今後の解決を期待したいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0