tanke25616429のアウトプット

IT技術の基本を勉強したことをアウトプットします。Linux、Kubernetes、クラウド中心です。百番煎じくらいだけど誰かの役に立てばそれはそれでうれしい。

マネージドサービスとフルマネージドサービスの違い

マネージドサービス

本来のサービスに付随する作業を、サービス事業者が請け負ってくれるサービス。

例)

  • 本来のサービス:サーバホスティングサービス、付随する作業:サーバ設定、運用監視等

 → 後者のサーバの利用に付随する作業をサービス利用者側で実施しなくてよい。

フルマネージドサービス

マネージドサービスより、請け負ってくれる範囲が広いサービスで、利用者はサービスに付随する技術的な対応や管理をほぼしなくてよいもの。

例)

  • 本来のサービス:DBMS機能、付随する作業:DBMSそのものの障害監視や障害時の再起動、自動的なバックアップデータ保存

  → 後者のDBMS利用に付随する作業をサービス利用者側でしなくてよい。当然、DBがホストされているサーバの運用監視はやってくれるので、マネージドサービスよりもやってくれる範囲が広いといえる*1

厳密な違いはあるのか?

マネージドサービスとフルマネージドサービスは概ね先述した違いを指すが、厳密な定義があるわけではない。したがってクラウドベンダなどのサービス事業者が「マネージドサービス」「フルマネージドサービス」と言っていても実際に利用する際は、どこまでを利用者が実施する必要があり、どこまでをサービス事業者がやってくれるかを具体的に確認するのが望ましい。自分が想像する「フルマネージドサービス」より、提供されている範囲が狭いかもしれない。

参考にしたもの

マネージドサービスとフルマネージドサービスの違いと、メリット・デメリット|i-TECマネージドクラウド

e-words.jp

www.gixo.jp

*1:この例だとミドルウェア管理をやってくれるものがフルマネージドサービスのように見える。実際にそのように使われている感覚がある。なお、SaaSはアプリケーションの利用をクラウド上で行うが、付随する作業はすべてSaaS事業者がやってくれるので、まさにフルマネージドサービスと言える。

SQS

SQSとは

Amazon Simple Queue Serviceの略。Amazonが提供するフルマネージドのメッセージキューイング機能をサービスとして提供している。

メッセージキューイングとは

異なるアプリケーションプログラム間で動作を連携させてデータを交換させる際の方式のひとつで、送るデータをキューと呼ばれるデータ領域に保持し、データを受ける側の処理が完了するのを待たずに次の処理へ移る方式のこと。アプリケーション間のデータ連携を非同期で行うことができる。

参考にしたもの

aws.amazon.com

www.sophia-it.com

コンテナ内でコマンド実行する方法

目的

コンテナ内でコマンド実行する方法について簡単に整理する。

背景

コンテナの使い方

コンテナは仮想マシンと異なり、汎用的なOSを提供するのではなく、特定の仕事(例えばWebサービスの提供)を実行する目的で存在する*1。1コンテナ1プロセスが基本である。

では、コンテナ内で実行するプロセスはどのように指定されるのであろうか。以降でdockerを例に記載する。

コンテナ実行までの流れ

まず、実行するdockerコンテナがどのように作られるかの流れをおさらいする。

まず、Docker Hub等のコンテナレジストリから、イメージを取得する。取得したイメージをそのまま使うケースもあるが、実際にはカスタマイズがしたいので、Dockerfileと呼ばれる指示書のようなもので、そのイメージに対し各種コマンドを実行し、コンテナイメージを作成する。そのイメージをdocker runコマンドで実行する。

