タケハタのブログ

プログラマの生き方、働き方、技術について雑多に書いていくブログです。

Kubernetesでローカル環境を構築してHTTP通信できるまで

先月書いた記事でDcokerでローカルにコンテナの作成をしましたが、今度はそれをKubernetesで作ってみたいと思います。

参考にした資料は下記の書籍です。
book.impress.co.jp gihyo.jp

Kubernetesとは?

「コンテナオーケストレーションエンジン」と言われています。
現代のWebサービスなどでは、アプリケーションサーバーを複数並べてロードバランサーで分散したり、データベースをはじめとするミドルウェアごとにサーバーを立て、それぞれ分散する作りがほとんどだと思います。

Dockerがこのサーバー1台ごとのコンテナを作成するものとすると、Kuernetesはそのコンテナ化された環境を複数台並べた時の、デプロイやスケーリングなどを自動化するようなものです。

Docker for MacのKubernetes有効化

もしDocker for Macが入っていない場合は、下記からダウンロード、インストールしてください。

docs.docker.com

そしてPreferenceを開き、Kubernetesタブから「Enabel Kubernetes」を選択し、Applyを押してください。
ここから有効化するまでに少し時間がかかります。

f:id:take7010:20190317173258p:plain

完了すると、下記のように「Kubernetes is running」と表示されます。

f:id:take7010:20190317173317p:plain

Kubernetesで環境構築

Kubernetesのリソースの構成

Kubernetesはリソースと呼ばれるものの単位で管理をするのですが、今回は動かすのに最低限必要な、下記のリソースについて書きます。

  • Pod
  • Replicaset
  • Deployment
  • Service

イメージとしてはすごくざっくり書くと、

  • Pod・・・コンテナが立てられているリソース
  • ReplicaSet・・・Podを複数持っていて、指定された個数を保てるよう管理しているリソース
  • Deployment・・・ReplicaSetを複数持ち、世代管理しているリソース

みたいな感じで、 Pod < ReplicaSet < Deployment という関係性になります。
Serviceに関しては、これらで作られた環境に対しての、ロードバランシング等を提供するリソースです。

言葉だけだと理解しづらいと思うので、実際に作っていきましょう。

Pod

Podは、Kubernetesのリソースの最小単位です。
実際にコンテナを立てるのはこのPodの中になります。

マニフェストファイルの記述

Kubernetesは、マニフェストファイルと呼ばれるYAMLファイルで、リソースの情報を記述します。

まずは前回の記事の最後にdocker-composeで作ったものと同じ環境をKubernetesのPodとして作ります。
docker-composeは下記のxmlで作成しました。

version: "3"
services:
  hello:
    image: ntakehata/hello:latest
    ports:
      - 9000:8080
  nginx:
    image: nginx:1.13.5-alpine
    ports:
      - 80:80

Kubernetesでは「マニフェストファイル」と呼ばれるYAMLファイルを記述し、リソースを作成します。
まずは次のマニフェストファイルを作ってください。
ここではsample-pod.yamlという名前にしています。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
  - name: hello
    image: ntakehata/hello:latest
    ports:
    - containerPort: 8080
  - name: nginx
    image:  nginx:1.13.5-alpine

kind は作成するリソースの種類を指定します。今回の場合はPodになります。
metadata.name はリソースの名前です。

spec.containers 配下はPod内に作成するコンテナの設定です。docker-composeと似たような感じですね。
name でコンテナの名前を指定して、imageports でコンテナのイメージと受け付けるポートを指定しています。

Podの作成

そして、 kubectl apply というコマンドでPodを作成します。

ntakehata$ kubectl apply -f sample-pod.yaml
pod "sample-pod" created

この kubectl apply は、 metadata.name で指定した名前のリソースが存在しなければ新規作成、存在すれば更新をしてくれます。
-f は対象のマニフェストファイルのファイル名やディレクトリ名を指定するオプションです。
ここではファイル名を指定していますが、ディレクトリ名をしていすると、そのディレクトリ配下にある全てのマニフェストファイルに対して実行されます。

作成されたPodを確認します。
リソースの確認には kubectl get というコマンドを使います。

ntakehata$ kubectl get pods
NAME                READY     STATUS    RESTARTS   AGE
sample-pod          2/2       Running   0          17s

今回はPodの存在を確認するので、 pods というパラメータを付けています。
後述するReplicaSet、Deployment、Serviceといったものも、 replicasets deployments services と付ければ確認できます。

