メインコンテンツに移動

マイクロサービス向け継続的統合・継続的デリバリー実践ガイド

マイクロサービスでは、ひとつの大きなアプリケーションをまとめて変更するのではなく、複数の小さなサービスを独立して開発、試験、配備します。この構成は開発速度を上げやすい一方で、サービス数が増えるほど、依存関係、試験範囲、配備順序、障害時の切り戻しが複雑になります。そのため、継続的統合・継続的デリバリーは、単なる自動化ではなく、マイクロサービス全体を安全に進化させるための中核になります。

継続的統合・継続的デリバリーのパイプラインは、変更が入ったときに、取得、検査、試験、成果物作成、コンテナ画像作成、脆弱性確認、配備、配備後確認までを一貫して処理します。GitLab公式文書では、パイプラインは継続的統合・継続的デリバリーの基本要素であり、分岐への送信、統合要求、予定実行、手動実行などを契機に動かせるものとして説明されています。

この記事では、マイクロサービス向けの継続的統合・継続的デリバリーを、実務で使える粒度で解説します。単体サービスの自動化だけでなく、複数サービスの依存関係、契約試験、コンテナ画像、段階的配備、監視、戻し、秘密情報、チーム運用まで含めて、長く保守できる構成を目指します。

1. マイクロサービス向け継続的統合・継続的デリバリーとは

マイクロサービス向け継続的統合・継続的デリバリーとは、複数の独立したサービスに対して、変更の検査、試験、成果物作成、配備、確認を自動化し、サービス単位で安全にリリースできる状態を作る取り組みです。単一アプリケーションの自動化と違い、サービス間の契約、配備順序、後方互換性、障害影響範囲まで考える必要があります。

この仕組みがないと、サービスが増えるたびに手作業が増え、どの変更がどのサービスに影響するのか分かりにくくなります。マイクロサービスでは「小さく分ける」だけでは不十分で、それぞれを継続的に届ける仕組みまで設計して初めて価値が出ます。

1.1 マイクロサービスで自動化が重要になる理由

マイクロサービスは、サービスごとに開発、試験、配備を分けられることが利点です。しかし、サービス数が多くなると、手作業で品質確認や配備を行う運用はすぐに限界を迎えます。ひとつのサービス変更が、別のサービスの通信形式や認証方式に影響する場合もあるため、毎回同じ品質門を通す必要があります。

継続的統合・継続的デリバリーを導入すると、変更ごとに同じ手順で検査でき、問題があれば早い段階で止められます。人の記憶や経験に依存せず、パイプラインが品質の入口になるため、チームが増えても運用を安定させやすくなります。

1.2 単一アプリケーションとの考え方の違い

単一アプリケーションでは、ひとつのリポジトリ、ひとつの成果物、ひとつの配備単位として扱えることが多いです。一方、マイクロサービスでは、サービスごとにリポジトリ、依存関係、試験、成果物、配備先が分かれる場合があります。

そのため、パイプラインも単純な一本線ではなく、サービス単位の小さなパイプラインと、全体整合性を見る横断的なパイプラインを組み合わせます。個別サービスの速度と、全体システムの安全性を両立させることが大切です。

1.3 継続的統合の役割

継続的統合の役割は、変更が入るたびに早く問題を見つけることです。マイクロサービスでは、静的検査、単体試験、結合試験、契約試験、画像作成前の品質確認などが含まれます。

ここで重要なのは、すべてを重い試験にしないことです。軽い検査を早く行い、重い試験は必要な条件で実行することで、開発速度と品質のバランスを取れます。

1.4 継続的デリバリーの役割

継続的デリバリーの役割は、いつでも安全に配備できる成果物を作り続けることです。単にコンテナ画像を作るだけでなく、設定、秘密情報、移行手順、監視、戻し方まで含めて準備します。

マイクロサービスでは、あるサービスだけを先に配備することが多いため、後方互換性が非常に重要です。配備できる成果物であっても、他サービスとの契約を壊していないことを確認する必要があります。

1.5 継続的配備との関係

継続的配備は、品質門を通過した変更を自動的に本番へ反映する運用です。継続的デリバリーは「配備可能な状態を保つ」ことに重点があり、継続的配備は「実際に自動で配備する」ことに踏み込みます。

マイクロサービスでは、すべてのサービスを最初から完全自動配備にする必要はありません。重要度が低い内部サービスから自動化し、本番影響が大きいサービスは承認や段階的配備を挟むなど、危険度に応じて設計します。

2. マイクロサービス配備と単一アプリケーション配備の違い

マイクロサービスの継続的統合・継続的デリバリーを設計するには、まず単一アプリケーション配備との違いを理解する必要があります。見た目は同じ「試験して配備する」流れでも、失敗時の影響、確認すべき範囲、成果物の数、配備順序が大きく異なります。

この違いを理解しないまま、単一アプリケーション向けのパイプラインをそのまま増やすと、サービス数が増えた瞬間に管理が破綻します。マイクロサービスでは、各サービスの独立性を保ちつつ、全体として壊れない仕組みを作ることが重要です。

2.1 配備単位の違い

単一アプリケーションでは、ひとつの成果物を作ってまとめて配備する構成が一般的です。試験もアプリケーション全体を対象にしやすく、配備後の確認も比較的まとまります。

