Adding Terraform CICD reference for Gitlab and related README (#1450)

This commit is contained in:
Nicholas M. Iodice 2020-10-22 03:31:09 -04:00 коммит произвёл GitHub
Родитель c9f9591f6b
Коммит a2ef0541d7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 394 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euox pipefail
az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID"

Просмотреть файл

@ -0,0 +1,34 @@
# This file contains the variables and jobs for the dev stage
.dev-vars: &dev-vars
ARM_CLIENT_ID: $DEV_ARM_CLIENT_ID
ARM_CLIENT_SECRET: $DEV_ARM_CLIENT_SECRET
AZURE_STORAGE_ACCOUNT_NAME: $DEV_AZURE_STORAGE_ACCOUNT_NAME
AZURE_STORAGE_ACCOUNT_CONTAINER: $DEV_AZURE_STORAGE_ACCOUNT_CONTAINER
AZURE_STORAGE_ACCOUNT_SUBSCRIPTION: $DEV_AZURE_STORAGE_ACCOUNT_SUBSCRIPTION
VAR_FILE_NAME: 'DEV_TF_VARS'
ENVIRONMENT: 'dev'
DevBuild:
extends: .build
stage: Dev-Build
variables:
<<: *dev-vars
only:
- master
- merge_requests
- web
DevRelease:
extends: .release
stage: Dev-Release
variables:
<<: *dev-vars
needs:
- job: DevBuild
artifacts: true
when: on_success
only:
- master
- merge_requests
- web

Просмотреть файл

@ -0,0 +1,34 @@
# This file contains the variables and jobs for the integration stage
.integration-vars: &integration-vars
ARM_CLIENT_ID: $INTEGRATION_ARM_CLIENT_ID
ARM_CLIENT_SECRET: $INTEGRATION_ARM_CLIENT_SECRET
AZURE_STORAGE_ACCOUNT_NAME: $INTEGRATION_AZURE_STORAGE_ACCOUNT_NAME
AZURE_STORAGE_ACCOUNT_CONTAINER: $INTEGRATION_AZURE_STORAGE_ACCOUNT_CONTAINER
AZURE_STORAGE_ACCOUNT_SUBSCRIPTION: $INTEGRATION_AZURE_STORAGE_ACCOUNT_SUBSCRIPTION
VAR_FILE_NAME: 'INTEGRATION_TF_VARS'
ENVIRONMENT: 'integration'
IntegrationBuild:
extends: .build
stage: Integration-Build
variables:
<<: *integration-vars
only:
- master
needs:
- job: DevRelease
artifacts: false
IntegrationRelease:
extends: .release
stage: Integration-Release
variables:
<<: *integration-vars
needs:
- job: IntegrationBuild
artifacts: true
when: manual
allow_failure: false
only:
- master

Просмотреть файл

@ -0,0 +1,43 @@
# This file contains all of the checks that need to happen
# before a build and release.
# Cache dependent modules + proviers and upload an artifact. We need to
# make sure that the backend configuration is not configured, since it will
# need to be done for each stage. The configuration per stage may differ, so
# it makes sense to defer the initialization.
InitTF:
stage: Init
script: .ci/tf-init-without-backend.sh
artifacts:
paths:
- .terraform/
only:
- master
- merge_requests
# Lint check terraform files
LintTF:
stage: Pre-Build
script: .ci/tf-lint.sh
only:
- master
- merge_requests
# Validate terraform configuration
ValidateTF:
stage: Pre-Build
script: .ci/tf-validate.sh
needs:
- job: InitTF
artifacts: true
only:
- master
- merge_requests
# Lint check go files
lintGo:
stage: Pre-Build
script: .ci/go-lint.sh
only:
- master
- merge_requests

Просмотреть файл

@ -0,0 +1,34 @@
# This file contains the variables and jobs for the prod stage
.prod-vars: &prod-vars
ARM_CLIENT_ID: $PROD_ARM_CLIENT_ID
ARM_CLIENT_SECRET: $PROD_ARM_CLIENT_SECRET
AZURE_STORAGE_ACCOUNT_NAME: $PROD_AZURE_STORAGE_ACCOUNT_NAME
AZURE_STORAGE_ACCOUNT_CONTAINER: $PROD_AZURE_STORAGE_ACCOUNT_CONTAINER
AZURE_STORAGE_ACCOUNT_SUBSCRIPTION: $PROD_AZURE_STORAGE_ACCOUNT_SUBSCRIPTION
VAR_FILE_NAME: 'PROD_TF_VARS'
ENVIRONMENT: 'prod'
ProdBuild:
extends: .build
stage: Prod-Build
variables:
<<: *prod-vars
only:
- master
needs:
- job: IntegrationRelease
artifacts: false
ProdRelease:
extends: .release
stage: Prod-Release
variables:
<<: *prod-vars
needs:
- job: ProdBuild
artifacts: true
when: manual
allow_failure: false
only:
- master

Просмотреть файл

@ -0,0 +1,27 @@
# This file contains jobs that can be extended by stage-specific
# build and release steps
# Generic terraform build job
.build:
environment:
name: $ENVIRONMENT
artifacts:
paths:
- .terraform/
- "$PLAN_FILE"
script:
- .ci/az-login.sh
- .ci/tf-init-for-stage.sh
- .ci/tf-workspace-select.sh
- .ci/tf-plan.sh
# Generic terraform release job
.release:
environment:
name: $ENVIRONMENT
allow_failure: false
script:
- .ci/az-login.sh
- .ci/tf-init-for-stage.sh
- .ci/tf-workspace-select.sh
- .ci/tf-apply.sh

Просмотреть файл

@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Note: the omission of the `pipefail` flag is intentional. It allows this
# step to succeede in the case that there are no `*.go` files in the
# infrastructure repository.
set -euox
echo "Linting Go Files... If this fails, run 'go fmt ./...' to fix"
# This runs a go fmt on each file without using the 'go fmt ./...' syntax.
# This is advantageous because it avoids having to download all of the go
# dependencies that would have been triggered by using the './...' syntax.
FILES_WITH_FMT_ISSUES=$(find . -name "*.go" | grep -v '.terraform' | xargs gofmt -l | wc -l)
# convert to integer...
FILES_WITH_FMT_ISSUES=$(($FILES_WITH_FMT_ISSUES + 0))
# set exit code accordingly
exit $FILES_WITH_FMT_ISSUES

Просмотреть файл

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euox pipefail
terraform apply -input=false -auto-approve $PLAN_FILE

Просмотреть файл

@ -0,0 +1,4 @@
# #!/usr/bin/env bash
set -euox pipefail
terraform init -backend-config "storage_account_name=$AZURE_STORAGE_ACCOUNT_NAME" -backend-config "container_name=$AZURE_STORAGE_ACCOUNT_CONTAINER"

Просмотреть файл

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euox pipefail
terraform init -backend=false

Просмотреть файл

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euox pipefail
echo "Linting Terraform Files... If this fails, run 'terraform fmt -recursive' to fix"
terraform fmt -recursive -check

Просмотреть файл

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euox pipefail
# workaround for https://gitlab.com/gitlab-org/gitlab-foss/-/issues/65763
terraform plan -var-file="${!VAR_FILE_NAME}" -out "$PLAN_FILE"

Просмотреть файл

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euox pipefail
terraform validate

Просмотреть файл

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euox pipefail
terraform workspace new $ENVIRONMENT || terraform workspace select $ENVIRONMENT

Просмотреть файл

@ -0,0 +1,40 @@
# Extension points not yet implemented:
# (1) Run infrastructure unit tests in precheck stage
# (2) Run infrastructure integration tests
# Configure the base image for CI jobs here.
#
# To override the entrypoint see the documentation here:
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#overriding-the-entrypoint-of-an-image
#
# To use a custom image, use the following syntax:
# name: "$CI_REGISTRY/<your image here>:<your tag here>"
image:
name: "{{IMAGE_SLUG}}"
entrypoint:
- '/usr/bin/env'
- 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
include:
- '/.ci/ci-stages.yml'
- '/.ci/ci-prechecks.yml'
- '/.ci/ci-dev.yml'
- '/.ci/ci-integration.yml'
- '/.ci/ci-prod.yml'
before_script:
- terraform version
stages:
- Init
- Pre-Build
- Dev-Build
- Dev-Release
- Integration-Build
- Integration-Release
- Prod-Build
- Prod-Release
variables:
TF_IN_AUTOMATION: "true"
PLAN_FILE: tfplan.out

Просмотреть файл

@ -0,0 +1,13 @@
FROM hashicorp/terraform:0.12.29
# Add common dependencies
RUN apk update && \
apk add openssl curl tar gzip bash ca-certificates coreutils
# Add Azure CLI
RUN \
apk add py3-pip && \
apk add --virtual=build gcc libffi-dev musl-dev openssl-dev python3-dev make && \
pip3 --no-cache-dir install -U pip && \
pip3 --no-cache-dir install azure-cli && \
apk del --purge build

Просмотреть файл

@ -0,0 +1,72 @@
# Terraform Deployments on Gitlab
This repository contains CICD templates that can deploy [Terraform](https://www.terraform.io/) templates for production systems into Azure using Gitlab.
## Automated CICD
Deployment of Terraform Templates are fully automated via the [GitLab Pipeline](./.gitlab-ci.yml).
**Terminology**
* `init` causes Terraform modules to be downloaded/cached
* `lint` applies lint checks to the IAC templates and any Go files
* `build` is a Terraform plan
* `release` is a Terraform apply
The table below outlines when a deployment will happen to each stage:
> **Note**: Manual approvals are **always required** before deploying to non-`dev` environments
| Action | Pipeline Stages (sequential) |
| --- | --- |
| Manual branch build | `dev::build`, `dev::release` |
| Create/Update PR | `init`, `lint`, `dev::build`, `dev::release` |
| Merge PR | `init`, `lint`, `dev::build`, `dev::release`, `integration::build`, `integration::release`, `prod::build`, `prod::release` |
| Master Branch Build | Same as above |
## Infrastructure Rollbacks
It is possible that Terraform deployments will need to be rolled back. To rollback use `git revert` commands or simply make another commit to return your configuration to a previous state in the infrastructure as code repository.
Be sure to create a local git branch, then commit, push, and generate a pull request on GitLab.
## Usage
**Step 1: Azure & Gitlab Configuration**
All Azure and Gitlab configuration required to use these templates should be provisioned using the [`gitlab-bootstrap-iac-cicd`](https://github.com/microsoft/cobalt/tree/master/infra/templates/gitlab-bootstrap-iac-cicd) template from project [Cobalt](https://github.com/microsoft/cobalt). No other manual configuration is necessary.
**Step 2: Build and Push Gitlab Runner Base Image**
The CICD templates in this folder assume the following tools are installed.
* Terraform v0.12.x
* Golang
* Azure CLI
The included [`Dockerfile.sample`](Dockerfile.sample) can be used as a starting point. Use these commands to push the base image to the ACR:
```bash
# Configure environment
$ ACR_NAME="..."
$ IMAGE="..."
$ TAG="latest"
# Build and push image
$ az acr login -n "$ACR_NAME"
$ docker build -f Dockerfile.sample . -t "$ACR_NAME.azurecr.io/$IMAGE:$TAG"
$ docker push "$ACR_NAME.azurecr.io/$IMAGE:$TAG"
```
**Step 3: Configure Gitlab Pipeline to Use Base Image**
Now insert a custom value for the base image reference/property in `.gitlab-ci.yml`:
> **Note**: The use of `\$CI_REGISTRY` in the command below is intentional. When this pipeline is exercised, the value of `CI_REGISTRY` will be resolved because the [`gitlab-bootstrap-iac-cicd`](https://github.com/microsoft/cobalt/tree/master/infra/templates/gitlab-bootstrap-iac-cicd) template from step 1 configured it to point to the correct container registry.
```bash
$ sed -i '' "s/{{IMAGE_SLUG}}/\$CI_REGISTRY\/$IMAGE:$TAG/g" .gitlab-ci.yml
```
**Step 4: Write Some Terraform!**
At this point, you can begin writing a Terraform template for your deployment. The [`sample.tf`](./sample.tf) file is a sample Terraform template that shows a simple but working Terraform file that uses the backend state and variables configured through the Gitlab/Azure bootstrapping process referenced above.

Просмотреть файл

@ -0,0 +1,44 @@
# This file in intended to show how to leverage the following, which are provisioned
# through the Azure/Gitlab bootstrapping process.
# (1) Backend State
# (2) TF Vars
#
# See README.me for more
provider "azurerm" {
version = "=2.22"
features {}
}
terraform {
backend "azurerm" {
key = "terraform.tfstate"
}
}
variable "env" {
type = string
description = "The name of the environment to provision. Examples: dev, qa, prod"
}
variable "resource_group" {
type = string
description = "The resource group to deploy into"
}
variable "acr_id" {
type = string
description = "The resource identifier for AKS to attach to"
}
output "echo_env" {
value = var.env
}
output "echo_resource_group" {
value = var.resource_group
}
output "echo_acr_id" {
value = var.acr_id
}