learn_k8s_2!

はい、前回がk8sクラスタの構築部分でした。ここからは実際に運用をどうするか?ってところに焦点を当てていきたいと思います。

前回の冒頭の記事はいい感じだったので、ここにも書いておきたいと思います。

ことはじめ

k8sという技術が注目を浴びている。web業界での近年の大きな変化としてはアプリケーションアーキテクチャの変化が挙げられる。従来は、アプリケーションを構成するソフトはモノリシック(一枚板)であった。つまり、アプリケーションは、一つのソースコードで1プロセスで動いているような感じだった。しかし、このモノリシックなアーキテクチャではソースコードが複雑で、変更が加えにくい等の問題があった。チームで開発する際も、メンバーみんなが同じソースコードをつかってビルドをする必要がある等、いろいろと面倒なことが多かったと思う。そこで、近年はアプリ開発にはマイクロサービスアーキテクチャが採用されている。マイクロサービスアーキテクチャは、小さなコンポーネントの集合が全体として一つのアプリケーションを構成しているようなアーキテクチャである。

自分も意図せずして、開発してきたアプリはマイクロアーキテクチャにしていたが、こちらの方が各コンポーネントの役割をきちんと明確化して進められるので、開発を分担できるのと、変更を加えるとき、役割がコンポーネントに分かれているので、各コンポーネントの中身だけを変えればよく、管理が簡単になると思われる。つまり、APIだけそろえておけば、後は中身はなんだっていいということだ。 これによって、アジャイル開発が非常に簡単になると思われる。 そして、このコンポーネントをひとつひとつをコンテナ化するってのも近年の大きな流れだ。コンテナ化することで、そのコンテナはCPUのアーキテクチャさえそろっていればどんなマシン上でも動くようになるからだ。そして、コンテナ化されたコンポーネント(マイクロサービス)をうまく協調させるのが コンテナオーケストレーションツールってはなしだ。 コンポーネントを協調させる、と書いたが、具体的には(k8sの機能は非常に多いので、俺が理解できる、かつ、大事そうなものだけをピックアップする)、

  1. コンテナのスケジューリング
  2. スケーリング/オートスケーリング
  3. 障害時のセルフヒーリング
  4. ロードバランシング
  5. ワークロードの管理 とかがある。

k8sの基本的なコンポーネント

参考動画 基本用語説明 dbと連携させたjsアプリを題材に、k8sのコンポーネントを説明していくよ!

  1. cluster k8sのリソースを管理する集合体のこと

  2. node 物理マシン、もしくは仮想マシンのこと。つまり、ホストのこと。 ノードには、master nodeと普通のnodeがある。

master nodeはkubernetesを管理するため、次の管理コンポーネントを持つ

  1. kube apiserver:kubernetesのAPIを公開する。kubectlからの操作を受け付ける役割。kubeletからもアクセスを受けるし、他にもいろいろなクライアントがある。これがclusterへのgatewayになる。ユーザは必ずkube apiserverを通してクラスターとやり取りをするということだね。

  2. etcd:分散kvs。クラスタのバッキングストアとして使用される。ログとかが記録されている。etcdは分散kvs、ということはetcdを何個か立てることが可能、ということでして、そうするとetcd間で内容の一貫性を保たないといけないわけですね。ということは?お?層です。分散合意アルゴリズムのraftが使われているわけですね。最高です。

  3. kube scheduler:コンテナを配置する最適なnodeを選択する。ここも研究の対象になりえるところではある。

  4. kube controller manager: リソースを制御する

k8sでソフトで実現される概念的なコンポーネント (下で紹介するが、これをリソースと呼ぶ。)

Nodeはコンテナ化されたアプリケーションを実際に実行するホスト

  1. pod コンテナの集合体。PodはNodeの中で動作し、一つ以上のコンテナを持つ。 K8sにデプロイするときは、Pod単位で行う。(実際はdeployという単位でコンテナをデプロイするんです) pod一つでなにか機能を果たす、とかそういう感じでpodにまとめるのだと思われる。 そうだね、1 application per Podというのが基本らしい。