マイクロサービスでは、サービスごとに成果物が作られ、それぞれ別々のタイミングで配備されます。そのため、ひとつのサービスが新しくなっても、周辺サービスが古い版のまま動く前提を置く必要があります。

2.2 試験範囲の違い

単一アプリケーションでは、同じ実行環境内で関数や内部部品の関係を試験しやすいです。変更箇所が広くても、ひとつの試験集合で確認できる場合があります。

マイクロサービスでは、通信越しの連携が増えるため、単体試験だけでは不十分です。通信契約、応答形式、認証、時刻差、ネットワーク失敗など、サービス間の境界に関する試験が必要になります。

2.3 障害影響の違い

単一アプリケーションでは、失敗が全体停止につながることがあります。その一方で、障害範囲がひとつのアプリケーション内に収まり、切り戻し対象も明確になりやすいです。

マイクロサービスでは、ひとつのサービスの障害が部分的な機能停止にとどまる場合もありますが、依存関係によって連鎖的に広がることもあります。そのため、配備後の監視と自動戻しの設計がより重要になります。

2.4 比較表

以下の表は、単一アプリケーション配備とマイクロサービス配備の違いを整理したものです。実際の設計では、組織規模、サービス数、利用者影響、運用体制に合わせて調整します。

比較項目単一アプリケーション配備マイクロサービス配備
成果物ひとつにまとまりやすいサービスごとに分かれる
試験範囲全体試験を組みやすい契約試験と結合試験が重要
配備順序単純になりやすい依存関係に左右される
障害範囲全体停止になりやすい部分停止または連鎖障害になりやすい
戻し方ひとつの版に戻しやすいサービス単位で戻しが必要
監視アプリ全体中心サービス別と全体の両方が必要
版管理単一版で管理しやすいサービスごとの版管理が必要

2.5 違いを設計へ反映する方法

この違いを踏まえると、マイクロサービス向けのパイプラインでは、サービス単位の速度と全体の安全性を分けて考える必要があります。各サービスの単体試験や画像作成は速く実行し、横断的な確認は必要なタイミングで実行します。

また、すべてのサービスを同じ重さのパイプラインにしないことも大切です。利用者影響が大きいサービス、外部公開されるサービス、基盤となる認証サービスなどは、より厳しい品質門を置くべきです。

3. リポジトリ戦略

マイクロサービスの継続的統合・継続的デリバリーでは、リポジトリ戦略がパイプライン構成に大きな影響を与えます。全サービスをひとつのリポジトリで管理するか、サービスごとに分けるかによって、変更検知、試験範囲、権限管理、共通部品の扱いが変わります。

どちらが絶対に正しいという話ではありません。重要なのは、チーム構成、サービス数、共通部品の量、配備頻度、所有権に合う形を選ぶことです。

3.1 単一リポジトリの利点

単一リポジトリでは、複数サービスを同じ変更履歴で管理できます。共通部品、設定、検査規則、パイプラインの共通化がしやすく、横断的な変更を一度の統合要求で扱いやすいです。

一方で、サービス数が増えると、どの変更がどのサービスに影響するかを判定する仕組みが必要になります。すべての変更で全サービスの試験を実行すると、パイプラインが重くなりすぎるためです。

3.2 複数リポジトリの利点

複数リポジトリでは、サービスごとの所有権を明確にできます。各チームが自分たちのサービスを独立して開発し、必要なタイミングで配備しやすくなります。

ただし、全体の整合性を保つ仕組みが弱くなる場合があります。共通の検査規則、画像作成規則、契約試験、版管理を別途整えないと、サービスごとに品質のばらつきが出ます。

3.3 変更検知の設計

単一リポジトリでは、変更されたディレクトリを見て、対象サービスだけを試験・ビルドする設計が有効です。たとえば services/payment が変わった場合は決済サービスのパイプラインだけを動かす形です。

複数リポジトリでは、リポジトリ単位で変更検知しやすくなりますが、共通ライブラリ変更時に影響サービスをどう再検査するかが課題になります。依存関係の追跡と再実行の仕組みが必要です。

3.4 所有権の明確化

マイクロサービスでは、各サービスの所有者を明確にすることが重要です。誰が試験を直し、誰が配備を承認し、誰が障害対応するのかが曖昧だと、パイプラインが失敗したまま放置されます。

リポジトリ戦略は、所有権の表現にも関係します。単一リポジトリでも、ディレクトリごとに担当チームを定義し、変更時のレビュー担当を自動で割り当てる運用が有効です。

3.5 単一リポジトリ向け設定例

単一リポジトリでは、変更されたファイルから対象サービスを判定し、必要な処理だけを動かす構成が便利です。以下は考え方を示す簡略例です。

変更検知例

 

stages:  - detect  - test  - build detect_changed_services:  stage: detect  script:    - git diff --name-only origin/main...HEAD > changed.txt    - grep '^services/payment/' changed.txt && echo payment > services.txt || true    - grep '^services/order/' changed.txt && echo order >> services.txt || true  artifacts:    paths:      - services.txt test_payment:  stage: test  script:    - cd services/payment    - ./gradlew test  rules:    - changes:        - services/payment/**/*

 

4. パイプライン設計

マイクロサービス向けのパイプライン設計では、速く失敗させる段階、成果物を作る段階、配備する段階、配備後に確認する段階を分けます。すべてをひとつの巨大な処理にすると、失敗理由が見えにくくなり、保守も難しくなります。

