LoginSignup
2
1

More than 3 years have passed since last update.

CentOS 8 でPodmanを利用してHTTP通信をリバースプロキシしていたが、コンテナ間でTCP通信できなくなった

Last updated at Posted at 2020-08-07

ある時、内部利用限定のサーバーでCentOS 8を立ててGitLabを運用していた。

GitLabはPlantUMLサーバーのURL指定するだけで、
マークダウンに書いたPlantUMLをレンダリングできるようになるので
PlantUMLも同一サーバー内で起動することにした。

GitLabは公式がパッケージインストールを推奨していたのでdnf installしていたが、
PlantUMLはDockerで動かそうと思った。

しかし、RHEL 8がDockerサポートしていない関係から、
作業時点では、CentOS 8もDocker Community Editionのインストール手順でサポート対象になっていなかった。

一応GitHubにはissueが存在しており、CentOS 8サポートの動きがちらほら見えるが、まだ作業途中らしい。

Support centos 8   · Issue #873 · docker/for-linux · GitHub

じゃあRHEL 8はDockerがないのかと思ったが、PodmanというRedHat製のコンテナツールがあるようだったので、
当面はこれでしのごうと思った。

NOTE: DockerでいうところのコンテナはPodmanではポッドと呼ぶようだが、面倒なのでこの投稿内では区別せずに全部コンテナと呼ぶ。

構成

Podmanを導入するにあたり、サーバーへのすべてのHTTP系リクエストをNginxでリバースプロキシしてやろうと考えた。

一部の人間しか利用しないサーバーだが、URLを打つたびにいちいちポート番号を指定するのが面倒だと考えたからだ。

PodmanでNginxを80番ポートで起動し、GitLabやPlantUMLはサブURLのアクセスでリクエストを割り振ることにした。

GitLabは/gitlab/サブディレクトリで起動し、GitLab用のNginxもリッスンポートを適当に変更するように/etc/gitlab/gitlab.rbの設定を変更した。

PlantUMLはpodman runで起動するだけなので簡単だった。

余談

PlantUMLのイメージは公式のこのイメージのJettyサーバーのイメージ使わせてもらった。

しかし、このイメージはPlantUMLをROOT.warとしてデプロイしている。

Java Servletの仕様を知らなければわからないことだが、Java Servletは.warのファイル名で
WEBサーバーにデプロイされたWEBアプリケーションのルートパスを決定する仕組みになっている。

例えばbar.warをデプロイすると、そのWEBサーバーの/bar/にアクセスすると
WEBアプリケーションの/にマッピングされたコントローラー(厳密にはJava Servletだが)が呼び出しされる。

この中で、ROOT.warという名前は特別で、/にWEBアプリケーションをマッピングする。

PlantUMLはリバースプロキシのNginxから/plantuml/へのアクセスをリバースプロキシしているが、
プロキシ先のURLが/になってしまった。

イメージ提供元はdocker build時にBUILD_ARG渡してROOT.war以外に名前を変更できるので、
docker-composeを使うように案内している。

しかし、Podmanにもdocker-compose互換を目指すpodman-composeが存在するが、
今のところうまく動作しない部分が多いようなので利用は見送った。

PlantUMLは/で起動することになるが、リバースプロキシで到達するだけなら問題ない。

ただし、リバースプロキシ下でのリダイレクトが難しくなったが、
GitLabからの利用だけであればリダイレクトすることはないと考え、リダイレクトの件は放置することにした。

Podmanで起きたトラブル

サーバーを再起動したらコンテナが停止していた

サーバーを再起動したところ、Podmanで起動していたコンテナが起動していない。

podman run --restart=alwaysをでコンテナを起動していたが、
今のところPodmanはオプションを受け付けるがサーバー再起動後にコンテナを起動しないらしい。

RHELのドキュメントなどを見る限り、Systemd Unit Fileでpodomanでコンテナを起動する様にしろということらいい。

少し面倒だが、内部利用サーバーなので再起動もめったにしないので運用でカバーする事にした。

何もしていないのにコンテナ間で通信できなくなった

本題。

GitLabはPlantUMLのURLを設定していれば、
MarkdownやAsciiDoc内にPlantUMLのDSLを書くだけで、PlantUMLによるレンダリング結果を出力する様にしてくれる。

ある日、Nginx経由でGitLabに接続していると、Markdown内に表示されているはずの
PlantUMLが表示されておらず、ブラウザのデベロッパーツールで確認すると
PlantUMLへの接続がタイムアウトしている事に気が付いた。

NginxのコンテナログをみるとNginx側でもPlantUMLへのリバースプロキシ接続がタイムアウトしている。

しかし、NginxからGitLabへのリバースプロキシは動作している。
PlantUMLもコンテナログを見る限り正常に動作し続けている。

何より不思議なのがcurlで直接PlantUMLのポート番号を指定するとレスポンスが返ってくる。

しかし、Nginxコンテナ内からPlantUMLコンテナに対してcurlでリクエストを行うとタイムアウトが発生する。
というかTCPコネクションが確立していない。

原因は不明だがNginxコンテナからPlantUMLコンテナの通信だけが成立しなくなっているようだった。

通信状況は以下のような感じ。

SoWkIImgAStDuShBJqbL24ujAaijKgZcKb0eIaqkISnBpqbLSCyiyKbCua8H2yXFoKtC0oj45lPBpyohG1CBo4dCAmdrzG4ArtBLSa4iUjmyxN7poiTDonutRLD8B5PmAielBqujuk82cw1WevkJcbQYQmUrMy5AmTyRBbMKcPu1b8CR39JrS-VYWXgXe5jQWAeHJGPi3AO4mZo8.png

コンテナ間だけで通信が成立しない事例について調べてみると、以下のissueがヒットした。

内容を呼んでみるとカーネルモジュールの br_netfilter がロードされている必要があるが、
CentOS 8はデフォルトでロードされていないらしい。

このコメントで提示してくれているように、
echo br_netfilter > /etc/modules-load.d/podman.confで br_netfilter モジュールをロードするようにするのが恒久的な解決策になるようだ。

試しにmodprobe br_netfilterすると、NginxからPlantUMLへのリバースプロキシが復活した。

しかし、br_netfilter がロードされていないのが原因だと書かれているが、
この事象はNginxとPlantUMLのコンテナを起動して数日が経過してから発生したので、
ちょっと事象が違うような気もする。

この事象に見舞われた時に使用していたPodmanのバージョンは1.xだった、
最新版は2.xでメジャーバージョンアップしているので、
最新バージョンであればこのような問題は起きないかもしれない。

正直Dockerの代替として使うには、ちょっと問題が多いように感じた。

2020年9月18日追記

CentOS 8向けのパッケージが追加された: https://github.com/docker/for-linux/issues/873#issuecomment-694654334

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1