k8sはvirtual networkを提供。各Podはこの仮想ネットワーク上でIPアドレスを持っている。 そして、これが結構大事な概念だんだが、Podは結構簡単に死ぬ。そして、Podが死んだら、新しいPodがデプロイされるのだが、その時にIPアドレスが変わってしまうというのが不便らしい。その時に使うのがServiceらしい。

  1. Container Dockerコンテナのこと

  2. ReplicaSet 同一仕様のPodを複数生成する仕組み。 ReplicaSetを複数持っておくことで、一つのReplicaSetが死んでも他のReplicaSetに 処理を移すことでシステムが死んでいる時間をなくす。 後は、ロードバランスもできる。

データベースは基本的にk8sクラスタの外で管理する。というのも、ステートを考えるのが面倒くさいかららしいです。

  1. Service Serviceは、Podにアクセスするための経路を定義。 PodのIPアドレスを固定できる。 外部への公開ポイントもここで設定する。

  2. Deployment ReplicaSetの上位リソースで、ReplicaSetを管理する。 つまり、 DeploymentがReplicaSetを管理し、ReplicaSetがPodを管理する。

  3. ingress クラスタ外部からのエンドポイント?

  4. ConfigMap Podsの設定ファイル

  5. Secret used to store secret data。他人に見られたくないデータをここで管理する。 例えば、環境変数とか、properties fileとか。 base64 encoded formatで保存される。

ここからデータベースの話 データベースがリスタートした時にデータはぶっ飛んでしまうよね?インメモリデータベースなんだだから。これを防ぐのがvolumesコンポーネント。まあ、この話はdockerでも普通に結構出てくるよね。

  1. volumesmanage data persistence 物理ストレージをpodに割り当てる。これでデータベースpodがぶっ壊れても外部ストレージに残っているらしい。k8sは doesn’t

  2. StatefulSet なんか、状態を管理するためのコンポーネントなのかな。

ここまでで、k8sの基本コンポーネントの説明は終わった。

k8sでどのようにアプリが実行されるのか

マスターノードがワーカーノードを管理するっていうのはいいよね。 ワーカノードは、Podsを動かすために3つのプロセスが動いている必要がある。

  1. コンテナランタイム(dockerとかcontainerdとか。この辺も勉強するとdockerは単なるフロントエンドであるということとかがわかる。内部ではcontainerdが使われていて、さらにその下ではruncが動いていたりする。)

  2. Kubelet : interface between container and node。リソースのマネジメントをする。kubeletがコンテナの起動を担当するわけですね。kube-scheduler によって紐付けられた(スケジュールされた)Podを kubelet が認識して、そのPodを自身のNodeで起動させる。 また、実行しているPodの監視・管理も行う

  3. Kube proxy : forwards the request。コミュニケーションのマネジメント。KubernetesのServiceオブジェクトを元にルーティングを行う。実体はiptablesのルールを発行し、パケットの制御を行っている

では、ワーカーノードとinteractするにはどうすればいいのか?という疑問。 はい、これらワーカノードはマスターノードによって管理されているんですね。 で、マスターノードで動いているプロセスが4つあって、それが先ほども説明した4つだね。

  1. Api server
  2. Scheduler
  3. Pods Controller manager detects cluster state change -> request scheudler to place new pods.
  4. etcd is the cluster brain. cluster changes get stored in the key value store. cluster内で起こったことのログがここにたまっているということ。 アプリのデータはここには溜まっていませんよ!!ってのは大事なこと。あくまでメタ情報がここにたまっていく。

k8sの働きの全体像としては、 kubectlを使ってkubeAPIサーバにリクエストが送られ、kubeapi-serverがschedulerやcontrolerに指示を出して、さらにそこからkubeletに指示が出される感じです。指示の内容とかはetcdにたまっています。そしてそして、kubeletが各ノード上でコンテナランタイムとのインターフェースになっていて、コンテナラインタイムを経由してコンテナを経てるわけですね。これはすごい。

で、これも大事なんだけど、k8sはシステムの各コンポーネント(リソース) を「常に望ましい状態にたもつ」のが仕事です。つまり、システム全体を常に管理しているわけですね。コンテナが死んだら復活させるって感じで。運用者からしたら、こんなにいいツールがあるんか!ってくらい素晴らしいツールだと思います。 でね、「望ましい状態」を定義するのがマニフェストファイルなんだよね。マニフェストには、リソースを書くんです。どんなリソースがあるか?下を見てください。

