Oracle Cloudの無料枠でKubernetesクラスタを構築する(完全版)

Oracle Cloudの無料枠でKubernetesクラスタを構築する(完全版)

author potpro(ぼとぷろ)
2021/06/01

Oracle Cloudの無料枠でKubernetesクラスタを構築する(完全版)

前回の記事はこちらです。この記事は前回の記事のリマスターみたいなものとなっております。

読む必要はありませんが、この記事よりも詳しく用語の説明をしている部分もあるため、読んだ方が問題が解消できるかもしれません。

Oracle Cloudの無料枠だけでKubernetes(k3s)クラスタを構築する

この記事にて、Kubernetesクラスタを作成してから1年と半年ほど・・・

1年くらいはノーメンテで動作していることを確認していました。

しかし・・・1年を超えたくらいで動作しなくなってしまいまして、やはりスペック に関しては非常に厳しいものがあったようです。

kubectl打ってタイムアウトになってしまうこともしばしばあり、当然ながら実用的にアプリケーションを動作させるのは無理だな、ということでそのまま放置しちゃっていました。

そして時が過ぎて、いきなりすごいニュースが自分のTLに流れてきました。

オラクル、OCIで“1コア=1セント/時間”のArmベースインスタンスを発表

まずはAlways Free Armサービスだ。これまでOCIでは20以上のサービスにおいてAlways Free(永久無償枠)サービスを提供してきたが、今回ここにAmpere A1 Computeが加わる。具体的には、4 OCPU/メモリ24GBまでのAmpere A1 Computeインスタンスが、無料で永続的に利用できる。

4 OCPU/メモリ24GB

え????メモリ24GBのインスタンスがAlways Free???何考えてんだOracle???

とまあ、詐欺や落とし穴を疑うレベルでした。だってメモリ24GBって普通に借りるだけでもめちゃくちゃ高いよ?ARMインスタンスだとしてもさあ。

これはもう、やるしかない、ということで仕事も放り出す勢いで試してました。

Oracle Cloud Always Free(Ampere)

結論から言うと詐欺なんかではありませんでした。当然ですが・・・

調べていく中でAlways Freeで使用できるリソースは、簡単に言うとこんな感じ。

Always Free Resources

  • 前の記事で作ったVM(VM.Standard.E2.1.Micro x2)はそのまま使用可能
  • エフェメラルパブリックIPアドレス(自動的に付けられるPublicIP)が2つまで使用可能
  • 予約済パブリックIPアドレス(付け替え可能なPublicIP)は1つまで使用可能になっているので、上の項目と合わせて__実質PublicIP3つ__まで、課金アカウントにすると50まで増える
  • Block Volumeは最大100200GBまで、VM1台に自動で50GB使用される、超えると課金なので注意(少しやらかした)
  • 新しいARM VM(VM.Standard.A1.Flex)は、立ち上げ可能なOSが制限されている、Ubuntu、Oracle Linuxなどが使用可能
  • VM.Standard.A1.FlexのAlways Free 枠は4 OCPU/24 GBを自由に割り当てて使用できる ←ここ重要

※追記 Block Volumeは最大200GBまでと書いていたのですが、100GBまでの間違いでした。そのため、1台に50GBは必要のため、3台以上稼働させるとBlock Volumeの課金対象となります。

※更に追記 Block VolumeのFree Tierがこっそり変更されて、200GBに増量されました。これで4台立てても完全に無料枠に収まるので問題ありません。

最後の項目が重要なのですが、つまりどういうことかというと・・・

__4 OCPU/メモリ24 GBのVM1台の構成__でも、__1 OCPU/メモリ6 GBのVM4台__でも、Always Free枠で建てることができるってことです。

Because the VM.Standard.A1.Flex shape is a flexible shape, you can customize the number of OCPUs and amount of memory that are allocated when you create or resize an instance. You can use all of the Always Free OCPUs and memory to create a single instance, or create multiple smaller instances that each use a portion of the resources.