f:id:tanke25616429:20200731101542p:plain
コンテナ実行までの流れ(「さくらのナレッジ Docker入門(第四回)」https://knowledge.sakura.ad.jp/15253/より引用)

コンテナ内で実行するプロセスの指定

コンテナ内で実行するプロセスは以下のいずれかの方法で指定できる。 - Dockerfile内で命令を書く - docker runコマンド実行時のオプションで指定する

実際は上記を組み合わせて使うことで、より柔軟に実行するプロセスを指定できる。

Dockerfileの命令とdocker run命令のオプション

大雑把には、次のように理解できる。 - ENTRYPOINTdocker run 実行時に行われるコマンド*2 - CMD:コマンドのデフォルト引数

が、docker runコマンド実行時のオプション指定と組合せると上記の表現では理解できない挙動があるのでもう少し書く。ENTRYPOINTCMDの有無で場合わけする。

f:id:tanke25616429:20200731111524p:plain
ENTRYPOINTなし CMDなし

f:id:tanke25616429:20200731111702p:plain
ENTRYPOINTあり CMDなし

f:id:tanke25616429:20200731111902p:plain
ENTRYPOINTなし CMDあり

f:id:tanke25616429:20200731112027p:plain
ENTRYPOINTあり CMDあり

ここからわかる通り、基本はコマンドは1つしか実行できない。1コンテナ1プロセスという考え方ともマッチする。とはいえ、複数実行したいケースも当然ある。その方法は別記事にて記載する。

RUN命令について

なお、DockerfileにはRUN命令もあるが、毛色が違うので分けて考えておくのがよい。これもコンテナ内で実行するコマンドを指定しているという面では似ているが、apt-getyum等、コンテナ実行のために必要なパッケージを準備するものとして使われる。コンテナが担う主のタスクそのものを実行することはできない。つまりdocker run時には実行されない。

Kubernetesにおけるコンテナの実行

Kubernetesのpodやdeploymentのmanifestにおいて、コンテナについてcontainers:フィールド内で記述できるが、dockerにおけるENTRYPOINTとCMDに対応するフィールドがある。 ENTRYPOINTに対応するのがcommand:で、CMDに対応するのがargs:である。CMDcommandが対応するではないので注意(紛らわしい)。Kubernetesでは、コンテナを実行するときは例えばkubectl exec ポッド名/コンテナ名 -it -- 引数(コマンドやオプション)で行うが、このときの引数部とcommand:args:の関係はdockerと同じである。

例:podのmanifest

apiVersion: v1
kind: Pod
metadata:
  name: command-demo
spec:
  containers:
  - name: command-demo-container
    image: ubuntu
    command: ["ls", "-l"]
    args: ["-a", "--color"]

例:実行例(ls -l -fが実行される)

$ kubectl exec command-demo -it -- -f

参考にしたもの

Kubernetes完全ガイド impress top gearシリーズ | 青山 真也 | 工学 | Kindleストア | Amazon

Udemy - Certified Kubernetes Administrator(CKA)with Practice Tests

shinkufencer.hateblo.jp

Docker入門(第四回)~Dockerfileについて~ | さくらのナレッジ

DockerfileのCMDとENTRYPOINTを改めて解説する - Qiita

Docker お勉強 03 Dockerfile - sioaji2012のブログ

Dockerfileを改善するためのBest Practice 2019年版

*1:なので、マイクロサービスアーキテクチャの議論とコンテナの議論がセットで出てくるという面があると思われる。

*2:docker run時にENTRYPOINTを上書きしたい場合は、--entrypointというオプションで指定することができる。

KubernetesのServiceにおけるDNS動作の確認方法

背景・目的

Kubernetesではserviceリソースをpodやdeploymentから作成すると、そのKubernetesクラスタ内のコンテナから名前解決ができるようになる。名前解決ができることの確認方法を整理する。

準備:podとserviceの作成

まず、適当なpodを作成する。podのIPが10.244.1.6と割り振られていることがわかる(この値は後で使う)。serviceはデフォルト(タイプはClusterIPとなる)で、ポートは適当に80番で公開することとする。

master $ kubectl run nginx-pod --image=nginx
pod/nginx-pod created
master $ kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx-pod   1/1     Running   0          8s    10.244.1.6   node01   <none>           <none>
master $ kubectl expose pod nginx-pod --name=nginx-svc --port=80
service/nginx-svc exposed
master $ kubectl describe svc nginx-svc
Name:              nginx-svc
Namespace:         default
Labels:            run=nginx-pod
Annotations:       <none>
Selector:          run=nginx-pod
Type:              ClusterIP
IP:                10.107.129.2
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.6:80
Session Affinity:  None
Events:            <none>

serviceの名前解決の確認

確認のためのクライアントとしてbusyboxのコンテナを作成し、そのコンテナの中からnslookupを使って名前解決を試みる。

master $ kubectl run test --image=busybox:1.28 -it -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

DNSに渡すクエリとしてサービス名のnginx-svcだけ渡せば名前解決ができる。DNSサーバのアドレスが10.96.0.10となっていることがわかる。これが何ものかは別記事で触れる。

なぜ、サービス名だけでよいのかは/etc/resolv.confを確認するとわかる。search default.svc.cluster.local svc.cluster.local cluster.localと書かれており、補完が効くようになっている。

/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

よって、名前を途中まで入れても同様に名前解決ができる。以下では試していないが、nginx-svc.default.svc.cluster.localとフルで入れても問題ない。

/ # nslookup nginx-svc.default
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc.default
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local
/ # nslookup nginx-svc.default.svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc.default.svc
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

podの名前解決

pod作成時に付与されたIPアドレスがX.Y.Z.Wだとすると、X-Y-Z-W.default.podでpodに対し名前解決ができる*1。今回はpodのIPが10.244.1.6なので、10-244-1-6.default.podをクエリとして投げると、podのIPが返ってきていることがわかる。

/ # nslookup 10-244-1-6.default.pod
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10-244-1-6.default.pod
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local

↑の一番下の行を見ると、10-244-1-6.nginx-svc.default.svc.cluster.localがフルの名前であるようである。実際、10-244-1-6.nginx-svc等、/etc/resolv.confsearchで補完できる投げ方ならば同様に名前解決が可能である。

/ # nslookup 10-244-1-6.nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10-244-1-6.nginx-svc
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local

補完できない形で名前解決を試みても失敗する。以下、なんとなくできそうだができない例である。

/ # nslookup 10-244-1-6
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve '10-244-1-6'
/ # nslookup nginx-pod.nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'nginx-pod.nginx-svc'

逆引き

IPアドレスから逆引きすることもできる。

/ # nslookup 10.244.1.6
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10.244.1.6
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local
/ # nslookup 10.107.129.2
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10.107.129.2
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

*1:ただ、これではDNSにクエリを投げる時点で、X-Y-Z-Wという文字列がわかっており、ほぼ名前解決できる状態になっているためIPアドレスを知ることが目的ではないように思われる。

シンプルなpod / deploymentをコマンドラインで作る手順

目的

シンプルなpod / deploymentをコマンドラインで作る手順を整理する。複雑なことをしたいときは-o yamlオプションでYAMLファイルに書き出して編集し、kubectl create -f 作成したYAMLファイル名*1したほうがやりやすいことが多い。

バージョン

Kubernetesの1.18で確認。

master $ kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:58:59Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:50:46Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}

