Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions README-Bicep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# IaC-CycleCloud: Bicep template for Azure CycleCloud environment building

## Pre-requisites
· Enter "Cloud Shell" in console top-right or use your bastion terminal with [Azure CLI installed](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#azure-cli).

· Has a SSH Keypair created in [Azure portal](https://docs.microsoft.com/en-us/azure/virtual-machines/ssh-keys-portal) or [using CLI](https://docs.microsoft.com/en-us/azure/cyclecloud/how-to/install-arm?view=cyclecloud-8#ssh-keypair).

## Setup
1. Create service principal

```shell
az ad sp create-for-rbac --name CycleCloudApp --years 1
```

The output will display a number of parameters. You will need to save the appId, password, and tenant:

```
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "CycleCloudApp",
"name": "http://CycleCloudApp",
"password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```

2. Execute:

```shell
git clone https://github.com/CycleCloudCommunity/cyclecloud_arm.git
cd HPC-IaC-Garage/IaC-CycleCloud

AF2TenantID = '<your-tenant-id>'
AF2AppID = '<your-app-id>'
AF2AppSecret = '<your-app-secret>'
AF2UserPass = '<yourpass>'
AF2SSHPublic = '<your-ssh-publickey>'
az group create --name rgHPC --location southeastasia
az deployment group create -g rgHPC --template-file ./HPC-IaC-Garage/IaC-CycleCloud/cyclecloudiac.bicep --parameters spTenantId=$AF2TenantID spAppId=$AF2AppID spAppSecret=$AF2AppSecret keySSHpublic=$AF2SSHPublic userPass=$AF2UserPass
```

3. Wait 10-20 minutes.

4. Check the ready resources. Go to console page "Home->Resource groups->rgHPC->Deployments" to check the resource created in rgHPC. Find the cycleVM's public IP/DNS name to visit CycleCloud console by browser.

5. Customize your deployment by parameters appending:
a. IP scope prefix can be defined by parameter "prefixIPaddr='10.163'" to avoid CIDR collision.
b. Can deploy an ANF volume for further HPC cluster using through "boolANFdeploy=true" and select the volume size as "sizeANFinTB=8"
c. Can define the whitelisted IP cidr for CycleCloud portal access to enhance security, as "cidrWhitelist='167.220.0.0/16'".
d. Template will create a new storage account. Can disable this building by "boolStAcctdeploy=false" and provide the existed storage account by "nameStAcct='<yourStAcctname>'"

For example:

```shell
az deployment group create -g rgHPC --template-file ./HPC-IaC-Garage/IaC-CycleCloud/cyclecloudiac.bicep --parameters spTenantId=$AF2TenantID spAppId=$AF2AppID spAppSecret=$AF2AppSecret keySSHpublic=$AF2SSHPublic userPass=$AF2UserPass prefixIPaddr='10.163' boolANFdeploy=true sizeANFinTB=4 cidrWhitelist='xx.xx.0.0/16' boolStAcctdeploy=false nameStAcct='<exist-storageaccount>'
```

6. Tear down

```shell
az group delete -g rgHPC
```




303 changes: 303 additions & 0 deletions cyclecloudiac.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
// CycleCloud environment buiding template

param spTenantId string
param spAppId string
@secure()
param spAppSecret string
param keySSHpublic string
param userName string = 'cycleadmin'
@secure()
param userPass string

param curlocation string = resourceGroup().location
param prefixDeploy string = 'af${uniqueString(resourceGroup().id)}'
param prefixIPaddr string = '10.18' //Will create 10.18.0.0/16 VNet accordingly
param boolStAcctdeploy bool = true
param nameStAcct string = toLower('${prefixDeploy}')
param boolANFdeploy bool = false
param sizeANFinTB int = 4
param cidrWhitelist string = '0.0.0.0/0'
param typeSovereign string = 'public'

var skuCycleVM = 'Standard_D4s_v3'
var skuCycleDisk = 'Standard_LRS' //Option: Premium_LRS
var nameVM = '${prefixDeploy}-cycleVM'
var nameNIC = '${prefixDeploy}-cycleNIC'
var nameNSG = '${prefixDeploy}-cycleNSG'
var nameIP = '${prefixDeploy}-cycleIP'
var nameRg = resourceGroup().name
var nameANFacct = '${prefixDeploy}-anfacct'
var nameANFcapool = '${prefixDeploy}-pool'
var nameANFvol = 'volprotein'

resource cyclevnet 'Microsoft.Network/virtualNetworks@2021-05-01' = {
name:'${prefixDeploy}-cyclevnet'
location: curlocation
properties: {
addressSpace: {
addressPrefixes: [
'${prefixIPaddr}.0.0/16'
]
}
subnets: [
{
name: 'cycle'
properties: {
addressPrefix: '${prefixIPaddr}.1.0/24'
}
}
{
name: 'anf'
properties: {
addressPrefix: '${prefixIPaddr}.2.0/24'
delegations: [
{
name: 'Microsoft.NetApp.volumes'
properties: {
serviceName: 'Microsoft.NetApp/volumes'
}
}
]
}
}
{
name: 'user'
properties: {
addressPrefix: '${prefixIPaddr}.3.0/24'
}
}
{
name: 'compute'
properties: {
addressPrefix: '${prefixIPaddr}.4.0/22'
}
}
]
}
}

resource cycleEIP 'Microsoft.Network/publicIPAddresses@2021-05-01' = {
name: nameIP
location: curlocation
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
idleTimeoutInMinutes: 4
dnsSettings: {
domainNameLabel: toLower('${prefixDeploy}')
}
}
}

resource cycleNSG 'Microsoft.Network/networkSecurityGroups@2021-05-01' = {
name: nameNSG
location: curlocation
properties: {
securityRules: [
{
name: 'AllowSecuredCyclePortalInBound'
properties: {
protocol: 'Tcp'
access: 'Allow'
direction: 'Inbound'
sourcePortRange: '*'
destinationPortRange: '443'
sourceAddressPrefix: cidrWhitelist
destinationAddressPrefix: 'VirtualNetwork'
priority: 1000
}
}
{
name: 'AllowCyclePortalInBound'
properties: {
protocol: 'Tcp'
access: 'Allow'
direction: 'Inbound'
sourcePortRange: '*'
destinationPortRange: '80'
sourceAddressPrefix: cidrWhitelist
destinationAddressPrefix: 'VirtualNetwork'
priority: 1001
}
}
{
name: 'AllowSSHLink'
properties: {
protocol: 'Tcp'
access: 'Allow'
direction: 'Inbound'
sourcePortRange: '*'
destinationPortRange: '22'
sourceAddressPrefix: cidrWhitelist
destinationAddressPrefix: '*'
priority: 1002
}
}
]
}
}

resource cycleNIC 'Microsoft.Network/networkInterfaces@2021-05-01' = {
name: nameNIC
location: curlocation
properties: {
enableAcceleratedNetworking: false
enableIPForwarding: false
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
primary: true
privateIPAddressVersion: 'IPv4'
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: cycleEIP.id
}
subnet: {
id: cyclevnet.properties.subnets[0].id
}
}
}
]
networkSecurityGroup: {
id: cycleNSG.id
}
}
}