これに追及している人は気づいていないのか見ていないのですが、これもすごすぎませんか・・・?

無料で4台サーバ借りれるんですよ???大丈夫か?本当にお金取られない?って思います。

つまり、数台構成のクラスタを立ててみるというようなことも可能ということです。

今回の要件にピッタリ。ということで、ちゃんと複数台のクラスタを組みます。

今回の構成

Always Free枠を生かして、今回はこんな構成にします。

oc

  • ocloud-potproject-arm1 2 OCPU / Mem 12GB (マスター、コントロールブレーンノード)
  • ocloud-potproject-arm2 1 OCPU / Mem 6GB (ワーカーノード)
  • ocloud-potproject-arm3 1 OCPU / Mem 6GB (ワーカーノード)

の3台構成です。OSは今回Ubuntu 20.04を使用しています。

本当に立てれました。しかし、前回と同じく空きインスタンスが無い場合には__Out of Capacity__エラーで起動することができないことがあります。

数時間待って、根気よくトライしていればいつかは獲得できます。戦争です。Japan East(東京)リージョンは激戦区ですが、話によるとまだ東京よりは人の少ないJapan Central(大阪)リージョンが狙い目だとか。

kubeadm

前回は軽いという判断でk3sを使用しましたが、今回はスペック十分ということで公式で推奨されているkubeadmを使用して構築できます。

kubeadmを使用してのクラスタの構築は、公式サイトにも乗っているのでやりやすいです。

kubeadmを使ってクラスターを構築する

実はほぼここに書いてあることをやっているので、構築方法に関しては一緒と思います。

構築(全VM共通)

sshで接続する部分などは省略します。また、基本的に3台ともPublicIPを設定しています。

Oracle CloudのVMは、基本的にPublicIPを持っていないとインターネットに接続できないためです。

iptablesがブリッジを通過するトラフィックを処理できるようにする

modprobe br_netfilter
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

iptablesがnftablesバックエンドを使用しないようにする

Ubuntu 20.04はデフォルトで iptables v1.8.4 (legacy) だったので設定不要。

ポート許可

Oracle Cloudは最初からiptablesがかなり厳しく設定されており、内部ネットワークでもTCPポートは22以外ほぼ遮断されています。

iptablesを抹消してもいいのですが、ちゃんと設定します。

しかもOracle Cloudはufwなどのコマンドがうまく動作しないため、iptablesを直接いじってiptables-restoreするのが手っ取り早いので、この方法を取っています。

/etc/iptables/rules.v4を編集します。

この部分を-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPTの後くらいに追加します。

-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2379 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2380 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10250 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10251 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10252 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --match multiport --dports 30000:32767 -j ACCEPT

全て、Kubernetesで開放が必要なポートとなります。

また、reject-with icmp-host-prohibitedの設定が存在すると、no route no hostでcurlなどで接続できなくなってしまうので、この2つを削除します。

-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited

その後、iptablesを更新します。永続化もされます。iptables -Sで確認ができます。

sudo iptables-restore < /etc/iptables/rules.v4

containerdのインストール

Dockerをわざわざインストールする必要もないので、推奨されているコンテナランタイムであるcontainerdだけインストールします。

# 設定
cat > /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

# 必要なカーネルパラメータの設定をします。これらの設定値は再起動後も永続化されます。
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system

# (containerdのインストール)
## リポジトリの設定
### HTTPS越しのリポジトリの使用をaptに許可するために、パッケージをインストール
apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common

## Docker公式のGPG鍵を追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

## Dockerのaptリポジトリの追加
add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"

## containerdのインストール
apt-get update && apt-get install -y containerd

# containerdの設定
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

kubeadm、kubelet、kubectlのインストール

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

sudo apt-get update

sudo apt-get install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl

kubeletの起動

systemctl daemon-reload
systemctl restart kubelet

