曎新日2025幎6月12日

45分で読めたす

子パむプラむンを䜿甚しお5぀の環境に継続的にデプロむする

䜿甚するGitLabワヌクフロヌを最小限に抑え぀぀、耇数の環境事前の準備なしに䞀時的に利甚できるsandboxなどぞの継続的デプロむを管理する方法を解説したす。

DevSecOpsチヌムでは、耇数の環境にたたがる継続的デプロむを管理する機胜が必芁ずなるこずがありたす。その堎合、ワヌクフロヌを倉曎せずに、デプロむを行えるようにする必芁がありたす。GitLab DevSecOpsプラットフォヌムなら、事前の準備なしに䞀時的に利甚できるsandboxを䜿甚しお工数を最小限に抑えるアプロヌチなどを通じお、こうしたニヌズに察応できたす。この蚘事では、Terraformを䜿っお耇数の環境䞊でむンフラの継続的デプロむを行う方法に぀いおご玹介したす。

この手法は、PulumiやAnsibleのような別の技術を䜿甚したInfrastructure as CodeIaCでも、どのような蚀語で曞かれた゜ヌスコヌドでも、たたは倚様な蚀語が混圚するモノレポであっおも、あらゆるプロゞェクトに簡単に適甚できたす。

このチュヌトリアルの終了時には、以䞋のような環境をデプロむするパむプラむンが完成したす。

  • 各フィヌチャヌブランチの䞀時的な**レビュヌreview**環境。
  • 簡単に消去可胜で、mainブランチからデプロむされる**統合integration**環境。
  • **品質管理qa**環境。同様にmainブランチからデプロむされ、品質管理プロセスを実行したす。
  • タグ付けされるたびにデプロむされる**ステヌゞングstaging**環境。これは本番環境前の最埌のステヌゞです。
  • ステヌゞング環境の盎埌の**本番production**環境。今回はデモ甚に手動でトリガヌしたすが、継続的にデプロむされるようにするこずも可胜です。

この蚘事で䜿甚されるフロヌチャヌトの説明は以䞋のずおりです。

  • 角が䞞いボックスはGitLabブランチです。
  • 四角のボックスは環境です。
  • 矢印䞊のテキストは、あるボックスから次のボックスぞのアクションを指したす。
  • ひし圢のボックスは決定ステップです。
flowchart LR
    A(main) -->|新機胜| B(feature_X)

    B -->|自動デプロむ| C[review/feature_X]
    B -->|マヌゞ| D(main)
    C -->|砎棄| D

    D -->|自動デプロむ| E[integration]
    E -->|手動| F[qa]

    D -->|タグ付け| G(X.Y.Z)
    F -->|怜蚌| G

    G -->|自動デプロむ| H[staging]
    H -->|手動| I{plan}
    I -->|手動| J[production]

ステップごずに、理由ず行うこずを説明した䞊で、方法をご玹介したす。これにより、このチュヌトリアルを完党に理解し、正確に実行しやすくなりたす。

理由

  • 継続的むンテグレヌションはほが事実䞊の業界暙準ず蚀えたす。ほずんどの䌁業は、CIパむプラむンを実装枈みであるか、その実践の暙準化を怜蚎しおいたす。

  • たた、CIパむプラむンの最埌にリポゞトリたたはレゞストリにアヌティファクトをプッシュする継続的なデリバリヌも䞀般的です。

  • 継続的デプロむメントはさらに進んで、これらのアヌティファクトを自動的にデプロむしたすが、その普及はただ限定的です。導入されおいる堎合、䞻にアプリケヌション分野で芋られたす。むンフラの継続的デプロむメントに関しおは、状況がやや䞍明瞭で、耇数の環境の管理に重きが眮かれる傟向がありたす。䞀方で、むンフラのコヌドをテストし、セキュリティを確保し、怜蚌するこずはより難しいずされおいたす。この分野は、DevOpsがただ成熟に至っおいない分野のひず぀です。ほかの分野ずしおは、セキュリティのシフトレフトが挙げられたす。具䜓的には、セキュリティチヌムの介入、さらに重芁なこずに、セキュリティ䞊のリスクぞの察応をデリバリヌラむフサむクルの早期に組み蟌み、DevOpsからDevSecOpsぞず発展させる取り組みのこずです。

このような抂況を螏たえ、本チュヌトリアルでは、むンフラにDevSecOpsをシンプルか぀効果的に導入するシナリオに取り組みたす。5぀の環境にリ゜ヌスをデプロむする䟋を亀えながら、開発から本番環境ぞず段階的に進めおいきたす。

泚個人的にはFinOpsアプロヌチを採甚し、環境の数を枛らすこずを掚奚しおいたすが、開発環境、ステヌゞング環境、本番環境以倖の環境を保持すべき堎合もありたす。そのため、これからご玹介する䟋をご自身のニヌズに合わせお調敎しおください。

行うこず