リソース

  1. pod
  2. replicaset
  3. service
  4. deployment
  5. job

まあいろいろあるけど、これだけ覚えておけば十分。これらをマニフェストに書き込んでいくわけですね。

マニフェストファイルについて

k8sはマニフェストファイルに書かれた内容に従ってPodを作る。マニフェストの内容をkubectlでk8sに提出すると、それが、etcdに「望ましい状態」として登録される。で、マニフェストはリソース単位で書いていくわけですね。つまり、podとか、serviceとか、deploymentとか。で、俺みたいな初心者が扱うリソースは、デプロイメントとサービスだけです。デプロイメントでコンテナを管理、サービスでネットワークを管理するからですね。

意外なことにPod単体でデプロイすることはないんですね。それは、コンテナの数を望ましい状態に保つ役割を果たすのが、replicasetだからですね。つまり、デプロイメント単位でデプロイするんですね。

マニフェストファイルに記述する内容

大きな項目として、4つあります。この4項目を書けば大丈夫です。

  1. apiVersion: APIグループとそのバージョン
  2. kind: リソースの種類
  3. metadata: メタデータ
  4. spec: リソースの中身

apiVersionとkindに関しては、定義したいリソースの種類によって決まっています。 pod : core/v1(apiVersion), Pod(kind)

service : core/v1(apiVersion), Service(kind)

Deployment : apps/v1(apiVersion), Deployment(kind)

ReplicaSet : apps/v1, ReplicaSet

という感じですね。

メタデータとスペックに何を書くか。まあ、メタデータはリソースの名前です。kubectl get deploymentsとか名前を見るためです。 スペックは何か。だけど、これはリソースの定義なので、マニフェストファイルに記述する内容で一番重要なところです。

Podsをリソースにしたときのマニフェストファイルの書き方

デプロイメントの中にPodを入れるということなので、まずはPodのマニフェストファイルの書き方から勉強しましょう、ということです。題材は、apacheサーバのデプロイです。

apiVersion: v1
kind: Pod
metadata:
  nama: apache000
  labels:
    app: apa000kube
spec:
  containers:
    - name: apa000ex91
      image: httpd
      ports:
        - containerPort: 80
  type: NodePort
  ports:
    - port: 8099
      targetPort: 80
      protocol: TCP
      nodePort: 30080
  selector:
    app: apa000kube

って感じですね。specのtypeだけど、まあ後でせつめいしますわ。 ちなみに、yamlで - は配列を表します。なるほどって感じでですね。

Deploymentのマニフェストファイルの書き方。

Podのマニフェストファイルは大部分が再利用される。 新たにspec.templateというのができるわけですね。書いていきたいと思います。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apa000dep
spec:
  selector:
    matchLabels:
      app: apa000kube
  replicas: 3
  template:
    metadata:
      labels:
        app: apa000kube
    spec:
      containers:
        - name: apa000ex91
          image: httpd
          ports:
          - containerPort: 80

次、サービスファイルだね。

apiVersion: v1
kind: Service
metadata:
  name: apa000ser
spec:
  type: NodePort
  ports:
    - port: 8099
      targetPort: 80
      protocol: TCP
      nodePort: 30080
  selector:
    app: apa000kube

タイプを見てほしいんだけど、これはね、まあ外部との通信をどうするかって話。4つの種類があって、 ClusterIP,NOdePort,LoadBalancer,ExternalNameなんだけど。 ClusterIpは、ClusterIPでServiceにアクセスできるようにする (外からはアクセスできない) NodePortはワーカノードのIPでServiceにアクセスできるようにする LoadBalancerはロードバランサーのIPでServiceにアクセスできるようにする ExternalNameはPodからサービスを通じて外に出るための設定

特定のノードに特定のリソースをデプロイする方法

これ大事だねー。やっぱりマシンのスペックごとに得意不得意があるわけじゃない。頑張りましょう。

