朝日ネット 技術者ブログ

朝日ネットのエンジニアによるリレーブログ。今、自分が一番気になるテーマで書きます。

pfSense の HAProxy との戦い方

サーバインフラ担当の porianes です。

この記事では、 pfSense の HAProxy プラグインの使い方について、簡単に説明します。 HAProxy 自体の説明はあまりしないので、 HAProxy マニュアルを見ながら読むと理解が深まるかもしれません。

はじめに

HAProxy とはなにか

HAProxy はリバースプロキシの実装の一つであり、 特にロードバランス (複数のサーバに負荷を適切に分散する) と可用性確保 (サーバが停止しても他のサーバを利用してサービスを継続できる) に焦点を当てたソフトウェアです。 記述方法に少し癖があるものの、設定ファイルの書き方次第でかなり柔軟な制御ができます。

朝日ネットでは Nginx や Apache が動いているウェブサーバにリクエストを振り分けたり、 一部のアクセス制御を行う用途で使用しています。

pfSense とはなにか

pfSense は FreeBSD をベースにした、 WEB GUI を備えたソフトウェアルータです。 FreeBSD の IP 実装を利用したルーティングやフィルタリング、フェイルオーバー等を基本機能として備えている他、 多彩なプラグインによる拡張が可能です。

HAProxy プラグインが存在し、 pfSense の GUI の中で HAProxy の設定ができるようになっています。 朝日ネットで動いている HAProxy は、大部分が pfSense の中で動いています。

導入方法

pfSense のインストールをして、管理画面 (Web) で System > Package Manager を開きます。 Available Packages のタブから haproxy を検索し、インストールします。

HAProxy の Setting で、 Enable HAProxy にチェックを入れて設定を Save して Apply すると、 HAProxy が起動します。

設定方法

HAProxy の設定は Services > HAProxy の中にあります。 Templates の中にいくつか設定例が収録されています。

試しに Serving multiple domains from 1 frontend のテンプレートをロードしてみると、 バックエンドが 3 つ、フロントエンドが 2 つロードされます。

生成された設定の確認

pfSense の HAProxy プラグインの GUI は単純な設定しかしないならとっつきやすいでしょうが、 複雑な設定や後述の pass-through を使い出すと、GUIについてのまともなマニュアルがないこともあり、分かりづらい部分多く感じられます。 そんなときは、GUI上の設定から生成された設定ファイルを確認して、状態を整理する必要が出てくるでしょう。 設定のファイルは /var/etc/haproxy/ に生成されますが、 Services > HAProxy >Settings の画面下部の show automatically generated configuration. でも確認できます。 こうして設定ファイルの形になってしまえばその読み方は HAProxy の設定と同じですから、 HAProxy のマニュアルを見ながら設定方法を検討できます。

GUI 上の show automatically generated configuration. の表示
生成された設定ファイルを確認するボタン。 test configuration のボタンは、設定にエラーがあるときのみ表示。

設定を変更したら、この機能を使って意図通りの設定になっているか確認するのが良いでしょう。 特に ACL 周りの自動生成には難があり、GUIの設定から直感的に理解できない挙動をすることが多いように思います。

残念ながら設定の適用 (Apply ボタンの押下) 前にこれを確認する機能はありませんが、 設定にエラーがある (例えば、 Global Advanced pass thru に invalid などと書き込むことで意図的に発生させられます) と show automatically generated test configuration. が追加で表示されるようになり、適用前の設定が表示できます。 奇妙なやり方ですが、一応、適用前の設定を確認できます *1

Shared フロントエンド

Serving multiple domains from 1 frontend テンプレートの、 example_multipledomains_forum という名前のフロントエンドは Shared Frontend です。この、「Shared Frontend」こそが、私がこの記事を書こうと思った理由であり、このGUIでのHAProxyの設定を難解にしている原因です*2

これは概念的には「1つのポートで複数のサービスを提供する」ような設定をするための、 「複数のサービス」に対応するものであり、設定の中で「1つのポート」に相当するものを「Primary frontend」として選択するようになっています。 しかし、HAProxy にはそのような概念はありません。 これらの Shared なフロントエンドは、単に1つの frontend に統合されます。