良いパイプラインは、段階名を見るだけで流れが理解できます。どの段階が品質確認で、どの段階が成果物作成で、どの段階が本番影響を持つのかを明確にすることが大切です。

4.1 段階を分ける考え方

パイプラインは、取得、依存関係解決、静的検査、単体試験、契約試験、画像作成、画像検査、配備、配備後確認という流れに分けると整理しやすいです。軽い検査を前に置き、重い処理や危険な処理を後ろに置きます。

これにより、書式違反や単純な試験失敗であれば早く検出できます。コンテナ画像作成や配備のような時間とリスクの大きい工程を、不要に実行しなくて済みます。

4.2 サービス単位の独立性

マイクロサービスでは、各サービスのパイプラインを独立させることが重要です。ひとつのサービスの失敗が、関係のないサービスの配備を止め続ける構成は避けます。

ただし、完全に独立させるだけでは全体の整合性が弱くなります。サービス単位のパイプラインに加えて、契約試験や結合確認のような横断的な確認を設けます。

4.3 共通テンプレートの利用

複数サービスで同じような処理を繰り返す場合、パイプラインの共通テンプレートを用意すると保守しやすくなります。検査、試験、画像作成、脆弱性確認などは、多くのサービスで似た構成になります。

ただし、共通化しすぎると、個別サービスの事情を反映しにくくなります。共通部分は品質門や画像作成規則に限定し、サービス固有の試験や配備条件は明示的に残すと扱いやすくなります。

4.4 失敗時に止める場所

すべての失敗を同じ重さで扱うと、運用が窮屈になります。静的検査や単体試験の失敗は即座に止めるべきですが、一部の非重要な任意検査は警告として扱う段階もあり得ます。

ただし、本番配備に関わる品質門は曖昧にしないことが重要です。警告を積み重ねたまま配備できる構成にすると、やがて誰も警告を見なくなります。

4.5 パイプライン構成例

以下は、マイクロサービスの一般的なパイプライン構成例です。実際には利用する道具に応じて書き方は変わりますが、段階の考え方は共通です。

構成例

 

stages:  - validate  - unit_test  - contract_test  - build_image  - scan_image  - deploy_staging  - smoke_test  - deploy_production validate:  stage: validate  script:    - ./scripts/lint.sh    - ./scripts/check-format.sh unit_test:  stage: unit_test  script:    - ./scripts/unit-test.sh contract_test:  stage: contract_test  script:    - ./scripts/contract-test.sh build_image:  stage: build_image  script:    - ./scripts/build-image.sh deploy_staging:  stage: deploy_staging  script:    - ./scripts/deploy-staging.sh

 

5. 自動試験戦略

マイクロサービスの継続的統合では、自動試験の設計が品質を大きく左右します。単体試験だけを増やしても、サービス間の契約が壊れていれば本番で障害になります。反対に、結合試験だけに頼ると遅く不安定なパイプラインになります。

重要なのは、速い試験と重い試験を分け、それぞれの目的を明確にすることです。単体試験、契約試験、結合試験、端から端までの試験、配備後確認を役割ごとに配置します。

5.1 単体試験

単体試験は、サービス内部の関数、部品、処理単位を検証します。実行が速く、失敗原因を特定しやすいため、すべての変更で必ず実行する品質門に向いています。

マイクロサービスでは、単体試験を軽視すると各サービスの品質がばらつきます。サービス間の試験を増やす前に、まず各サービスが単独で正しく動くことを確認できる状態にします。

5.2 契約試験

契約試験は、サービス間で約束された要求と応答の形式を確認する試験です。提供側サービスが応答形式を変えたとき、利用側サービスが壊れないかを早く検出できます。

マイクロサービスでは、契約試験が非常に重要です。すべてのサービスを実際に起動して結合試験するより軽く、通信境界の破壊を早期に見つけやすいためです。

5.3 結合試験

結合試験は、複数サービスを実際に接続して動作を確認します。契約上は正しくても、認証、設定、データベース、通信時間、ネットワーク制約によって失敗することがあります。

ただし、結合試験は重くなりやすく、不安定になりやすいです。すべての変更で全体結合試験を実行するのではなく、重要な経路や対象サービスに絞る設計が必要です。

5.4 端から端までの試験

端から端までの試験は、利用者に近い操作を通して、複数サービスをまたいだ業務流れを確認します。注文、決済、通知、在庫更新のような一連の動きを検証する場合に有効です。

この試験は価値が高い一方で、実行時間が長く、失敗原因の特定が難しいことがあります。数を増やしすぎず、最重要経路に絞って実行することが現実的です。

5.5 試験配置例

以下は、試験を重さごとに分けた配置例です。軽い試験はすべての変更で実行し、重い試験は主要分岐や配備前に実行します。

試験設定例

 

unit_test:  stage: test  script:    - ./scripts/unit-test.sh contract_test:  stage: test  script:    - ./scripts/contract-test.sh integration_test:  stage: integration  script:    - docker compose -f test-compose.yml up -d    - ./scripts/integration-test.sh    - docker compose -f test-compose.yml down  rules:    - if: '$CI_COMMIT_BRANCH == "main"' e2e_test:  stage: e2e  script:    - ./scripts/e2e-test.sh  when: manual

 

6. コンテナ画像作成

