Kubernetes 完全ガイド

WorkloadsAPIs カテゴリ

Pod

Pod のデザインパターン

サイドカーパターン

サイドカーパターンは、メインのコンテナに加えて、補助的な機能を追加するコンテナを内包したパターン。
多くの場合はデータや設定にまつわるパターンである。

  • 特定の変更を検知した際に動的に設定を変更するコンテナ
  • Git リポジトリとローカルストレージを同期するコンテナ
  • アプリケーションのログファイルをオブジェクトストレージに転送するコンテナ

アンバサダーパターン

アンバサダーパターンは、メインのコンテナが外部のシステムと接続する際に代理で中継を行うコンテナを内包したパターン。
メインコンテナと外部のシステムが疎結合になることで、アプリケーションから見ると環境差を考慮する必要がなくなる。

  • メインコンテナから常に localhost を指定してアンバサダーコンテナのみへ接続し、開発環境では単一のデータベースを使用しているが、本番環境では分割されたデータベースを使用する

アダプターパターン

アダプターパターンは、外部からのリクエストに対して差分を吸収するコンテナを内包したパターン。
BFF のようなもの。

  • Prometheus などの監視ソフトウェアで決まったフォーマットでメトリクスを整形する

Pod の作成

pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  dnsPolicy: ClusterFirst
  containers:
  - name: nginx-container
    image: nginx:1.16
    workingDir: /tmp

Pod の DNS 設定とサービスディスカバリ

DNS サーバに関する設定は「spec.dnsPolicy」に記述。

ClusterFirst(デフォルト)

クラスタ内の DNS サーバを使って名前解決を行い、解決できない場合アップストリームの DNS サーバに問い合わせを行う。

None

クラスタ外の DNS サーバを参照させたい場合、「spec.dnsConfig」に設定したい値を記述する。
しかし、クラスタ内 DNS を利用したサービスディスカバリができなくなる。

Default

Kubernetes Node の DNS 設定をそのまま引き継ぐ場合には、「spec.dnsPolicy: Default」に設定。

DNS 設定の確認

$ kubectl exec -it sample-pod -- cat /etc/resolv.conf

静的な名前解決(/etc/hosts)

DNS による名前解決の前に/etc/hosts ファイルによる静的な名前解決を行う。
「spec.hostAliases」で/etc/hosts を書き換えることが可能。

ReplicaSet

Pod のレプリカを作成し、指定した数の Pod を維持し続けるリソース。
同じラベルをもつ Pod を ReplicaSet 外で作成した場合は、RS が Pod を増やしすぎた勘違いし、既存の Pod を削除してしまうため、ラベルはユニークにつける必要がある。

rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sample-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.6

Deployment

複数の ReplicaSet を管理することで、ローリングアップデートやロールバックなどを実現するリソース。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.6

Deployment に変更があると ReplicaSet が作成されるが、この「変更」とは作成される Pod の内容の変更で「spec.template」に変更がある場合である。(Pod の構造体のハッシュ値をラベル付で管理しているため、Pod の内容に変更がない場合既存の ReplicaSet を利用するようになっている。)

Deployment 更新の一時停止

安全のために、Deployment に対する変更を行なっても適用は待ってほしい場合がある。
即時適用を一時停止したい場合は、「kubectl rollout pause」を実行し、再開するには「kubectl rollout resume」を実行。

Deployment のアップデート

Recreate は、一度全ての Pod を削除してから再度 Pod を作成するためダウンタイムが発生する。

ServiceAPIs カテゴリ

Kubernetes クラスタのネットワークと Service

Kubernetes クラスタを構築するとノードごとに Pod のための内部ネットワークを自動的に構成する。この内部ネットワークが自動構成されているため、Pod は Service を利用せずとも Pod 間通信を行うことが可能。
しかし、Service を利用することには以下のメリットがある。

  • Pod 宛トラフィックのロードバランシング
  • サービスディスカバリとクラスタ内 DNS

Pod 宛トラフィックのロードバランシング