例えば、Serving multiple domains from 1 frontend のフロントエンドはこのように変換されます。

GUIで入力した2つのフロントエンドの設定が、設定ファイル上で1つのフロントエンドの設定へ統合されている様子
pfSense の設定画面と HAProxy の設定ファイルの対応

結果1つのフロントエンドにすべて書くのと同じ設定になりますが、 フロントエンド一覧で「On」のカラムを操作するとフロントエンドごとに無効化できる *3 ため、 部分的に無効化したい用事があるときには便利です。

shared なフロントエンドは実際には1つのフロントエンドなので、親で設定したACLを子で使用したり、子で設定したACLを親や兄弟が使ったりできます。 ACLの名前が衝突しないように気をつける必要がありそうです。 すべての ACL を親に設定して、子では Actions のみ設定するというのもありかもしれません。

設定の pass-through

pfSense の HAProxy 設定画面は、 HAProxy の豊富な機能のほんの一部の設定しかできません。 しかし、あちこちに「書いたテキストをそのまま設定ファイルに pass-through する」機能があり、これを使うと色々できるようになります。 例えば、次のような pass-through が可能です

設定ファイルのglobalセクション
Settings の Global Advanced pass thru に書けます
frontend の bind 行
フロントエンドの External address の Advanced 欄に書けます
backend の server 行
追加時に Advanced の欄に書けます。また、 [+] ボタンから、後で変更することもできます。 すべての server に同じことを書く場合、 Advanced settings の中の Per server pass thru が使えます。
frontend/backend の acl
ACL の Expression のところで `Custom acl:` を選択して書けます
frontend/backend の Action (http-request, tcp-request, use_backend等)
Action の種類を Custom にすると custom action の部分に書けます
frontend の、その他の設定
Advanced settings の中に Advanced pass thru があります。(shared でないフロントエンドのみ)
backend の、その他の設定
Advanced settings の中に Backend pass thruがあります。

listen セクションを作ることはできないようですが、フロントエンドとバックエンドを適切に組み合わせれば、 listen と同じことを実現できるはずです。

pfSense に固有の便利機能

pfSense の HAProxy には、 pfSense 自体の機能と連携する機能があります。

設定の同期

Settings の中の Configuration synchronization のチェックボックスで、2台の pfSense で HAProxy の設定を同期できます。 pfSense 本体の設定で同期設定をしたホストが同期対象です。

IPアドレス

bind するアドレスを pfSense の IF のアドレスから選択できます。 ACL のマッチング条件も、 pfSense 本体の Firewall で設定した Alias を利用できます。 (Source IP matches IP or Alias: を選択)

おわりに

わたしは正直なところ pfSense はあまり好きではありませんが、 挙動の詳細を知ることができる利点のある、オープンソースであることは好印象です。 クローズドソースでマニュアルもあまり充実していないアプライアンスより、 こういったフリーソフトを使ったファイヤーウォールやロードバランスがもっと流行ればいいと思っています。

Community Edition が無料でダウンロードできるので、興味があれば試してみてください。

HAProxy とは関係ない話になってしまいますが、試しに家のルータを pfSense に置き換えてみる*4などいかがでしょう。 PPPoE を利用しているなら、おそらく置き換えられる家が多いと思います。

*1:このやり方は裏技的なので、重要な HAProxy なら、専用のテスト環境で試すのが良いと思います

*2:個人の感想です

*3:無効化された設定は、設定ファイルに書かれなくなります

*4:もちろん、家族に相談してからやってくださいね

LibreChatの採用とGPT-4の開放(社内用ChatGPTクローンのアップデート)

朝日ネットで技術部門の執行役員をしている草場です。
前回に引き続き、社内用ChatGPTについての取り組みを紹介します。

前回記事はこちら techblog.asahi-net.co.jp

  • 6月以降のできごと
  • コスト
  • OSS選定(LibreChat選定)
    • Azure OpenAI Serviceでも言語モデルの変更が可能
    • 認証オプション
    • コンフィグでの機能制御
    • メンテナンス・更新頻度
  • システム構成
  • 苦労話
    • Azureでのモデル切替の設定方法
    • Automated Moderation System
    • Google認証
  • 今後について
  • 最後に
  • 付録(.env diff)