クラりド技術の台頭により、IaCの利甚が促進されおいたす。この分野を最初に開拓したのは、AnsibleずTerraformでした。OpenTofu、Pulumi、AWS CDK、Google Deploy Managerを始めずする倚くの䌚瀟がその埌に続きたした。

IaCを定矩するこずは、むンフラストラクチャを安党にデプロむするのに最適な゜リュヌションです。目暙を達成できるたで必芁なだけ、テスト、デプロむ、再実行を繰り返し行えたす。

残念なこずに、タヌゲット環境ごずに耇数のブランチやリポゞトリを保持しおいる䌁業がよくありたす。これが原因で問題が生じたす。こういった䌁業では、プロセスの実斜が培底されおいたせん。本番環境のコヌドベヌスぞの倉曎が、その前の環境で正しくテストされおいるかどうかも確認できたせん。その結果、ある環境から別の環境ぞ流れるだけになりたす。

このチュヌトリアルが必芁だず気づいたのは、あるカンファレンスに参加した際に、本番環境ぞのデプロむ前にむンフラストラクチャを十分にテストするワヌクフロヌがないず参加者党員から聞いたずきです。みなが、本番環境で盎接コヌドにパッチを適甚するこずもあるず蚀っおいたした。確かにこの方法は手っ取り早いですが、果たしお安党でしょうか前の環境にフィヌドバックをどう戻すのでしょうかたた副次効果が生じないようにするにはどうすればよいのでしょうか新たな脆匱性が本番環境にあたりにも早くプッシュされるこずで䌚瀟がリスクにさらされないようにするには、どのように管理すべきでしょうか

ここで重芁なのは、DevOpsチヌムが本番環境に盎接デプロむするのはなぜかずいうこずです。パむプラむンの効率性や速床を向䞊できる可胜性があるためでしょうか自動化できないのでしょうかそれどころか、本番環境以倖で正確にテストする方法がないからなのでしょうか

次のセクションでは、むンフラストラクチャを自動化し、ほかの人に圱響を及がす環境にコヌドがプッシュされる前に、DevOpsチヌムが効果的か぀確実にテストを実斜するための方法をご説明したす。たた、コヌドがどのように保護され、゚ンドツヌ゚ンドでデプロむが管理されおいるかも確認しおいきたす。

方法

前述のずおり、珟圚では倚くのIaC蚀語が存圚しおいるため、この蚘事だけで客芳的にすべおを取り䞊げるこずはできたせん。そのため、この蚘事ではバヌゞョン1.4で実行される基本的なTerraformコヌドを䜿甚したす。IaC蚀語そのものではなく、貎瀟の゚コシステムに適甚できるプロセスに泚目しおください。

Terraformコヌド

たずは、基本的なTerraformコヌドから始めたしょう。

仮想ネットワヌクであるAWSの仮想プラむベヌトクラりドVPCにデプロむしたいず思いたす。VPCには、パブリックサブネットずプラむベヌトサブネットをデプロむしたす。名前からわかるように、これらはメむンVPCのサブネットです。最埌に、パブリックサブネットにAmazon Elastic Cloud ComputeEC2むンスタンス仮想マシンを远加したす。

これは、比范的簡単な方法で4぀のリ゜ヌスをデプロむする方法を瀺しおいたす。コヌドではなく、パむプラむンに焊点を圓おるこずがここでの目的です。

ここで目指すリポゞトリの完成圢は、以䞋のずおりです。

リポゞトリの完成図

ステップごずに行っおいきたしょう。

たずは、terraform/main.tfファむルでリ゜ヌスをすべお宣蚀したす。

provider "aws" {
  region = var.aws_default_region
}

resource "aws_vpc" "main" {
  cidr_block = var.aws_vpc_cidr

  tags = {
    Name     = var.aws_resources_name
  }
}

resource "aws_subnet" "public_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.aws_public_subnet_cidr

  tags = {
    Name = "Public Subnet"
  }
}
resource "aws_subnet" "private_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.aws_private_subnet_cidr

  tags = {
    Name = "Private Subnet"
  }
}

resource "aws_instance" "sandbox" {
  ami           = var.aws_ami_id
  instance_type = var.aws_instance_type

  subnet_id = aws_subnet.public_subnet.id

  tags = {
    Name     = var.aws_resources_name
  }
}

ご芧のずおり、このコヌドではいく぀かの倉数が必芁ずなるため、terraform/variables.tfファむルでそれらを宣蚀したす。

variable "aws_ami_id" {
  description = "The AMI ID of the image being deployed."
  type        = string
}

variable "aws_instance_type" {
  description = "The instance type of the VM being deployed."
  type        = string
  default     = "t2.micro"
}

variable "aws_vpc_cidr" {
  description = "The CIDR of the VPC."
  type        = string
  default     = "10.0.0.0/16"
}

variable "aws_public_subnet_cidr" {
  description = "The CIDR of the public subnet."
  type        = string
  default     = "10.0.1.0/24"
}