kubectl runコマンド

普通にkubectl run ポッド名 --image=イメージ名でPodを作成できる。これも以前のバージョンではエラーが出たような気がする*2

master $ kubectl run mypod --image=nginx
pod/mypod created

master $ kubectl get po
NAME    READY   STATUS    RESTARTS   AGE
mypod   1/1     Running   0          50s

--generator=run-pod/v1をつけても同じことができる。ただし、将来的にdepricatedになる旨の警告が出る。

master $ kubectl run mypod-2 --generator=run-pod/v1 --image=nginx
Flag --generator has been deprecated, has no effect and will be removed in the future.
pod/mypod-2 created
master $ kubectl get po
NAME      READY   STATUS    RESTARTS   AGE
mypod     1/1     Running   0          3m39s
mypod-2   1/1     Running   0          88s

レプリカ数(deploymentに含まれるpodの数*3)をオプションで指定すれば自動でdeploymentにしてくれるかと思いきや、--replicasのオプション自体がないようである。

master $ kubectl run mydeploy --image=nginx --re(tabを押下)
--record            --recursive         --requests          --requests=         --request-timeout   --request-timeout=  --restart           --restart=

kubectl createコマンド

kubectl runではなくkubectl createを使う方法もある。これで作れるリソースは下記の通りである。podは作れない。

master $ kubectl create(tabを押下)
clusterrole          configmap            deployment           namespace            priorityclass        role                 secret               serviceaccount
clusterrolebinding   cronjob              job                  poddisruptionbudget  quota                rolebinding          service

いきなりレプリカ数が複数のdeploymentは作れないようである。

master $ kubectl create deployment mydeploy --image=nginx --replicas=2
Error: unknown flag: --replicas
See 'kubectl create deployment --help' for usage.

したがって、レプリカ数が1のdeploymentを作成し、しかるのちにレプリカ数をkubectl scaleコマンドで増やす等の二段階のやり方になる。