マイクロサービスでは、各サービスをコンテナ画像として配布する構成が多く使われます。コンテナ画像を使うと、実行環境を一定にしやすく、クラスター環境へ配備しやすくなります。

ただし、コンテナ画像は作ればよいものではありません。小さく、安全で、追跡可能で、再現しやすい画像にする必要があります。画像名とタグの規則も、サービスが増えるほど重要になります。

6.1 画像をサービス単位で作る理由

マイクロサービスでは、サービスごとに独立して配備できることが重要です。そのため、画像もサービス単位で作成し、変更があったサービスだけを再作成できるようにします。

すべてのサービスをひとつの巨大な画像にまとめると、マイクロサービスの独立性が失われます。変更していないサービスまで再配備が必要になり、障害範囲も広がります。

6.2 複数段階ビルド

複数段階ビルドでは、複数の FROM を使い、ある段階で作った成果物だけを次の段階へコピーできます。Docker公式文書では、不要なものを最終画像に残さず、必要な成果物だけを選んでコピーできる仕組みとして説明されています。

マイクロサービスでは、各サービスの画像を小さく保つことが運用効率に直結します。画像が小さければ取得が速くなり、配備時間や復旧時間も短くしやすくなります。

6.3 画像タグの設計

画像タグには、コミット識別子、ビルド番号、サービス名、環境名、版番号などを含めます。latest だけに依存すると、どのコードが配備されたのか追跡しづらくなります。

本番で障害が起きたとき、画像タグからソース変更、試験結果、配備履歴へたどれることが重要です。タグ規則は全サービスで統一し、例外を少なくします。

6.4 画像保存先

画像は、信頼できる登録先に保存します。登録先にはアクセス権限、保存期間、脆弱性検査、監査ログが必要です。サービス数が多いほど、登録先の整理が重要になります。

画像名には組織名、サービス名、環境区分を含めると管理しやすくなります。不要な古い画像を残しすぎると費用や検索性の問題が出るため、保持規則も決めます。

6.5 画像作成例

以下は、ひとつのサービス画像を複数段階ビルドで作る例です。実際には言語や実行環境に合わせて調整してください。

Dockerfile例

 

FROM golang:1.22 AS builder WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/service ./cmd/service FROM gcr.io/distroless/static-debian12 COPY --from=builder /out/service /service USER nonroot:nonroot ENTRYPOINT ["/service"]

 

7. クラスター配備

マイクロサービスでは、複数のサービスをクラスター上で動かすことが多くなります。クラスター配備では、単に新しい画像を反映するだけでなく、段階的更新、正常性確認、設定変更、戻し方まで考える必要があります。

クラスター基盤を使う場合、宣言的な設定をリポジトリで管理し、パイプラインから変更を反映する構成が扱いやすいです。手作業で設定を変えると、実際の状態とリポジトリの状態がずれてしまいます。

7.1 配備定義の管理

配備定義は、リポジトリで管理するのが望ましいです。どの画像を、どの環境へ、どの設定で配備するのかを変更履歴として残せます。

マイクロサービスでは、サービス数が多いため、配備定義が散らばると管理が難しくなります。サービスごとの定義と環境ごとの上書きを整理し、見通しを保ちます。

7.2 段階的更新

クラスター配備では、古い実行単位を一度に消すのではなく、新しい実行単位へ段階的に置き換える方式が使われます。Kubernetes公式文書では、ローリング更新は古いポッドを新しいポッドへ段階的に置き換えることで、停止時間なしの更新を可能にすると説明されています。

マイクロサービスでは、段階的更新により影響範囲を抑えられます。ただし、古い版と新しい版が同時に動く時間があるため、通信形式やデータ形式の後方互換性が必要です。

7.3 正常性確認

配備後には、サービスが起動しただけでなく、実際に利用可能かを確認する必要があります。起動確認、準備完了確認、簡単な業務確認を分けて考えると安全です。

正常性確認が弱いと、壊れたサービスが正常として扱われ、利用者影響が広がります。マイクロサービスでは依存先の状態にも左右されるため、確認内容を丁寧に設計します。

7.4 環境ごとの差分

検証環境、本番環境、一時環境では、設定や資源量が異なります。差分を手作業で管理すると、検証では成功したのに本番で失敗する原因になります。

環境ごとの差分は、設定ファイルや値ファイルとして明示し、パイプラインから一貫して適用します。秘密情報は別管理にし、通常の設定と混ぜないことが重要です。

7.5 配備例

以下は、画像タグを差し替えてクラスターへ反映する簡略例です。実際には承認、監視、戻し、通知を加えることが多いです。

配備コマンド例

 

deploy_staging:  stage: deploy  script:    - kubectl set image deployment/payment payment=$REGISTRY/payment:$IMAGE_TAG -n staging    - kubectl rollout status deployment/payment -n staging deploy_production:  stage: deploy  script:    - kubectl set image deployment/payment payment=$REGISTRY/payment:$IMAGE_TAG -n production    - kubectl rollout status deployment/payment -n production  when: manual

 

8. 契約管理

マイクロサービスの継続的統合・継続的デリバリーでは、サービス間の契約管理が欠かせません。契約とは、要求、応答、状態コード、事象形式、認証方法、エラー形式など、サービス間で守る約束です。

契約が曖昧なまま配備を自動化すると、提供側は問題なく配備できても、利用側が突然壊れることがあります。マイクロサービスでは、内部実装よりも境界の安定性が重要になります。