これで全てのVMの共通する処理は完了です。この時点でKubernetesクラスタの要件は整っている感じになります。

構築(マスターのみ)

Kubernetesマスター・コントロールプレーンの作成

kubeadmを使用すると、ほぼ1コマンドでクラスタを作成してくれます。

sudo kubeadm init --pod-network-cidr=10.244.0.0/16

これでクラスタが立ち上がりましたので、kubectlが使用可能になるはずです。 ここで失敗した場合は、何か足らないものがあるはず。

成功した場合、

kubeadm join XX.XX.XX.XX:6443 --token XXXX.XXXX \
        --discovery-token-ca-cert-hash sha256:XXXX

というようなコマンドが表示されます。

これを、ワーカーノードで打ち込むと、ワーカーとしてクラスタに追加させることができます。

kubectl設定

# ユーザからコマンドを実行できるように作成
# ここからubuntuユーザに戻る
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get node
# > ubuntu@ocloud-potproject-arm1:~$ kubectl get node
# NAME                     STATUS   ROLES                  AGE     VERSION
# ocloud-potproject-arm1   NotReady control-plane,master   1h      v1.21.1

このようになっていればマスタークラスタはOKです。まだNotReadyのままで問題ないです。

構築(ワーカーのみ)

workerノードは、実際にPodなどが動作するノードとなります。 今回はocloud-potproject-arm2,ocloud-potproject-arm3となります。

ワーカーノードの作成

Kubernetesマスター・コントロールプレーンの作成で出てきたkubeadm joinのコマンドを打ち込むと、クラスタに追加されます。

マスターでkubectl get nodeを打つと、追加されていることが確認できるはずです。

kubectl get node
# > ubuntu@ocloud-potproject-arm1:~$ kubectl get node
# NAME                     STATUS   ROLES                  AGE     VERSION
# ocloud-potproject-arm1   NotReady control-plane,master   1h      v1.21.1
# ocloud-potproject-arm2   NotReady <none>                 1h      v1.21.1
# ocloud-potproject-arm3   NotReady <none>                 1h      v1.21.1

flannelのインストール

これでクラスタの構築は完了と思いきや、Pod同士が通信するためのネットワークアドオンを導入しないとまだPod間の通信が出来ない状態になっています。

Podの状態を確認しても、まだCoreDNSがRunningになっていません。

ubuntu@ocloud-potproject-arm1:~$ kubectl get pods -n kube-system
NAME                                             READY   STATUS    RESTARTS   AGE
coredns-558bd4d5db-nqjj5                         0/1     Pending   0          153m
coredns-558bd4d5db-qwsdm                         0/1     Pending   0          153m
etcd-ocloud-potproject-arm1                      1/1     Running   0          153m
kube-apiserver-ocloud-potproject-arm1            1/1     Running   0          153m
kube-controller-manager-ocloud-potproject-arm1   1/1     Running   0          153m
kube-proxy-g9xvn                                 1/1     Running   0          91m
kube-proxy-jxkt9                                 1/1     Running   0          153m
kube-proxy-zdxng                                 1/1     Running   0          89s
kube-scheduler-ocloud-potproject-arm1            1/1     Running   0          153m

そのため、flannelというOSSのネットワークアドオンの導入をします。

本当は、公式に書いてあるCalicoをインストールしたかったのですが、ARM64アーキテクチャで問題があるようでインストールに失敗したため、今回はflannelにしています。

