概要

  • こんにちわ、新川です。Oracle Cloud Infrastructure (OCI) のOKE に入門中です。OKE は、正式名称「Oracle Cloud Infrastructure Container Engine for Kubernetes」。OCI が提供するマネージドのKubernetes サービスで、コンテナ化されたアプリケーションを構築し、運用・管理を容易にするサービスです。
  • 今回は、OKE のクラスタを作成、Nginx コンテナをデプロイしてロードバランサー経由でインターネットに公開するまでの手順をハンズオン形式で詳しく解説します。

 

ハンズオンのシナリオ

  • 今回のハンズオンでは、以下のゴールを目指します。
    • ハンズオン1:ネットワークやセキュリティリストの作成、kubectl など環境の準備を行う。
    • ハンズオン2:既存のネットワークに、無料枠を活用したコスト効率の良いOKE クラスタ(Basic Cluster + シェイプ:VM.Standard.A1.Flex のノード)を構築する。
    • ハンズオン3:Nginx コンテナをデプロイし、Serviceリソースをtype: LoadBalancer で作成、OCI のロードバランサー経由でインターネットに公開する。
    • ハンズオン4:curlコマンドで、公開したNginxにアクセスし、正常な応答を確認する。
    • ハンズオン5:後片付け。

 

前提条件

 

OKE 構築のハンズオン

ハンズオン1:環境を準備する

kubectl のインストール

  • ローカル端末に、kubectl のインストールを行います。
$ cd /tmp
$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   138  100   138    0     0    557      0 --:--:-- --:--:-- --:--:--   556
100 57.7M  100 57.7M    0     0  16.7M      0  0:00:03  0:00:03 --:--:-- 19.8M

$ ls -l kubectl
-rw-r--r-- 1 niikawa niikawa 60559544 Aug 28 09:15 kubectl

$ sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

$ which kubectl
/usr/local/bin/kubectl

$ kubectl version --client
Client Version: v1.34.0
Kustomize Version: v5.7.1

 

VCN、サブネットの作成

  • OKE クラスタ、コントロールプレーンを配置するVCN を作成します。
  • 以下のブログを参考に、VCN(vcn01)、パブリックサブネット(subnet01)、プライベートサブネット(subnet02)を作成します。

 

セキュリティリストにIngress Rules 追加

  • セキュリティリストに以下2つのIngress Rules を追加します。
    • お使いのPC(アクセス元)からOKE クラスタのKubernetes API endpoint へ通信を行うため、Ingress Rulesにお使いのPCのパブリックIP アドレスからTCP/ 6443 への通信を許可します。
    • ノードプール内の各ノードとクラスタ(コントロールプレーン)間の通信ができるように許可します。(以下の例では、Source CIDRにVCNのCIDRを指定、DestinationのPortにAll を指定しています)
  • 上記はハンズオン用の設定です。実案件では、ネットワーク要件の確認を行ってください。こちらのOracle Cloud Infrastructureドキュメントを参照してください。

 

 

ハンズオン2:OKE クラスタを構築する

  • OCIの管理コンソールにて、左ナビゲーションから「Developer Services」→「Kubernetes Clusters (OKE)」を選択します。
  • 「Create cluster」を選択します。

 

  • 以下の画面で、「Custom create」を選択し、「Submit」を選択します。

 

  • クラスタの設定を行います。「Name」、「Compartment」、「Kubernetes version」を指定します。

 

  • Network typeに、「VCN-native pod networking」を選択します。
  • クラスタのネットワークとして、VCN および Kubernetes API endpoint subnet を選択します。今回は、サブネットにパブリックサブネット(subnet01)を選択します。

 

  • Kubernetes API endpointの Public IPv4 address assign をチェックします。

 

  • Load balancer subnets を選択します。今回は、サブネットにパブリックサブネット(subnet01)を選択します。

 

  • Node Pool の設定を行います。「Name」、「Compartment」の指定、「Node type」に「Managed」を選択します。

 

  • Node Placement Configuration の設定を行います。Availability domainの指定、Worker nodeのサブネットを選択します。今回は、サブネットにプライベートサブネット(subnet02)を選択します。

 

  • Shape and image の設定を行います。今回はNode shapeに「VM.Standard.A1.Flex」を選択します。

 

  • Node pool options の設定を行います。Node count は「1」を指定します。

 

  • Boot volume の設定はデフォルトとします。
  • Pod communication の設定を行います。Pod のサブネットを選択します。今回は、サブネットにプライベートサブネット(subnet02)を選択します。

 

  • Review の画面が表示されます。内容を確認し、「Create a Basic cluster」のチェックを付けます。
  • 「Create cluster」を選択します。

 

  • クラスタの作成が開始されたことを確認します。

 

  • クラスタの作成が完了し、Cluster status が Active になることを確認します。

  • 続けて、ノードプールの作成が完了し、Node pool status が Active になることを確認します。

 

  • ローカル端末からクラスタに接続するため、「Access Cluster」を選択します。
  • 以下の画面が表示されます。「Local Access」を選択します。画面の指示に従い、ローカル端末で操作を行います。

 

  • 以下、操作例です。
