LoginSignup
0
1

Serviceとは

Serviceは、クラスター内で1つ以上のPodとして実行されているネットワークアプリケーションを公開する方法です。

なぜServiceが必要なのか

KubernetesのPodは、クラスターの状態に合わせて作成されたり削除されたりします。例えば、あるノードがダウンしてしまったときに、そのノードで動いていたPodを他のノードで再作成する場合などが考えられます。そのようなシナリオの場合、Pod自体に外部向けのIPアドレスを割り当てていると、ユーザーは新しく再作成されたPodのIPアドレスをいちいち取得して修正する必要があります。
image.png

そこでワンクッション挟んで、Serviceというリソースに外部向けIPアドレスを割り当て、このIPアドレスを固定しておくことでユーザーはPodの状態にかかわらず同一のIPアドレスでPodにアクセスすることができるようになります。
image.png

ServiceとPodの結び付け

ServiceとPodの結び付けは、基本的にはセレクターを用いて行われます。Podに付与したラベルを見て、適切なPodにトラフィックをルーティングします。
image.png

Serviceの作成方法

Podの時と同様、Serviceを作成する方法は二つあります。

  1. ワンライナーで作成する
  2. マニフェストファイルから作成する

ワンライナーで作成する

まずは、以下のコマンドでnginxのPodを作成します。

kubectl run nginx-pod --image=nginx --port=80

次に、Serviceを作成します。

kubectl expose pod nginx-pod --type=NodePort --name=nginx-service --port=80 --target-port=80

解放されたポートを確認します。

$ kubectl describe svc nginx-service
Name:                     nginx-service
Namespace:                default
Labels:                   run=nginx-pod
Annotations:              <none>
Selector:                 run=nginx-pod
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.150.153
IPs:                      10.96.150.153
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30127/TCP <= この値
Endpoints:                10.0.10.79:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Podが配置されたNodeのIPを確認します。

$ kubectl get po -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
nginx-pod               1/1     Running   0          23m   10.0.10.79    10.0.10.71    <none>           <none>

上記の出力から、10.0.10.71のノードに配置されていることが分かります。
以上から、以下のコマンドでアクセスできるかを確認します。

$ curl 10.0.10.71:30127
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

接続できていることが分かります。

ServiceとPodの結びつきはセレクターとラベルで行うというお話をしましたが、ワンライナーで作成する場合、それらを指定していません。では、セレクターとラベルはどのように定義されているのでしょうか?

まず、Serviceのセレクターを確認します。

$ kubectl describe svc nginx-service
Name:                     nginx-service
Namespace:                default
Labels:                   run=nginx-pod
Annotations:              <none>
Selector:                 run=nginx-pod <= セレクター
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.150.153
IPs:                      10.96.150.153
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30127/TCP
Endpoints:                10.0.10.79:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

セレクターは、run=nginx-podになっていることが分かります。
次に、nginx-podのラベルを確認してみます。

$ kubectl describe po nginx-pod
Name:             nginx-pod
Namespace:        default
Priority:         0
Service Account:  default
Node:             10.0.10.71/10.0.10.71
Start Time:       Tue, 25 Jun 2024 02:38:24 +0000
Labels:           run=nginx-pod  <= ラベル
Annotations:      <none>
Status:           Running
IP:               10.0.10.79
IPs:
  IP:  10.0.10.79
Containers:
  nginx-pod:
    Container ID:   cri-o://c444353ec04d9a00a4ddcdede7932930799b31c9cd1ac84e20a56d6d6c65672c
    Image:          nginx
    Image ID:       e0c9858e10ed8be697dc2809db78c57357ffc82de88c69a3dee5d148354679ef
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Tue, 25 Jun 2024 02:38:25 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-62dd9 (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True
  Initialized                 True
  Ready                       True
  ContainersReady             True
  PodScheduled                True
Volumes:
  kube-api-access-62dd9:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:                      <none>

Podには、run=nginx-podのラベルが付与されていることが分かります。kubectl runコマンドでPodを作成したとき、Pod名を指定したと思いますが、それがそのままrun=nginx-podに来ています。Serviceを作成する際は、kubectl expose pod nginx-podでこのPodを指定しているので、セレクターにもrun=nginx-podが設定できています。

マニフェストファイルから作成する

kubectl run nginx-pod --image=nginx --port=80で作成した先ほどのPodに接続するためのServiceを、次はマニフェストファイルから作成してみます。

まずは、先ほど作成したServiceを削除します。

$ kubectl get svc
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP,12250/TCP   47d
nginx-service   NodePort    10.96.150.153   <none>        80:30127/TCP        79m

$ kubectl delete svc nginx-service
service "nginx-service" deleted

次に、以下のマニフェストファイルを作成します。

nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport-service
spec:
  type: NodePort
  selector:
    run: nginx-pod
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30007

spec.selectorには、Podのラベルであるrun=nginx-podを指定します。spec.ports.nodePortには、適当に30007を指定しました(基本的には30000-32767を割り当てます)。

このマニフェストファイルをクラスターに適用します。

$ kubectl apply -f nginx-service.yaml
service/nginx-nodeport-service created

接続を確認します。

$ kubectl get svc # 作成したServiceを確認
NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
kubernetes               ClusterIP   10.96.0.1      <none>        443/TCP,12250/TCP   47d
nginx-nodeport-service   NodePort    10.96.227.37   <none>        80:30007/TCP        6s

$ kubectl get po -o wide # Podが配置されたノードのIPアドレスを確認
NAME                    READY   STATUS    RESTARTS   AGE    IP            NODE          NOMINATED NODE   READINESS GATES
nginx-pod               1/1     Running   0          101m   10.0.10.79    10.0.10.71    <none>           <none>

$ curl 10.0.10.71:30007 # 接続を確認
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

kubectl exposeコマンドの時と同様、正しく接続できていることが分かります。

その他のServiceタイプ

今回は例としてNodePortを使いましたが、Serviceには以下のタイプがあります。

  • ClusterIP
  • NodePort
  • LoadBalancer
  • ExternalName

ClusterIP

クラスター内部のIPでServiceを公開します。このタイプでは、クラスター内部からのみ接続できます。

NodePort

今回作成したServiceのタイプです。各ノードのIPにて、静的なポート上でServiceを公開します。
ServiceにClusterIPが作成されるので、クラスター内部からの通信の場合はこのServiceのClusterIPを使って通信します。
クラスター外部からの通信の場合は、PodがデプロイされたノードのIPとNodePortで公開しているポートを調べて、通信します。

LoadBalancer

Service用にロードバランサ―をプロビジョニングして、ロードバランサ―経由でアクセスするためのタイプです。クラウドプロバイダー上で使用すると、自動でそのクラウドプロバイダーが提供するロードバランサ―が作成され、Serviceに紐づきます。
マネージドのKubernetesを使う場合は特に何の事前準備もなく利用できますが、そうでない場合はクラウドプロバイダー毎に必要なクラウドコントローラーマネージャをインストールする必要があります。

このタイプでPodを公開した場合、Podがデプロイされたノードに関わらず、ロードバランサ―のパブリックIPアドレスでPodにアクセスすることができます。
image.png

ExternalName

クラスタ内の名前解決を、クラスタ外部のDNS名にマッピングするために使用されます。これによって、クラスタ内のアプリケーションが内部的に定義された名前を使用して、クラスタ外部のリソースにアクセスできるようになります。

まとめ

今回はServiceについて概要を説明しました。次回はPodのレプリカを維持するための、Replicasetについて説明したいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1