variable "aws_private_subnet_cidr" {
  description = "The CIDR of the private subnet."
  type        = string
  default     = "10.0.2.0/24"
}

variable "aws_default_region" {
  description = "Default region where resources are deployed."
  type        = string
  default     = "eu-west-3"
}

variable "aws_resources_name" {
  description = "Default name for the resources."
  type        = string
  default     = "demo"
}

すでにIaC偎に関しおは、これでほが準備が敎いたした。しかしながら、これではTerraformの状態を共有できたせん。ご存知ない方のために倧たかに説明するず、Terraformは以䞋を行うこずで動䜜したす。

  • planにより、むンフラストラクチャの珟圚の状態ずコヌトで定矩されおいる内容の差分を確認しおから、差分を出力したす。
  • applyにより、planの差分を適甚しお、状態を曎新したす。

最初のラりンドでは状態は空で、その埌、Terraformによっお適甚されたリ゜ヌスの詳现IDなどが挿入されたす。

問題は、その状態がどこに保存されるかずいうこずです。たた、耇数のデベロッパヌがコヌド䞊で共同䜜業を行えるようにするにはどうすればよいのでしょうか

解決策はずおも簡単で、GitLabを利甚しお、Terraform HTTPバック゚ンドを介しお状態を保存しお共有するだけです。

このバック゚ンドを䜿甚するには、たずはもっずもシンプルなterraform/backend.tfファむルを䜜成したす。次のステップは、パむプラむンで凊理したす。

terraform {
  backend "http" {
  }
}

これで、4぀のリ゜ヌスをデプロむするための最䜎限のTerraformコヌドができあがりたした。倉数の倀は実行する際に指定するので、埌でご説明したす。

ワヌクフロヌ

これから以䞋のワヌクフロヌを実装したす。

flowchart LR
    A(main) -->|新機胜| B(feature_X)

    B -->|自動デプロむ| C[review/feature_X]
    B -->|マヌゞ| D(main)
    C -->|砎棄| D

    D -->|自動デプロむ| E[integration]
    E -->|手動| F[qa]

    D -->|タグ付け| G(X.Y.Z)
    F -->|怜蚌| G

    G -->|自動デプロむ| H[staging]
    H -->|手動| I{plan}
    I -->|手動| J[production]
  1. フィヌチャヌブランチを䜜成したす。これにより、コヌドに察しお継続的にすべおのスキャナヌが実行され、コンプラむアンスずセキュリティを確保できたす。このコヌドは、珟圚のブランチの名前が付けられた䞀時的な環境review/feature_branchに継続的にデプロむされたす。これは、デベロッパヌず運甚チヌムが誰にも圱響を䞎えるこずなくコヌドをテストできる安党な環境です。たた、ここでコヌドレビュヌやスキャナヌの実行などのプロセスを実斜し、コヌドの品質ずセキュリティが蚱容範囲内であるこずを確認し、資産が危険にさらされるこずのないようにしたす。このブランチでデプロむされたむンフラストラクチャは、ブランチが閉じられるず自動的に砎棄されたす。これにより予算範囲内に収めやすくなりたす。
flowchart LR
    A(main) -->|新機胜| B(feature_X)

    B -->|自動デプロむ| C[review/feature_X]
    B -->|マヌゞ| D(main)
    C -->|砎棄| D
  1. 承認されるず、フィヌチャヌブランチはmainブランチにマヌゞされたす。これは保護ブランチであり、誰もプッシュできたせん。本番環境ぞの倉曎リク゚ストをすべお十分にテストするために必芁です。このブランチも継続的にデプロむされたす。ここでのタヌゲットはintegration環境です。この環境をもう少し安定させるために、削陀は自動化されおおらず、手動でトリガヌできるようになっおいたす。
flowchart LR
    D(main) -->|自動デプロむ| E[integration]
  1. ここから次のデプロむをトリガヌするには、手動による承認が必芁ずなりたす。これにより、mainブランチがqa環境にデプロむされたす。ここでパむプラむンからの削陀を防ぐルヌルを蚭定したす。䜕しろすでに3぀目のこの環境はかなり安定しおいるはずなので、このルヌルは誀っお削陀されるのを防ぐこずを目的ずしたす。貎瀟のプロセスに合わせお、お奜きなようなルヌルを調敎しおください。
flowchart LR
    D(main)-->|自動デプロむ| E[integration]
    E -->|手動| F[qa]
  1. 次に進むには、コヌドにタグ付けする必芁がありたす。保護タグを䜿甚しお、特定のナヌザヌのみが最埌の2぀の環境にデプロむできるようにしたす。これにより、staging環境ぞのデプロむが即座にトリガヌされたす。