続きを読む

オブジェクト指向を5年間理解できなかった人間がオブジェクト指向を説明する(第6回)

こんにちは。朝日ネット社員のjiweenです。

前回までで重要なパターンは説明し終わりました。

最終回となる今回では、初学者にとって必要性が低いと判断し後回しにしていたパターンに触れます。 GoFパターンのマニアでなければ、読み飛ばしていただいても問題ありません。

最後では連載のまとめを行います。

続きを読む

シェルスクリプトとの対比で理解するPythonのsubprocess

はじめに

開発部の ikasat です。

皆さんは git, ssh, rsync のような外部コマンドを呼び出すスクリプトを書きたくなったことはありますか? 個人的にこの類のスクリプトは最初はシェルスクリプトとして書くのですが、改修を重ねるうちに肥大化して処理も複雑になり、 後から Python のような汎用プログラミング言語で書き直すことがよくあります。

外部コマンド呼び出しを書き直す際に、Git 操作のために pygit2、 SSH 接続のために paramiko のようなライブラリをわざわざ使うのは大がかりだったり、 rsync に相当するようなこなれたライブラリが存在しなかったりする場合があります。 そのような時は標準ライブラリの subprocess モジュールを利用し、Python から外部コマンドを呼び出すことになるでしょう。

しかしながら、Python のチュートリアルページには subprocess モジュールの解説はなく、 いきなり標準ライブラリのリファレンスを読むことになります。 subprocess モジュールはバージョンアップに従いAPIが多数追加されており、また各種OSの事情が同じ箇所に記載されているため、一見して利用法をなかなか掴みにくいです。

この記事では対象環境を Linux に絞り、シェルスクリプトと Python スクリプトを対比した上で subprocess モジュールの典型的な利用方法について述べます。 また、記事の後半では subprocess モジュールの詳細に立ち入り、込み入ったケースでの注意点について記載します。

対象読者

  • subprocess を雰囲気で利用している人
    • 具体的には公式のリファレンスや巷の解説記事を多少読んで import subprocess したことがある人
  • はじめに
  • 対象読者
  • 対象環境
  • シェルスクリプトとPythonの比較
    • コマンドを起動する(最も単純な使い方)
    • 終了ステータスを取得する
    • 標準出力を捕捉する
    • 標準入出力をリダイレクトする
    • 標準エラー出力を標準出力にマージして捕捉する
    • 出力を全て捨てる
    • 終了ステータスが0でなければ例外を発生させる
    • Pythonのバイト列・文字列をコマンドに渡す
    • 並行処理を行う
    • Popen と communicate で標準入出力を扱う
    • パイプ処理を行う
    • タイムアウトを設定する
    • シェル経由でコマンドを起動する(要注意)
  • subprocessの詳細仕様と内部実装
    • プロセス間通信の流れ(概要)
    • プロセス間通信の実装(詳細)
    • 子プロセス同士をパイプする際に close が必要な理由
    • Pythonとパイプ書き込みエラー
    • デッドロックと communicate
  • おわりに
  • 採用情報
続きを読む

オブジェクト指向を5年間理解できなかった人間がオブジェクト指向を説明する(第5回)

こんにちは。朝日ネット社員のjiweenです。 今日もデザインパターンを分析します。

今回は、データとその処理を分離して扱うパターンが3つ(Iterator, Visitor, Observer)登場します。ここでは、第2回で説明した「データと振る舞いの一体化は強制されない」ということを思い出してください。どのパターンでもデータと振る舞いが本質的に別の流動性を持っており、そのため自然と分離が起こります。

続きを読む

エンジニアが家庭に浸かって成長した話 ~育児休業体験記~

朝日ネットのエンジニアのxfuzzy(男性)です。 私事ですが、妻が第一子を妊娠・出産し、私も育児休業(育休)を取得しましたので、育休取得の経緯や会社とのやり取りをレポートさせていただきます。

  • 育休制度の概要
  • 育休を取ると決めるまで
  • 育休前
  • 育休取得中
  • 育休後
    • 日々の業務で意識していること
  • まとめ
  • 採用情報
続きを読む