できるらしいけど、そこもk8sにまかせるのがいいらしいとか。

サービスに特定のIPアドレスを付与する方法

これがないとサービス同士がうまく連携するとかできないと思うんだが。。。どうやるんだ? これもできるらしいけど、k8sに任せるのがいいとか。 あー-、なるほどね。理解。特定のIPアドレスを付与する必要がないんだ。なぜなら、DNSがいるからだってさ。フーン。サービス名でやり取りするんだってさ。つまり、アプリの方もdnsでやり取りする相手を選択する必要があるって感じだね。

以下、chatGPTから帰ってきた答えです。

I understand your concern. When you specify a specific IP address for a Kubernetes Service, it can have implications for the way Pods communicate with each other within the cluster. Here's how it works:

When you assign a specific IP address to a Service using the loadBalancerIP or externalIPs fields, it typically applies to external or ingress traffic coming into the cluster. Pods within the cluster usually do not directly use the external IP address of a Service to communicate with each other. Instead, they rely on the ClusterIP, DNS, or service name to communicate with other services.

Here's a breakdown of how communication typically works within a Kubernetes cluster:

Pod-to-Pod Communication: Pods communicate with each other using the ClusterIP or DNS name of the Service. When one Pod wants to communicate with another, it uses the Service's DNS name or ClusterIP, which Kubernetes manages. Specifying a specific IP for a Service doesn't affect this internal communication.

Service Discovery: Kubernetes automatically manages DNS entries for Services. Each Service gets a DNS entry in the form of <service-name>.<namespace>.svc.cluster.local. Pods can use this DNS name to discover and communicate with services within the cluster.

External Access: When external traffic (e.g., from the internet) needs to access a Service, that's when you might specify a specific IP address using loadBalancerIP or externalIPs. This IP is typically used by external load balancers or ingress controllers to route traffic to the appropriate Service.

In summary, specifying a specific IP address for a Service is primarily for external access. It does not affect Pod-to-Pod communication within the cluster, as Pods still use Service names, ClusterIPs, or DNS for internal communication. Kubernetes abstracts the networking layer and manages the routing of traffic within the cluster, making it easier to maintain and scale applications.

If you have specific requirements for Pod-to-Pod communication within your cluster that are not met by the default Service behavior, you may want to consider using additional networking solutions or Network Policies to control communication between Pods. However, this should be done with caution, as it can add complexity to your cluster configuration.

まあ、 ..svc.cluster.local これが特手のサービスのドメインになるってことよね。なるほど。つまり、アプリでは、これを設定すればいいって話か。素晴らしい。DNSはどこで動いてるんだ?kubectl get service –all-namespacesの結果

NAMESPACE              NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
default                kubernetes                  ClusterIP   10.96.0.1       <none>        443/TCP                  13d 
kube-system            kube-dns                    ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP   13d 
kubernetes-dashboard   dashboard-metrics-scraper   ClusterIP   10.97.249.230   <none>        8000/TCP                 24h
kubernetes-dashboard   kubernetes-dashboard        ClusterIP   10.100.181.30   <none>        443/TCP                  24h

って感じで、ちゃんと動いてるんですね。どのタイミングでデプロイされたのかはちょっと気になるところではありますが。

で、サービスのマニフェストで、metadata.nameの欄に書いたやつが、dnsの名前になるから気を付けてくれ。そこがマジで大事!です。

kubectlの基本コマンド

kubectl –helpの中身


 Find more information at: https://kubernetes.io/docs/reference/kubectl/

Basic Commands (Beginner):
  create          Create a resource from a file or from stdin
  expose          Take a replication controller, service, deployment or pod and expose it as a new Kubernetes service     
  run             Run a particular image on the cluster
  set             Set specific features on objects

Basic Commands (Intermediate):
  explain         Get documentation for a resource
  get             Display one or many resources
  edit            Edit a resource on the server
  delete          Delete resources by file names, stdin, resources and names, or by resources and label selector

Deploy Commands:
  rollout         Manage the rollout of a resource
  scale           Set a new size for a deployment, replica set, or replication controller
  autoscale       Auto-scale a deployment, replica set, stateful set, or replication controller