また、下記のようにカンマで区切って複数のリソースをまとめて確認することもできます。

ntakehata$ kubectl get pods,replicasets,deploymentes

Pod内のコンテナに接続して確認

Podは作成しただけではlocalhostからHTTP等で接続することはできません。
これをリクエストを受けれるようにする方法は後述するので、一旦下記のコマンドで動作確認します。

ntakehata$ kubectl exec sample-pod -c hello curl http://localhost:8080
Defaulting container name to hello.
Use 'kubectl describe pod/sample-pod -n default' to see all of the containers in this pod.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13  100    13    0     0   2096      0 --:--:-- --:--:-- --:--:--  2600Hello World!!

kubectl exec というコマンドを使うと、Pod上でコマンドを実行することができます。
ここではsample-pod上でcurlコマンドを実行し、hello.goを呼び出しています。

-c オプションで指定しているのは、Pod内のアクセスしたいコンテナ名です。
もし単一のコンテナしかないPodの場合は、このオプションは不要です。

また、下記のようにすることで、Pod内のコンテナに擬似的にログインしたように操作することもできます。

ntakehata$ kubectl exec -it sample-pod -c hello /bin/bash
root@sample-pod:/go#

下記のように、コマンドを実行して起動の確認もできます。

root@sample-pod:/go# curl http://localhost:8080
Hello World!!
root@sample-pod:/go# curl http://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Podの削除

Podの削除は、 kubectl delete というコマンドを実行します。

ntakehata$ kubectl delete pod sample-pod
pod "sample-pod" deleted

パラメータとしてリソースの種類、名前を渡します。

ReplicaSet

ReplicaSetは、複数のPodの集合体のようなイメージです。
Podを指定した個数作成し、障害が発生した時は新たなPodを作成して入れ替えて復旧して、指定の個数をキープしてくれます。

ReplicaSetの作成

ReplicaSetのマニフェストファイルは、下記のようになります。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sample-replicaset
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: hello
        image: ntakehata/hello:latest
        ports:
        - containerPort: 8080
      - name: nginx
        image:  nginx:1.13.5-alpine

kind の指定を ReplicaSet にしています。
複数のPodの集合体と書きましたが、 replicas で指定している数値がそのPodの数(レプリカ数)になります。
また、 spec.template 配下が中に作成するPodの情報が記述されていて、その下の spec 配下はPodのマニフェストファイルと同じ内容になります。
selector template.metadata.labesl については後述します。

ReplicaSetの作成も、Podと同様に kubectl apply コマンドを実行します。

ntakehata$ kubectl apply -f sample-replicaset.yaml
replicaset.apps "sample-replicaset" created

そして、 kubectl get コマンドで確認すると、下記のようになります。

ntakehata$ kubectl get pods,replicasets
NAME                          READY     STATUS    RESTARTS   AGE
pod/sample-replicaset-5grdf   2/2       Running   0          38s
pod/sample-replicaset-bkdvc   2/2       Running   0          38s
pod/sample-replicaset-vb44j   2/2       Running   0          38s

NAME                                      DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-replicaset   3         3         3         38s

sample-replicasetというReplicaSetと、それに紐づくPodが3つ作成されています。

ntakehata$ kubectl get replicasets -o wide
NAME                DESIRED   CURRENT   READY     AGE       CONTAINERS    IMAGES                                       SELECTOR
sample-replicaset   3         3         3         1m        hello,nginx   ntakehata/hello:latest,nginx:1.13.5-alpine   app=sample-app

selector、ラベル

障害が発生した時は新たなPodを作成して入れ替えて復旧してくれると前述しましたが、落ちたかどうかの監視に「ラベル」の値が使われます。
template.metadata.labels.app で指定している値で、ここでは sample-app になります。

そして、なんという名前のラベルを監視対象にするかを、 selector.matchLabels.app で指定しています。
なので template.metadata.labels.app で指定した名前と違う名前を書いてしまうと、エラーが発生して作れないようになっています。

Deployment

Deploymentは、ReplicaSetを複数世代管理して

Deploymentの作成

Deploymentのマニフェストファイルは下記です。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: hello
        image: ntakehata/hello:latest
        ports:
        - containerPort: 8080
      - name: nginx
        image:  nginx:1.13.5-alpine

ReplicaSetとほぼ同じで、kindがDeploymentになっています。
こちらも同じく kubectl apply で作成し、 kubectl get で確認します。

