0
点赞
收藏
分享

微信扫一扫

Gitlab CI + Terraform 部署 Azure 环境

Gitlab 和 Terraform都是很流行的DevOps工具,下面简单的记录一下如何使用他们在Azure上部署一个服务。在这个例子里面,Gitlab是作为我们的Git Repo,同时也是作为 CICD Pipeline来使用的。

准备工作

首先是准备工作,我们需要配置一个Service Principal可以允许从第三方的程序访问Azure,我们还需要配置一个Storage Account来保存我们的Terraform的状态文件。

1. App 注册

如果配置过任何的Azure SSO的项目,或者利用API访问过Azure,会知道这个步骤对于所有的第三方程序来访问Azure都是必须的。

登录到 Azure Admin Portal - > App Registration - > New Registration
image.png

创建之后,去certificate& secrets里面创建一个client secret
image.png

记录下来,稍后会用。

然后来到overview的界面,记录下application id和tenant id
image.png

2. 分配IAM 权限

这一步需要给app授权。一般授权可以在IAM里面做,如果要精细规划,可以考虑在graph api里面配置。

Home -> Subscription ->IAM -> Add Role assignment
image.png

给我们刚刚注册的app 分配 contributor的权限
image.png

3. 创建一个storage account

Home – Storage Account - Create

image.png

然后去 Data Storage -> Containers -> Create a new blob container

image.png

Gitlab的配置

1. 首先需要配置变量

把下面的变量信息准备好,我们才能从Gitlab访问Azure的资源。另外注意如果要在terraform直接调用变量,定义需要使用下面这种形式 TF_VAR_变量名
Settings -> CI/CD -> Variables

• ARM_ACCESS_KEY: Storage account的 key
• ARM_CLIENT_ID: App 的 id
• ARM_CLIENT_SECRET: 我们在app里面创建的 client secret
• ARM_SUBSCRIPTION_ID: 账号subscrption的 id
• ARM_TENANT_ID: Azure AD tenant的ID

image.png

2. CICD 文件

gitlab的CICD配置文件,他会自动找一个可用的runner来启动。
.gitlab-ci.yaml

image:
  name: hashicorp/terraform:latest
  entrypoint:
    - '/usr/bin/env'
    - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'

before_script:
  - rm -rf .terraform
  - terraform --version
  - terraform init

stages:
  - validate
  - plan
  - apply

validate:
  stage: validate
  script:
    - terraform validate

plan:
  stage: plan
  script:
    - terraform plan -out "planfile"
  dependencies:
    - validate
  artifacts:
    paths:
      - ./planfile

apply:
  stage: apply
  script:
    - terraform apply -input=false "planfile"
  dependencies:
    - plan

3. Terraform的文件

azure-user-data.sh 这个文件是我的user data的脚本,虚拟机启动的时候,自动执行,安装docker,docker-compose,并注册一个gitlab的 runner
注意我这里传入的${runner_token}的变量,来自于main.tf里面的template_file, 而 template_file里面的变量 var.runner_token又是在 variable.tf里面定义的,然后默认值是从 gitlab CI的 Variable里面赋值的

#!/bin/bash
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
cd /root
sudo mkdir config
sudo cd config
cat << EOT >> docker-compose.yml
version: '3.3'
services:
  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./config:/etc/gitlab-runner
    restart: unless-stopped
EOT
docker-compose up -d
docker-compose exec gitlab-runner gitlab-runner register --non-interactive --url https://gitlab.com/ --registration-token ${runner_token} --executor docker --docker-image python3.9 --docker-image docker

main.tf

terraform {
  required_version = ">=0.12"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "vmss" {
  name     = var.resource_group_name
  location = var.location
  tags     = var.tags
}

resource "random_string" "fqdn" {
  length  = 6
  special = false
  upper   = false
  numeric = false
}

resource "azurerm_virtual_network" "vmss" {
  name                = "vmss-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = var.location
  resource_group_name = azurerm_resource_group.vmss.name
  tags                = var.tags
}

resource "azurerm_subnet" "vmss" {
  name                 = "vmss-subnet"
  resource_group_name  = azurerm_resource_group.vmss.name
  virtual_network_name = azurerm_virtual_network.vmss.name
  address_prefixes     = ["10.0.2.0/24"]
}

resource "azurerm_virtual_machine_scale_set" "vmss" {
  name                = "vmscaleset"
  location            = var.location
  resource_group_name = azurerm_resource_group.vmss.name
  upgrade_policy_mode = "Manual"

  sku {
    name     = "Standard_DS1_v2"
    tier     = "Standard"
    capacity = 2
  }

  storage_profile_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-focal"
    sku       = "20_04-lts-gen2"
    version   = "latest"
  }

  storage_profile_os_disk {
    name              = ""
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  storage_profile_data_disk {
    lun           = 0
    caching       = "ReadWrite"
    create_option = "Empty"
    disk_size_gb  = 10
  }

  os_profile {
    computer_name_prefix = "vmlab"
    admin_username       = var.admin_user
    admin_password       = var.admin_password
    custom_data          = data.template_file.linux-vm-cloud-init.rendered
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }

  network_profile {
    name    = "terraformnetworkprofile"
    primary = true

    ip_configuration {
      name      = "IPConfiguration"
      primary   = true
      subnet_id = azurerm_subnet.vmss.id
    }
  }

  tags = var.tags
}

# Data template Bash bootstrapping file
data "template_file" "linux-vm-cloud-init" {
  template = file("azure-user-data.sh")
  vars = {
    runner_token = "${var.runner_token}"
  }
}

provider.tf

# State Backend
terraform {
  backend "azurerm" {
    resource_group_name   = "rg1"
    storage_account_name  = "gitlabstoragetest"
    container_name        = "terraform-state-file"
    key                   = "test.terraform.tfstate"
  }
}

variable.tf

variable "resource_group_name" {
   description = "Name of the resource group in which the resources will be created"
   default     = "myResourceGroup"
}

variable "location" {
   default = "eastasia"
   description = "Location where resources will be created"
}

variable "tags" {
   description = "Map of the tags to use for the resources that are deployed"
   type        = map(string)
   default = {
      environment = "codelab"
   }
}

variable "application_port" {
   description = "Port that you want to expose to the external load balancer"
   default     = 80
}

variable "admin_user" {
   description = "User name to use as the admin account on the VMs that will be part of the VM scale set"
}

variable "admin_password" {
   description = "Default password for admin account"
}

variable "runner_token" {
  description = "project gitlab runner token "
}

效果图

image.png

image.png

举报

相关推荐

0 条评论