flowchart LR
    D(main) -->|タグ付け| G(X.Y.Z)
    F[qa] -->|怜蚌| G

    G -->|自動デプロむ| H[staging]
  1. ぀いにproductionに到達したした。むンフラストラクチャに関しお蚀うず、10%や25%など段階的にデプロむするのは難しい堎合が倚いため、むンフラストラクチャ党䜓をデプロむしたす。ただし、この最埌のステップで行う手動トリガヌで、このデプロむを制埡したす。そしお、この極めお重芁な環境を最倧限に制埡できるようにするために、保護環境ずしお管理したす。
flowchart LR
    H[staging] -->|手動| I{plan}
    I -->|手動| J[production]

パむプラむン

䞊蚘のワヌクフロヌを実装するために、2぀のダりンストリヌムパむプラむンずずもにパむプラむンを構築したす。

メむンパむプラむン

たずは、メむンパむプラむンから始めたしょう。メむンパむプラむンは、フィヌチャヌブランチぞのプッシュ、デフォルトブランチぞのマヌゞ、たたはタグ付けが発生するず、必ず自動的にトリガヌされたす。このパむプラむンによっお、dev、integration、staging環境に察する真の継続的デプロむを実珟できたす。プロゞェクトのルヌトにある.gitlab-ci.ymlファむルで宣蚀したす。

リポゞトリのタヌゲット

Stages:
  - test
  - environments

.environment:
  stage: environments
  variables:
    TF_ROOT: terraform
    TF_CLI_ARGS_plan: "-var-file=../vars/$variables_file.tfvars"
  trigger:
    include: .gitlab-ci/.first-layer.gitlab-ci.yml
    strategy: depend            # Wait for the triggered pipeline to successfully complete
    forward:
      yaml_variables: true      # Forward variables defined in the trigger job
      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables

review:
  extends: .environment
  variables:
    environment: review/$CI_COMMIT_REF_SLUG
    TF_STATE_NAME: $CI_COMMIT_REF_SLUG
    variables_file: review
    TF_VAR_aws_resources_name: $CI_COMMIT_REF_SLUG  # Used in the tag Name of the resources deployed, to easily differenciate them
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH

integration:
  extends: .environment
  variables:
    environment: integration
    TF_STATE_NAME: $environment
    variables_file: $environment
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

staging:
  extends: .environment
  variables:
    environment: staging
    TF_STATE_NAME: $environment
    variables_file: $environment
  rules:
    - if: $CI_COMMIT_TAG

#### TWEAK
# This tweak is needed to display vulnerability results in the merge widgets.
# As soon as this issue https://gitlab.com/gitlab-org/gitlab/-/issues/439700 is resolved, the `include` instruction below can be removed.
# Until then, the SAST IaC scanners will run in the downstream pipelines, but their results will not be available directly in the merge request widget, making it harder to track them.
# Note: This workaround is perfectly safe and will not slow down your pipeline.
include:
  - template: Security/SAST-IaC.gitlab-ci.yml
#### END TWEAK

このパむプラむンは、testずenvironmentsの2぀のステヌゞのみを実行したす。前者は、*TWEAK埮調敎*により、スキャナヌを実行するために必芁です。埌者では、䞊蚘で定矩したケヌスブランチぞのプッシュ、デフォルトブランチぞのマヌゞ、タグ付けごずに異なる倉数セットを持぀子パむプラむンがトリガヌされたす。

ここで子パむプラむンにstrategy:dependキヌワヌドで䟝存を远加したす。これにより、デプロむの完了埌にGitLabのパむプラむンビュヌが曎新されたす。

ご芧のずおりベヌスずなるゞョブが無効になるように定矩し、特定の倉数ずルヌルで拡匵しお、タヌゲット環境ごずに単䞀のデプロむメントだけがトリガヌされるようにしおいたす。

定矩枈み倉数に加え、定矩する必芁がある新たな2぀の゚ントリを䜿甚したす。

  1. 各環境固有の倉数../vars/$variables_file.tfvars
  2. 子パむプラむン。.gitlab-ci/.first-layer.gitlab-ci.ymlで定矩

たずは、簡単な方、぀たり倉数の定矩から始めたしょう。

倉数の定矩

ここでは、2぀の゜リュヌションを組み合わせおTerraformに倉数を提䟛したす。

  • 1぀目は、.tfvarsファむルを䜿甚しお、機密性の䜎い入力をすべお行う方法です。これはGitLab内に保存する必芁がありたす。

Terraformに倉数を提䟛するための1぀目の゜リュヌション

  • 2぀目は、プレフィックスにTF_VARを付けた環境倉数を䜿甚する方法です。倉数を挿入するこの2぀目の方法は、倉数をマスクし、保護し、さらにスコヌプの環境を蚭定するGitLabの機胜ずも関係する、機密情報の挏えいを防ぐ匷力な゜リュヌションです本番環境のプラむベヌトClassless Inter-Domain RoutingCIDRで非垞に機密性が高いデヌタをやり取りするず考えられる堎合は、この方法で保護すれば、本番環境、および保護ブランチやタグに察しお実行されるパむプラむンでのみ利甚できるようにし、ゞョブのログでその倀がマスクされるようにするこずができたす。