ntakehata$ kubectl apply -f sample-deployment.yaml
deployment.apps "sample-deployment" created
ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         3         3            3           15s

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-7c85f5b6b4   3         3         3         15s

NAME                                     READY     STATUS    RESTARTS   AGE
pod/sample-deployment-7c85f5b6b4-2jcg4   2/2       Running   0          15s
pod/sample-deployment-7c85f5b6b4-2vt2j   2/2       Running   0          15s
pod/sample-deployment-7c85f5b6b4-hrcjj   2/2       Running   0          15s

Deploymentと、それに紐づくReplicaSet、Podができあがっているのが見えます。

Deploymentの更新

作成しただけだとReplicaSetと同じに見えますが、更新するとDeploymentの意味が分かります。
ここまで前回の記事で書いた ntakehata/hello:latest のイメージを使ってきましたが、そちらを更新します。

マニフェストファイルを下記のように変更してください。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: hello
        image: ntakehata/hello:deployment
        ports:
        - containerPort: 8080
      - name: nginx
        image:  nginx:1.13.5-alpine

コンテナ hello のイメージを、 ntakehata/hello:deployment に変更しました。
そして kubectl apply で更新します。
--record は、更新時のコマンドを履歴として残すために付けるオプションで、後ほど参照します。

ntakehata$ kubectl apply -f sample-deployment.yaml --record
deployment.apps "sample-deployment" configured

すると徐々に新しいReplicaSet、Podが立ち上がり、古いPodと入れ替わっていきます。
下記は更新中に何度か kubectl get で確認した例です。

ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         4         2            3           1d

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-74d6d58584   2         2         1         7s
replicaset.extensions/sample-deployment-7c85f5b6b4   2         2         2         1d

NAME                                     READY     STATUS              RESTARTS   AGE
pod/sample-deployment-74d6d58584-85ds4   2/2       Running             0          7s
pod/sample-deployment-74d6d58584-hgvxr   0/2       ContainerCreating   0          1s
pod/sample-deployment-7c85f5b6b4-2jcg4   2/2       Running             0          1d
pod/sample-deployment-7c85f5b6b4-2vt2j   0/2       Terminating         0          1d
pod/sample-deployment-7c85f5b6b4-hrcjj   2/2       Running             0          1d
ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         4         2            3           1d

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-74d6d58584   2         2         1         10s
replicaset.extensions/sample-deployment-7c85f5b6b4   2         2         2         1d

NAME                                     READY     STATUS              RESTARTS   AGE
pod/sample-deployment-74d6d58584-85ds4   2/2       Running             0          10s
pod/sample-deployment-74d6d58584-hgvxr   0/2       ContainerCreating   0          4s
pod/sample-deployment-7c85f5b6b4-2jcg4   2/2       Running             0          1d
pod/sample-deployment-7c85f5b6b4-hrcjj   2/2       Running             0          1d
ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         4         3            3           1d

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-74d6d58584   3         3         2         14s
replicaset.extensions/sample-deployment-7c85f5b6b4   1         1         1         1d

NAME                                     READY     STATUS              RESTARTS   AGE
pod/sample-deployment-74d6d58584-85ds4   2/2       Running             0          14s
pod/sample-deployment-74d6d58584-hgvxr   2/2       Running             0          8s
pod/sample-deployment-74d6d58584-xws5q   0/2       ContainerCreating   0          3s
pod/sample-deployment-7c85f5b6b4-hrcjj   2/2       Running             0          1d
ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         3         3            3           1d

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-74d6d58584   3         3         3         28s
replicaset.extensions/sample-deployment-7c85f5b6b4   0         0         0         1d

NAME                                     READY     STATUS    RESTARTS   AGE
pod/sample-deployment-74d6d58584-85ds4   2/2       Running   0          28s
pod/sample-deployment-74d6d58584-hgvxr   2/2       Running   0          22s
pod/sample-deployment-74d6d58584-xws5q   2/2       Running   0          17s

sample-deployment-7c85f5b6b4 のPodが徐々に減り、 sample-deployment-74d6d58584 が立ち上がっていき最終的に全て入れ替わっているのが分かります。
これをローリングアップデートと言います。

ReplicaSetは今立ち上がっているPodを更新するのに対して、Deploymentは新しいPodを立ち上げ、ヘルスチェックなどをしながら反映していってくれます。
実用ではPodやReplicaSetを直接扱うことなく、このDeploymentなどのリソースを通して構成することが基本のようです。