Cluster Management Commands:
  certificate     Modify certificate resources
  cluster-info    Display cluster information
  top             Display resource (CPU/memory) usage
  cordon          Mark node as unschedulable
  uncordon        Mark node as schedulable
  drain           Drain node in preparation for maintenance
  taint           Update the taints on one or more nodes

Troubleshooting and Debugging Commands:
  describe        Show details of a specific resource or group of resources
  logs            Print the logs for a container in a pod
  attach          Attach to a running container
  exec            Execute a command in a container
  port-forward    Forward one or more local ports to a pod
  proxy           Run a proxy to the Kubernetes API server
  cp              Copy files and directories to and from containers
  auth            Inspect authorization
  debug           Create debugging sessions for troubleshooting workloads and nodes
  events          List events

Advanced Commands:
  diff            Diff the live version against a would-be applied version
  apply           Apply a configuration to a resource by file name or stdin
  patch           Update fields of a resource
  replace         Replace a resource by file name or stdin
  wait            Experimental: Wait for a specific condition on one or many resources
  kustomize       Build a kustomization target from a directory or URL

Settings Commands:
  label           Update the labels on a resource
  annotate        Update the annotations on a resource
  completion      Output shell completion code for the specified shell (bash, zsh, fish, or powershell)

Other Commands:
  api-resources   Print the supported API resources on the server
  api-versions    Print the supported API versions on the server, in the form of "group/version"
  config          Modify kubeconfig files
  plugin          Provides utilities for interacting with plugins
  version         Print the client and server version information

Usage:
  kubectl [flags] [options]

って感じです。

では、上で作ったマニフェストファイルをもとにデプロイしてみますか。

kubectl apply -f ./apache_dep.yml
kubectl apply -f ./apache_srv.yml

これでデプロイ。 ちゃんと動いていますね。すごいです。

これ何が起こってるのかわからなかったのが、ワーカノードの30080にアクセスしてもつながったところ。どういうことっていう。 ufw で30080は開けてすらいないのに。何が起こっているんや。。。 ー->これに関してはデプロイしたレプリカの数の話やな。5つのポッドをデプロイして、それが、ワーカノードでも走ってたってこと。レプリカの数を1にすると、ワーカでは動かなくなったので。

マニフェストファイルを編集して、ポッド数が変わっているか見てみる

deploymentの方で、replicaの数を5にしてみる。 その後、

kubectl apply -f ./apache_dep.yml
kubectl get pods

をやると、確かにpodsの数が変わっているんですよね。すごいです。 1にしてapplyすると、

NAME                         READY   STATUS        RESTARTS   AGE
apa000dep-749fc84c84-9snbl   0/1     Terminating   0          20m
apa000dep-749fc84c84-gl8fq   0/1     Terminating   0          2m49s
apa000dep-749fc84c84-l4zp9   1/1     Running       0          20m
apa000dep-749fc84c84-n7xs8   0/1     Terminating   0          20m
apa000dep-749fc84c84-qq2dl   0/1     Terminating   0          2m49s

した後、ちゃんと止まった。。。。すごい。。。! さらに、デプロイするコンテナの種類も変えることができるんです!! deploymentのマニフェストの方の、containersの中にimageをnginxにしてapplyすると。。。

NAME                         READY   STATUS              RESTARTS   AGE
apa000dep-749fc84c84-l4zp9   1/1     Running             0          22m
apa000dep-8468f698b8-rpqhb   0/1     ContainerCreating   0          5s

からの、

NAME                         READY   STATUS        RESTARTS   AGE
apa000dep-749fc84c84-l4zp9   1/1     Terminating   0          22m
apa000dep-8468f698b8-rpqhb   1/1     Running       0          7s

からの。。

NAME                         READY   STATUS    RESTARTS   AGE
apa000dep-8468f698b8-rpqhb   1/1     Running   0          46s

驚き。。。。

kubectlを使って、実際に中をいろいろ見ていく

デプロイされているポッド一覧を、ネームスペース関係なく全部表示

kubectl get pods --all-namespaces

特定のネームスペースにデプロイされているポッド一覧を表示

kubectl get pods -n <NAMESPACE>

