Entwicklung steht ohne Warteschlangen und Ausfallzeiten

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: 





  1. Terraform-Statusdatei - Standardmäßig können wir keine Variable im Wert des Statusdateinamens verwenden. Sie müssen etwas erfinden oder ein anderes Produkt verwenden.





  2. 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

  1. Gitlab CI führt die Pipeline aus. Bindet alle anderen Komponenten zusammen.





  2. Terraform .





  3. Configuration manager(CM) - .





  4. 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 

      
      



  1. env.sh



    - (\).





  2. :





  3. DEPLOY_DIR



    .





  4. scripts/subnets.txt .





  5. Terraform.





  6. git .





  7. scripts/subnets.txt







scripts/subnets.txt:





172.28.50.0
172.28.51.0
172.28.52.0
...
      
      



. CIDR  scripts/create_env.sh







  1. Wir haben die Grundlage, die es uns ermöglicht, einen neuen Stand bereitzustellen, indem wir pipline in Gitlab CI ausführen.





  2. Reduzierte Infrastrukturkosten unseres Unternehmens.





  3. Entwickler sind nicht untätig und können Stände erstellen und löschen, wenn sie diese benötigen.





  4. 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





  5. Wir können mit Gitlab-Triggern spielen  und neue Stände aus der Pipeline der Entwicklungsteams bereitstellen, indem wir Versionen von Diensten übertragen.








All Articles