問題:Reactサーバのホスト名を取得する方法は?
あなたは以下のようにkubernetesを使ってReactサーバーのレプリカを生成し、冗長化しました。
さて、同じIPアドレスにアクセスしても、実際には違うPodのReactサーバーにアクセスしていることを確認するために、各Reactサーバーのホストネームをレンダリング時に表示したいと思います。
こんなとき、どうすれば良いでしょう??
ちなみに、クライアントサイドで以下のコードで取得できるのは、今回取得したいものではないです。
const hostname = window.location.hostname;
console.log(`Hostname: ${hostname}`);
例えば、Qiitaのページを開いているときに、ブラウザの開発者ツールを開いて以上を実行すると、以下が表示されます。
Hostname: qiita.com
これは、FQDNであり実際にはロードバランサーやプロキシーサーバのアドレスを示しています。実際にReactを動かしているサーバーやポッドのホスト名ではないですね。
(クライアントサイドレンダリングの)Reactのコードはブラウザ上で実行されていますので、クライアントサーバーのコードに最初から工夫がなされていなければ、ブラウザからでは、どうやったってポッドに振り分けられる前までのアドレスしか分かりません。
作戦:Pod起動時にホストネームをテキストファイルに書き込む
では、どうすれば、Reactサーバが置かれているPodのホストネームを取得できるのでしょうか?
泥臭いながら、考えられる作戦として「ポッド作成時にホストネームをテキストファイルに書き込み、それを読み込むようにする」があります。
具体的には以下です。
- Reactアプリケーションをコンテナ化し、kubenetesのPod内でコンテナをデプロイする
- コンテナ起動時に、ホストネームを記述したhostname.txtを生成し、/react-app/public/以下に保存
- Reactのコンポーネントレンダリング時に、hostname.txtを読み込み、記述されたホストネームを表示
以下でその具体的手順を紹介します。
1. テキストファイルテキストを読み込むロジック
あとでPublicフォルダにホストネームが書かれたテキストファイルを置くので、先にそれを読み込み表示するロジックを作成しておきます。
function App() {
const [ hostname, setHostname] = useState("");
const getHostname = async () => {
const reponse = await fetch(`${process.env.PUBLIC_URL}/hostname.txt`);
const text = await reponse.text();
setHostname(text);
return text;
};
useEffect(
() => {getHostname();}, [hostname]
);
return (
<div>{`pod name : ${hostname}`}</div>
)
}
2. アプリケーションのコンテナ化
create-react-app
コマンドなどでReactのアプリケーションを作ったあと、package.jsonなどがあるのと同じ階層に、以下のDocerfileとstartup.sh(コンテナ起動時に実行したいコマンドをまとめて書くためのファイル)を作成します。
FROM node:16.13.0-alpine AS builder
WORKDIR /usr/local/app
COPY . .
RUN yarn --frozen-lockfile && \
yarn build
FROM nginx:1.20-alpine
COPY --from=builder /usr/local/app/build /usr/share/nginx/html
COPY startup.sh /startup.sh
RUN chmod 744 /startup.sh
CMD ["/startup.sh"]
以下のstartup.shが、コンテナ起動時に実行されますが、見ての通り、一行目でホストネームをhostname.txtへと書き込んでいます。
hostname >> /usr/share/nginx/html/hostname.txt
nginx -g "daemon off;"
次に、コンテナイメージをビルドしていきます。
コマンドは以下です。(DockerHubにプッシュしますので、先にDockerHubにサインアップしておく必要があります。以下、あなたのアカウント名をyournameとします。)
docker build --tag {yourname}/react-app:latest --no-cache .
docker run --name react-app --rm --publish 3000:80 {yourname}/react-app:latest
docker push {yourname}/react-app:latest
ビルドしたイメージのDockerHubへUploadも終わり、これで準備は完了です。
3. kubenetesでPodを3つ作成し、Reactアプリケーションを冗長化する
kubernetesでPodを3つ作るには、以下のyamlファイルを作成します。ローカルで実行していますので、ここではminikube使っています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: react-app
spec:
replicas: 3
selector:
matchLabels:
app: react-app
template:
metadata:
labels:
app: react-app
spec:
containers:
- name: react
image: {yourname}/react-app # Edit
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: react-app
spec:
type: NodePort
selector:
app: react-app
ports:
- port: 3000
targetPort: 80
protocol: TCP
name: react-app
そして、以下のコマンドを実行します。
minikube start
kubectl apply --filename ./deployment-service-react.yaml
minikube service reputation-checker-react
で、アプリのデプロイとアドレスの公開までできます。
以下↓に自分の環境で実行したときのスクリーンショットを貼ります。
クロームのシークレットウィンドウを用いて同じアドレスにアクセスすると、表示されるPodの名前が異なることが分かります。
まとめ
さて、以上の手順を経ることで、KubenetesでReactサーバが複数のPodに置かれ冗長化されたときの、各Reactサーバが置かれているPodのホスト名を表示することができることを示しました。
実際問題、ホストネームを表示したいときなんてかなり稀ですが、どうしても確認したくなった時は以上をお試しください。