$ oci -v
3.65.0

$ ls -l $HOME/.kube
ls: cannot access '/home/niikawa/.kube': No such file or directory

$ mkdir -p $HOME/.kube

$ oci ce cluster create-kubeconfig --cluster-id ocid1.cluster.oc1.ap-tokyo-1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --file $HOME/.kube/config --region ap-tokyo-1 --token-version 2.0.0  --kube-endpoint PUBLIC_ENDPOINT
Private key passphrase:
New config written to the Kubeconfig file /home/niikawa/.kube/config

$ echo "export KUBECONFIG=$HOME/.kube/config" >> .bash_profile

  • kubectl コマンドを実行し、クラスタへの接続が成功したことを確認します。

 

$ kubectl get nodes
Private key passphrase:
NAME        STATUS   ROLES   AGE    VERSION
10.0.1.26   Ready    node    110m   v1.33.1

 

 

トラブルシューティング①

  • クラスタへの接続(oci ce cluster create-kubeconfigコマンド)を行った後、kubectl コマンドで以下のエラーが出力され、タイムアウトとなる。
$ kubectl get nodes
Private key passphrase:
E0829 10:46:46.080259    3167 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://161.33.155.81:6443/api?timeout=32s\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)"
E0829 10:47:16.081223    3167 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://161.33.155.81:6443/api?timeout=32s\": dial tcp 161.33.155.81:6443: i/o timeout"
E0829 10:47:46.082455    3167 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://161.33.155.81:6443/api?timeout=32s\": dial tcp 161.33.155.81:6443: i/o timeout"
E0829 10:48:16.083420    3167 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://161.33.155.81:6443/api?timeout=32s\": dial tcp 161.33.155.81:6443: i/o timeout"
E0829 10:48:46.084191    3167 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://161.33.155.81:6443/api?timeout=32s\": dial tcp 161.33.155.81:6443: i/o timeout"
Unable to connect to the server: dial tcp 161.33.155.81:6443: i/o timeout

 

  • 原因はお使いのPC(アクセス元)からOKE クラスタのKubernetes API endpoint へ通信が許可されていないことです。ハンズオン1 を確認し、セキュリティリストにIngress Rules を追加します。

 

トラブルシューティング②

  • ノードプールの作成は完了したが、ノードの「Node state」が「Updating」となり、「Kubernetes node condition」が「Unavailable」と出力される。

  • 原因は、ノードとクラスタ(コントロールプレーン)間の通信が許可されておらず、ノードがノードプールに参加できないことです。ハンズオン1 を確認し、セキュリティリストにIngress Rules を追加します。
  • ノードからコントロールプレーンへ通信が成功すると、ノードの「Node state」が「Active」となり、「Kubernetes node condition」が「Ready」と出力されます。

 

ハンズオン3:Nginx デプロイとロードバランサー経由で公開する

  • Nginx のpod を起動するdeployment リソースを作成します。kubectl create deployment コマンドを使用します。
  • 補足として、このコマンドでデプロイが行われると、deployment リソースには、自動でlabel、selector に「nginx-deployment」が付与されます。
$ kubectl get nodes
Private key passphrase:
NAME        STATUS   ROLES   AGE   VERSION
10.0.1.26   Ready    node    14h   v1.33.1

$ kubectl get deployment
Private key passphrase:
No resources found in default namespace.
$ kubectl get pods
Private key passphrase:
No resources found in default namespace.