現在の名前空間にデプロイされているポッド一覧を表示

kubectl get pods

すべての名前空間にデプロイされているサービス一覧を取得

kubectl get services --all-namespaces

こっちの方が使うかもな。

すべての名前空間にデプロイされているデプロイメント一覧を取得

kubectl get deployments --all-namespaces

各ノードに割り当てられたポッド一覧を取得

kubectl get pods -o wide

その他のtips

自分でビルドしたイメージをデプロイする方法

まあわからんけど、とりあえず、自分でプライベートなコンテナレジストリは作れるみたいだぞい。 プライベートコンテナレジストリの作り方

特定のポッドなかに入る方法

kubectl exec -it apa000dep-8468f698b8-v89xm -- /bin/bash

実は、ワーカノードで働いているやつにもアクセスできるようになるが、一つだけ気を付けてほしいのが、kubeapiserverがワーカノードのkubeletにアクセスするときは10250にアクセスするので、ここのポートを開けておく必要があるよって話。

sudo ufw allow 10250

でもこれ開けなくても、workernodeのkubeletとマスターはいい感じにれんけいしているようにみえたんだね。何が起こっているんだが。いや、開かないとだめですね。なんでさっきいけたかはわからんが、基本的には開くようにしましょう。

実験

特定のポッドに入り、自分で自分を落とすとどうなるか?

マスターが動いてるポッド以外はインターネットに接続できない件

The inability of containers running on worker nodes to access the internet while those on master nodes can could be due to several reasons related to network configuration, security, or firewall settings. Here are some common factors to check:

mrkeeのproxyがおかしいので何とかして直してほしい。どっかで設定ミスった可能性が高い。overlay network周りかな。おそらく。これまじでなぞやなー--。ずっとだめだな。

これに関してですが、原因は、cgroup driverの設定を変えた後、containerdを再起動しなかったことでした。 マジで、こういうところで時間を食ってしまうのはもったいないー-!!くー-!

dashboardにアクセスできないのは、NodePortにしていないからだね。

いや、cniのプラグインが入ってないからじゃないかって思い始めてます。マジで何を入れればいいのかわかりません。

cniプラグインは絶対に入れてください。

んで、一回入れると、/etc/cni/net.dに設定ファイルが残ります。 これ、自分で消さない限りずっと残ります。気をつけてください。 kubeadm resetでリセットしたつもりが、そこにずっとcalicoが残っていて、うまく動かなかった、なんてこともありました。気をつけてくれ。ちなみに、flannelを入れてから、 journalctl -u kubelet -fして出ていた、以下のエラー、