8.1 通信契約

通信契約には、経路、要求形式、応答形式、必須項目、任意項目、状態コードなどが含まれます。これらを文書だけでなく、機械的に検証できる形にすることが望ましいです。

通信契約を明示すると、提供側と利用側が独立して開発しやすくなります。変更が契約を壊す場合、パイプラインで早く検出できます。

8.2 事象契約

事象駆動のマイクロサービスでは、送信される事象の名前、項目、意味、版が重要になります。事象の項目を削除したり意味を変えたりすると、購読側サービスが壊れる可能性があります。

事象契約も、要求応答型の通信と同じように管理する必要があります。特に非同期処理では失敗が遅れて現れるため、配備前の契約確認が大切です。

8.3 後方互換性

マイクロサービスでは、古い版と新しい版が同時に動くことがあります。そのため、新しい版の提供側は、古い利用側が期待する応答を壊さないようにします。

後方互換性を守るには、項目の削除や意味変更を避け、追加を中心に変更する設計が有効です。破壊的変更が必要な場合は、移行期間と複数版対応を設けます。

8.4 契約破壊の検出

契約破壊は、本番で見つけるのではなく、統合要求や配備前に検出するべきです。契約試験をパイプラインに入れることで、提供側の変更が利用側の期待を壊していないか確認できます。

契約試験は、サービス数が多いほど価値が高まります。全サービスを毎回実行しなくても、変更サービスと依存関係のある契約だけを対象にすると現実的です。

8.5 契約定義例

以下は、簡略化した通信契約の例です。実務では仕様記述、契約試験道具、事象登録簿などを使って管理します。

契約例

 

service: payment endpoint: /payments method: POST request:  required:    - orderId    - amount    - currency response:  status: 201  body:    required:      - paymentId      - status      - createdAt compatibility:  breaking_changes:    - remove_required_field    - change_field_type    - change_status_code

 

9. データベース変更

マイクロサービスでは、サービスごとにデータを所有する設計がよく使われます。そのため、継続的統合・継続的デリバリーでは、アプリケーションの配備だけでなく、データベース変更も安全に扱う必要があります。

データベース変更は、アプリケーションコードより戻しにくい場合があります。特に列削除、型変更、データ変換は危険が大きいため、段階的な移行を前提にします。

9.1 サービスごとのデータ所有

マイクロサービスでは、各サービスが自分のデータを所有する形にすると、独立性を保ちやすくなります。別サービスのデータベースを直接参照すると、結合度が高まり、配備の自由度が下がります。

データが必要な場合は、通信や事象を通じて連携します。この設計により、データベース構造の変更が他サービスへ直接波及しにくくなります。

9.2 移行手順の自動化

データベース移行は、パイプラインから制御できるようにします。誰かが手作業で本番データベースへ変更を入れる運用は、履歴が残りにくく危険です。

移行手順は、リポジトリで管理し、検証環境で実行確認してから本番へ適用します。パイプラインでは、移行の順序、対象環境、失敗時の扱いを明確にします。

9.3 後方互換な変更

安全なデータベース変更では、古いアプリケーションと新しいアプリケーションが同時に動いても問題ない形を目指します。まず新しい列を追加し、アプリケーションを対応させ、利用が安定してから古い列を削除する流れです。

このような段階的変更は手間がかかりますが、マイクロサービス配備では非常に重要です。配備中に複数版が共存するため、データ形式もその前提で設計します。

9.4 戻しにくい変更の扱い

列削除や大規模なデータ変換は、失敗時に簡単に戻せない場合があります。パイプラインで自動実行する場合でも、承認、バックアップ、検証、監視を強化するべきです。

戻せない変更を小さく分けることも重要です。一度に大きな移行を行うと、失敗時の影響が大きくなり、原因特定も難しくなります。

9.5 移行パイプライン例

以下は、検証環境と本番環境で移行を分ける例です。本番移行は手動承認にして、影響が大きい変更を不用意に実行しないようにします。

移行例

 

migrate_staging:  stage: migrate  script:    - ./scripts/db-migrate.sh staging migrate_production:  stage: migrate  script:    - ./scripts/db-backup.sh production    - ./scripts/db-migrate.sh production  when: manual  rules:    - if: '$CI_COMMIT_BRANCH == "main"'

 

10. 秘密情報と設定管理

マイクロサービスでは、サービスごとに接続先、認証情報、外部サービス鍵、証明書、設定値が存在します。継続的統合・継続的デリバリーでは、これらを安全に扱いながら、自動配備できるようにする必要があります。

秘密情報をリポジトリに直書きする運用は避けるべきです。設定と秘密情報を分け、環境ごとの差分を明確にし、パイプラインから必要な範囲だけ参照します。

10.1 設定と秘密情報を分ける

通常の設定値と秘密情報は分けて管理します。例えば、機能切り替え値やタイムアウト値は通常設定として管理できますが、パスワードや秘密鍵は別の安全な仕組みで扱います。

この分離により、設定変更のレビューと秘密情報の保護を両立できます。秘密情報を含まない設定はリポジトリで変更履歴を残しやすくなります。

10.2 環境ごとの設定

検証、本番、一時環境では、接続先や資源量が異なります。環境差分を曖昧にすると、検証では動いたのに本番で失敗する原因になります。