また、下記のコマンドで更新状況を確認することもできます。

ntakehata$ kubectl rollout status deployment sample-deployment
deployment "sample-deployment" successfully rolled out

ロールバック

Deploymentは、更新した後にロールバックすることもできます。
まず、下記の kubectl rollout コマンドで更新した履歴の確認をします。

ntakehata$ kubectl rollout history deployment sample-deployment
deployments "sample-deployment"
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=sample-deployment.yaml --record=true
2         kubectl apply --filename=sample-deployment.yaml --record=true

この中の CHANGE-CAUSE に入っている値が、前述の更新時の --record オプションを付けた場合に記録される内容です。
REVISION の2が現在の状態、1が更新前の状態になります。

ロールバックは下記のコマンドで実行します。
--to-revision で戻したいリビジョン番号を指定します。

ntakehata$ kubectl rollout undo deployment sample-deployment --to-revision 1
deployment.apps "sample-deployment"

そして、ロールバックが完了すると下記のようになります。

ntakehata$ kubectl get deployments,replicasets,pods
NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/sample-deployment   3         3         3            3           1d

NAME                                                 DESIRED   CURRENT   READY     AGE
replicaset.extensions/sample-deployment-74d6d58584   0         0         0         8m
replicaset.extensions/sample-deployment-7c85f5b6b4   3         3         3         1d

NAME                                     READY     STATUS    RESTARTS   AGE
pod/sample-deployment-7c85f5b6b4-747j6   2/2       Running   0          19s
pod/sample-deployment-7c85f5b6b4-95xht   2/2       Running   0          11s
pod/sample-deployment-7c85f5b6b4-ck9fq   2/2       Running   0          15s

今度は sample-deployment-74d6d58584 のPodが消え、 sample-deployment-7c85f5b6b4 のPodが復活していますね。

Service

前述しましたが、Pod内の各コンテナに対して直接HTTP等でアクセスすることはできません。
そこでServiceというリソースを使います。

これは各Podへのロードバランシングを提供する機能です。

ClusterIPでのロードバランシング

まず、下記のマニフェストファイルでServiceを作ってみます。

apiVersion: v1
kind: Service
metadata:
  name: sample-service
spec:
  type: ClusterIP
  ports:
    - name: nginx
      port: 80
    - name: go
      port: 8080
  selector:
    app: sample-app

他のリソースと同様、 kind をServiceを指定することで作成できます。
selector.app で指定しているのが、ロードバランシングの対象とするリソースのラベルです。
先ほどDeploymentで作った「sample-app」を対象としています。

ここでは spec.type の中で ClusterIP を指定しています。
これはServiceに、同じクラスタの中からのみアクセスできるIPを持ったロードバランサーを作ってくれます。
なのでこのServiceではまだローカル環境から直接アクセスすることはできません。

一旦このServiceを作成します。

ntakehata$ kubectl apply -f sample-service.yaml
service "sample-service" created

そして作成したServiceの情報を確認します。