Sep 28 23:37:01 mrlee kubelet[406820]: I0928 23:37:01.388695  406820 kuberuntime_gc.go:360] "Error getting ContainerStatus for containerID" containerID="56b759f21f1129ad8b13fc0e9b556f9dba375c7dc4af38d9eb6fa21724d1a380" err="rpc error: code = NotFound desc = an error occurred when try to find container \"56b759f21f1129ad8b13fc0e9b556f9dba375c7dc4af38d9eb6fa21724d1a380\": not found"
Sep 28 23:37:01 mrlee kubelet[406820]: E0928 23:37:01.388940  406820 remote_runtime.go:432] "ContainerStatus from runtime service failed" err="rpc error: code = NotFound desc = an error occurred when try to find container \"058b85edeac0488c6e5d6ebaa0b034fe9986cc2c712789a5515cc9e6c413a477\": not found" containerID="058b85edeac0488c6e5d6ebaa0b034fe9986cc2c712789a5515cc9e6c413a477"
Sep 28 23:37:01 mrlee kubelet[406820]: I0928 23:37:01.388963  406820 kuberuntime_gc.go:360] "Error getting ContainerStatus for containerID" containerID="058b85edeac0488c6e5d6ebaa0b034fe9986cc2c712789a5515cc9e6c413a477" err="rpc error: code = NotFound desc = an error occurred when try to find container \"058b85edeac0488c6e5d6ebaa0b034fe9986cc2c712789a5515cc9e6c413a477\": not found"
Sep 28 23:37:01 mrlee kubelet[406820]: E0928 23:37:01.389157  406820 remote_runtime.go:432] "ContainerStatus from runtime service failed" err="rpc error: code = NotFound desc = an error occurred when try to find container \"c170fe0ae620773c121c924d451dde4cf15209a33b1abf30c5b4a900c353a782\": not found" containerID="c170fe0ae620773c121c924d451dde4cf15209a33b1abf30c5b4a900c353a782"
Sep 28 23:37:01 mrlee kubelet[406820]: I0928 23:37:01.389172  406820 kuberuntime_gc.go:360] "Error getting ContainerStatus for containerID" containerID="c170fe0ae620773c121c924d451dde4cf15209a33b1abf30c5b4a900c353a782" err="rpc error: code = NotFound desc = an error occurred when try to find container \"c170fe0ae620773c121c924d451dde4cf15209a33b1abf30c5b4a900c353a782\": not found"
Sep 28 23:37:01 mrlee kubelet[406820]: E0928 23:37:01.389377  406820 remote_runtime.go:432] "ContainerStatus from runtime service failed" err="rpc error: code = NotFound desc = an error occurred when try to find container \"43de5166d3c898819c6cc230233ddda34c81802f4fce7a4686257b30422d8209\": not found" containerID="43de5166d3c898819c6cc230233ddda34c81802f4fce7a4686257b30422d8209"
Sep 28 23:37:01 mrlee kubelet[406820]: I0928 23:37:01.389396  406820 kuberuntime_gc.go:360] "Error getting ContainerStatus for containerID" containerID="43de5166d3c898819c6cc230233ddda34c81802f4fce7a4686257b30422d8209" err="rpc error: code = NotFound desc = an error occurred when try to find container \"43de5166d3c898819c6cc230233ddda34c81802f4fce7a4686257b30422d8209\": not found"
Sep 28 23:37:35 mrlee kubelet[406820]: I0928 23:37:35.956270  406820 pod_startup_latency_tracker.go:102] "Observed pod startup duration" pod="kube-system/kube-proxy-q5grb" podStartSLOduration=94.956117999 podCreationTimestamp="2023-09-28 23:36:01 +0000 UTC" firstStartedPulling="0001-01-01 00:00:00 +0000 UTC" lastFinishedPulling="0001-01-01 00:00:00 +0000 UTC" observedRunningTime="2023-09-28 23:36:03.412550298 +0000 UTC m=+2.209335112" watchObservedRunningTime="2023-09-28 23:37:35.956117999 +0000 UTC m=+94.752902813"

これも出なくなったと。これらに関してはマジで完璧ですわ。

ネットにつながらない & デフォルトでインストールされているコマンドが少なすぎる中で使えるコマンド

ifconfigの代わり、hostname -I pingの代わり、curlで疎通チェック

どうやら、ポッド間の通信がうまく行ってないようである。

厳密に言うと、別々のノードに割り当てられたポッド間での通信がうまく行かない。 10.244.1.17 (10.244.1.0がmrleeに割り当てられているネットワーク)から、 mrlee(192.168.3.7)へのcurlはうまく行く、たとえば、 curl 10.244.1.14 とかね。 curl 192.168.3.7 これも、自分のノード上だからうまく行っているっぽいんですよ。 しかし、別のノードへのcurlはうまく行かない。まじで。 curl 10.244.2.17 とかね。これよまじで。pod間の通信がうまく行ってないんですわ。しっかりしてくれや!!!って話なわけで。 これはやっぱり、overlayネットワークがうまく設定できてないんでしょうな。もしくはFlannelがちゃんと動いてないか。どっちかしか考えられんな。

これに関して、

/etc/cni/10-containerd.bridge みたいなので、ちゃんとpod-networkのciderを設定したら、ましになった気がします。でもまだ動いてないんですよね。なぜや??jhonnyのkubeletでもちゃんと動いてません。なぜだー-い。 いや、etc/cni/10-containerdはデフォルトでは何もいらないのかな?そんな気がしてきました。どうなんでしょう。いるんかね? うーんやっぱり 10-containerd-net.conflistはない方がうまく動くみたい。 これがあると、コンテナのdeleteもまともにいかなくなってしまうからね。まじでなんなんやー--。って感じですが。