環境ごとの差分は、明示的な設定ファイルや値ファイルとして管理します。環境名を条件にして、パイプラインが正しい設定を適用するようにします。

10.3 秘密情報の注入

秘密情報は、実行時または配備時に安全な保管先から注入します。パイプラインのログに値を出さず、必要なサービスだけが参照できるようにします。

サービス数が多い場合、すべてのサービスに同じ秘密情報を渡すのは危険です。サービスごと、環境ごと、用途ごとに権限を分けることが安全です。

10.4 ローテーション

秘密情報は一度作ったら終わりではありません。鍵やトークンは定期的に更新し、漏えい時には素早く無効化できるようにします。

継続的統合・継続的デリバリーの設計では、秘密情報の更新が配備を壊さないようにします。新旧両方を一時的に受け付ける設計や、段階的切り替えが必要になる場合があります。

10.5 設定注入例

以下は、環境別の設定ファイルを使って配備する簡略例です。秘密情報そのものはファイルに含めず、保管先から参照する前提です。

設定例

 

deploy_payment:  stage: deploy  script:    - ./scripts/render-config.sh environments/production/payment.yaml    - ./scripts/deploy-service.sh payment production  rules:    - if: '$CI_COMMIT_BRANCH == "main"'

 

11. 安全性検査

マイクロサービスの継続的統合・継続的デリバリーでは、安全性検査を後付けにしないことが重要です。サービス数が多いほど、脆弱な依存関係、危険な設定、過剰な権限が紛れ込みやすくなります。

安全性検査は、開発の最後に一度だけ行うものではありません。依存関係、ソースコード、コンテナ画像、配備定義、秘密情報の漏えいを、パイプラインの各段階で確認します。

11.1 依存関係検査

各サービスは、それぞれ依存ライブラリを持ちます。依存関係の脆弱性を検査しないと、ひとつのサービスだけでなく、連携する機能全体に影響が出る可能性があります。

依存関係検査は、統合要求時と定期実行の両方で行うと効果的です。新しい脆弱性は後から見つかるため、変更がなくても再検査する価値があります。

11.2 コンテナ画像検査

コンテナ画像には、基盤画像、実行時ライブラリ、証明書、設定ファイルなどが含まれます。アプリケーションコードが安全でも、基盤画像に問題があれば危険です。

画像検査は、画像作成後、登録先へ送る前に行うと分かりやすいです。重大な問題が見つかった場合は、配備前に止めます。

11.3 秘密情報漏えい検査

秘密情報がリポジトリに混入すると、パイプラインを通じて広がる可能性があります。トークン、鍵、パスワード、証明書が含まれていないかを自動検査します。

漏えい検査は、統合要求の早い段階で実行します。見つかった場合は、その値を削除するだけでなく、既に漏れた秘密情報を無効化する必要があります。

11.4 配備定義の検査

配備定義には、権限、資源制限、公開範囲、実行ユーザーなどが含まれます。設定ミスにより、不要に広い権限や外部公開が発生することがあります。

配備前に定義を検査することで、危険な設定を本番へ持ち込む前に止められます。サービス数が増えるほど、手作業の確認だけでは限界があります。

11.5 安全性検査例

以下は、依存関係、画像、配備定義を段階的に検査する例です。実際に使う道具は組織の標準に合わせて選びます。

検査例

 

security_scan:  stage: security  script:    - ./scripts/scan-dependencies.sh    - ./scripts/scan-secrets.sh image_scan:  stage: security  script:    - ./scripts/scan-image.sh $REGISTRY/payment:$IMAGE_TAG manifest_scan:  stage: security  script:    - ./scripts/scan-manifest.sh k8s/production/payment.yaml

 

12. 段階的リリース

マイクロサービスでは、変更を一気に全利用者へ反映するより、段階的に広げる方が安全です。段階的リリースを使うと、問題が起きた場合の影響範囲を抑えながら、新しい版を確認できます。

段階的リリースには、ローリング更新、青緑配備、カナリア配備、機能切り替えなどがあります。どれを選ぶかは、サービスの重要度、利用者数、監視の精度、戻しやすさによって変わります。

12.1 ローリング更新

ローリング更新は、古い実行単位を少しずつ新しい実行単位へ置き換える方法です。KubernetesのDeploymentでは、古いReplicaSetを段階的に縮小し、新しいReplicaSetを段階的に拡大する形で更新されます。

この方式は標準的で扱いやすいですが、古い版と新しい版が同時に動く時間があります。そのため、通信契約とデータ形式の後方互換性が必要です。

12.2 青緑配備

青緑配備は、現在の環境とは別に新しい環境を用意し、切り替えによって新しい版を公開する方法です。切り替え前に新環境を検証できるため、安心感があります。

ただし、同じ規模の環境を二つ用意する必要があり、費用や運用が重くなることがあります。データベース変更が絡む場合も、単純な切り替えでは済まないことがあります。

12.3 カナリア配備

カナリア配備は、一部の利用者や一部の通信だけを新しい版へ流し、問題がないことを確認しながら広げる方法です。影響範囲を小さくできるため、重要なサービスで有効です。

ただし、通信制御と監視が弱いと、カナリア配備の意味が薄れます。新旧の差を判断できる指標を事前に決めておく必要があります。

12.4 機能切り替え

機能切り替えは、コードを配備しても機能をすぐ有効にせず、設定で利用範囲を制御する方法です。配備と公開を分けられるため、リスクを下げやすくなります。