Deployment を使用して Pod を複数起動できるが、Pod は起動するごとにそれぞれ異なる IP アドレスが割り当てられる。自前でロードバランシングを実装するとすると、毎回 Pod の IP を調べて設定しなければならない。

名前によるポートの参照

Pod のポート定義に名前を付与しておくことで、名前を用いた参照を行うことが可能。この機能を利用することで、異なる宛先のポート番号を扱うことが可能。

pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: simple-named-pord-pod-80
  labels:
    app: sample-app
spec:
  containers:
  - name: nginx-container
    image: amsy810/echo-nginx:v2.0
    ports:
      - name: http
        containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: simple-named-pord-pod-81
  labels:
    app: sample-app
spec:
  containers:
  - name: nginx-container
    image: amsy810/echo-nginx:v2.0
    ports:
      - name: http
        containerPort: 81
---
apiVersion: v1
kind: Service
metadata:
  name: sample-named-port-service
spec:
  type: ClusterIP
  ports:
  - name: "http-port"
    protocol: "TCP"
    port: 8080
    targetPort: http
  selector:
    app: sample-app

クラスタ内 DNS とサービスディスカバリ

サービスディスカバリとは、特定の条件の対象となるメンバを列挙したり、名前からエンドポイントを判別する機能。

  • 環境変数を利用したサービスディスカバリ
  • DNS A レコードを利用したサービスディスカバリ
  • DNS SRV レコードを利用したサービスディスカバリ

環境変数を利用したサービスディスカバリ

Pod 内からは、環境変数でも同じ Namespace のサービスが確認できるようになっている。

$ kubectl exec -it [pod名] -- env | grep -i sample_clsuterip
SAMPLE_CLUSTERIP_SERVICE_HOST=[ServiceのPodのホスト]
SAMPLE_CLUSTERIP_SERVICE_PORT=8080

DNS A  レコードを利用したサービスディスカバリ

Service リソースの IP アドレスを接続元コンテナの設定ファイルなどで明示的に指定してしまうと、Service 作成のたびに設定ファイルなどの変更が必要になる。
DNS 名を利用すれば、Service の再作成による IP アドレスの変更も気にする必要がありませんし、設定ファイルの変更を行う必要もありません。

正式な FQDN は、[Service 名].[Namespace 名].svc.cluster.local となっている。
コンテナ内の/etc/resolv.conf に下記のような記述があるため、[Service 名].default や[Service 名]だけでも名前解決できるようになる。

$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- cat /etc/resolv.conf
nameserver 10.11.240.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
...

また、逆引きもできるようになっている。

$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod --command -- dig -x 10.11.253.80

:: ANSWER SECTION::
80.253.11.10.in-addr.arpa. 30 IN PTR sample-clusterip.default.svc.cluster.local.

DNS SRV レコードを利用したサービスディスカバリ

SRV レコードとは、DNS で定義されるそのドメインについての情報の種類の一つで、そのドメインで提供されているサービスの詳細な情報を記述するためのもの。

SRV レコードを使って Service のエンドポイント(宛先のホスト名と Port 番号)も確認できる。SRV レコードは、Port めいと Protocol を利用することで、サービスを提供している Port 番号を含めたエンドポイントを DNS で解決する仕組み。
レコードの形式は、[_Service の Port 名].[_Protocol].[Service 名].[Namespace 名].svc.cluster.local である。

$ kubectl run --image=amsy810/tools:v2.0 --restart=Never --rm -i testpod \
  --command -- dig _http-port._tcp.sample-clusterip.default.svc.cluster.local SRV

:: ANSWER SECTION::
_http-port._tcp.sample-clusterip.default.svc.cluster.local. 30 IN SRV 10 100 8080
sample-clusterip.default.svc.cluster.local.

Node Local DNS Cache

大規模なクラスタでのパフォーマンスを向上させるために各ノードのローカル上に DNS キャッシュサーバを用意する仕組みがある。

ClusterIP Service

ClusterIP 宛の通信は、各ノード上で実行しているシステムコンポーネントの kube-proxy が Pod 向けに転送を行う。