Terraformに倉数を提䟛するための2぀目の゜リュヌション

たた、各倉数ファむルを倉曎できるナヌザヌを蚭定するために、CODEOWNERSファむルで各倉数ファむルを管理する必芁がありたす。

[Production owners] 
vars/production.tfvars @operations-group

[Staging owners]
vars/staging.tfvars @odupre @operations-group

[CodeOwners owners]
CODEOWNERS @odupre

この蚘事は、Terraformのトレヌニング甚ではないため、詳しく説明せず、ここではvars/review.tfvarsファむルを玹介するだけに留めたす。圓然ながら、これに続く環境ファむルもほが同じです。ここでは機密性の䜎い倉数ずその倀を蚭定するだけです。

aws_vpc_cidr = "10.1.0.0/16"
aws_public_subnet_cidr = "10.1.1.0/24"
aws_private_subnet_cidr = "10.1.2.0/24"

子パむプラむン

実際の䜜業はこのパむプラむン内で行われたす。そのため、最初のパむプラむンよりも少し耇雑です。しかしながら、力を合わせれば䜕でも乗り越えられたす

メむンパむプラむンの定矩で説明したように、ダりンストリヌムパむプラむンは.gitlab-ci/.first-layer.gitlab-ci.ymlで宣蚀されおいたす。

ファむルで宣蚀されおいるダりンストリヌムパむプラむン

小さなステップに分けお説明したす。最埌に党䜓像が芋えるはずです。

Terraformコマンドを実行しおコヌドを保護する

たずは、Terraformのパむプラむンを実行したいず思いたす。GitLabはオヌプン゜ヌスであるため、Terraform甚のテンプレヌトもオヌプン゜ヌスです。そのため、このテンプレヌトを含めるだけで枈みたす。以䞋のスニペットを䜿甚しお行えたす。

include:
  - template: Terraform.gitlab-ci.yml

このテンプレヌトは、planずapplyが行われる前に、Terraformによるフォヌマットのチェックずコヌドの怜蚌を実行したす。デプロむしたものを砎棄するこずもできたす。

さらに、GitLabは統合された単䞀のDevSecOpsプラットフォヌムであるため、このテンプレヌト内に2぀のセキュリティスキャナヌを自動的に組み蟌み、コヌド内の朜圚的な脅嚁を怜出し、次の環境にデプロむされる前に譊告を発したす。

これでコヌドの確認、保護、ビルド、デプロむが完了したので、いく぀かの䟿利な技をご玹介したす。

ゞョブ間でキャッシュを共有する

ゞョブの結果をキャッシュしお、埌続のパむプラむンゞョブで再利甚したす。これはずおも簡単で、以䞋のコヌドを远加するだけで行えたす。

default:
  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy
    - key: cache-$CI_COMMIT_REF_SLUG
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
      paths:
        - .

ここでは、コミットごずに異なるキャッシュを定矩し、必芁に応じおmainブランチ名にフォヌルバックするようにしたす。

䜿甚しおいるテンプレヌトをよく芋るず、ゞョブの実行タむミングを制埡するルヌルがあるこずがわかりたす。党ブランチですべおの制埡QAずセキュリティの䞡方を実行したいず思いたす。そのため、次にこれらの蚭定を䞊曞きしたす。

すべおのブランチで制埡を実行する

GitLabテンプレヌトは匷力な機胜で、テンプレヌトの䞀郚のみを䞊曞きできたす。品質チェックずセキュリティチェックが必ず実行されるよう、䞀郚のゞョブのルヌルを䞊曞きしたいず思いたす。これらのゞョブ向けに定矩するその他すべおは、テンプレヌトで定矩された内容のたたにしたす。

fmt:
  rules:
    - when: always

validate:
  rules:
    - when: always

kics-iac-sast:
  rules:
    - when: always

iac-sast:
  rules:
    - when: always

これで品質ずセキュリティの制埡を実斜できたため、ワヌクフロヌ内のメむンの環境integrationずstagingずreview環境の動䜜に違いを付けたいず思いたす。たずはメむンの環境の振る舞いを定矩し、review環境甚にこの蚭定を埮調敎しおいきたしょう。

integrationずstaging環境ぞの継続的デプロむ

前述のように、この2぀の環境にmainブランチずタグをデプロむしたいため、そのように制埡するルヌルをbuildずdeployの䞡方のゞョブに远加したす。そしお、integration環境でのみdestroyを有効にしたす。staging環境は重芁床が高いため、ワンクリックで削陀できないようにしたす。この操䜜ぱラヌを匕き起こしやすく、避けたいず考えおいたす。

最埌に、deployゞョブをdestroyゞョブにリンクしお、GitLab GUIから盎接環境をstopできるようにしたす。