ただし、切り替え設定が増えすぎると管理が難しくなります。不要になった切り替えは削除し、古い分岐がコード内に残り続けないようにします。

12.5 リリース方式の選び方

以下の表は、段階的リリース方式の違いを整理したものです。万能な方式はないため、サービスの特性に合わせて選びます。

方式向いている場面注意点
ローリング更新一般的なサービス更新新旧版の同時稼働に注意
青緑配備切り替え前に新環境を検証したい場合環境費用とデータ変更が課題
カナリア配備影響範囲を絞って確認したい場合監視指標と通信制御が必要
機能切り替え配備と公開を分けたい場合古い切り替えの整理が必要

カナリア配備例

 

deploy_canary:  stage: deploy  script:    - ./scripts/deploy-canary.sh payment $IMAGE_TAG --traffic 10    - ./scripts/check-metrics.sh payment --window 10m promote_canary:  stage: deploy  script:    - ./scripts/promote-canary.sh payment --traffic 100  when: manual

 

13. 監視と配備後確認

マイクロサービスの継続的統合・継続的デリバリーでは、配備して終わりではありません。配備後にサービスが正常に動いているか、利用者影響が出ていないかを確認する必要があります。

監視が弱い状態で自動配備を進めると、問題が起きても検出が遅れます。自動化を強めるほど、配備後確認と監視の精度も強めるべきです。

13.1 起動確認

起動確認は、サービスが実行状態になったかを見る最初の確認です。コンテナが起動しているだけでなく、起動処理が完了しているかを確認します。

ただし、起動確認だけでは利用可能とは言えません。依存先に接続できない、設定が間違っている、業務処理が失敗する場合もあります。

13.2 準備完了確認

準備完了確認は、サービスが通信を受け付けてもよい状態かを判断します。データベース接続、外部サービス接続、必要な設定読み込みが完了しているかを確認します。

マイクロサービスでは、準備完了確認が弱いと、まだ使えないサービスへ通信が流れてしまいます。配備基盤とアプリケーションの確認設計を合わせることが重要です。

13.3 簡易業務確認

簡易業務確認は、実際の利用に近い軽量な操作を実行して、配備後の動作を確認します。たとえば、注文サービスなら注文作成の模擬処理、決済サービスなら検ることが重要です。

13.3 簡易業務確認

簡易業務確認は、実際の利用に近い軽量な操作を実行して、配備後の動作を確認します。たとえば証用決済の確認などです。

この確認は重くしすぎないことが大切です。配備のたびに時間がかかりすぎると、パイプライン全体が遅くなり、運用しづらくなります。

13.4 指標による判定

配備後は、失敗率、応答時間、再起動回数、通信量、待ち行列、資源使用率などを確認します。カナリア配備や自動戻しを行う場合、これらの指標が判断材料になります。

指標は、事前にしきい値を決めておくことが重要です。配備後に人が感覚で判断するだけでは、自動化の効果が弱くなります。

13.5 配備後確認例

以下は、配備後に簡易確認と指標確認を行う例です。実務では監視基盤と連携し、異常時に自動で戻す構成も検討します。

確認例

 

smoke_test:  stage: verify  script:    - ./scripts/health-check.sh payment production    - ./scripts/smoke-test.sh payment production metric_check:  stage: verify  script:    - ./scripts/check-error-rate.sh payment --threshold 1    - ./scripts/check-latency.sh payment --p95 500

 

14. 自動戻しと障害対応

マイクロサービスの配備では、問題が起きたときに素早く戻せることが重要です。自動化された配備は速い反面、問題も速く広がる可能性があります。そのため、戻し方を最初から設計しておく必要があります。

戻しは、単に古い画像へ戻すだけではありません。データベース変更、事象形式、外部連携、機能切り替え、キャッシュ状態まで含めて考える必要があります。

14.1 戻し可能な成果物

戻すためには、過去に配備した成果物を追跡できる必要があります。画像タグ、コミット識別子、設定版、配備時刻が分からなければ、安全に戻せません。

パイプラインでは、配備した画像タグを記録し、どのサービスにどの版が入ったかを保存します。障害時には、その情報を使って素早く判断します。

14.2 自動戻しの条件

自動戻しは、失敗率や応答時間などの指標がしきい値を超えた場合に実行できます。カナリア配備では、問題を検出した段階で新しい版への通信を止める構成が有効です。

ただし、自動戻しには誤判定のリスクもあります。しきい値が厳しすぎると、正常な変動でも戻ってしまいます。監視指標の品質が重要です。

14.3 手動戻しとの使い分け

すべてを自動戻しにする必要はありません。単純なアプリケーション失敗は自動戻しに向いていますが、データ変更や外部連携を伴う障害では人の判断が必要な場合があります。

手動戻しでも、手順は自動化しておくべきです。人が判断し、パイプラインが安全な戻し操作を実行する形にすると、速度と安全性を両立できます。

14.4 障害時の情報収集

戻しを行う前後で、ログ、指標、配備履歴、設定差分を保存します。戻した後に原因分析を行うためには、障害時点の情報が必要です。

情報収集を後回しにすると、問題が消えた後に原因が追えなくなります。自動戻しを行う場合でも、調査用の情報を残す処理を入れます。

14.5 戻し例

