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
创建之后,去certificate& secrets里面创建一个client secret
记录下来,稍后会用。
然后来到overview的界面,记录下application id和tenant id
2. 分配IAM 权限
这一步需要给app授权。一般授权可以在IAM里面做,如果要精细规划,可以考虑在graph api里面配置。
Home -> Subscription ->IAM -> Add Role assignment
给我们刚刚注册的app 分配 contributor的权限
3. 创建一个storage account
Home – Storage Account - Create
然后去 Data Storage -> Containers -> Create a new blob container
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
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 "
}
效果图