Help us understand the problem. What is going on with this article?

Kubernetesでのコンポーネント間の通信をまとめる

はじめに

CaaS(Container as a Service)を使った開発は増えてきていることと思います。
私自身もCaaS環境にてリリースを行うプロダクトを複数持っています。
そしてプロダクトを設計していくときに大事なのが、ネットワークですね。
マイクロサービス化していく中で、サービス同士での通信をする機会というのは増えていくと思います。
なので、今回Caas環境のサービスであるKubernetesの通信をまとめます。

なお、この記事に書くにあたり作成したコードは全て walk8243/kubernetes-communication にあります。

まとめる通信

まとめる対象の通信は以下の画像にある通りです。
通信は、緑の四角のコンテナから、青の四角のコンテナに向けて送信します。
まとめる通信の内容

デプロイファイル

Kubernetesにデプロイする際に使用するコードは全て、 walk8243/kubernetes-communication/deploy.yaml にあります。

この記事中では、Kubernetesを扱うことのできる minikube を使っています。
minikube が既にインストールされていることを前提に進めていきますので、インストールしていない場合は Minikubeのインストール - Kubernetes を参考にインストールしてください。

サーバーの基本設定

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: nginx
        image: nginx

上の設定をベースとして、ルートにアクセスされた際、 Hello World! と書かれた index.html を返します。

クライアントの基本設定

apiVersion: v1
kind: Pod
metadata:
  name: client
spec:
  containers:
  - name: shell
    image: centos
    command:
    - /bin/sh
    - "-c"
    - "-"
    args:
    - "while :; do sleep 1000; done"

shell というコンテナがあります。このコンテナからサーバーに対してアクセスします。
なお、クライアントコンテナには、以下のようなスクリプトでログインします。

kubectl exec -it client -c shell /bin/bash

実際に通信してみる

使用するコンテナなどをデプロイするためのスクリプトは用意しています。
よろしければGitHubから walk8243/kubernetes-communication をクローンしてお使いください。

# Linuxの場合
sh deploy.sh

# Windowsの場合
.\deploy.cmd

全てのケースにおいて、 Hello World! が返ってくれば通信成功です。

ケース①コンテナ間(同一ポッド内)

同じPodの中で、異なるContainer同士での通信を行います。
ここでは、ポートとUNIXドメインソケットの2つ方法をご紹介致します。

このケースの中でログインするコンテナは、 Deployment によって作成されたコンテナになるので、 Deployment を指定してログインします。

kubectl exec -it deploy/server -c shell --namespace=k8s-communication /bin/bash

ポートで接続

受信方法

ポートを使ったリクエストの受信には、nginxのDockerイメージで用意してくれている80番ポートをそのまま使います。

送信方法

curl コマンドで、リクエストを送信します。

curl localhost

UNIXドメインソケットで接続

UNIXドメインソケットを用いた通信に関しては、 Node.jsでもUNIXドメインソケットを使いたい#unixドメインソケットとは に書いていますので、是非ご覧ください。

以下にような設定で、通信を行うことができます。

受信方法

受信するためのnginxの設定は以下になります。

/etc/nginx/conf.d/socket.conf
server {
    listen       unix:/var/sock/nginx.sock;
    root   /usr/share/nginx/html;
    index  index.html index.htm;
}

なお、 /var/sock/nginx.sock は通信開始時に配置されるので、デプロイ時に用意するのはsockファイルを配置するためのフォルダです。
/var/sock はKubernetesの Volume を使って作成します。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: server
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: socket-dir
          mountPath: /var/sock
      volumes:
      - name: socket-dir
        emptyDir: {}

送信方法

以下のコマンドを叩くことで、 /var/sock/nginx.sock を使ってUNIXドメインソケットによるリクエストの送信ができます。
なお、送信に利用している ncyum install nc でインストールしています。

echo 'GET /' | nc -U /var/sock/nginx.sock

このときの /var/sock フォルダは、受信側の nginx コンテナと Volume で共有しています。

ケース②ポッド間(同一ネームスペース内)

ネームスペース k8s-communication 内にあるサービス server を使ってリクエストを送信します。

curl server

使用するネームサーバーの情報は以下のようになっています。

/etc/resolv.conf
nameserver 10.96.0.10
search k8s-communication.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

この中の k8s-communication.svc.cluster.local でドメイン解決が行われています。

ケース③ポッド間(ネームスペース違い)

ケース②と同じように curl server としても、リクエストは届きません。
届かない理由は、ドメイン解決ができないことにあります。
なので、ケース②と使用するネームサーバーを変えます。

今回のようなネームスペースが違う場合で使用するネームサーバーは svc.cluster.localcluster.local になります。
svc.cluster.local を使うケースは、 Service に向かって通信を行う場合です。
今回はケース②と同様にネームスペース k8s-communication 内にあるサービス server を使ってリクエストを送信したいため、 svc.cluster.local を使用します。
先ほどのケース②と同じようにネームサーバー k8s-communication.svc.cluster.local を見に行くことができるように、リクエスト送信時のホスト名を少し工夫します。

curl server.k8s-communication

これで、ネームサーバー svc.cluster.local 経由で、ネームサーバー k8s-communication.svc.cluster.local を見に行くことが可能になり、無事リクエストが到達できるようになります。

なお、ネームスペース k8s-communication-sub でのネームサーバーの情報は以下の通りです。

/etc/resolv.conf
nameserver 10.96.0.10
search k8s-communication-sub.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

ケース④サーバー間

ここでは、minikubeの外からの通信を想定しています。
Kubernetesの中に作成したServiceを外部からアクセスできるようにするために、以下のコマンドを使用します。
このコマンドは、デプロイスクリプトの中に含まれています。

minikube service server --namespace=k8s-communication

上記のコマンドを実行後に、以下のコマンドを実行して、リクエスト先のURLを表示してください。
そこで表示されたURLをコピーして、ブラウザなどからアクセスしてください。

minikube service server --namespace=k8s-communication --url=true

おわりに

今回、4パターンの場所からサーバーに向けてリクエストを送信してみました。
近い距離の方が簡単に通信できますが、遠くなっても適切に設定してあげればちゃんと通信することは可能です。
また、Kubernetes内でDNSの設備はしっかりとしているので、ルールさえ押さえておけば、固定値で簡単に扱えます。
通信方法に怖がらず、何を作りたいかに合わせてモノを設計していきましょう!!

walk8243
ただの乃木オタです。 業務中に感じた良く分からない気持ち悪さを、形にして解決するにはどうしたらいいかを考えながら記事を書いてます。 執筆は握手会の会場でできるからいいですね!
yahoo-japan-corp
Yahoo! JAPAN を運営しています。
https://www.yahoo.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした