開発日報

窓際エンジニアの開発備忘。日報は嘘です。

【連載】Kubernates入門・GKEデプロイと発展的利用 第4回 ~ Serviceの概念と詳細 ~

はじめに

この連載ではコンテナオーケストレーションツールである、 Kubernatesの使い方を学びます。
今回はReplicasetとDeploymentについて学習します。

サンプルコード

こちらに順次アップしていきますー。

連載記事一覧

連載記事一覧

Service

ServiceはKubernetesクラスタ内において、Podの集合(ReplicaSet等)に対する経路やサービスディスカバリを提供するためのリソースです。Serviceのターゲットとなる一連のPodは、Serviceで定義するラベルセレクタによって決定されます。

  • サービスディスカバリ : APIへの接続先が動的に変わる場合に、クライアントが接続先を切り替えるのではなく、クライアントからは一貫した名前でアクセスできるようにする仕組み

simple-replicaset-with-label.yamlを作成し、ReplicaSetを2つ定義します。 どちらのReplicaSetも内容はほぼ同じですが、releaseというラベルの内容がそれぞれspringとsummerとなっています。

# simple-replicaset-with-label.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo-spring
  labels:
    app: echo
    release: spring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
      release: spring
  template:
    metadata:
      labels:
        app: echo
        release: spring
    spec:
      containers:
      - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8080
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8080

---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo-summer
  labels:
    app: echo
    release: summer
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echo
      release: summer
  template:
    metadata:
      labels:
        app: echo
        release: summer
    spec:
      containers:
      - name: nginx
        image: gihyodocker/nginx:latest
        env:
        - name: BACKEND_HOST
          value: localhost:8080
        ports:
        - containerPort: 80
      - name: echo
        image: gihyodocker/echo:latest
        ports:
        - containerPort: 8080

マニフェストファイルをapplyし、作成されたPodを確認してみます。releaseラベルにspringとsummerを持つPod・ReplicaSetがそれぞれ実行されていることがわかります。

$ kubectl apply -f simple-replicaset-with-label.yaml
replicaset.apps/echo-spring created
replicaset.apps/echo-summer created

$ kubectl get pod -l app=echo -l release=spring
NAME                READY   STATUS    RESTARTS   AGE
echo-spring-drhn8   2/2     Running   0          2m38s

$ kubectl get pod -l app=echo -l release=summer
NAME                READY   STATUS    RESTARTS   AGE
echo-summer-rxvmg   2/2     Running   0          3m55s
echo-summer-zzjsv   2/2     Running   0          3m55s

release=summerを持つPodだけにアクセスできるようなServiceを作ってみましょう。
次のようにsimple-service.yamlを作成します。
spec.selector属性には、ServiceのターゲットとなるPodのラベルを設定します。

# simple-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    app: echo
    release: summer
  ports:
    - name: http
      port: 80

PodのラベルがServiceにセレクタで定義しているラベルと合致した場合、対象のPodはそのServiceのターゲットとなります。

f:id:yuuu1993g:20191113075133p:plain

simple-service.yamlをapplyしてServiceを作成します。

$ kubectl apply -f simple-service.yaml
service/echo created

$ kubectl get svc echo
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
echo   ClusterIP   10.102.218.109   <none>        80/TCP    7s

実際にrelease=summerを持つPodだけにアクセスできるか確認しましょう。

原則にServiceはKubernetesクラスタの中からしかアクセスできません。
そのためKubernetesクラスタ内に一時的なデバッグコンテナをデプロイし、コンテナ内からcurlコマンドで確認します。

リクエストとしては「http://【サービス名】」となります。 デバッグコンテナ内に入ったら、http://echo/に対してHTTPリクエストを何回か送信します。

$ kubectl run -i --rm --tty debug --image=gihyodocker/fundamental:0.1.0 --restart=Never -- bash -il
 If you don't see a command prompt, try pressing enter.
 debug:/# curl http://echo/
 Hello Docker!!debug:/#

各Podのログを確認してみましょう。

# springラベルがついたPod。アクセスは来ていない。
$ kubectl logs -f echo-spring-drhn8 -c echo
2019/11/12 22:24:44 start server

# summerラベルがついたPod。アクセスが来ている。
$ kubectl logs -f echo-summer-rxvmg -c echo
2019/11/12 22:24:43 start server
2019/11/12 23:05:01 received request
2019/11/12 23:05:06 received request
2019/11/12 23:05:07 received request

# summerラベルがついたPod。アクセスが来ている。
$ kubectl logs -f echo-summer-zzjsv -c echo
2019/11/12 22:24:46 start server
2019/11/12 23:05:05 received request
2019/11/12 23:05:05 received request
2019/11/12 23:05:06 received request
2019/11/12 23:05:07 received request

ClusterIP Service

作成されるServiceには様々な種類があり、yaml内で定義できます。デフォルトがClusterIP Serviceです。
ClusterIPではKubernetesクラスタ上の内部IPアドレスにServiceを公開できます。これにより、あるPodから別のPod群へのアクセスはServiceを介して行うことができ、かつService名で名前解決ができるようになります。ただし、外からはリーチできません。

NodePort Service

NodePort Serviceはクラスタ外からアクセスできるServiceです。 NodePort ServiceはClusterIPを作るという点においてはClusterIP Serviceと同じです。各ノード上からServiceポートへ接続するためのグローバルなポートを開けるという違いがあります。

# simple-nodeport-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: echo
spec:
  type: NodePort
  selector:
    app: echo
  ports:
    - name: http
      port: 80
$ kubectl apply -f simple-nodeport-service.yaml
service/echo configured

$ kubectl get svc echo
NAME   TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
echo   NodePort   10.102.218.109   <none>        80:30270/TCP   50m

$ curl http://127.0.0.1:30270
Hello Docker!!

LoadBalancer Service

LoadBalancer ServiceはローカルKubernetes環境では利用できないServiceです。主に各クラウドプラットフォームで提供されているロードバランサーと連携するためのものです。

ExternalName Service

ExternalName Serviceはselectorもport定義も持たないかなり特殊なServiceです。Kubernetesクラスタ内から外部のホストを解決するためのエイリアスを提供します。
例えば、次のようなServiceを作成するとgihyo.jpをgihyoで名前解決できるようになります。

apiVersion: v1
kind: Service
metadata:
  name: gihyo
spec:
  type: ExternalName
  externalName: gihyo.jp

まとめ

今回はServiceについて学びました。
次回はIngressについて学びます。