以下は、直前の画像タグへ戻す簡略例です。実務では、戻し対象の確認、承認、指標監視、通知を組み合わせます。

戻し例

 

rollback_payment:  stage: rollback  script:    - PREVIOUS_IMAGE=$(./scripts/get-previous-image.sh payment production)    - kubectl set image deployment/payment payment=$PREVIOUS_IMAGE -n production    - kubectl rollout status deployment/payment -n production    - ./scripts/health-check.sh payment production  when: manual

 

15. 運用しやすい体制づくり

マイクロサービス向け継続的統合・継続的デリバリーは、技術設定だけでは成功しません。サービス所有者、レビュー方針、品質門、配備権限、障害対応、改善の仕組みを含めて運用体制を作る必要があります。

パイプラインは一度作って終わるものではありません。サービスが増え、利用者が増え、障害事例が増えるほど、継続的に見直していくべき運用資産です。

15.1 サービス所有者を明確にする

各サービスには、責任を持つチームや担当者が必要です。パイプラインが失敗したとき、誰が直すのか分からない状態では、継続的統合は機能しません。

所有者は、コードだけでなく、試験、配備、監視、障害対応にも責任を持ちます。マイクロサービスでは、作って終わりではなく、運用まで含めて所有する考え方が重要です。

15.2 品質門を統一する

サービスごとに品質基準がばらばらだと、全体の信頼性が下がります。最低限の静的検査、単体試験、画像検査、配備後確認は、全サービスで共通化するべきです。

一方で、すべてを同じ厳しさにする必要はありません。利用者影響が大きいサービスには追加の契約試験や承認を入れ、内部補助サービスには軽量な流れを用意するなど、段階を分けます。

15.3 配備権限を管理する

本番配備には適切な権限管理が必要です。誰でも本番へ配備できる状態は危険ですが、承認が重すぎると速度が落ちます。

継続的デリバリーでは、品質門を通過した成果物だけを配備可能にし、危険度に応じて承認を挟みます。自動化と統制のバランスが重要です。

15.4 失敗から改善する

パイプライン失敗や配備障害は、単なる作業ミスとして片付けず、仕組みを改善する材料にします。失敗した原因を、試験不足、監視不足、権限不足、手順不足に分解します。

改善は小さく継続することが大切です。一度に理想形を作るより、障害や遅延の原因をひとつずつ潰していく方が定着します。

15.5 完成形の流れ

最終的には、変更が入ると自動で検査され、必要な試験が実行され、画像が作られ、安全性が確認され、検証環境へ配備され、配備後確認を通過したものだけが本番候補になります。そのうえで、サービスの重要度に応じて、承認付き配備、カナリア配備、自動戻しを選びます。

この流れが整うと、マイクロサービスの数が増えても、各チームが独立して安全に変更を届けられます。継続的統合・継続的デリバリーは、開発速度を上げるだけでなく、変更への恐怖を減らし、運用の再現性を高める仕組みになります。

全体パイプライン例

 

stages:  - validate  - test  - contract  - build  - security  - deploy_staging  - verify_staging  - deploy_production  - verify_production validate:  stage: validate  script:    - ./scripts/lint.sh    - ./scripts/format-check.sh unit_test:  stage: test  script:    - ./scripts/unit-test.sh contract_test:  stage: contract  script:    - ./scripts/contract-test.sh build_image:  stage: build  script:    - IMAGE_TAG=${CI_COMMIT_SHORT_SHA}    - ./scripts/build-image.sh payment $IMAGE_TAG    - echo $IMAGE_TAG > image_tag.txt  artifacts:    paths:      - image_tag.txt security_scan:  stage: security  script:    - IMAGE_TAG=$(cat image_tag.txt)    - ./scripts/scan-image.sh payment $IMAGE_TAG deploy_staging:  stage: deploy_staging  script:    - IMAGE_TAG=$(cat image_tag.txt)    - ./scripts/deploy.sh payment staging $IMAGE_TAG verify_staging:  stage: verify_staging  script:    - ./scripts/health-check.sh payment staging    - ./scripts/smoke-test.sh payment staging deploy_production:  stage: deploy_production  script:    - IMAGE_TAG=$(cat image_tag.txt)    - ./scripts/deploy-canary.sh payment production $IMAGE_TAG --traffic 10  when: manual  rules:    - if: '$CI_COMMIT_BRANCH == "main"' verify_production:  stage: verify_production  script:    - ./scripts/check-metrics.sh payment production --window 10m    - ./scripts/promote-canary.sh payment production --traffic 100

 

おわりに

マイクロサービス向けの継続的統合・継続的デリバリーは、単にパイプラインを書くだけでは完成しません。サービス単位の独立性、契約管理、データベース変更、コンテナ画像、段階的配備、配備後確認、自動戻し、秘密情報管理を組み合わせて、初めて安全に機能します。

最初からすべてを完璧に作る必要はありません。まずは各サービスで、静的検査、単体試験、画像作成、検証環境への配備を安定させます。その後、契約試験、画像検査、カナリア配備、自動戻し、監視連携を段階的に加えると、チームに定着しやすくなります。

マイクロサービスは、分割すれば自然に速くなるわけではありません。分割されたサービスを安全に変更し続ける仕組みがあってこそ、開速度と信頼性が両立します。継続的統合・継続的デリバリーを運用資産として育てることが、マイクロサービス開発を長く成功させるための重要な土台です。

LINE Chat