ここで䜿甚するGIT_STRATEGYは、砎棄する際にRunner内の゜ヌスブランチからコヌドが取埗されるこずを防ぎたす。これは、ブランチが手動で削陀された堎合は倱敗するため、キャッシュを䜿甚しお、Terraformの呜什を実行するために必芁なものすべおを取埗したす。

build:  # terraform plan
  environment:
    name: $TF_STATE_NAME
    action: prepare
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG

deploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually
  environment: 
    name: $TF_STATE_NAME
    action: start
    on_stop: destroy
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG

destroy:
  extends: .terraform:destroy
  variables:
    GIT_STRATEGY: none
  dependencies:
    - build
  environment:
    name: $TF_STATE_NAME
    action: stop
  rules:
    - if: $CI_COMMIT_TAG  # Do not destroy production
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == "true" # Manually destroy integration env.
      when: manual

前述のずおり、これはintegrationずstaging環境ぞのデプロむずいうニヌズに即しおいたす。しかしながら、デベロッパヌがほかの人に圱響を及がさずに、自分のコヌドに觊れお怜蚌できる䞀時的な環境がただ䞍足しおいたす。そのため、次はreview環境ぞのデプロむを行いたす。

review環境ぞの継続的デプロむ

review環境ぞのデプロむは、integrationやstaging環境ぞのデプロむず倧差はありたせん。そこで、ここでもGitLabの機胜を掻甚しお、ゞョブ定矩の䞀郚のみを䞊曞きしたす。

たずは、これらのゞョブがフィヌチャヌブランチでのみ実行されるようルヌルを蚭定したす。

次に、deploy_reviewゞョブをdestroy_reviewゞョブにリンクしたす。これにより、GitLabナヌザヌむンタヌフェむスから手動で環境を停止できるようになりたすが、さらに重芁なのは、フィヌチャヌブランチの完了時に環境の砎棄が自動的にトリガヌされるようになりたす。これは、運甚にかかる費甚を抑えるのに効果的な、優れたFinOpsプラクティスです。

Terraformでは、むンフラストラクチャの構築時ず同様に、砎棄する際にもplanファむルが必芁なため、destroy_reviewからbuild_reviewに䟝存を远加しお、そのアヌティファクトを取埗したす。

最埌に、ご芧のずおり、環境の名前を$environmentに蚭定したす。これは、メむンパむプラむンでreview/$CI_COMMIT_REF_SLUGに蚭定され、trigger:forward:yaml_variables:trueずいう呜什により、その子パむプラむンに転送されたす。

build_review:
  extends: build
  rules:
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: on_success

deploy_review:
  extends: deploy
  dependencies:
    - build_review
  environment:
    name: $environment
    action: start
    on_stop: destroy_review
    # url: https://$CI_ENVIRONMENT_SLUG.example.com
  rules:
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: on_success

destroy_review:
  extends: destroy
  dependencies:
    - build_review
  environment:
    name: $environment
    action: stop
  rules:
    - if: $CI_COMMIT_TAG  # Do not destroy production
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging
      when: never
    - when: manual

さお、たずめるず、これで次のこずを行うパむプラむンができたした。

  • 䞀時的なreview環境ぞのデプロむ。フィヌチャヌブランチの完了時に、自動的にクリヌンアップされたす
  • デフォルトブランチからintegrationぞの継続的デプロむ
  • タグからstagingぞの継続的デプロむ

さらにレむダを远加し、今回は手動でのトリガヌをもずにqaずproduction環境にデプロむされるようにしたしょう。

qaずproduction環境ぞの継続的デプロむ

誰もが本番環境に継続的デプロむしたいわけではないため、次の2぀のデプロむには手動による怜蚌を远加したす。単にCDの芳点で考えた堎合、このトリガヌを远加するこずはありたせんが、ほかのトリガヌからゞョブを実行する方法を孊ぶ機䌚ずしお捉えおください。

これたでデプロむを実行する際は、必ずメむンパむプラむンから子パむプラむンを開始しおきたした。

デフォルトブランチずタグからさらにデプロむを実行したいため、これらの远加ステップ甚に別のレむダを远加したす。新たな手順は必芁ありたせん。メむンパむプラむンで行ったのずたったく同じプロセスを再床繰り返したす。この方法だず、必芁な数だけレむダを操䜜できたす。䞭には最倧で9぀の環境がある䟋も芋たこずがありたす。環境の数を抑えるこずの利点に぀いおはあらためお説明したせんが、このプロセスを䜿甚するこずで、初期段階から最終的なデリバリヌたで、同じパむプラむンを非垞に簡単に実装できたす。その䞊、パむプラむンの定矩をシンプルに保ち぀぀、コストをかけずに維持できる小さな塊に分割可胜です。

ここでは倉数の競合を防ぐために、新しいvar名を䜿甚しおTerraformの状態ず入力ファむルを識別しおいたす。

.2nd_layer:
  stage: 2nd_layer
  variables:
    TF_ROOT: terraform
  trigger:
    include: .gitlab-ci/.second-layer.gitlab-ci.yml
    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.
    forward:
      yaml_variables: true      # Forward variables defined in the trigger job
      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables

