# Google Cloud Credentials / Service Account / Bucket para armazenar o Terraform State
export GOOGLE_CREDENTIALS_FILE="${HOME}/trash/credentials.json"
if [ -e "${GOOGLE_CREDENTIALS_FILE}" ]; then
if which jq > /dev/null; then
GOOGLE_PROJECT=$(jq .project_id ${GOOGLE_CREDENTIALS_FILE} -r)
else
GOOGLE_PROJECT="$(grep project_id ${GOOGLE_CREDENTIALS_FILE} | awk -F '"' '{ print $4 }')"
fi
export GOOGLE_PROJECT
else
echo "File doesn't exists: ${GOOGLE_CREDENTIALS_FILE}"
exit 1
fi
export GOOGLE_CREDENTIALS=$(cat "${GOOGLE_CREDENTIALS_FILE}" | tr -d "\n")
export GOOGLE_BACKEND_CREDENTIALS="${GOOGLE_CREDENTIALS}"
export GOOGLE_BUCKET="silvios-wasp-foundation-k9z"
export GOOGLE_PREFIX="terraform"
export GOOGLE_CREDENTIALS_BASE64=$( echo "${GOOGLE_CREDENTIALS}" | base64 | tr -d "\n")
export GOOGLE_BACKEND_CREDENTIALS_BASE64=$(echo "${GOOGLE_BACKEND_CREDENTIALS}" | base64 | tr -d "\n")
# Empacotando o Projeto de Exemplo
git clone https://github.com/smsilva/terraform-packager.git
cd terraform-packager
export STACK_INSTANCE_NAME=wasp-files
# Build
env DEBUG=2 scripts/stackbuild examples/google-bucket
# Run
env DEBUG=1 scripts/stackrun google-bucket:edge plan
env DEBUG=1 scripts/stackrun google-bucket:edge apply
env DEBUG=0 scripts/stackrun google-bucket:edge output
Terraform Packager é uma coleção de scripts e templates para empacotar código Terrraform.
O objetivo é criar um artefato que seja autosuficiente e personalizável.
Uma imagem criada usa o conceito de Stacks e contém essencialmente:
- Terraform: binário em uma versão específica do Terraform
- HCL Code: Código Terraform usado para criar recursos
- Providers: Os Terraform Providers serão baixados somente durante o build da imagem.
Esse conceito procura seguir a fisolofia de "build once", ou seja, o build do artefato ocorre apenas uma vez e o mesmo artefato pode ser usado para criar várias instâncias da Stack usando diferentes credenciais.
- Você precisará instalar o
yq
utilitário para leitura de arquivos yaml. - Docker
- Estes comandos foram testados no
Ubuntu 20.04
.
Se preferir ver um vídeo curto: Terraform Packager: empacotando código Terraform
Para empacotar um código Terraform com o terraform-packager
você precisa garantir que o diretório root do seu Módulo Terraform possua um arquivo stack.yaml
com as seguintes variáveis:
name: azure-nome-do-seu-modulo
version: 0.1.0
terraform:
version: 1.0.9
backend: azurerm
O exemplo usado considera que você possua variáveis de ambiente do Azure Resource Manager configuradas:
ARM_SUBSCRIPTION_ID................: ID_DE_UMA_SUBSCRIPTION_NA_AZURE
ARM_TENANT_ID......................: ID_DO_TENANT_DA_SUBSCRIPTION
ARM_CLIENT_ID......................: ID_DE_UMA_SERVICE_PRINCIPAL_CRIADA_PARA_USO_COM_TERRAFORM
ARM_CLIENT_SECRET..................: SECRET_DA_SERVICE_PRINCIPAL_ACIMA
ARM_STORAGE_ACCOUNT_NAME...........: NOME_DO_STORAGE_ACCOUNT_QUE_SERA_USADO_PARA_ARMAZENAR_O_TFSTATE
ARM_STORAGE_ACCOUNT_CONTAINER_NAME.: NOME_DO_STORAGE_ACCOUNT_CONTAINER
ARM_SAS_TOKEN......................: UM_TOKEN_TEMPORARIO_USADO_PARA_ACESSAR_A_STORAGE_ACCOUNTS
scripts/stackbuild "examples/azure-null-resource"
scripts/stackrun azure-null-resource:latest plan
scripts/stackrun azure-null-resource:latest apply
Embora não recomendável por ferir o princípio de que um artefato deveria sempre produzir o mesmo resultado, é possível passar um arquivo tfvars através de um volume para o container e usá-lo nos comandos Terraform.
export LOCAL_TERRAFORM_VARIABLES_DIRECTORY="${PWD}/examples/docker/custom-image"
scripts/stackrun azure-null-resource:latest plan -var-file=/opt/variables/terraform.tfvars
scripts/stackrun azure-null-resource:latest apply -var-file=/opt/variables/terraform.tfvars -auto-approve
scripts/stackbuild examples/azure-null-resource
docker build \
--rm \
--tag mystack:latest "examples/docker/custom-image"
scripts/stackrun mystack:latest plan
scripts/stackrun mystack:latest apply
name: azure-null-resource
terraform:
version: 1.8.5
backend: local
5.2. Por padrão o state será gerado no diretório configurado na variável de ambiente LOCAL_TERRAFORM_OUTPUT_DIRECTORY
:
export LOCAL_TERRAFORM_OUTPUT_DIRECTORY="$(mktemp -d -t terraform-XXXXXXXXXX)"
echo "Terraform output directory: ${LOCAL_TERRAFORM_OUTPUT_DIRECTORY}"
env DEBUG=2 scripts/stackbuild examples/azure-null-resource
export TERRAFORM_STATE_FILE="azure-null-resource/terraform.state.json"
env DEBUG=2 scripts/stackrun azure-null-resource plan
env DEBUG=2 scripts/stackrun azure-null-resource apply
find "${LOCAL_TERRAFORM_OUTPUT_DIRECTORY?}" -type f
Exemplo de saída:
/tmp/terraform-Q72cCQBbWz/terraform.state
/tmp/terraform-Q72cCQBbWz/azure-null-resource/terraform.state.json
/tmp/terraform-Q72cCQBbWz/terraform.plan.json
/tmp/terraform-Q72cCQBbWz/terraform.plan
/tmp/terraform-Q72cCQBbWz/plan_detailed_exitcode
/tmp/terraform-Q72cCQBbWz/terraform.plan.txt
cat /tmp/terraform-Q72cCQBbWz/azure-null-resource/terraform.state.json
Se você precisar executar scripts durante a fase de build, você pode criar um diretório .tfp/scripts/build
na raiz do seu repositório.
.
├── .tfp
│ └── scripts
│ └── build
│ └── install-az-cli
├── README.md
├── cz.yaml -> ../../cz.yaml
├── src
│ ├── main.tf
│ └── provider.tf
└── stack.yaml
Exemplo para o script install-az-cli
:
#!/bin/bash
apk add py3-pip
apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo make
pip install --upgrade pip
pip install azure-cli
az version
Se você precisar executar scripts durante runtime, você pode criar um diretório .tfp/scripts/runtime
na raiz do seu repositório.
.
├── .tfp
│ └── scripts
│ └── runtime
│ ├── after-apply
│ ├── after-destroy
│ ├── after-init
│ ├── after-plan
│ ├── before-apply
│ ├── before-destroy
│ ├── before-init
│ └── before-plan
├── README.md
├── cz.yaml -> ../../cz.yaml
├── src
│ ├── main.tf
│ └── provider.tf
└── stack.yaml
O script stackrun' vai montar os arquivos de credenciais do Azure CLI no container caso os arquivos existam e a variável de ambiente
ARM_CLIENT_ID` esteja vazia.
Caso necessite, você pode alterar as variáveis que identificam os arquivos de credenciais do Azure CLI:
# Abaixo as variáveis usadas pelo terraform-packager para identificar os arquivos de credenciais do Azure CLI com seus respectivos valores padrão
export TF_PACKAGER_AZURE_ACCESS_TOKEN_FILE="${HOME}/.azure/access_token.json"
export TF_PACKAGER_AZURE_PROFILE_FILE="${HOME}/.azure/azureProfile.json"
export TF_PACKAGER_AZURE_MSAL_TOKEN_CACHE_FILE="${HOME}/.azure/msal_token_cache.json"
ATENÇÃO: Antes de executar
stackbuild
oustackrun
, certifique-se de ter obtido um token de acesso usando o comando:
export TF_PACKAGER_AZURE_ACCESS_TOKEN_FILE="${HOME}/.azure/access_token.json"
export TF_PACKAGER_AZURE_PROFILE_FILE="${HOME}/.azure/azureProfile.json"
export TF_PACKAGER_AZURE_MSAL_TOKEN_CACHE_FILE="${HOME}/.azure/msal_token_cache.json"
az account get-access-token > "${TF_PACKAGER_AZURE_ACCESS_TOKEN_FILE?}"
stackrun azure-cli-auth-example:latest plan
Se você precisar configurar chaves SSH para acessar repositórios privados, você pode criar um arquivo ${HOME}./ssh/config
seguindo exemplo abaixo:
# GitHub
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_ed25519
# Azure DevOps
Host ssh.dev.azure.com
HostName ssh.dev.azure.com
IdentityFile ~/.ssh/id_rsa
# Global
Host *
User git
PubkeyAcceptedAlgorithms +ssh-rsa
HostkeyAlgorithms +ssh-rsa
StrictHostKeyChecking no
Variável de Ambiente | Descrição | Exemplo |
---|---|---|
DEBUG |
Nível de depuração | DEBUG=2 |
LOCAL_TERRAFORM_OUTPUT_DIRECTORY |
Diretório onde o Terraform irá armazenar os arquivos de saída | LOCAL_TERRAFORM_OUTPUT_DIRECTORY="$(mktemp -d -t terraform-XXXXXXXXXX)" |
LOCAL_TERRAFORM_VARIABLES_DIRECTORY_EXTRA |
Todos os arquivos do diretórios serão volumados em /opt/src |
LOCAL_TERRAFORM_VARIABLES_DIRECTORY_EXTRA="${PWD}/examples/custom-image" |
LOCAL_TERRAFORM_VARIABLES_DIRECTORY |
Diretório local que será volumado em /opt/variables |
LOCAL_TERRAFORM_VARIABLES_DIRECTORY="${PWD}/examples/custom-image/tfvars-files" |
TERRAFORM_STATE_FILE |
Nome do arquivo de state | TERRAFORM_STATE_FILE="azure-null-resource/terraform.state.json" |
TF_PACKAGER_AZURE_ACCESS_TOKEN_FILE |
Arquivo de token de acesso do Azure CLI | TF_PACKAGER_AZURE_ACCESS_TOKEN_FILE="${HOME}/.azure/access_token.json" |
TF_PACKAGER_AZURE_MSAL_TOKEN_CACHE_FILE |
Arquivo de cache de token MSAL do Azure CLI | TF_PACKAGER_AZURE_MSAL_TOKEN_CACHE_FILE="${HOME}/.azure/msal_token_cache.json" |
TF_PACKAGER_AZURE_PROFILE_FILE |
Arquivo de perfil do Azure CLI | TF_PACKAGER_AZURE_PROFILE_FILE="${HOME}/.azure/azureProfile.json" |
TF_PACKAGER_DOCKER_PROGRESS |
Definie como exibir p progresso do build do container Docker | TF_PACKAGER_DOCKER_PROGRESS=plain (auto , plain , tty , rawjson ) |
TF_PACKAGER_TEMPORARY_BUILD_CONTEXT_DIRECTORY |
Diretório temporário para o build do container Docker | TF_PACKAGER_TEMPORARY_BUILD_CONTEXT_DIRECTORY="$(mktemp -d -t terraform-XXXXXXXXXX)" |
env DEBUG=1 scripts/stackrun google-bucket:edge plan \
| sed \
-e '/You may now begin working with Terraform/,/commands will detect it and remind you to do so if necessary./d' \
-e '/Terraform used the selected providers/,/Resource actions are indicated with the following symbols:/d' \
-e '/Successfully configured the backend/,/unless the backend configuration changes./d' \
-e '/To perform exactly these actions/,/terraform apply "\/opt\/output\/terraform.plan\"/d'