Der Zweck des Artikels ist es, einen der möglichen Ansätze für die Organisation des flexiblen Einsatzes von Entwicklungs- / Prüfständen aufzuzeigen. Zeigen Sie, welche Vorteile uns der IaC-Ansatz in Kombination mit modernen Tools bietet.
Hintergrund
Es gibt mehrere Stände für Entwickler - Entwickler, Tests, Produktion. Neue Versionen von Produktkomponenten werden mehrmals täglich angezeigt.
Infolgedessen sind die vorhandenen Stände belegt, die Entwickler warten untätig darauf, dass einer der Stände geräumt wird.
Die Schaffung zusätzlicher statischer Stände wird das Problem lösen, jedoch zu einer Überfülle dieser Stände führen, wenn die Entwickleraktivität abnimmt, und infolgedessen die Infrastrukturkosten des Unternehmens erhöhen.
Eine Aufgabe
Damit Entwickler Stände basierend auf den aktuellen Anforderungen selbst bereitstellen und entfernen können.
Stapel
Gitlab CI, Terraform, Bash, jede private / öffentliche Cloud.
Technische Schwierigkeiten:
Terraform-Statusdatei - Standardmäßig können wir keine Variable im Wert des Statusdateinamens verwenden. Sie müssen etwas erfinden oder ein anderes Produkt verwenden.
Subnetze - Jede neue Umgebung muss in einem isolierten Subnetz erstellt werden. Sie müssen freie / ausgelastete Subnetze steuern, eine Art analoges DHCP, aber für Subnetze.
Algorithmus
Gitlab CI führt die Pipeline aus. Bindet alle anderen Komponenten zusammen.
Terraform .
Configuration manager(CM) - .
Bash .
development-infrastructure/ deploy/ env1/ main.tf backend.tf ansible-vars.json subnets.txt env2/ ... cm/ ... modules/ azure/ main.tf variables.tf scripts/ env.sh subnets.txt .gitlab-ci.yml
deploy - - terraform CM, .
cm - , Ansible .
modules - terraform
scripts - bash
.gitlab-ci.yml:
stages:
- create environment
- terraform apply
- cm
- destroy environment
.template:
variables:
ENV: $NAME_ENV
when: manual
tags: [cloudRunner01]
only:
refs:
- triggers
Create environment:
stage: create environment
extends: .template
script:
- ./scripts/create_env.sh -e $ENV -a create
artifacts:
paths:
- deploy/${ENV}/backend.tf
- deploy/${ENV}/main.tf
- deploy/${ENV}/vars.json
Create instances:
stage: terraform apply
extends: .template
script:
- cd ./deploy/$ENV
- terraform init -input=false
- terraform validate
- terraform plan -input=false -out=tf_plan_$ENV
- terraform apply -input=false tf_plan_$ENV
Deploy applications:
stage: cm
extends: .template
script:
- # CM
- # , $ENV ,
- # ..
- # terraform
Destroy instances and environment:
stage: destroy environment
extends: .template
script:
- cd ./deploy/$ENV
- terraform init -input=false
- terraform destroy -auto-approve
- ./scripts/delete_env.sh -e $ENV -a delete
:
Create environment - , NAME_ENV, , git .
Create instances - ( ) , .
Deploy applications - Configuration Manager.
Destroy instances and environment - bash , . scripts/subnets.txt.
NAME_ENV, :
Git pipeline.
modules/base/main.tf:
#
provider "azurerm" {
version = "=1.39.0"
}
…
# , Azure. ,
resource "azurerm_resource_group" "product_group" {
name = "${var.env_name}"
location = "East Europe"
}
#
resource "azurerm_virtual_network" "vnet" {
name = "product-vnet"
resource_group_name = azurerm_resource_group.product_group.name
location = azurerm_resource_group.product_group.location
address_space = [var.vnet_address]
}
# bash
resource "azurerm_subnet" "subnet" {
name = "product-subnet"
resource_group_name = azurerm_resource_group.product_group.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefix = var.subnet_address
}
#
resource "azurerm_virtual_machine" "product_vm" {
name = "main-instance"
location = azurerm_resource_group.product_group.location
resource_group_name = azurerm_resource_group.product_group.name
network_interface_ids = [azurerm_network_interface.main_nic.id]
…
}
# ...
, , , .
, , , .
scripts/env.sh:
#!/bin/bash
set -eu
CIDR="24"
DEPLOY_DIR="./deploy"
SCRIPT_DIR=$(dirname "$0")
usage() {
echo "Usage: $0 -e [ENV_NAME] -a [create/delete]"
echo " -e: Environment name"
echo " -a: Create or delete"
echo " -h: Help message"
echo "Examples:"
echo " $0 -e dev-stand-1 -a create"
echo " $0 -e issue-1533 -a delete"
}
while getopts 'he:a:' opt; do
case "${opt}" in
e) ENV_NAME=$OPTARG ;;
a) ACTION=$OPTARG ;;
h) usage; exit 0 ;;
*) echo "Unknown parameter"; usage; exit 1;;
esac
done
if [ -z "${ENV_NAME:-}" ] && [ -z "${ACTION:-}" ]; then
usage
exit 1
fi
#
ENV_NAME="${ENV_NAME,,}"
git_push() {
git add ../"${ENV_NAME}"
case ${1:-} in
create)
git commit -am "${ENV_NAME} environment was created"
git push origin HEAD:"$CI_COMMIT_REF_NAME" -o ci.skip
echo "Environment ${ENV_NAME} was created.";;
delete)
git commit -am "${ENV_NAME} environment was deleted"
git push origin HEAD:"$CI_COMMIT_REF_NAME" -o ci.skip
echo "Environment ${ENV_NAME} was deleted.";;
esac
}
create_env() {
#
if [ -d "${DEPLOY_DIR}/${ENV_NAME}" ]; then
echo "Environment ${ENV_NAME} exists..."
exit 0
else
mkdir -p ${DEPLOY_DIR}/"${ENV_NAME}"
fi
#
NET=$(sed -e 'a$!d' "${SCRIPT_DIR}"/subnets.txt)
sed -i /"$NET"/d "${SCRIPT_DIR}"/subnets.txt
echo "$NET" > ${DEPLOY_DIR}/"${ENV_NAME}"/subnets.txt
if [ -n "$NET" ] && [ "$NET" != "" ]; then
echo "Subnet: $NET"
SUBNET="${NET}/${CIDR}"
else
echo "There are no free subnets..."
rm -r "./${DEPLOY_DIR}/${ENV_NAME}"
exit 1
fi
pushd "${DEPLOY_DIR}/${ENV_NAME}" || exit 1
# main.tf terraform
cat > main.tf << END
module "base" {
source = "../../modules/azure"
env_name = "${ENV_NAME}"
vnet_address = "${SUBNET}"
subnet_address = "${SUBNET}"
}
END
# C backend.tf terraform , state
cat > backend.tf << END
terraform {
backend "azurerm" {
storage_account_name = "terraform-user"
container_name = "environments"
key = "${ENV_NAME}.tfstate"
}
}
END
}
delete_env() {
#
if [ -d "${DEPLOY_DIR}/${ENV_NAME}" ]; then
NET=$(sed -e '$!d' ./${DEPLOY_DIR}/"${ENV_NAME}"/subnets.txt)
echo "Release subnet: ${NET}"
echo "$NET" >> ./"${SCRIPT_DIR}"/subnets.txt
pushd ./${DEPLOY_DIR}/"${ENV_NAME}" || exit 1
popd || exit 1
rm -r ./${DEPLOY_DIR}/"${ENV_NAME}"
else
echo "Environment ${ENV_NAME} does not exist..."
exit 1
fi
}
case "${ACTION}" in
create)
create_env
git_push "${ACTION}"
;;
delete)
delete_env
git_push "${ACTION}"
;;
*)
usage; exit 1;;
esac
env.sh
- (\).
:
DEPLOY_DIR
.
scripts/subnets.txt .
Terraform.
git .
-
scripts/subnets.txt
scripts/subnets.txt:
172.28.50.0
172.28.51.0
172.28.52.0
...
. CIDR scripts/create_env.sh
Wir haben die Grundlage, die es uns ermöglicht, einen neuen Stand bereitzustellen, indem wir pipline in Gitlab CI ausführen.
Reduzierte Infrastrukturkosten unseres Unternehmens.
Entwickler sind nicht untätig und können Stände erstellen und löschen, wenn sie diese benötigen.
Wir haben auch die Möglichkeit erhalten, virtuelle Maschinen in jeder Cloud zu erstellen, indem wir ein neues Terraform-Modul geschrieben und das Skript zum Erstellen / Löschen von Umgebungen geringfügig geändert haben
Wir können mit Gitlab-Triggern spielen und neue Stände aus der Pipeline der Entwicklungsteams bereitstellen, indem wir Versionen von Diensten übertragen.