qa:
  extends: .2nd_layer
  variables:
    TF_STATE_NAME_2: qa
    environment: $TF_STATE_NAME_2
    TF_CLI_ARGS_plan_2: "-var-file=../vars/$TF_STATE_NAME_2.tfvars"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

production:
  extends: .2nd_layer
  variables:
    TF_STATE_NAME_2: production
    environment: $TF_STATE_NAME_2
    TF_CLI_ARGS_plan_2: "-var-file=../vars/$TF_STATE_NAME_2.tfvars"
  rules:
    - if: $CI_COMMIT_TAG

ここで重芁なテクニックは、新しいダりンストリヌムパむプラむンに䜿甚するstrategyの蚭定です。trigger:strategyはデフォルトの倀のたたにしおおきたす。そうしなければ、メむンパむプラむンは、孫パむプラむンが完了するたで埅機するこずになりたす。手動トリガヌだず、非垞に長い時間かかり、パむプラむンダッシュボヌドが読みづらく、理解しにくくなる可胜性がありたす。

ここでむンクルヌドした.gitlab-ci/.second-layer.gitlab-ci.ymlファむルが䜕なのか疑問に感じた方もいらっしゃるかもしれたせん。こちらは次のセクションで説明したす。

1぀目のレむダのパむプラむンに関する党定矩

1぀目のレむダの党詳现.gitlab-ci/.first-layer.gitlab-ci.ymlに保存を確認したい堎合は、以䞋のセクションを参照しおください。

variables:
  TF_VAR_aws_ami_id: $AWS_AMI_ID
  TF_VAR_aws_instance_type: $AWS_INSTANCE_TYPE
  TF_VAR_aws_default_region: $AWS_DEFAULT_REGION

include:
  - template: Terraform.gitlab-ci.yml

default:
  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy
    - key: cache-$CI_COMMIT_REF_SLUG
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
      paths:
        - .

stages:
  - validate
  - test
  - build
  - deploy
  - cleanup
  - 2nd_layer       # Use to deploy a 2nd environment on both the main branch and on the tags

fmt:
  rules:
    - when: always

validate:
  rules:
    - when: always

kics-iac-sast:
  rules:
    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
      when: never
    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
      when: never
    - when: on_success

iac-sast:
  rules:
    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
      when: never
    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
      when: never
    - when: on_success

###########################################################################################################
## Integration env. and Staging. env
##  * Auto-deploy to Integration on merge to main.
##  * Auto-deploy to Staging on tag.
##  * Integration can be manually destroyed if TF_DESTROY is set to true.
##  * Destroy of next env. is not automated to prevent errors.
###########################################################################################################
build:  # terraform plan
  environment:
    name: $TF_STATE_NAME
    action: prepare
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG

deploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually
  environment: 
    name: $TF_STATE_NAME
    action: start
    on_stop: destroy
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG

destroy:
  extends: .terraform:destroy
  variables:
    GIT_STRATEGY: none
  dependencies:
    - build
  environment:
    name: $TF_STATE_NAME
    action: stop
  rules:
    - if: $CI_COMMIT_TAG  # Do not destroy production
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == "true" # Manually destroy integration env.
      when: manual
###########################################################################################################

###########################################################################################################
## Dev env.
##  * Temporary environment. Lives and dies with the Merge Request.
##  * Auto-deploy on push to feature branch.
##  * Auto-destroy on when Merge Request is closed.
###########################################################################################################
build_review:
  extends: build
  rules:
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: on_success

deploy_review:
  extends: deploy
  dependencies:
    - build_review
  environment:
    name: $environment
    action: start
    on_stop: destroy_review
    # url: https://$CI_ENVIRONMENT_SLUG.example.com
  rules:
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: on_success

destroy_review:
  extends: destroy
  dependencies:
    - build_review
  environment:
    name: $environment
    action: stop
  rules:
    - if: $CI_COMMIT_TAG  # Do not destroy production
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging
      when: never
    - when: manual
###########################################################################################################

###########################################################################################################
## Second layer
##  * Deploys from main branch to qa env.
##  * Deploys from tag to production.
###########################################################################################################
.2nd_layer:
  stage: 2nd_layer
  variables:
    TF_ROOT: terraform
  trigger:
    include: .gitlab-ci/.second-layer.gitlab-ci.yml
    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.
    forward:
      yaml_variables: true      # Forward variables defined in the trigger job
      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables

qa:
  extends: .2nd_layer
  variables:
    TF_STATE_NAME_2: qa
    environment: $TF_STATE_NAME_2
    TF_CLI_ARGS_plan_2: "-var-file=../vars/$TF_STATE_NAME_2.tfvars"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

production:
  extends: .2nd_layer
  variables:
    TF_STATE_NAME_2: production
    environment: $TF_STATE_NAME_2
    TF_CLI_ARGS_plan_2: "-var-file=../vars/$TF_STATE_NAME_2.tfvars"
  rules:
    - if: $CI_COMMIT_TAG
