Bicep์ Azure ๋ค์ดํฐ๋ธ IaC(Infrastructure as Code) ์๋ฃจ์ ์ผ๋ก, ARM ํ ํ๋ฆฟ์ผ๋ก ๋ณํํ์ฌ ๋ฆฌ์์ค ํ๋ก๋น์ ๋์ ๊ฐ์ํํฉ๋๋ค. ์ฝ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์ ์ธ์ ๋๋ฉ์ธ ํน์ ์ธ์ด(DSL)์ ๋๋ค.
๋ถ์ธ ์ฑ๋ช ํ๊ตญ์ด ์ค๋ ฅ์ด ๋ถ์ ํ์ฌ ์ด ๊ธ์ด ๊ตฌ๊ธ ๋ฒ์ญ๊ธฐ๋ฅผ ์ฃผ๋ก ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ถ์ ํํ ๋ฌธ๋ฒ๊ณผ ์ดํ๊ฐ ์์์ ์์ต๋๋ค. ์ด ์ ์ํด ๋ถํ๋๋ฆฌ๋ฉฐ, ์ถํ์ ๋ค์ ๊ฒํ ํ์ฌ ์์ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ค์น
Bicep ๊ด๋ จ ๋ช
๋ น์ ์ฌ์ฉํ๋ ค๋ฉด Azure CLI๊ฐ ํ์ํฉ๋๋ค. ์ค์น ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ค๋ฉด az version ๋ช
๋ น์ ์ฌ์ฉํ์ธ์. ์ค์น๋ Azure CLI ๊ตฌ์ฑ ์์๊ฐ JSON ํ์์ผ๋ก ํ์๋ฉ๋๋ค.
{
"azure-cli": "2.77.0",
"azure-cli-core": "2.77.0",
"azure-cli-telemetry": "1.1.0",
"extensions": {}
}๊ทธ ํ, bicep install ๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ Bicep ๋ชจ๋์ ์ค์นํฉ๋๋ค.
az bicep install๊ทธ๋ฌ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
Installing Bicep CLI v0.37.4...
The configuration value of bicep.use_binary_from_path has been set to 'false'.
Successfully installed Bicep CLI to "C:\Users\User\.azure\bin\bicep.exe".์ค์น๋ ๋ฒ์ ์ ํ์ธํ๋ ค๋ฉด bicep version ๋ช
๋ น์ ์ฌ์ฉํ์ธ์.
az bicep version์ ๊ทธ๋ ์ด๋ํ๋ ค๋ฉด ๋ค์์ ์คํํ์ธ์.
az bicep upgrade๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
Bicep์์ ๋ฆฌ์์ค๋ฅผ ์ ์ธํ๋ ๊ตฌ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. resource ํค์๋๋ ๋ค๋ฐ๋ฅด๋ ๋ด์ฉ์ด ๋ฆฌ์์ค ์ ์ธ์์ ๋ํ๋
๋๋ค. <Variable>์ ํ๋ก๋น์ ๋๋ ๋ฆฌ์์ค์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๋ฉฐ, ์คํฌ๋ฆฝํธ์์ ์ดํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. <ResourceType>๋ ์ ํจํ Azure ๋ฆฌ์์ค ์ ํ์ผ๋ก, ํ
ํ๋ฆฟ ํ์ด์ง์ ์ฐธ์กฐ ์น์
์์ ํด๋น ๋ฒ์ฃผ๋ณ๋ก ํ์ธํ ์ ์์ต๋๋ค. <DateVersion>์ ๋ฆฌ์์ค ํ๋ก๋น์ ๋์ ์ฌ์ฉํ API ๋ฒ์ ์ ๋ํ๋
๋๋ค. ๊ฐ ์ ์ธ ๋ธ๋ก ๋ด์์ ๋ฆฌ์์ค๋ฅผ ๊ตฌ์ฑํ๋ ๋งค๊ฐ๋ณ์์ ํด๋น ๊ฐ์ ์ง์ ํ ์ ์์ต๋๋ค.
resource <Variable> '<ResourceType>@<DateVersion>' = {
parameter: value
parameter2: value2
...
}๋ค์์ ์คํ ๋ฆฌ์ง ๊ณ์ ์ ์ ์ธํ๋ ์์์ ๋๋ค.
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'mydemostorage'
location: 'eastus'
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}์ด ํ์ผ์ deployment group create ๋ช
๋ น์ ์คํํ์ฌ ์คํํ ์ ์์ต๋๋ค. <existing-resource-group>์ ๊ธฐ์กด ๋ฆฌ์์ค ๊ทธ๋ฃน์ ์ด๋ฆ์ ๋ํ๋
๋๋ค.
az deployment group create \
--template-file main.bicep \
--resource-group <existing-resource-group>์ ๋ช
๋ น์ด๋ main.bicep ํ์ผ์ ๋ฆฌ์์ค ๊ทธ๋ฃน ์์ค์์ ๋ฐฐํฌํฉ๋๋ค. ๋ฐ๋ฉด์ ์๋ ๋ช
๋ น์ด๋ main.bicep ํ์ผ์ ๊ตฌ๋
์์ค์์ ๋ฐฐํฌํฉ๋๋ค.
az deployment sub create --location eastus --template-file main.bicep๊ธฐ๋ณธ ๊ตฌ๋ฌธ
ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ง์ฐฌ๊ฐ์ง๋ก Bicep์ ๋ณ์, ๋ฐ๋ณต๋ฌธ, ๋ชจ๋ ๋ฐ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ํจ์จ์ ์ด๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. Bicep์์๋ ์ธ๋ฏธ์ฝ๋ก ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
๋ณ์
๋ณ์๋ var ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ธํ ์ ์์ต๋๋ค. ๋ณ์ ์ ์ธ ์ ๋ฌธ์์ด ๋ณด๊ฐ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์๋ ์์๋ ์คํ ๋ฆฌ์ง ๊ณ์ ์ ์์น ๋ณ์๋ฅผ ์ด๋ฆ ์ ์ธ์ ์ผ๋ถ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
var storageAccountLocation = 'eastus'
var storageAccountName = 'mydemostorage${storageAccountLocation}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}๋ณ์์๋ ์ง์๋๋ ๋ชจ๋ ๋ฐ์ดํฐ ํ์์ ์ ์ฅํ ์ ์์ต๋๋ค.
๋ฐ๋ณต๋ฌธ
๋ฃจํ๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ๋ฐ๋ณตํ์ง ์๊ณ ๋ ๋ฐฐ์ด์ ํ์ฉํ์ฌ ์ฌ๋ฌ ๋ฆฌ์์ค๋ฅผ ๋ฐฐํฌํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐฐ์ด์ ์ง์ ๋ ์ฌ๋ฌ ์์น์ ๊ฐ๊ฐ ๋ค๋ฅธ ์คํ ๋ฆฌ์ง ๊ณ์ ์ ์์ฑํ ๋ ๋ฃจํ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐฐ์ด์ ์์๋ ์ค ๋ฐ๊ฟ ๋ฌธ์(\n) ๋๋ ์ผํ(,)๋ก ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
var regions1 = ['eastus', 'northeurope', 'uksouth']
var regions2 = [
'southeastasia'
'westeurope'
]์๋๋ regions1 ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ eastus, northeurope, uksouth ์ง์ญ์ ์คํ ๋ฆฌ์ง ๊ณ์ ์ ๋ฐฐํฌํ๋ ์์์
๋๋ค. ์ด๋ฆ์ Azure ์ ์ฒด์์ ๊ณ ์ ํด์ผ ํ๋ฏ๋ก ์ธ๋ฑ์ค ๋๋ ์ง์ญ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ์ด๋ฆ์ ์์ฑํด์ผ ํฉ๋๋ค.
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = [for (region, index) in regions1: {
name: 'mystorage${region}${index}'
location: region
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}]ํจ์
Bicep์ ์ง์ํ๋ ๋ฐ์ดํฐ ํ์์ ์กฐ์ํ๊ธฐ ์ํ ๋ค์ํ ๋ด์ฅ ํจ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ค์์ ๋ฌธ์์ด ๋ฐ ๋ฐฐ์ด ์ ํ์ ์ฌ์ฉ๋๋ ๋ช ๊ฐ์ง ํจ์์ ์์ ๋๋ค. ์ ์ฒด ํจ์ ๋ชฉ๋ก์ ๊ณต์ ๋ฌธ์์์ ํ์ธํ ์ ์์ต๋๋ค.
๋ฌธ์์ด์ concat ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ๊ฒฐํ ์ ์์ผ๋ฉฐ, toUpper ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฌธ์๋ก ๋ณํํ ์ ์์ต๋๋ค.
var hello string = 'hello'
var helloWorld string = concat(toUpper(hello), ', world!') // HELLO, world!๋ฐฐ์ด์ union ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ณต ์์ด ๋ณํฉํ ์ ์์ต๋๋ค.
var array1 = [1, 2, 3]
var array2 = [2, 3, 4]
var result = union(array1, array2) // [1, 2, 3, 4]๋ชจ๋
๋ชจ๋์ ์ฌ์ฉํ๋ฉด ๊ด๋ จ ๋ฆฌ์์ค๋ฅผ ๋ ผ๋ฆฌ์ ์ธ ๋ฐฉ์์ผ๋ก ๊ทธ๋ฃนํํ์ฌ ๋ฆฌ์์ค ์ํคํ ์ฒ๋ฅผ ์ ํํ๊ฒ ํํํ ์ ์์ต๋๋ค. ๋ชจ๋์ ๋งค๊ฐ๋ณ์, ๋ฆฌ์์ค ๋ฐ ์ถ๋ ฅ์ด๋ผ๋ ์ธ ๊ฐ์ง ์ฃผ์ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
๋งค๊ฐ๋ณ์๋ ํธ์ถ์๊ฐ ์ ๋ฌํ๋ ๋ฐ์ดํฐ์ด๋ฉฐ, param ํค์๋๋ก ํ์๋ฉ๋๋ค. ๋ฆฌ์์ค๋ ๋ชจ๋์ ์ํด ์ค์ ๋ก ์์ฑ๋ ๋ฆฌ์์ค์ด๋ฉฐ, ์ถ๋ ฅ์ ํธ์ถ์๊ฐ ํ์๋ก ํ ์ ์๋ ์์ฑ๋ ๋ฆฌ์์ค์ ๋ํ ์ค์ํ ์ ๋ณด(์: ๋ฆฌ์์ค ID)์
๋๋ค.
์๋ ์์๋ App Service ๋๋ ์น ์ฑ์ ๋ฐฐํฌํ๋ ๋ชจ๋์ ๋๋ค. App Service๋ App Service ํ๋์ด ํ์ํ๋ฏ๋ก, ์ด ๋ชจ๋์ ํด๋น ํ๋๋ ํจ๊ป ํ๋ก๋น์ ๋ํฉ๋๋ค.
@description('๋ชจ๋ ๋ฆฌ์์ค์ ์์น์
๋๋ค.')
param location string
@description('์ฑ ์๋น์ค ํ๋์ ์ด๋ฆ.')
param appServicePlanName string
@description('์น ์ฑ์ ์ด๋ฆ.')
param webAppName string
@description('๋ฐฐํฌ ํ๊ฒฝ.')
@allowed([ 'dev', 'prod' ])
param environmentType string
@description('๋ชจ๋ ๋ฆฌ์์ค์ ์ ์ฉํ ํ๊ทธ.')
param tags object = {}
var appServicePlanSkuName = (environmentType == 'prod') ? 'P2V3' : 'F1'
resource appServicePlan 'Microsoft.Web/serverfarms@2024-11-01' = {
name: appServicePlanName
location: location
sku: {
name: appServicePlanSkuName
}
tags: tags
}
resource webApp 'Microsoft.Web/sites@2024-11-01' = {
name: webAppName
location: location
properties:{
serverFarmId: appServicePlan.id
httpsOnly: true
}
tags: tags
}
@description('์น ์ฑ์ ๊ธฐ๋ณธ ํธ์คํธ ์ด๋ฆ')
output webAppHostName string = webApp.properties.defaultHostName์ฒซ ๋ ์ค์ ์ด ๋ชจ๋์ด location์ด๋ผ๋ ์ด๋ฆ์ ๋ฌธ์์ด ํ์
๋งค๊ฐ๋ณ์๋ฅผ ์
๋ ฅ์ผ๋ก ๋ฐ์ผ๋ฉฐ, @description ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ์ฌ ํ์ ๋งค๊ฐ๋ณ์์ ์๋ฏธ๋ฅผ ์ค๋ช
ํ๋ค๋ ๊ฒ์ ๋ํ๋
๋๋ค.
๋ํ appServicePlanSkuName์์๋ ์ผํญ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ environmentType ํ๊ฒฝ ์ ํ์ ๋ฐ๋ผ ํ์ํ SKU๋ฅผ ๊ฒฐ์ ํ๋๋ฐ, ์ผ๋ฐ์ ์ผ๋ก ํ๋ก๋์
ํ๊ฒฝ์์๋ ๋ ๊ฐ๋ ฅํ ์ปดํจํ
์ฑ๋ฅ์ด ํ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
๊ทธ๋ฐ ๋ค์, ์ ๊ณต๋ ๋งค๊ฐ๋ณ์์ ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ appServicePlan์ด๋ผ๋ ์์ง์ ์ธ ์ด๋ฆ์ผ๋ก App Service Plan์ ํ๋ก๋น์ ๋ํ๊ณ , serverFarmId: appServicePlan.id ์ค์์ ํด๋น App Service Plan ์๋์ ์น ์ฑ์ ํ๋ก๋น์ ๋ํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก, ์๋ก ์์ฑ๋ ์น ์ฑ์ webAppHostName์ ๋ฐํํฉ๋๋ค.
์ด๊ฒ์ด ๋ชจ๋ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋๋ค.
module appService 'modules/appService.bicep' = {
name: 'appService'
params: {
location: location
appServicePlanName: appServicePlanName
webAppName: webAppName
environmentType: environmentType
tags: tags
}
}๋ฐํ๋ ๊ฐ์ outputs ์์ฑ์ ํธ์ถํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
// ์ด ๋ณ์๋ ์ํ๋ ๊ณณ ์ด๋๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
var appName = appService.outputs.webAppHostName์ ์ฒด ์ฝ๋๋ ์ GitHub ์ ์ฅ์์์ ํ์ธํ ์ ์์ต๋๋ค.
๋ฉ์ธ ํ์ผ ๋งค๊ฐ๋ณ์ํ
๋ฉ์ธ ํ์ผ๋ param ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋งค๊ฐ๋ณ์ํํ ์ ์์ต๋๋ค.
@allowed([
'dev'
'prod'
])
param environment string
module appService 'modules/appService.bicep' = {
name: 'appService'
params: {
location: location
appServicePlanName: appServicePlanName
webAppName: webAppName
environmentType: environment // ์ฌ๊ธฐ์๋ ์ฌ์ฉ ๋์
tags: tags
}
}๊ทธ๋ฐ ๋ค์ ๋ฐฐํฌ ๋ช
๋ น์์ --parameters ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ณ ๋งค๊ฐ๋ณ์๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
az deployment group create \
--resource-group my-rg \
--template-file main.bicep \
--parameters environment=dev์ฃผ์ ๋ฐฐํฌ ํ์ผ์ ๋งค๊ฐ๋ณ์๊ฐ ๋ง์ ๊ฒฝ์ฐ, ๋ช
๋ น์ค์์ ํ๋์ฉ ์ ๋ฌํ๋ ๋์ .bicepparam ํ์ฅ์๋ก ๋๋๋ Bicep ๋งค๊ฐ๋ณ์ ํ์ผ์ ์ฌ์ฉํ์ฌ ๋งค๊ฐ๋ณ์๋ฅผ ์ฝ๋๋ก ์ ์ฅํ ์ ์์ต๋๋ค. ์ด ํ์ผ์ Docker์์ docker-compose.yml ํ์ผ์ด ์๋ํ๋ ๋ฐฉ์๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค.
์๋ ์์๋ main.dev.bicepparam ํ์ผ์์ main.bicep ๋ชจ๋์ ๋ํ ํ๊ฒฝ์ ์ ์ํฉ๋๋ค.
use 'main.bicep'
param environment = 'dev'๊ทธ๋ฐ ๋ค์ ๋ฐฐํฌ ์์๋ parameter ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์ด ๋งค๊ฐ๋ณ์ ํ์ผ์ ์ฐธ์กฐํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
az deployment group create \
--resource-group my-rg \
--parameters main.dev.bicepparam๋๊ตฌ
VS Code ํ์ฅ ํ๋ก๊ทธ๋จ
Bicep์ ๊ตฌ๋ฌธ ๊ฐ์กฐ ํ์, ์ธํ ๋ฆฌ์ผ์ค, ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ๋ฐฐํฌ ๊ตฌ์ฑ์ ์ดํดํ๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ ๋ฆฌ์์ค ์๊ฐํ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ VS Code ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ ๊ณตํฉ๋๋ค.
ํฌ๋งทํ
Bicep ํ์ผ์ format ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์ ์๋ฆฌ์์ ํ์์ ์ง์ ํ ์ ์์ต๋๋ค.
az bicep format --file <your-bicep-file>What-If
what-if ๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ๊ธฐ ์ ์ ํ๊ฒฝ์ ๋ฆฌ์์ค์ ์ด๋ค ๋ณํ๊ฐ ๋ฐ์ํ๋์ง ๋ฏธ๋ฆฌ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋ฐฐํฌ ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ์๋์น ์์ ๋ฐ์ดํฐ ์์ค์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
az deployment group what-if --resource-group my-rg --template-file main.bicep