NAKKA-Kの技術ブログ

技術に関する知見や考え方などを投稿します。

DockerとNuxtのSSRでConnectionRefusedが発生する問題の原因を解説する

Docker上でAPIサーバーとNuxt(SSR)を動かす環境で、connection refusedが発生したりしなかったりする問題に遭遇しました。 今回はその問題の発生原因について書いていきます。

一言で

今回の問題は直アクセス時nuxt-linkなどでのclientだけで完結する遷移時でasyncDataメソッドの実行場所が違うためです。

どういうこと?

前者のパターン

まずURLをアドレスバーに直打ちしてアクセスします。 この場合、クライアントでは表示すべきHTMLファイルやjsファイルが存在しない状態から処理が始まり、NuxtサーバーではSSRとしてasyncDataメソッドが実行されます。 そのためasyncDataメソッドにAPIアクセス処理があった場合、Dockerとして動くNuxtサーバー上から行われるためコンテナ~コンテナ間通信になります。

後者のパターン

このパターンでは既にクライアントに表示すべきHTMLファイルやjsファイルが存在していてページが表示されている状態とします。 ページが表示された状態からnuxt-link$router.pushを使って画面遷移をした場合、NuxtサーバーではなくクライアントでasyncDataメソッドが実行されます。 そのためasyncDataメソッドにAPIアクセス処理があった場合、クライアントからDockerコンテナに対してアクセスされるのでホスト~コンテナ間通信になります。

何が問題?

ホストからDockerコンテナへアクセスする場合localhost:8080のような形でアクセスできます。

f:id:NAKKA-K:20191010123923p:plain
クライアントからDockerコンテナへアクセス

しかしDockerコンテナ間のアクセスではコンテナの名前を元にドメインを解釈するため、api:8080のようなアドレスが必要になります。

f:id:NAKKA-K:20191010123951p:plain
Dockerコンテナん間のアクセス

そのためasyncDataメソッドでAPIアクセス処理を書いていると、Nuxtサーバー内で実行される時とクライアントで実行される時の2パターンでは実行結果が変わってしまうといった問題が発生してしまいます。

解決策

サーバー上での実行時と、クライアント上での実行時でURLを変えると解決します! サーバー上ではDockerコンテナ間の通信をする為、コンテナ名依存でURLを設定します。 クライアント上ではDockerコンテナの外からアクセスする為、解釈された後のURLを設定します。

nuxt.config.js

  axios: {
    baseURL: process.env.API_URL,
    browserBaseURL: process.env.API_URL_BROWSER
  },

.env

API_URL='http://api:8080/'
API_URL_BROWSER='http://localhost:8080'

まとめ

SSRをする場合は常に「APIアクセスがどこから行われるのか?」、「どういう環境で行われるのか?」、「本当にそのアドレスで正しいのか?」を意識するようにしましょう。 理解できればそんなに難しい話ではないということがわかります。

参考