「Dockerfile を書くベスト・プラクティス」の中では、「ほとんどの場合、1つのコンテナの中で1つのプロセスだけ実行すべきです。アプリケーションを複数のコンテナに分離することは、水平スケールやコンテナの再利用を簡単にします。サービスとサービスに依存関係がある場合は、 コンテナのlinkを使います。」[1] とあるが、k8sには、このlinkの機能が提供されれいない。 唯一近いものでは、「Communicate Between Containers in the Same Pod Using a Shared Volume」[2]しか発見できなかった。
そこで、同一POD内で、2つのコンテナが通信する場合の方法についてのメモです。
Pod について
Podの概要について、見直してみると、次の様に記述されていました。[4]
「Podは、アプリケーションコンテナ(場合によっては複数のコンテナ)、ストレージリソース、一意のネットワークIP、およびコンテナの実行方法を管理するオプションをカプセル化します。 Podは、Kubernetesのアプリケーションの単一のインスタンスです。単一のコンテナか、緊密に結合され、リソースを共有する少数のコンテナで構成されています。」
この表現を PHPのアプリケーション実行環境の一部に置き換えると、次の様な図になります。 この中で、今回注目するのは、赤色矢印の部分の実現方法です。
解決策
それぞれのコンテナにIPアドレスが付与されるのではなく、Podで同じIPアドレスとなるのであれば、それと同時にlocalhostも共有していることになります。 つまり、Web Container の localhostに、AP Container の php-fpm もポートを開いてリクエスト待ちしていることになります。
実際に AP Container に入って、net-toolsをインストールして、netstat で調べると、Web Container の TCP 80番ポートが見えています。
$ kubectl exec -it frontend-deploy-1665229993-12gd0 -c app bash
root@frontend-deploy-1665229993-12gd0:/var/www# netstat -natp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 6/nginx: master pro
tcp6 0 0 :::9000 :::* LISTEN 13/php-fpm.conf)
そこで、nginx側の設定で、もともと、dockerコマンドの --link オプションで 接続先コンテナを指定した部分を、次の様にlocalhostへ変更することで、接続が可能になります。
server {
listen 80;
index index.php index.html;
root /var/www;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass localhost:9000; <--- ここの部分は、--link で与えた名前からlocalhostへ変更する
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
k8sのyamlファイル
次のファイルが、kubectl へ与える Deployment のYAMLファイルの該当部分です。 永続ボリュームを共有する部分以外は、設定する必要はありません。
spec:
containers:
- name: app
image: registry.ng.bluemix.net/takara/app:v1
env:
- name: DB_USER
value: root
- name: DB_PASSWORD
value: root
resources: {}
volumeMounts:
- mountPath: /var/www
name: www-vol
subPath: www
- name: web
image: registry.ng.bluemix.net/takara/web:v2
ports:
- containerPort: 80
resources: {}
volumeMounts:
- mountPath: /var/www
name: www-vol
subPath: www
restartPolicy: Always
volumes:
- name: www-vol
persistentVolumeClaim:
claimName: mysql-claim1
参考資料
[1] Dockerfile を書くベスト・プラクティス http://docs.docker.jp/engine/userguide/eng-image/dockerfile_best-practice.html
[2] Communicate Between Containers in the Same Pod Using a Shared Volume https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/
[3] The containers in same pod shares the localhost, so you need not link containers, just use localhost:containerPort. https://stackoverflow.com/questions/27103763/kubernetes-configuration-to-link-containers#comment65978824_31768361
[4] Pod Overview https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/