TECH PLAY

SQLite

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

はじめに こんにちは、Checkout Reliabilityチームでバックエンドエンジニアをしているかがの( @ykagano )です! こちらは、「継続的な負荷テスト環境をBASEに構築しました」の第3回の記事です。 先に第1回、第2回を読んでいただくのをおすすめします。 継続的な負荷テスト環境をBASEに構築しました 〜 第1回: 負荷テストの全体像 - BASEプロダクトチームブログ 継続的な負荷テスト環境をBASEに構築しました 〜 第2回: 負荷生成ツールの構築と運用 - BASEプロダクトチームブログ こちらは第1回から紹介しているBASEの負荷テスト環境の構成図です。 負荷テスト環境の構成図 本記事では、モックツールとして採用したWireMockの選定理由から、実際の構築・運用方法までを紹介します。 モックツールの選定 モックツールも要求事項は負荷生成ツールと基本的には同じでした。 以下は第2回の記事からの要求事項の引用です。 OSSである クラウドはコストとセキュリティの両面でハードルが上がるため 分散実行が可能である 継続的負荷テスト環境としてスケーリングは必要 Web UIがある レポート品質が高い 学習コストが低い メンバーの誰もが利用できるようにしたい 実績が豊富である OSSが今後も保守される可能性が高い こちらもOSSの比較表を参考として整理しました。 ツール 分散実行可能 Web UI 学習コスト 実績が豊富 特徴 WireMock △(自前スクリプトが必要) △(標準UIなし) ○(機能が豊富) ◎ 業界標準。機能は強いが、UIと分散は独自実装が必要 MockServer △(状態は共有できない) ○ ○(機能が豊富) ○ UIあり・機能も豊富 Smocker △(分散は想定されていない) ○ ○(YAML/JSON定義が直感的) △ UI特化・軽量。個人/小規模チーム向け モックツールは他にも多数あるのですが、実績や保守性がWireMockとMockServerが突出しているように感じたため、まずこの2つを候補としました。 そして他のツールもWeb UIをそれぞれ実際に触ってみた結果、SmockerのUIが使いやすく思えたため候補に加えた形です。 しかし保守性を考えると実績の豊富なWireMockが良いと思っており、UIの課題と分散実行の部分をクリアできないかと調査を進めました。 継続的な負荷テストを実施するためには、複数のモックサーバーに対して、スタブの設定を容易かつ即時で変更できるUIが必要と考えていたためです。 WireMockのサードパーティのUIも探しましたが、複数のWireMockインスタンスに即時で反映できるようなUIはありませんでした。 そのため、個人的にWireMock HubというOSSを作ることにしました。 ykagano.github.io スタブの編集がUIから行え、複数のWireMockインスタンスに即時で反映できる機能をメインに実装しています。 WireMockと組み合わせることで、使い勝手の良い負荷テスト用のモックツールとなります。 wiremock.org WireMockの構築 ECSに構築しました。 下図では負荷テスト用にWireMockを2台起動しています。 Nginxは外部APIのRate-Limiter(流量制限)を再現するために使用しています。 ECSでのWireMockの構成 またその後ろにWireMock HubのAll-in-One版を起動しています。 1つのコンテナの中にNginx + WireMock Hub + WireMockを内包しています。 負荷テストのために、Web UIを持つWireMock Hubがスタブデータの管理とWireMockへの同期を行います。 負荷テスト用のWireMockは負荷テスト利用時にだけ起動していますが、WireMock Hubだけを日常的に起動しておくこともできます。 こうすることで負荷テスト以外の場面でも、外部APIの異常系のテストなどでWireMock Hubの内包するWireMockをUI付きで日常的に使用することができます。 今回負荷テスト環境を構築しましたが、副産物として、日常的にWireMockを使用できるようになったものとなります。 WireMock Hubの構成 WireMock HubはSQLiteのDBを持っています。 プロジェクトの配下にWireMockのインスタンスとスタブが紐付く構造にしています。 そのため、プロジェクトの持つスタブをインスタンスに対して入れ替えることも可能になっています。 プロジェクト ├─ インスタンス └─ スタブマッピング 実際にWireMock Hubに登録しているプロジェクトです。 WireMock Hubのプロジェクト画面 次はインスタンスです。 WireMock Hubのインスタンス画面 例えば、過去のプロジェクトで使用したスタブをもう一度使いたいという時に、プロジェクトの持つスタブを同期させて入れ替えることも、追記して他のプロジェクトで同期したスタブと同居することもできます。 このように、WireMock HubはWireMockを1台だけ利用したい場合にも便利に使えるようになっています。 WireMock Hubからのスタブ登録 WireMock Hubからのスタブの登録方法は以下の3種類があります。 UIでのスタブ編集(下図 Create Newボタンや編集アイコンボタン) スタブファイルのインポート機能(下図 Importボタン) プロキシ機能を使ったレコーディング機能(下図サイドメニューのRecording) WireMock Hubのスタブマッピング画面 このうち、負荷テスト環境の構築時は、主にレコーディング機能とインポート機能を使っていました。 レコーディング機能 レコーディング機能はWireMockが標準搭載している機能です。 まだ何もスタブに登録していない場合、レコーディング機能はとても役に立ちます。 WireMock Hubのレコーディング画面 レコーディング画面でTarget URLを指定して開始すると、WireMockが対象のURLに対するプロキシ(中継サーバ)になります。 この状態でBASEシステムと外部システムの間にWireMockを挟んで通常のリクエストを通すことができます。 図にするとこのように右上から通常の購入リクエストがBASEシステムに入ってきますが、 BASEシステムが左のWireMockに外部サービスへのリクエストを投げて、結果、外部サービスにリクエストが到達します。 WireMockがプロキシとして外部サービスに通信している図 こうすることで、WireMockに実リクエストが記録されます。 レコーディングを停止するとWireMockには記録された実リクエストがスタブとして登録されます。 WireMockのリクエストログにも記録されているため、リクエストログからWireMock Hubにスタブ登録することも可能です。 その後、汎用的なスタブにするための調整は必要ですが、レコーディング機能を使えば、スタブデータを手で書くことなく登録できます。 インポート機能 インポート機能はWireMock HubからWireMockのJSON形式とOpenAPI形式の両方がインポートできます。 WireMock形式のJSON例 { " mappings ": [ { " request ": { " method ": " GET ", " url ": " /test " } , " response ": { " status ": 200 , " headers ": { " Content-Type ": " application/json " } , " body ": " { \" message \" : \" success \" } ", " fixedDelayMilliseconds ": 2000 } , " priority ": 5 , " persistent ": true , " name ": " テストだよ ", " scenarioName ": " test ", " requiredScenarioState ": " Started ", " newScenarioState ": " Step_2 ", " metadata ": { " hub_isActive ": true } } ] , " meta ": { " total ": 1 } } 例えばレコーディング機能で記録したスタブを、WireMockのJSON形式でエクスポートしておけば、以降はClaude Codeで編集することができます。 例えばモニタリングツールに記録された外部APIの通信時間の平均をスタブの遅延時間(fixedDelayMilliseconds)に一律で設定するといったこともできますし、実際にこうしたスタブの設定調整をClaude Codeを通して行っています。 WireMock HubからWireMockへの自動同期 WireMock HubはWireMockとは疎結合なアプリケーションとして設計しています。 そのため、ECSでWireMockを再デプロイした場合、WireMock Hubに登録していたWireMockインスタンスのIPアドレスが変わってしまうことになります。 毎回、WireMockインスタンスのIPアドレスを調べて再登録せずに済むように、WireMock Hubにはインスタンスの再登録APIを用意しています。 下図が同期処理のシーケンス図となります。 LambdaのAPI経由でインスタンスIPリストを取得し、WireMock HubのAPIに渡すことで、インスタンスIPアドレスを更新し、WireMock Hubのプロジェクトに紐付くスタブをWireMockに自動同期します。 import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({ startOnLoad: true }); sequenceDiagram participant gha as GitHub Actions participant tf as Terraform participant ecs as ECS Fargate<br/>(WireMock Worker) participant sd as Service Discovery<br/>(Cloud Map) participant lambda as Lambda<br/>(wiremock-sync) participant hub as WireMock Hub %% Phase 1: Terraform デプロイ Note over gha, ecs: Phase 1: Terraform デプロイ gha ->> tf : wiremock-hub apply activate tf tf ->> hub : WireMock Hub デプロイ activate hub tf -->> gha : apply 完了 deactivate tf gha ->> tf : wiremock apply activate tf tf ->> ecs : WireMock Worker デプロイ activate ecs ecs ->> sd : タスクIP自動登録(HEALTHY) note right of sd : wiremock-worker.cart-load-test.local<br>→ 172.20.10.x tf -->> gha : apply 完了 deactivate tf %% Phase 2: GitHub Actions による Lambda invoke Note over gha, lambda: Phase 2: Lambda invoke gha ->> lambda : aws lambda invoke activate lambda %% Phase 3: Lambda 処理 Note over lambda, sd: Phase 3: Service Discovery からインスタンス取得 lambda ->> sd : discover_instances(HEALTHY のみ) activate sd sd -->> lambda : インスタンスIPリスト返却 deactivate sd %% Phase 4: Hub API → スタブ配信 Note over lambda, hub: Phase 4: Hub API 呼び出し → スタブ配信 lambda ->> hub : POST /hub/api/projects/{id}/instances/bulk-update note right of hub : {"instances": [...], "syncStubs": true} hub ->> hub : インスタンスIP更新 hub ->> hub : プロジェクトのスタブ定義を取得 hub ->> ecs : POST /__admin/mappings(各 Worker) ecs -->> hub : スタブ登録完了 hub -->> lambda : 同期結果 lambda -->> gha : 完了 deactivate lambda deactivate ecs deactivate hub この仕組みによって、WireMock側の再デプロイをしても、負荷テストに必要なスタブは常に担保されます。 おわりに WireMockはノーコードでスタブが作れますので、開発中APIの代替や異常系の通信テストなどにも便利です。 今回作ったWireMock環境は、カート機能だけでなく、社内で誰でも使えるモックツールとして日常的に使っていければと思います。 全3回の記事を最後までお読みいただきありがとうございました! モックを使ったテストに興味がありましたらぜひ採用情報をご覧ください! binc.jp
1. はじめに ジョブスケジューラは、限られた計算資源でタスク順序を整理するためのツールです。実行待ち、資源の競合、状態管理、履歴の追跡などを一貫して扱えるジョブスケジューラは、共有の計算サーバを使うHPC環境(High Performance Computing, いわゆるスパコン)では昔から使われてきました。計算処理が長時間になり、試したいパターンが複雑になるケースでは、多数の計算ジョブを登録・管理することで効率的に実験を回すことができます。 一方、最近ではClaude CodeやCodexなど、Coding Agentの進化と開発速度の加速により、個人の開発環境でもこのような
概要 前回の記事「 SSL/TLS証明書の有効期限短縮に備えて脱・手動更新① 」の続きとなります。 本記事では、Certbotサーバがどのように認証局(CA)から証明書を取得するのか、 そのための手段としてACME-DNSというソフトウェアがどのように関わるのかを説明します。 CertBOTを用いた証明書発行と設定の流れ Certbotが認証局(CA)から証明書を取得しする過程はこちらの図の通りですが、 これは大まかな流れとなります。 CAがCertBOTサーバに対して行うドメイン所有確認の手法には、 HTTP-01チャレンジとDNS-01チャレンジがあります。 HTTP-01 チャレンジは、 Web サーバーを使ってドメインの所有を証明する方式です。 Let’s Encryptなど認証局 は、「このドメインの管理者であるなら、Web サーバー上の特定の場所に指定した内容のファイルを置けるはずだ」という考え方で確認を行います。 ただし、認証局が対象ドメインに対して HTTP(ポート80)でアクセスするため、インターネットから対象ドメインの80番ポートへアクセスできる必要があります。 Webサーバーを公開していない環境や、80番ポートを外部公開できない環境では利用できないという制約があります。 本記事ではそのような制約を受けないDNS-01チャレンジを採用します。 DNS-01チャレンジ DNS-01チャレンジでは、下記のような流れで証明書取得が行われていきます。 HTTP-01チャレンジが「Web サーバーに置いたファイル(トークン)を見に来る」方式なのに対し、DNS チャレンジは「DNS に登録された情報を見に来る」方式です。 HTTP-01チャレンジとDNS-01チャレンジ、それぞれの特徴を比較すると表のようになります。 DNS-01チャレンジは80 番ポートの公開が不要であるため、メールサーバーや LDAPサーバーなど80 番ポートを使わないサーバーを対象にドメインの所有確認ができ、証明書自動取得を行えます。 一方で、DNS-01チャレンジには注意点もあります。一部のDNSサービスでは、そもそもAPIが公開されておらず、Certbotから自動で書き換える手段がありません。 すべての DNS プロバイダがAPI を提供しているわけではないため、APIがない場合はDNS-01 チャレンジの自動化はできず、更新のたびに手作業が必要になります。 その課題に対する対処法として、acme-dns というオープンソースソフトウェアが挙げられます。 ACME-DNSとは ACME-DNSは、DNS-01 チャレンジ認証を実施するための簡易 DNS サーバ、Web API サーバ機能を有するソフトウェアです。 https://github.com/joohoi/acme-dns acme-dns を使う場合、実際の DNS には最初に一度だけ設定を行います。 まず、ドメインを管理するDNS側で、サブドメイン(_acme-challenge)を、CNAMEを使ってACME-DNSサーバーへ向くように設定(委任)します。 これにより、認証局からのドメイン所有確認のクエリは、自動的にACME-DNSサーバーへと転送されるようになります。 また、ACME-DNSサーバーへの問い合わせを委任するための情報として、Aレコード、acme.example.comのNSレコードもメインのDNSに登録しています。 委任に必要なUUIDとはACME-DNSがFQDNごとに発行するもので、 ACME-DNSサーバーのエンドポイントを叩いた際に発行される情報ですが、 それを取得するコマンドはこの後説明させていただきます。 CertbotとACME-DNSを用いて証明書取得を行う具体的な流れは6つのステップです。 (なお、今回構築する環境では、CertbotとACME-DNSの機能が1つのサーバに同居している構成としています) まず、CertbotがACMEサーバに証明書を要求し、それに対してACMEサーバがドメイン所有を確認しようとDNSチャレンジを要求します。 次に、CertbotはACME-DNSのAPIを叩き、取得する証明書のFQDNに対応するUUIDのレコードに検証用トークンを書き込みます。 ACMEサーバがDNS検証を開始します。 メインDNSはCNAME設定に従い、問い合わせをACME-DNSサーバへ転送します。 ACME-DNSがUUIDに基づいた適切なトークンを回答することで検証が成功し、 証明書が発行されます。 結果、DNSのプロバイダにAPI がなくても、DNS チャレンジの自動更新が可能になります。CNAMEレコードさえ設定すればDNSのレコードを手でいじる手間がなくなり自動更新されるものとなります。 ACME-DNSの構築手順 まずは、ACME-DNSのソースコードを取得します。 # ACME-DNSのソースをGithubから取得 $ git clone https://github.com/joohoi/acme-dns # 設定ファイルやデータベース用のディレクトリを作成 $ cd acme-dns $ mkdir data db 次に、オリジナルをコピーした上で、設定ファイルを編集します。 $ cp config.cfg config.org $ vim config.cfg 下記のような内容に編集します。 [general] # DNS interface. Note that systemd-resolved may reserve port 53 on 127.0.0.53 # In this case acme-dns will error out and you will need to define the listening interface # for example: listen = "127.0.0.1:53" #listen = "127.0.0.1:53" listen = "0.0.0.0:53" # protocol, "both", "both4", "both6", "udp", "udp4", "udp6" or "tcp", "tcp4", "tcp6" protocol = "both" # domain name to serve the requests off of domain = "auth.example.org" # acme-dns が管理する DNS ゾーン名 # zone name server nsname = "auth.example.org" # domain で指定したゾーンのネームサーバ名 # admin email address, where @ is substituted with . nsadmin = "admin.example.org" # SOAレコード内の管理者メールアドレス # predefined records served in addition to the TXT records = [ # acme-dns サーバが固定で返す DNS レコードを定義 # domain pointing to the public IP of your acme-dns server auth.example.org. A 198.51.100.1, # specify that auth.example.org will resolve any *.auth.example.org records auth.example.org. NS auth.example.org., ] # debug messages from CORS etc debug = true # デバッグ用の詳細ログを出力するかどうかを指定する項目 [database] # Database engine to use, sqlite3 or postgres engine = "sqlite3" # acme-dns が TXT レコードや登録情報を保存するデータベースの種類を指定 # Connection string, filename for sqlite3 and postgres://$username:$password@$host/$db_name for postgres # Please note that the default Docker image uses path /var/lib/acme-dns/acme-dns.db for sqlite3 connection = "/var/lib/acme-dns/acme-dns.db" # データベースへの接続情報(保存先)を指定 # connection = "postgres://user:password@localhost/acmedns_db" [api] # listen ip eg. 127.0.0.1 #ip = "0.0.0.0" ip = "127.0.0.1" # API サーバが待ち受ける IP アドレスを指定。ACME-DNSサーバー内でAPI叩く構成であれば 127.0.0.1 を指定。 # disable registration endpoint disable_registration = false # /register エンドポイントを無効化するか指定する項目。false を設定することで、新しいサブドメインを ACME-DNS に登録することが可能。 # listen port, eg. 443 for default HTTPS port = "8080" # APIサーバの待受ポート # possible values: "letsencrypt", "letsencryptstaging", "cert", "none" tls = "none" # APIとの通信を HTTPS (TLS) で暗号化するかどうかを指定 # only used if tls = "cert" # tls = "cert" を選んだ際に使用する項目。ACME-DNS の API との通信を暗号化する際に使用する SSL/TLS 証明書のパスを指定。 tls_cert_privkey = "/etc/tls/example.org/privkey.pem" tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem" # only used if tls = "letsencrypt" acme_cache_dir = "api-certs" # tls = "letsencrypt" を選んだ際、API との通信に使用する証明書を保存するディレクトリ # optional e-mail address to which Let's Encrypt will send expiration notices for the API's cert notification_email = "" # tls = "letsencrypt" に設定している場合に使用。ACME-DNS の API との通信を暗号化する際に使用する証明書の期限を通知する先のメールアドレスを指定。 # CORS AllowOrigins, wildcards can be used corsorigins = [ # ブラウザから API を呼び出せる Web ページのドメインを指定する設定。 * ] # use HTTP header to get the client ip use_header = false # 接続してきたクライアントのIPアドレスを特定する際に、HTTPヘッダーの情報を使用するかどうかを指定する項目。 # header name to pull the ip address / list of ip addresses from header_name = "X-Forwarded-For" # use_header = true に設定した場合に、どの名前のHTTPヘッダにIPアドレスが入っているかを指定。 [logconfig] # logging level: "error", "warning", "info" or "debug" loglevel = "debug" # ログの出力レベルを指定 # possible values: stdout, TODO file & integrations logtype = "stdout" # ログの出力先を指定 # file path for logfile TODO # logfile = "./acme-dns.log" # format, either "json" or "text" logformat = "text" # 記録されるログのフォーマットを指定 設定ファイルを編集したら、諸々の準備を行います。 # Go言語の開発環境(コンパイラ)をインストール $ sudo dnf install -y golang # ソースコードから実行可能なプログラムを生成 $ go build # ビルドしたプログラムを、システム全体の実行用フォルダへ配置 $ sudo cp acme-dns /usr/local/bin/ # 配置されたことを確認 $ which acme-dns # 設定ファイル用のディレクトリを root 権限で作成 $ sudo install -d -m 755 -o root -g root /etc/acme-dns # 専用ユーザーの作成(この手順ではacmednsというユーザでACME-DNSを実行させることとしています) getent passwd acmedns || sudo useradd -r -s /sbin/nologin -d /var/lib/acme-dns -M acmedns # 設定ファイルをコピーしつつ、所有者を root、グループを acmedns に設定 # /path/to は git clone を実行ユーザーの home ディレクトリに置き換えます $ sudo rsync -a --chown=root:acmedns /path/to/acme-dns/config.cfg /etc/acme-dns/ # データディレクトリの作成と権限設定 sudo install -d -m 700 -o acmedns -g acmedns /var/lib/acme-dns # データベースファイルの空作成 sudo test -f /var/lib/acme-dns/acme-dns.db || sudo touch /var/lib/acme-dns/acme-dns.db # ファイルの所有権変更 sudo chown acmedns:acmedns /var/lib/acme-dns/acme-dns.db # ファイルのアクセス権制限 sudo chmod 600 /var/lib/acme-dns/acme-dns.db # 一般ユーザー(acmedns)に、特権が必要なポート(53番)を使うための権限を付与 $ sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/acme-dns 次に、ACME-DNSをSystemd化させて常駐化します。 $ sudo vim /etc/systemd/system/acme-dns.service こちらのファイルを下記のように編集します。 [Unit] Description=acme-dns authoritative DNS server for ACME DNS-01 Wants=network-online.target After=network-online.target [Service] User=acmedns Group=acmedns ExecStart=/usr/local/bin/acme-dns -c /etc/acme-dns/config.cfg WorkingDirectory=/var/lib/acme-dns Restart=on-failure RestartSec=2s # 低権限でも 53 を開ける(setcapコマンドを実行しているので不要ですが予備措置として記載) AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE NoNewPrivileges=true # ログは journal に流す StandardOutput=append:/var/log/acme-dns/acme-dns.log [Install] WantedBy=multi-user.target 編集後、サービスを読み込んで起動。 $ sudo systemctl daemon-reload $ systemctl restart acme-dns ここまで実行すれば、ACME-DNSの初期設定・構築は完了です。 次に、「3. 認証スクリプトの用意」のステップへ進みますが、次回の記事にて解説させていただきます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SSL/TLS証明書の有効期限短縮に備えて脱・手動更新② first appeared on SIOS Tech Lab .

動画

該当するコンテンツが見つかりませんでした

書籍