あるコンテナに入って、別のノード上にあるコンテナにpingしてみたんです。まあこれがやっぱり疎通を確認するのに一番簡単だってことでね、chatgptさんいわくね。でもね。 でね、tcpdumで見てみたんですよ。mrlee -> mrkeeにpingしてるんだけどね。 二つのノードのどちらにもtcpdumpを使ってみてみました。そしたらね、 mrlee から送られたパケットはちゃんとmrkeeの方にも届いていると。で、


Okay the two pods are running on different nodes. Do I have to set service for the two pods to be able to communicate?
>

No, you don't need to set up services for the two pods to communicate with each other if you're just testing direct pod-to-pod communication within a cluster. Services in Kubernetes are used to expose pods to either other parts of the cluster (like other pods) or externally (outside the cluster). They act as a load balancer and provide a stable IP and DNS name.

って感じなので、serviceを設定する必要はなしと。いやじゃあマジで何??マジでわからん。

きたああああああああああああああああああああああああああああ!!!!!!!!!!!!!!

やっときました。なんでかわからんけど、リブートしたらいろいろ来ました。 なんか、nerdctl0ってインターフェースがかぶっていたのが原因だったのかもしれません。 そんな気がしてきました。 リスタートしたら一気にうまくいくようになった。

ポイント

/etc/cni/net.dはflannelだけのでいい。 なんか、わからなくなったら、リブートかければいい nerdctl0があるとうまくいかないのかもしれない。これ大事。

いんたーねっとにもつながるようになったー---!!さいこうです。やったぜーやった。やっときたぜ。マジで神だぜ!これは勝ちだぜ!!ついに!!今週一週間かけた買いがあったぜ。マジで。最高だぜ。マジで最高だぜ。かったぜ、これは間違いなくかちだ。

ということで、インターネットにもつながるようになります。

ちなみに

ダッシュボードが動いていなかったのは、メトリクススクレイパーが動いていなかったから。 これは、

kubectl top pods

をしたときに、

error: Metrics API not available

になることからもわかりますね。よろしくおねがいしますー-。

pod-cidrとservice-cidrは別々にしないといけない

サービスのネットワークは、

ray@jhonny:~/k8s_manifest$ kubectl -n kube-system get configmap kubeadm-config -o=jsonpath='{.data.ClusterConfiguration}' | grep serviceSubnet
  serviceSubnet: 10.96.0.0/12

だし、 pod-cidrはkubeadmで設定した通り

--pod-network-cidr=10.244.0.0/16

ですね。はい。 で、これは別々にしないといけないんですよねー。 でも

so it is not possible to communicate between pod network and service network you mean?

In a Kubernetes cluster, you have two primary IP ranges:

Pod CIDR: This is the range from which individual pod IPs are allocated.
Service CIDR: This is the range from which service IPs are allocated.
Both ranges are distinct and don't overlap. However, in a properly configured Kubernetes cluster:

Pods can communicate with other pods using pod IPs.
Pods can communicate with services using service IPs.
Services forward traffic to pods based on their selectors and the pods' IPs.
So, if you have a service with IP 10.110.235.126 (from the Service CIDR) and a pod with IP 10.244.1.11 (from the Pod CIDR), the pod should be able to reach the service using the service IP 10.110.235.126, and the service will forward the traffic to the appropriate backend pods based on its configuration.

If there's an issue communicating between a pod and a service, it's typically due to:

Service Configuration: The service might not have correct selectors, or there might not be any pods matching the service's selectors.
Network Policies: There might be network policies in place that restrict communication.
CNI Configuration: The Container Network Interface (CNI) plugin might be misconfigured.
Application Configuration: The application in the pod might not be listening on the expected port, or it might be filtering traffic in some way.
DNS Issues: If using a service DNS name, there could be a problem with DNS resolution.
However, the distinction between Pod CIDR and Service CIDR does not inherently prevent communication between pods and services. It's designed to allow such communication seamlessly. If it's not working, there's a configuration or networking issue that needs troubleshooting.

ってことで、DNSでipは解決できているし、なんだろう。

参考文献

いい感じのスライド []