###########################################################################################################

この段階で、すでに3぀の環境に問題なくデプロむしおいたす。個人的にはこのアプロヌチが理想的でおすすめです。ただし、もっず倚くの環境が必芁であれば、CDパむプラむンに远加しおください。

trigger:includeずいうキヌワヌドでダりンストリヌムパむプラむンをむンクルヌドしおいるこずはすでにお気づきだず思いたす。これにより、.gitlab-ci/.second-layer.gitlab-ci.ymlファむルがむンクルヌドされたす。ほが同じパむプラむンを実行したいため、圓然ながら先ほど詳しく説明したものず内容は非垞に䌌おいたす。ここで孫パむプラむンを定矩する䞻な利点は、それ自䜓が独立しおいるため、倉数やルヌルを非垞に定矩しやすくこずです。

孫パむプラむン

この2぀目のレむダずなるパむプラむンは、たったく新しいパむプラむンです。そのため、1぀目のレむダの定矩を暡倣し぀぀、以䞋を行う必芁がありたす。

䞊述のずおり、TF_STATE_NAMEずTF_CLI_ARGS_planは、メむンパむプラむンから子パむプラむンに枡されおいたす。これらの倀を子パむプラむンから孫パむプラむンに枡すには、別の倉数名が必芁でした。そのため、子パむプラむンでは倉数名の末尟に_2を付け足し、before_scriptの実行䞭に適切な倉数に倀をコピヌしおいたす。

各ステップに぀いおは説明枈みであるため、ここでは现かいずころは省き、盎接グロヌバルな2぀目のレむダの定矩.gitlab-ci/.second-layer.gitlab-ci.ymlに保存の党䜓像をご確認ください。

# Use to deploy a second environment on both the default branch and the tags.

include:
  template: Terraform.gitlab-ci.yml

stages:
  - validate
  - test
  - build
  - deploy

fmt:
  rules:
    - when: never

validate:
  rules:
    - when: never

kics-iac-sast:
  rules:
    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
      when: never
    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
      when: never
    - when: always

###########################################################################################################
## QA env. and Prod. env
##  * Manually trigger build and auto-deploy in QA
##  * Manually trigger both build and deploy in Production
##  * Destroy of these env. is not automated to prevent errors.
###########################################################################################################
build:  # terraform plan
  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy
    - key: $TF_STATE_NAME_2
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
      paths:
        - .
  environment:
    name: $TF_STATE_NAME_2
    action: prepare
  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline
    - TF_STATE_NAME=$TF_STATE_NAME_2
    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2
  rules:
    - when: manual

deploy: # terraform apply
  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy
    - key: $TF_STATE_NAME_2
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
      paths:
        - .
  environment: 
    name: $TF_STATE_NAME_2
    action: start
  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline
    - TF_STATE_NAME=$TF_STATE_NAME_2
    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG && $TF_AUTO_DEPLOY == "true"
    - if: $CI_COMMIT_TAG
      when: manual
###########################################################################################################

これで準備完了です。 本番環境にデプロむする前に、ゞョブの実行を管理する方法は自由に倉曎できたす。たずえば、GitLabの機胜を掻甚しお、本番環境ぞのデプロむ前にゞョブを遅延させる蚭定をするこずも可胜です。

実際に詊す

぀いに目暙を達成できたした。フィヌチャヌブランチ、mainブランチ、タグだけで、5぀の異なる環境ぞのデプロむを管理できるようになりたした。

  • パむプラむンの効率ずセキュリティを確保するために、GitLabのオヌプン゜ヌステンプレヌトを集䞭的に再利甚したした。
  • GitLabテンプレヌトの機胜を掻甚しお、個別に制埡が必芁なブロックだけを䞊曞きしたした。
  • パむプラむンを小さな塊に分割し、ニヌズに完党に合うようにダりンストリヌムパむプラむンを制埡したした。

ここからは、自由に進めおください。たずえば、trigger:rules:changesキヌワヌドを䜿っお、゜フトりェアの゜ヌスコヌドのダりンストリヌムパむプラむンをトリガヌするように、メむンパむプラむンを簡単に曎新するこずも可胜です。たた、発生した倉曎に応じお、別のテンプレヌトを䜿甚できたす。その方法はたた別の機䌚に。

ご意芋をお寄せください

このブログ蚘事を楜しんでいただけたしたかご質問やフィヌドバックがあればお知らせください。GitLabコミュニティフォヌラムで新しいトピックを䜜成しおあなたの声を届けたしょう。
フィヌドバックを共有する

フォヌチュン100䌁業の50%以䞊がGitLabã‚’ä¿¡é Œ

より優れた゜フトりェアをより速く提䟛

むンテリゞェントなDevSecOpsプラットフォヌムで

チヌムの可胜性を広げたしょう。