$ kubectl create deployment nginx-deployment --image=nginx
Private key passphrase:
deployment.apps/nginx-deployment created
$ kubectl get deployment
Private key passphrase:
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   0/1     1            0           13s
$ kubectl get pods
Private key passphrase:
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-6cfb98644c-kgnxn   1/1     Running   0          27s

 

  • Nginx をロードバランサー経由で公開するためのservice リソースを作成します。
  • 以下のYAML を使用します。
    • ロードバランサーのShapeに「10Mbps」を指定します。
    • selector には、deployment リソースに合わせて、「nginx-deployment」を指定します。
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  annotations:
    # 無料枠の10Mbpsロードバランサーを指定し、コストを最小化
    service.beta.kubernetes.io/oci-load-balancer-shape: "10Mbps"
spec:
  # LoadBalancerタイプを指定してOCIのロードバランサーを作成
  type: LoadBalancer
  ports:
  - port: 80         # ロードバランサーのポート
    targetPort: 80   # Pod(コンテナ)のポート
  selector:
    # このラベルを持つPodにトラフィックを転送
    app: nginx-deployment

 

  • service リソースをデプロイします。
$ kubectl apply -f nginx-service.yaml
Private key passphrase:
service/nginx-service created

 

ハンズオン4:動作確認

  • ロードバランサーのIPアドレスを確認します。
$ kubectl get service nginx-service
Private key passphrase:
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
nginx-service   LoadBalancer   10.96.247.156   150.230.216.172   80:31104/TCP   26s

 

  • OCIの管理コンソールからもロードバランサーの作成が確認できました。

 

  • セキュリティリストには自動で以下2つのIngress Rule が追加されました。Cloud Controller Manager とOCI の連携により、ロードバランサーからワーカーノードへの通信が正しく行われるように、必要なセキュリティリストのルールを自動的に追加します。
    • Port 31104 はkubectl get service コマンドで出力されたノードのポート番号となります。ロードバランサーはワーカーノードのポートへ転送を行う必要があります。
    • Port 10256 はヘルスチェック用のポート番号となります。

 

  • curl コマンドで疎通確認を行います。200 OK のステータスが返り、Nginx のwelcomeページが表示されることを確認します。

 

トラブルシューティング③

  • curl コマンドを実行した結果、ロードバランサーからPod にトラフィックが到達しない。
$ curl http://158.179.178.120
curl: (56) Recv failure: Connection reset by peer

$ curl http://158.179.178.120
curl: (52) Empty reply from server

 

  • deployment リソース、service リソースの selector パラメータの指定が異なる場合、Pod へトラフィックが転送されず、上記のようなエラーとなります。
  • deployment 、service の各リソースのパラメータ確認方法を以下に紹介します。
$ kubectl get deployment

$ kubectl describe deployment nginx-deployment

$ kubectl get pods

$ kubectl describe pod nginx-deployment-xxxxxxxxxx-xxxxx

$ kubectl get service nginx-service

$ kubectl describe service nginx-service

 

ハンズオン5:後片付け

  • ハンズオンが終わったら、不要なリソースを削除します。kubectl delete コマンドを使用して、service リソース、deployment リソースの削除を行います。
$ kubectl delete -f nginx-service.yaml
Private key passphrase:
service "nginx-service" deleted from default namespace

$ kubectl delete deployment nginx-deployment
Private key passphrase:
deployment.apps "nginx-deployment" deleted from default namespace

 

  • 最後に、OCIの管理コンソールからOKE クラスタを削除します。

 

まとめ

  • このハンズオンを通じて、OKE クラスタの作成からNginx の公開までの一連の流れを経験しました。OKE のデプロイ作業はとても分かりやすく、複雑な部分はありませんでした。本来のコンテナアプリケーションの作り込みやKubernetes の理解に時間を割くことができます。
  • スムーズな構築のポイントは、クラスタ作成前に、OKE が必要とする通信要件を理解し、セキュリティリストを正しく設定しておくことです。その後のトラブルを大幅に減らすことができます。
  • この記事で構築した環境は、新しいコンテナアプリケーションをデプロイしたり、Ingressや永続ボリュームといった、より高度なKubernetesの機能を学んだりするための出発点となります。ぜひここから、さらにOKE 学習広げていきましょう。