master $ kubectl create deployment mydeploy --image=nginx
deployment.apps/mydeploy created
master $ kubectl describe deployments.apps mydeploy
Name:                   mydeploy
Namespace:              default
CreationTimestamp:      Thu, 30 Jul 2020 03:32:06 +0000
Labels:                 app=mydeploy
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=mydeploy
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
(略)
master $ kubectl scale deployment mydeploy --replicas=2
deployment.apps/mydeploy scaled
master $ kubectl describe deployments.apps mydeploy
Name:                   mydeploy
Namespace:              default
CreationTimestamp:      Thu, 30 Jul 2020 03:32:06 +0000
Labels:                 app=mydeploy
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=mydeploy
Replicas:               2 desired | 2 updated | 2 total | 1 available | 1 unavailable

いきなりレプリカ数が複数のdeploymentを作る方法だが、kubectl Cheat Sheet | Kubernetes を見ても特になさそうである。

まとめ

  • podを作成する:kubectl run pod名 --image=イメージ名
  • deploymentを作成する:kubectl create deployment deployment名 --image=イメージ名

ほとんどのリソースはkubectl createで作れそうなので、podだけrunで作る、と覚えておけばよさそう。

*1:もしくはkubectl apply -f ファイル名

*2:Podを作成時は--generator=run-pod/v1をオプションでつけないといけない気がしたが、つけなくてもできるようである。逆につけないとDeploymentが作成された気もする。残念ながら前のバージョンのクラスタが手元にないので確認はしてない。

*3:普段意識することはないが、正確にはdeploymentの中にreplicasetがあり、そこに含まれるpodの数である。

KubernetesにおけるデフォルトのDockerレジストリ

コンテナイメージの取得元

背景

Kubernetesをインストールした状態で、pod(や、deployment)を作成することができる。このときに、コンテナのイメージは手動であらかじめダウンロードしていない。Kubernetesのインストールパッケージの中に膨大なコンテナイメージが含まれているはずもないので、インターネット越しに取ってきているはずである。どこから持ってきているのだろうか。

[root@master01 ~]# kubectl run nginx-pod --image=nginx
W0729 10:19:46.316434     519 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client.
pod/nginx-pod created

Docker Hub

結論から言うと、Docker Hubというレジストリ・サービスがあり、特に取得するレジストリを指定しない場合はそこから取ってくる*1

Docker Hub以外のレジストリから取得する場合は明示的に指定する。試しに適当なイメージでPodを作成してみたのが次に示す例である*2

[root@master01 ~]# kubectl run test-pod --image=quay.io/coreos/flannel:v0.12.0-amd64
pod/test-pod created
[root@master01 ~]# kubectl get pod test-pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
test-pod   1/1     Running   0          31s   10.0.30.83   worker02   <none>           <none>

quay.io/coreos/というレジストリの場所を示す文字列が入っている。Docker Hubから取得する場合は--image=nginx等のレジストリの場所を示す文字列は省略可能である。

配置対象のワーカノードにもイメージがpullされているのがわかる。REPOSITORYの列を見るとquay.io/coreos/と取得元のレジストリがわかるようになっている。

