※このブログではサーバー運用、技術の検証等の費用のため広告をいれています。
記事が見づらいなどの問題がありましたらContactからお知らせください。

<前のページ
【Kubernetes】redisのレプリケーションを実装する方法
次のページ>
【Kubernetes】MinikubeでIngressによるServiceの公開方法の解説

【Kubernetes】Serviceの各タイプについて解説

kubernetes Minikube kubectl k8s サーバー開発

投稿日:2020年10月15日

このエントリーをはてなブックマークに追加
KubernetesではPod間の通信や外部へのアプリケーションの公開にServiceというリソースを使用します。Serviceにはいろいろなタイプがあります。この記事ではServiceについて実践を交えつつ解説していきます。

はじめに

KubernetesではPod間の通信や外部へのアプリケーションの公開にServiceというリソースを使用します。Serviceにはいろいろなタイプがあります。

この記事ではServiceについて実践を交えつつ解説していきます。

環境について

  • kubectl version 1.19.2
  • minikube version 1.13.1

ClusterIP

まずは一番基本的なタイプのClusterIPのServiceを作成します。このサービスを作成することでPodからPodへアクセスするための内部IPを定義することができます。

これによって複数のPodに対してクラスター内部のPodのみ単一のIPアドレスでアクセスできます。

例えばmysqlサーバーやRedisサーバーなどは外部から直接アクセスすることはなく、アプリケーションサーバーなどからのみアクセスできるようにしておけば良いためこのClusterIpのServiceを使用します。

yamlファイルを作成します。このyamlファイルではServiceとDeploymentの定義を一つのyamlファイルで定義します(詳しくは【【Kubernetes】1つのyamlファイルで複数のリソースの定義をする方法】)。

clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  selector:
    app: webapp1-clusterip-pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp1-clusterip-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp1-clusterip-pod
  template:
    metadata:
      labels:
        app: webapp1-clusterip-pod
    spec:
      containers:
        - name: webapp1-clusterip-pod
          image: nginx:1.18.0-alpine
          ports:
            - containerPort: 80

まずはyamlの後半部分ではapp=webapp1-clusterip-podというlabelを持ったPodのReplicaSetとそれを管理するDeploymentを作成する定義です。

前半部分の定義ではDeploymentで管理されるPodのポート80へのプロキシのServiceを定義しています。

ここからリソースを作成します。

ターミナル
$ kubectl apply -f clusterip.yaml

確認してみます。

ターミナル
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   21m
my-service   ClusterIP   10.107.205.136   <none>        80/TCP    16m
$ kubectl get rs
NAME                                    DESIRED   CURRENT   READY   AGE
webapp1-clusterip-deployment-6cff5d45   2         2         2       16m
$ kubectl get pods
NAME                                          READY   STATUS    RESTARTS   AGE
webapp1-clusterip-deployment-6cff5d45-6795q   1/1     Running   0          16m
webapp1-clusterip-deployment-6cff5d45-7dbbm   1/1     Running   0          16m

ServiceのTypeは複数存在しますが、今回の様に.spec.typeに何も指定しなかった場合には今回の様にClusterIPタイプのサービスが作成されます。

公式の定義によると

クラスター内部のIPでServiceを公開します。このタイプではServiceはクラスター内部からのみ疎通性があります。

このServiceを通じてPodに、Minikubeのホストからアクセスしてみます。

ターミナル
$ minikube ssh
$ curl 10.107.205.136
<!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のサンプルのレスポンスを受け取ることができました。

sshから退出してServiceとDeploymentを削除しておきます。

ターミナル
$ exit
$ kubectl delete -f clusterip.yml

NodePort

次にNodePortタイプのServiceを作成してみます。NodePortタイプについて公式ドキュメントでは以下のように説明されています。

【公式の説明】

各NodeのIPにて、静的なポート(NodePort)上でServiceを公開します。そのNodePort のServiceが転送する先のClusterIP Serviceが自動的に作成されます。<NodeIP>:<NodePort>にアクセスすることによってServiceにアクセスできるようになります。

つまり基本的に外部に公開するPodへのアクセスを定義するServiceです。

ClusterIPが自動的に作成されるため、内部からのアクセスも外部からのアクセスもどちらも可能です。

例えばDjangoなどのアプリケーションサーバーなどの公開にはこれを使用します。

実際にNodePortサービスのyamlファイルを作ってみます。

nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp1-nodeport-svc
  labels:
    app: webapp1-nodeport-svc
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30080
  selector:
    app: webapp1-nodeport-pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp1-nodeport-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp1-nodeport-pod
  template:
    metadata:
      labels:
        app: webapp1-nodeport-pod
    spec:
      containers:
        - name: webapp1-nodeport-container
          image: nginx:1.18.0-alpine
          ports:
            - containerPort: 80
---

まずはyamlの後半部分ではapp=webapp1-nodeport-podというlabelを持ったPodのReplicaSetとそれを管理するDeploymentを作成する定義です。

前半部分の定義ではDeploymentで管理されるPodのポート80にプロキシするNodePortタイプのServiceを定義しています。

これを適用させることでNodeの30080番ポートに対してapp= webapp1-nodeport-podというラベルのPodを公開できます。

ターミナル
$ kubectl apply -f nodeport.yaml

確認してみましょう。