resource cycleStAcct 'Microsoft.Storage/storageAccounts@2021-08-01' = if (boolStAcctdeploy) {
name: nameStAcct
location: curlocation
sku: {
name: 'Standard_ZRS'
}
kind: 'StorageV2'
}

resource anfAcct 'Microsoft.NetApp/netAppAccounts@2021-10-01' = if (boolANFdeploy) {
name: nameANFacct
location: curlocation
}

resource anfPool 'Microsoft.NetApp/netAppAccounts/capacityPools@2021-10-01' = if (boolANFdeploy) {
name: nameANFcapool
location: curlocation
parent: anfAcct
properties: {
serviceLevel: 'Premium'
size: sizeANFinTB*1024*1024*1024*1024
}
}

resource anfVolume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2021-10-01' = if (boolANFdeploy) {
name: nameANFvol
location: curlocation
parent: anfPool
properties: {
creationToken: nameANFvol
subnetId: cyclevnet.properties.subnets[1].id
usageThreshold: sizeANFinTB*920*1024*1024*1024 //alerting at 90%
exportPolicy: {
rules: [
{
ruleIndex: 1
allowedClients: '${prefixIPaddr}.0.0/16'
nfsv3: false
nfsv41: true
unixReadWrite: true
unixReadOnly: false
cifs: false
}
]
}
protocolTypes: [
'NFSv4.1'
]
}
}

resource cycleVM 'Microsoft.Compute/virtualMachines@2021-11-01' = {
name: nameVM
location: curlocation
identity: {
type: 'SystemAssigned'
}
properties: {
hardwareProfile: {
vmSize: skuCycleVM
}
networkProfile: {
networkInterfaces: [
{
id: cycleNIC.id
}
]
}
osProfile: {
adminUsername: userName
computerName: nameVM
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
keyData: keySSHpublic
path: '/home/${userName}/.ssh/authorized_keys'
}
]
}
}
}
storageProfile: {
dataDisks: [
{
caching: 'ReadOnly'
createOption: 'Empty'
diskSizeGB: 128
lun: 0
managedDisk: {
storageAccountType: skuCycleDisk
}
}
]
imageReference: {
offer: 'CentOS-HPC'
publisher: 'OpenLogic'
sku: '8_1'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
caching: 'ReadWrite'
managedDisk: {
storageAccountType: skuCycleDisk
}
osType: 'Linux'
}
}
}
}

var cyclefqdn = cycleEIP.properties.dnsSettings.fqdn
resource cycleVMExtension 'Microsoft.Compute/virtualMachines/extensions@2021-11-01' = {
name: 'CycleExtension'
location: curlocation
parent: cycleVM
properties: {
autoUpgradeMinorVersion: true
protectedSettings: {
commandToExecute: 'python3 cyclecloud_install.py --acceptTerms --applicationSecret ${spAppSecret} --applicationId ${spAppId} --tenantId ${spTenantId} --azureSovereignCloud ${typeSovereign} --username ${userName} --password ${userPass} --publickey "${keySSHpublic}" --hostname ${cyclefqdn} --storageAccount ${nameStAcct} --resourceGroup ${nameRg} --useLetsEncrypt --webServerPort 80 --webServerSslPort 443 --webServerMaxHeapSize 4096M'
}
publisher: 'Microsoft.Azure.Extensions'
settings: {
fileUris: [
'https://raw.githubusercontent.com/CycleCloudCommunity/cyclecloud_arm/feature/update_cyclecloud_install/cyclecloud_install.py'
]
}
type: 'CustomScript'
typeHandlerVersion: '2.0'
}
}

output anfExportIP string = boolANFdeploy ? anfVolume.properties.mountTargets[0].ipAddress : ''
output urlCycleCloud string = 'https://${cyclefqdn}'