[root@worker02 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
(略)
quay.io/coreos/flannel      v0.12.0-amd64       4e9f801d2217        4 months ago        52.8MB
(略)

参考にしたもの

  1. knowledge.sakura.ad.jp

  2. www.slideshare.net

*1:直接的に書かれているものが見つけられなかったので、傍証より確認した。参考リンクの1.より「kubectlコマンドでPodを作成するには、作成するPodの情報を記述したYAML形式ファイルを用意し、それを「kubectl create」コマンドの引数として与えれば良い。たとえば、「httpd」(DockerHubで公開されている、Docker公式のApache HTTP Serverを含んだコンテナイメージ)というイメージからコンテナを作成し、そのコンテナの80番ポートに外部からアクセスできるようにするには、以下のような設定ファイル(「pod-httpd.yaml」)を用意する。」という記載があった。直接的に調べるには、kubectl runの内部的な仕組みを知る必要があるが今回は割愛した。kubectl runがdocker runを呼び出し実行しているなら、ソースコードまで追わなくてもdocker側の仕様からわかる。参考リンク2.ではP.49にdocker pullを行うとDocker Hubからイメージを取ってくる図が記載されている

*2:実際にflannelをインストールする場合はflannelのイメージをただpodとして動かすのはダメなので注意。あくまでこれは適当なコンテナイメージを指定したかったためである。flannelを入れたければ、kurbenetes.io等にある手順に従い、manifestファイルをkubectl apply -fすることでインストールする必要がある。

KubernetesのServiceで出てくる各種ポートの意味

本記事の目的

KubernetesでServiceを作成するとPortTragetPortNodePortといろいろなポートが出てくる。忘れがちなのでメモする。

[root@master01 ~]# kubectl describe svc nginx
Name:                     nginx
Namespace:                default
Labels:                   app=nginx
Annotations:              <none>
Selector:                 app=nginx
Type:                     NodePort
IP:                       10.108.101.153
Port:                     <unset>  8080/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30082/TCP
Endpoints:                10.0.1.21:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

NodePort

KuberntesのServiceにはいくつかType(種類)がある。NodePort Serviceはその一つである。NodePort Serviceを作成すると、NodePortというポート番号が設定できる。

このとき、Kubernetesの各ノードのIPにアクセスできるネットワークから、以下のURLでServiceにアクセスできる*1

http://<各ワーカノードのIP(複数ある場合、どのワーカでもよい)>:<NodePortのポート番号>

以下に例を示す。192.168.0.102192.168.0.103はそれぞれワーカノードのIPアドレスである。アクセス元はワーカノードへの疎通性があるところなら何でもよいので、ここではマスターノードからアクセスする。nginxのデフォルトページの応答が返ってきていることがわかる。

[root@master01 ~]# curl http://192.168.0.102:30082
<!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>
[root@master01 ~]# curl http://192.168.0.103:30082
<!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>

それぞれのワーカノードで、NodePortとして設定されているポート番号(この場合は30082)の待ち受け状況を確認する。kube-proxという文字が見えるのでkube-proxyというプロセスがNodePortのポート番号で待ち受けているのが実態とわかる。

ワーカノード1で確認。

[root@worker01 ~]# ss -antu | grep 30082
tcp    LISTEN     0      128       *:30082                 *:*
[root@worker01 ~]# lsof -i :30082
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
kube-prox 3270 root    8u  IPv4  69766      0t0  TCP *:30082 (LISTEN)

ワーカノード2で確認。

[root@worker02 ~]# ss -antu |grep 30082
tcp    LISTEN     0      128       *:30082                 *:*
[root@worker02 ~]# lsof -i :30082
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
kube-prox 2369 root    8u  IPv4  43557      0t0  TCP *:30082 (LISTEN)

Port

KubernetesでServiceを作成するとデフォルトではClusterIP*2というIPが生成される。Portは作成したServiceへClusterIP経由でアクセスする際のポート番号である。ClusterIPはKubernetesクラスター内のコンテナからアクセスできる。以下のURLでアクセス可能。

http://<ClusterIP>:<Portで指定のポート番号>

以下に例を示す。コンテナ内に入り、コンテナ内からnginxの応答が返ってきていることがわかる。この例だとServiceのアクセス先とアクセス元のコンテナが同じなのでわかりにくいが、別に他のコンテナでも同じ方法でアクセスできる。

[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          119d
nginx        NodePort    10.108.101.153   <none>        8080:30082/TCP   11h
[root@master01 ~]# kubectl get pod nginx-f89759699-pksbl
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-pksbl   1/1     Running   0          2d22h
[root@master01 ~]# kubectl exec nginx-f89759699-pksbl -it -- /bin/sh
# curl http://10.108.101.153:8080
<!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>

TargetPort

Serviceとして公開されたアプリケーションの処理の実体を担うコンテナがアクセスを待ち受けているポート番号である。このポートは外部からアクセスするためのURLになるものではない。http://<ClusterIP>:<Portで指定のポート番号>でアクセスを受けたとき、コンテナから見るとTargetPortでアクセスを受けたものとして処理される*3

確認するには、コンテナに入りhttp://localhost:<TargetPortで指定のポート番号>にアクセスしてみればよい。

[root@master01 ~]# kubectl exec nginx-f89759699-pksbl -it -- /bin/sh
# curl http://localhost:80
<!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>

なお、アプリケーション側の設定も正しい必要がある。例えばnginxではnginxのアプリケーションが待ち受けるポートの設定が記述されている。以下の通り、80番ポートでリッスンしており、KubernetesのServiceのTargetPortと一致していることがわかる。

# cat /etc/nginx/conf.d/default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

*1:マスターノードもワーカノードとして使う場合はマスターノードのIPからでもアクセス可能。

*2:ClusterIPはServiceのTypeでもある。

*3:NodePortでサービスを公開している場合、実際にはClusterIPのサービスがその裏で動いている。http://<各ワーカノードのIP>:<NodePortのポート番号>でアクセスを受けた後、いったんClusterIPでアクセスを受ける形になる。