ターミナル
$ kubectl apply -f nodeport.yaml 
service/webapp1-nodeport-svc configured
deployment.apps/webapp1-nodeport-deployment unchanged
(base) ogihara@ubuntu:~/kubernetes_sample/networking$ kubectl get deployments
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
webapp1-nodeport-deployment   2/2     2            2           12m
$ kubectl get rs
NAME                                     DESIRED   CURRENT   READY   AGE
webapp1-nodeport-deployment-675d7896c6   0         0         0       12m
webapp1-nodeport-deployment-68fddbcc5f   2         2         2       8m21s
$ kubectl get pods
NAME                                           READY   STATUS    RESTARTS   AGE
webapp1-nodeport-deployment-68fddbcc5f-cfk5m   1/1     Running   0          8m23s
webapp1-nodeport-deployment-68fddbcc5f-vhp5m   1/1     Running   0          8m28s
$ kubectl get svc
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes             ClusterIP   10.96.0.1       <none>        443/TCP        103m
webapp1-nodeport-svc   NodePort    10.103.32.197   <none>        80:30080/TCP   8m37s

それぞれのリソースは問題なく動いているようです。

実際にサービスにアクセスできるかどうか確認してみます。

NodePortのServiceには<NodeのIPアドレス>:<NodePort>でアクセスできます。これら値の確認方法について詳しくは【Kubernetes】ServiceのIPアドレスとポートについてを参照してください。

ブラウザでアクセスしてみると以下のようなNginxのデフォルトページが表示されます。

▲NodeのPortから公開されているページ

最後にServiceとDeploymentを削除しておきます。

ターミナル
$ kubectl delete -f nodeport.yaml

ExternalIP

複数のNodeクラスターがある場合は、ClusterIPタイプのIPのExternalIPを使用することでもServiceを公開させることができます。

ExternalIPにはNodeのIPを指定します。

今回使用しているMinikubeは仮想的マシンで単一ノードのKubernetesクラスターを形成しているため、まずはローカルにおけるこのNodeのローカルIPアドレスを取得します。

ターミナル
$ minikube ip
192.168.39.91

次にyamlファイルを作成します。

externalip.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp1-externalip-svc
  labels:
    app: webapp1-externalip-svc
spec:
  type: ClusterIP
  ports:
    - port: 80
  externalIPs:
    - 192.168.39.91
  selector:
    app: webapp1-externalip-pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp1-externalip-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp1-externalip-pod
  template:
    metadata:
      labels:
        app: webapp1-externalip-pod
    spec:
      containers:
        - name: webapp1-externalip-app
          image: nginx:1.18.0-alpine
          ports:
            - containerPort: 80
---

基本的にClusterIPの節で解説した内容とほとんど同じです。

ここでは新しくServiceのディレクティブの.spec.externalIPsでNodeのIPアドレスを指定しています。もしここで複数のNodeのIPアドレスを指定した場合はそれらのアドレスで公開することができます。

ターミナル
$ kubectl describe svc webapp1-externalip-svc
Name:              webapp1-externalip-svc
Namespace:         default
Labels:            app=webapp1-externalip-svc
Annotations:       <none>
Selector:          app=webapp1-externalip-pod
Type:              ClusterIP
IP:                10.105.182.125
External IPs:      192.168.39.91
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         172.17.0.3:80,172.17.0.4:80
Session Affinity:  None
Events:            <none>

ローカルのブラウザから確認してみるとnginxのサンプルページが確認できます。

▲ブラウザから確認したサンプルページ

LoadBalancer

よくクラウドのGCPのComputeEngineやAWSのEC2インスタンスでサーバーを立てた際に、クラウドのロードバランサーサービスを通して公開したりします。KubernetesのServiceにはLoadBalacerタイプが用意されています。GKEなどのクラウドのKubernetesエンジンではこのタイプが指定された際にはクラウドのロードバランサーが自動的に使用されます。

今回はそのままローカルでロードバランサーを作成してみます。

loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp1-loadbalancer-svc
  labels:
    app: webapp1-loadbalancer-svc
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: webapp1-loadbalancer-pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp1-loadbalancer-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp1-loadbalancer-pod
  template:
    metadata:
      labels:
        app: webapp1-loadbalancer-pod
    spec:
      containers:
        - name: webapp1-loadbalancer-app
          image: nginx:1.18.0-alpine
          ports:
            - containerPort: 80
---
ターミナル
$ kubectl apply -f loadbalancer.yaml

確認してみます。

ターミナル
$ kubectl describe svc webapp1-loadbalancer-svc
Name:                     webapp1-loadbalancer-svc
Namespace:                default
Labels:                   app=webapp1-loadbalancer-svc
Annotations:              <none>
Selector:                 app=webapp1-loadbalancer-pod
Type:                     LoadBalancer
IP:                       10.110.242.134
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30515/TCP
Endpoints:                172.17.0.3:80,172.17.0.4:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
$ minikube service webapp1-loadbalancer-svc --url
http://192.168.39.91:30515

ローカルのマシンからはhttp://192.168.39.91:30515でアクセスできます。


さいごに

今回はNetworkingについて学習しました。

一番よく使うことになるのはLoadBalancerタイプかな?クラウドで使う場合にはもう少し細かい設定があるみたいです。後々そのあたりも勉強していきます。

このエントリーをはてなブックマークに追加

<前のページ
【Kubernetes】redisのレプリケーションを実装する方法
次のページ>
【Kubernetes】MinikubeでIngressによるServiceの公開方法の解説

関連記事

記事へのコメント