このコマンドでflannelをデプロイします。正常に完了すれば、全てPodはRunningになり、nodeはReadyになるはずです(時間が少しかかります)。

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
ubuntu@ocloud-potproject-arm1:~$ kubectl get pods -n kube-system
NAME                                             READY   STATUS    RESTARTS   AGE
coredns-558bd4d5db-nqjj5                         1/1     Running   0          4d2h
coredns-558bd4d5db-qwsdm                         1/1     Running   0          4d2h
etcd-ocloud-potproject-arm1                      1/1     Running   0          4d2h
kube-apiserver-ocloud-potproject-arm1            1/1     Running   0          4d2h
kube-controller-manager-ocloud-potproject-arm1   1/1     Running   0          4d2h
kube-flannel-ds-8mgz5                            1/1     Running   0          3d23h
kube-flannel-ds-d7v5f                            1/1     Running   0          3d23h
kube-flannel-ds-tsrcz                            1/1     Running   0          3d23h
kube-proxy-g9xvn                                 1/1     Running   0          4d1h
kube-proxy-jxkt9                                 1/1     Running   0          4d2h
kube-proxy-zdxng                                 1/1     Running   0          3d23h
kube-scheduler-ocloud-potproject-arm1            1/1     Running   0          4d2h
kubectl get node
# > ubuntu@ocloud-potproject-arm1:~$ kubectl get node
# NAME                     STATUS   ROLES                  AGE     VERSION
# ocloud-potproject-arm1   Ready    control-plane,master   1h      v1.21.1
# ocloud-potproject-arm2   Ready    <none>                 1h      v1.21.1
# ocloud-potproject-arm3   Ready    <none>                 1h      v1.21.1

これで、本当にクラスタの完成です。お疲れさまでした。

Oracle Cloud側でのインターネットアクセスの許可

アタッチされたVNIC->イングレス・ルールより、インターネット側のアクセスを許可します。 具体的には、この辺りを許可にするとよいです。

  • 0.0.0.0/0 TCP 22 Port(デフォルト許可)
  • 0.0.0.0/0 ICMP 3,4,8
  • 10.0.0.0/16 すべて(内部ネットワークなので)
  • 0.0.0.0/0 TCP 30080

今回NodePortの30080のみ使用するので、30080だけ公開にしています。 Kubernetes API serverのTCP 6443はアクセスされると困るので、外部公開してはいけません。

Webサービスのデプロイと公開(NodePort)

前回と同じように、NodePortで動かしたコンテナがデプロイ&公開できるか、確認しましょう。

今回はcontainous/whoamiイメージをデプロイします。前に紹介したコンテナは、ARM64で動作しなかったため、これになりました。

apiVersion: v1
kind: Service
metadata:
  name: whoami-service
  labels:
    app: whoami
spec:
  selector:
    app: whoami
  type: NodePort
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
    nodePort: 30080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami-deployment
spec:
  selector:
    matchLabels:
      app: whoami
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
      - name: whoami
        image: containous/whoami
        ports:
        - containerPort: 80

デプロイが完了するのを待ちます。

ubuntu@ocloud-potproject-arm1:~$ kubectl get deployment
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
whoami-deployment   2/2     2            2           3m12s

完了したら、内部的と外部で接続が出来ているはずです。 Oracle Cloud側の設定もできていれば、外部からでもアクセス可能です。

ubuntu@ocloud-potproject-arm1:~$ curl [arm2のプライベートIPアドレス]:30080
Hostname: whoami-deployment-7548d6596b-kctgr
<略>

occloudchr

おわりに

今回は、やはりスペックもかなり高くなっているということで、動作に不満のようなものは一切ありませんでした。

そのまま運用していてもかなり安定しています。

というより、本当にスペックが高すぎるので、普通にWebサーバの運用もできそうな気持ち。

本編では言ってませんでしたが、UnixBenchでベンチマークを取ったところ、4 OCPU / 24GBはSingle: 1856.1、Multi: 3829.3というパフォーマンスをたたき出していて、__月4000円相当のVPSと同等の性能__という結果に。

ちなみに、前回使用したVM.Standard.E2.1.MicroはSingle: 400、Multi: 500くらいでした。ちょっと性能向上がおかしい。

x86とARMアーキテクチャで違うので、単純に比較するのは微妙ですが、本当にこんなの無料で使っていいんですかね?Oracleさん?大企業ってすげえや・・・と思いました。