ntakehata$ kubectl describe svc sample-service
Name:              sample-service
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"sample-service","namespace":"default"},"spec":{"ports":[{"name":"nginx","port"...
Selector:          app=sample-app
Type:              ClusterIP
IP:                10.100.151.175
Port:              nginx  80/TCP
TargetPort:        80/TCP
Endpoints:         10.1.0.148:80,10.1.0.149:80,10.1.0.150:80
Session Affinity:  None
Events:            <none>

kubectl describe リソースの詳細を確認するコマンドで、「リソースの種類」「リソース名」をパラメータに渡すことで実行します。
(svcはServiceのことです)

ここで IP: に入っている値がロードバランサーのIP、 Endpoints に入っている値が振り分け先のPodのIPになります。
下記のコマンドでここで紐付いている想定のPodのIPを確認してみましょう。

ntakehata$ kubectl get pods -l app=sample-app -o custom-columns="NAME:{metadata.name},IP:{status.podIP}"
NAME                                 IP
sample-deployment-5b447f977f-4wcbw   10.1.0.150
sample-deployment-5b447f977f-7ts2t   10.1.0.148
sample-deployment-5b447f977f-xmz4n   10.1.0.149

ServiceのEndpointsで入っていたIPと一致します。
このServiceは同じクラスタ内からのみアクセスできるので、下記のように一時的なPodを作成して、そこ経由で先ほど確認したServiceのIPに対してcurlコマンドを実行してみます。

ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175:8080
Hello Deployment!!

80、8080それぞれのポートでレスポンスが返ってきます。
これだけだとロードバランシングが行われているのが分かりづらいので、下記のコマンドで各Podのnginxのindex.htmlを、それぞれのhostnameが表示されるように変更します。

for PODNAME in `kubectl get pods -l app=sample-app -o jsonpath='{.items[*].metadata.name}'`; do kubectl exec -it ${PODNAME} -c nginx -- cp /etc/hostname /usr/share/nginx/html/index.html; done

そして何度かcurlを実行してみると、下記のように各Podに分散してアクセスしていることが分かります。

ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175
sample-deployment-5b447f977f-4wcbw
ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175
sample-deployment-5b447f977f-xmz4n
ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175
sample-deployment-5b447f977f-xmz4n
ntakehata$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- curl -s http://10.100.151.175
sample-deployment-5b447f977f-7ts2t

NordPort ServiceでNodeの外部からアクセス可能に

ClusterIPではクラスタ内でのアクセスを可能にしましたが、最後にNordPort Serviceを使ってクラスタ外からのアクセスを可能にします。
NordPort Serviceは、Kubernetesのクラスタノードの指定されたポートに対する全てのリクエストを受け、ロードバランシングする機能を提供します。

下記のマニフェストファイルを作ってください。

apiVersion: v1
kind: Service
metadata:
  name: sample-nodeport-service
spec:
  type: NodePort
  ports:
    - name: nginx
      port: 80
      targetPort: 80
      nodePort: 30080
    - name: go
      port: 8080
      targetPort: 8080
      nodePort: 30180
  selector:
    app: sample-app

今度は spec.typeNodePort を指定しています。
spec.ports ではいくつかのポートを記述しています。
それぞれ

  • port・・・ClusterIP側で受け付けるポート
  • targetPort・・・振り分け先のコンテナで受け付けるポート
  • nodePort・・・Node側で受け付けるポート

になります。
Node→ClusterIP→コンテナ という流れで転送されます。
ピンと来づらいと思うので、実際に作って見てみます。

ntakehata$ kubectl apply -f sample-nodeport-service.yaml
service "sample-nodeport-service" created

作成したNodeport Serviceの詳細確認。

ntakehata$ kubectl describe svc sample-nodeport-service
Name:                     sample-nodeport-service
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"sample-nodeport-service","namespace":"default"},"spec":{"ports":[{"name":"ngin...
Selector:                 app=sample-app
Type:                     NodePort
IP:                       10.99.244.108
LoadBalancer Ingress:     localhost
Port:                     nginx  8080/TCP
TargetPort:               80/TCP
NodePort:                 nginx  30080/TCP
Endpoints:                10.1.0.148:80,10.1.0.149:80,10.1.0.150:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

ここでも IP: に入っている値が、クラスタのIPになります。
なので例えば http://localhost:30080 にアクセスした場合

localhost:30080(nodePortで指定したポート) ↓ 10.99.244.108:80(portで指定したポート) ↓ 10.1.0.148:80 or 10.1.0.149:80 or 10.1.0.150:80(targetPortで指定したポート)

の流れで転送されることになります。
実際にローカルからcurlコマンドでアクセスしてみます。

ntakehata$ curl http://localhost:30080
sample-deployment-5b447f977f-xmz4n
ntakehata$ curl http://localhost:30080
sample-deployment-5b447f977f-4wcbw
ntakehata$ curl http://localhost:30080
sample-deployment-5b447f977f-7ts2t
ntakehata$ curl http://localhost:30080
sample-deployment-5b447f977f-xmz4n

先ほどと同じように、各Podにロードバランシングされてnginxのコンテナにアクセスしていますね。
30180ポートにアクセスすると、goのコンテナに転送されることも確認できます。

ntakehata$ curl http://localhost:30180
Hello Deployment!!

まとめ

すごくざっくりですが、ローカルにKubernetesで環境を作り、HTTPアクセスできるところまでまとめてみました。

今回は若干間飛ばして書いてあるところはあったりとか、Podの設計とかは全く触れずとりあえずdocker-composeで作っていたものをそのままKubernetes化したりとかざっくりと動かしているので、今度はもっとちゃんとして環境を作ります。

次はPodの設計とかを考えながら、Kotlinでデータベースとかアクセスして動かせる環境を作ろうかなと思っています。