Oracle Cloud（OCI）でのkubernetesクラスター構築

Oracle CloudのFree Tier（無料枠）が充実しているので、無料枠の範囲でkubernetesクラスターを構築してみます。
ほぼ、参考の記事をなぞって、そのあと自動化しています。

# 追記 2024.08.10
手順が複雑のため、TerraformとAnsibleで自動化しました。
- https://github.com/mzstrszk/oci_k8s-cluster

# 参考

- [Oracle Cloudの無料枠でKubernetesクラスタを構築する(完全版)](https://blog.potproject.net/2021/06/01/oracle-cloud-kubernetes/)
- [kubeadmのインストール](https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)

# Free Tier

- Oracle Cloud Compute
    - AMDプロセッサベースの、1/8OCPUと1GBのメモリーを搭載した2つの仮想マシン（OCPUとは、ハイパースレッディングが有効なXeonプロセッサの1物理コア相当のCPU性能）
    - ArmベースのAmpere A1コアを4つ搭載した24GBメモリのマシンで、仮想マシンを最大4つまで、1か月あたり3000OCPU時間と18000GB時間で利用可能
- Oracle Cloud Storage
    - 合計200GBまでの2つのブロックストレージボリューム
    - 10GBのオブジェクトストレージ
    - 10GBのアーカイブストレージが利用可能
- Oracle Autonomous Database
    - Autonomous Transaction Processing、Autonomous Data Warehouse、Autonomous JSON Database、APEX Application Developmentのうち、2つのデータベースそれぞれに1OCPUと20GBのストレージを利用可能
    - 1カ月あたりの読み取り数が1億3300万、1カ月あたりの書き込み数が1億3300万、1テーブルあたりのストレージが25GB、最大3つのテーブルを備えるNoSQLデータベースが利用可能
- 他
    - [https://www.oracle.com/jp/cloud/free/](https://www.oracle.com/jp/cloud/free/)

# k８sクラスターの構築

## コンピュート・インスタンスの作成

以下のインスタンスを作成する。

| インスタンス名 | CPU | メモリ | ブート・ボリューム | イメージ | Shape | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| k8s-master | 2 | 12GB | 47GB | Ubuntu 20.04 | Ampere（ARM） | マスターノード、コントロールプレーン |
| k8s-worker01 | 1 | 6GB | 47GB | Ubuntu 20.04 | Ampere（ARM） | ワーカーノード |
| k8s-worker02 | 1 | 6GB | 47GB | Ubuntu 20.04 | Ampere（ARM） | ワーカーノード |
- インスタンス作成時に以下を行う
    - イメージはUbuntu20.04、ShapeはAmpereのVM.Standard.A1.Flexを指定する
        - Ubuntu 22.04で構築すると動作が不安定であったため、20.04で構築した
        - マスター、ワーカーでCPUとメモリを変えている
    - 新規の仮想クラウド・ネットワーク、新規サブネットを作り、マスター、ワーカー共に同じネットワークに所属させる
    - プライベートIPv4アドレスの自動割り当て、パブリックIPv4アドレスの自動割り当てにチェックを入れる
    - Block Volumeはデフォルトでブートボリュームが46.6GB割り当てられる
    - ブロック・ボリュームはアタッチしなくて良い

## セキュリティリストの設定

設定した仮想クラウド・ネットワークのセキュリティ・リストに以下を設定する。

| 方向 | ソースタイプ | ソース | IPプロトコル | ソースポート範囲 | 宛先ポート範囲 |
| --- | --- | --- | --- | --- | --- |
| イングレス | CIDR | 10.0.0.0/16 | TCP | All | 6443 |
| イングレス | CIDR | 10.0.0.0/16 | TCP | All | 2379-2380 |
| イングレス | CIDR | 10.0.0.0/16 | TCP | All | 10250 |
| イングレス | CIDR | 10.0.0.0/16 | TCP | All | 10259 |
| イングレス | CIDR | 10.0.0.0/16 | TCP | All | 10257 |
| イングレス | CIDR | 0.0.0.0/0 | TCP | All | 30000-32767 |

## ネットワーク・セキュリティ・グループの設定

設定した仮想クラウド・ネットワークのネットワーク・セキュリティ・グループを設定し、インスタンスのプライマリVNICに割り当てる。

1. ネットワーク・セキュリティ・グループに以下を作成する
    - マスターノード用: k8s_,master
        
        
        | 方向 | ソース/宛先タイプ | ソース | IPプロトコル | ソースポート範囲 | 宛先ポート範囲 |
        | --- | --- | --- | --- | --- | --- |
        | エグレス | CIDR | 0.0.0.0/0 | すべて | すべて | すべて |
        | イングレス | NSG | k8s_worker | TCP | All | 6443 |
        | イングレス | NSG | k8s_worker | TCP | All | 2379-2380 |
        | イングレス | NSG | k8s_worker | TCP | All | 10250 |
        | イングレス | NSG | k8s_worker | TCP | All | 10259 |
        | イングレス | NSG | k8s_worker | TCP | All | 10257 |
    - ワーカーノード用: k8s_worker
        
        
        | 方向 | ソースタイプ | ソース | IPプロトコル | ソースポート範囲 | 宛先ポート範囲 |
        | --- | --- | --- | --- | --- | --- |
        | エグレス | CIDR | 0.0.0.0/0 | すべて | すべて | すべて |
        | イングレス | NSG | k8s_master | TCP | All | 10250 |
        | イングレス | CIDR | 0.0.0.0/0 | TCP | All | 30000-32767 |
2. インスタンスに作成したネットワーク・セキュリティ・グループを割り当てる

## インストールの準備

各ノードでインストールの準備を行う。

```bash
# システムアップデート
sudo apt update && sudo apt upgrade -y

# スワップの無効化
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# 必要なカーネルモジュールのロード
cat <<EOF | sudo tee /etc/modules-load.d/99-kubernetes-cri.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# ブリッジネットワークを通過するパケットをiptablesの処理対象にする。
# IP フォワーディングを有効にする。
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system
```

## iptablesの設定

マスターノード、ワーカーノードで必要なポートを開放する。OCIのUbuntuではufwは非推奨のようなので停止する。

- マスターノード
    
    ```bash
    # ufwの無効化
    sudo systemctl disable --now ufw
    
    # iptablesのルールを編集
    sudo vim /etc/iptables/rules.v4
    
    # ポート22の下に、以下を追加
    ---
    -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 10259 -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 10257 -j ACCEPT
    ---
    
    sudo iptables-restore < /etc/iptables/rules.v4
    ```
    
- ワーカーノード
    
    ```bash
    # ufwの無効化
    sudo systemctl disable --now ufw
    
    # iptablesのルールを編集
    sudo vim /etc/iptables/rules.v4
    
    # ポート22の下に、以下を追加
    ---
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 10250 -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --match multiport --dports 30000:32767 -j ACCEPT
    ---
    
    sudo iptables-restore < /etc/iptables/rules.v4
    ```
    

## コンテナランタイムのインストール

各ノードにcontainerdをインストールする。

```bash
# 依存関係のインストール
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg

# Dockerの公式GPGキーを追加
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Dockerのリポジトリをaptソースに追加
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
 
# containerdのインストール
sudo apt update
sudo apt install -y containerd.io

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

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

各ノードにkubernetesの各パッケージをインストールする。

```bash
# Kubernetesの公式GPGキーを追加
sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# Kubernetesのリポジトリを追加
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# kubeadm、kubelet、kubectlのインストール
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
```

## k8sクラスターの初期化とマスターノードの設定

マスターノードにて、k8sクラスターの初期化とマスターノードの設定を行う。

1. マスターノードでk8sクラスターを初期化する
    
    ```bash
    sudo kubeadm init --pod-network-cidr=10.244.0.0/16
    ```
    
2. 初期化が完了したら、表示される指示に従ってkubeconfigを設定する
    
    ```bash
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    # kubeletリスタート
    sudo systemctl daemon-reload
    sudo systemctl restart kubelet
    
    # ノードを確認する。
    kubectl get node
    # マスターノードのみ表示される。
    ```
    
3. ネットワークプラグインをインストールする
    
    ```bash
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    ```
    

## ワーカーノードの追加

各ワーカーノードにて、マスターノードの初期化時に表示されたコマンドを実行し、クラスターに追加する。

```bash
sudo kubeadm join <master-node-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
```

## 稼働確認

以下のコマンドで稼働状況を確認する。

```yaml
kubectl get nodes
# ノードの状態を確認（3つのノードがReady）

kubectl get pods -n kube-system
# k8sシステム関連のpodの状態を確認（全てがRunning）
```

# nginxデプロイ

k8sクラスターに、nginx Webサーバーをデプロイする。

1. 仮想クラウド・ネットワークのセキュリティ・リスト、ワーカーノードのネットワーク・セキュリティ・グループに以下を設定する
    
    
    | 方向 | ソースタイプ | ソース | IPプロトコル | ソースポート範囲 | 宛先ポート範囲 |
    | --- | --- | --- | --- | --- | --- |
    | イングレス | CIDR | 0.0.0.0/0 | TCP | All | 30080 |
2. 設定ファイルを作成する
    - レプリカは2
    - NodePortは30080
    
    ```bash
    vim nginx-sample.yaml
    ```
    
    ```yaml
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.14.2
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
    spec:
      type: NodePort
      selector:
        app: nginx
      ports:
        - port: 80
          targetPort: 80
          nodePort: 30080
    ```
    
3. 設定ファイルを適用する
    
    ```bash
    kubectl apply -f nginx-sample.yaml
    # deployment.apps、serviceを作成したログが出る。
    ```
    
4. 正常に稼働していることを確認する
    
    ```bash
    kubectl get pods
    
    NAME                                READY   STATUS    RESTARTS   AGE
    nginx-deployment-1111111111-xxxxx   1/1     Running   0          24s
    nginx-deployment-2222222222-xxxxx   1/1     Running   0          24s
    ```
    

5. http://<ワーカーノードのパブリックIP>:30080 でアクセスできることを確認する