Skip to content

Instantly share code, notes, and snippets.

@rfennell
Last active November 23, 2023 09:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfennell/c0aca11e656486b3fdb57845b18b9e3f to your computer and use it in GitHub Desktop.
Save rfennell/c0aca11e656486b3fdb57845b18b9e3f to your computer and use it in GitHub Desktop.
A BICEP file to deploy Snipe IT to Azure - see the comments below for usage details
version: "3"
services:
snipe-it:
image: snipe/snipe-it:latest
volumes:
- snipeit:/var/lib/snipeit
- snipeit-logs:/var/www/html/storage/logs
volumes:
snipeit:
external: true
snipeit-logs:
external: true
param SnipeITStorageAccount_name string
param SnipeITMySQLServer_name string
param SnipeITDB_name string
param SnipeITServerFarm_name string
param SnipeITWebsite_name string
param SnipeITMySQLLogin string
@secure()
param SnipeITMySQLPassword string
param SnipeITAppKey string
param SendGridAPIKey string
var dockerFile = loadFileAsBase64('./DockerCompose.yml')
var DockerComposeString = 'COMPOSE|${dockerFile}'
var azFileSettings = true
// Deployment of the storage account
resource SnipeITStorageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: SnipeITStorageAccount_name
location: resourceGroup().location
tags: {
Project: 'SnipeIT'
}
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: true
allowSharedKeyAccess: true
largeFileSharesState: 'Enabled'
networkAcls: {
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
services: {
file: {
keyType: 'Account'
enabled: true
}
blob: {
keyType: 'Account'
enabled: true
}
}
keySource: 'Microsoft.Storage'
}
accessTier: 'Hot'
}
// Nested deployments implicitly depend on parent resource
// Nested deployment of file services for the storage account
resource SnipeITStorageAccountFileServices 'fileServices' = {
name: 'default'
// Nested deployment of specific file shares
// SSL cert and app data file share
resource SnipeITCertFileShare 'shares' = {
name: 'snipeit'
properties: {
accessTier: 'TransactionOptimized'
shareQuota: 102400
enabledProtocols: 'SMB'
}
}
// Logs file share
resource SnipeITLogsFileShare 'shares' = {
name: 'snipeit-logs'
properties: {
accessTier: 'TransactionOptimized'
shareQuota: 102400
enabledProtocols: 'SMB'
}
}
}
}
resource SnipeITMySQLServer 'Microsoft.DBforMySQL/flexibleServers@2022-09-30-preview' = {
name: SnipeITMySQLServer_name
location: resourceGroup().location
tags: {
Project: 'SnipeIT'
}
sku: {
name: 'Standard_B1s'
tier: 'Burstable'
}
properties: {
administratorLogin: SnipeITMySQLLogin
administratorLoginPassword: SnipeITMySQLPassword
storage: {
storageSizeGB: 20
iops: 360
autoGrow: 'Enabled'
autoIoScaling: 'Enabled'
}
version: '8.0.21'
backup: {
backupRetentionDays: 7
geoRedundantBackup: 'Disabled'
}
replicationRole: 'None'
network: {
publicNetworkAccess: 'Enabled'
}
}
}
// MySql settings required else the initial migration fails
resource MySqlServer_innodb_buffer_pool_dump_at_shutdown 'Microsoft.DBforMySQL/flexibleServers/configurations@2022-01-01' = {
parent: SnipeITMySQLServer
name: 'innodb_buffer_pool_dump_at_shutdown'
properties: {
value: 'OFF'
}
}
resource MySqlServer_innodb_buffer_pool_load_at_startup 'Microsoft.DBforMySQL/flexibleServers/configurations@2022-01-01' = {
parent: SnipeITMySQLServer
name: 'innodb_buffer_pool_load_at_startup'
properties: {
value: 'OFF'
}
}
resource MySqlServer_sql_generate_invisible_primary_key 'Microsoft.DBforMySQL/flexibleServers/configurations@2022-01-01' = {
parent: SnipeITMySQLServer
name: 'sql_generate_invisible_primary_key'
properties: {
value: 'OFF'
}
}
resource MySqlServerFirewallRules_AzureIps 'Microsoft.DBforMySQL/flexibleServers/firewallRules@2022-01-01' = {
name: 'AllowAllWindowsAzureIps'
parent: SnipeITMySQLServer
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '0.0.0.0'
}
}
//Deployment of the server farm
resource SnipeITServerFarm 'Microsoft.Web/serverfarms@2022-03-01' = {
name: SnipeITServerFarm_name
location: resourceGroup().location
tags: {
Project: 'SnipeIT'
}
sku: {
name: 'B1'
tier: 'Basic'
size: 'B1'
family: 'B'
capacity: 1
}
kind: 'linux'
properties: {
reserved: true
}
}
// SQL Database deployment
resource SnipeITDatabase 'Microsoft.DBforMySQL/flexibleServers/databases@2022-01-01' = {
name: SnipeITDB_name
parent: SnipeITMySQLServer
location: resourceGroup().location
properties: {
charset: 'utf8mb4'
collation: 'utf8mb4_general_ci'
}
}
resource SonarQubeWebSite 'Microsoft.Web/sites@2022-09-01' = {
name: SnipeITWebsite_name
location: resourceGroup().location
dependsOn: [
SnipeITDatabase
SnipeITStorageAccount
]
tags: {
Project: 'SnipeIT'
}
kind: 'app,linux,container'
properties: {
enabled: true
serverFarmId: SnipeITServerFarm.id
siteConfig: {
appCommandLine: ''
linuxFxVersion: DockerComposeString
acrUseManagedIdentityCreds: false
alwaysOn: true
scmType: 'None'
}
}
resource SnipeITWebsiteAppSettings 'config@2021-02-01' = {
name: 'appsettings'
properties: {
APP_DEBUG: 'false'
APP_KEY: SnipeITAppKey
APP_URL: 'https://${SnipeITWebsite_name}.azurewebsites.net'
DB_CONNECTION: 'mysql'
DB_SSL: 'true'
DB_SSL_IS_PAAS: 'true'
DB_SSL_CA_PATH: '/var/lib/snipeit/DigiCertGlobalRootCA.crt.pem'
MYSQL_DATABASE: SnipeITDB_name
MYSQL_USER: SnipeITMySQLLogin
MYSQL_PASSWORD: SnipeITMySQLPassword
MYSQL_PORT_3306_TCP_ADDR: '${SnipeITMySQLServer_name}.mysql.database.azure.com'
MYSQL_PORT_3306_TCP_PORT: '3306'
DOCKER_REGISTRY_SERVER_URL: 'https://index.docker.io/'
DOCKER_REGISTRY_SERVER_USERNAME: ''
DOCKER_REGISTRY_SERVER_PASSWORD: ''
WEBSITES_ENABLE_APP_SERVICE_STORAGE: 'false'
MAIL_DRIVER: 'smtp'
MAIL_ENV_ENCRYPTION: 'tcp'
MAIL_PORT_587_TCP_ADDR: 'smtp.sendgrid.net'
MAIL_PORT_587_TCP_PORT: '587'
MAIL_ENV_USERNAME: 'apikey'
MAIL_ENV_PASSWORD: SendGridAPIKey
MAIL_ENV_FROM_ADDR: 'alerts@mydomain.com'
MAIL_ENV_FROM_NAME: 'Snipe IT'
}
}
resource SnipeITWebsiteConfig 'config@2021-02-01' = if (azFileSettings == true) {
name: 'web'
properties: {
azureStorageAccounts: {
'snipeit': {
type: 'AzureFiles'
accountName: SnipeITStorageAccount.name
shareName: 'snipeit'
mountPath: '/var/lib/snipeit'
accessKey: SnipeITStorageAccount.listKeys().keys[0].value
}
'snipeit-logs': {
type: 'AzureFiles'
accountName: SnipeITStorageAccount.name
shareName: 'snipeit-logs'
mountPath: '/var/www/html/storage/logs'
accessKey: SnipeITStorageAccount.listKeys().keys[0].value
}
}
}
}
}
@montoyasg
Copy link

montoyasg commented Sep 8, 2023

Used the bicep template and deployment is successful but the web app does not start up.

Am running into the follow error from app service deployment logs

2023-09-08T05:11:29.726Z ERROR - Exception in multi-container config parsing: Exception: System.Exception, Msg: Invalid config file, must have at least one container in the pod definition..
2023-09-08T05:11:29.727Z ERROR - Start multi-container app failed

@rfennell
Copy link
Author

rfennell commented Sep 8, 2023

Sorry I am not a Docker expert, all the steps I followed are detailed https://blogs.blackmarble.co.uk/rfennell/setting-up-snipe-it-on-azure/, that works for us

@ekanelee
Copy link

I deployed using your template and all resources where deployed except mysql flexible server with this error message
{"code":"InternalServerError","message":"An unexpected error occured while processing the request. Tracking ID: '7820246c-8591-432b-8041-dbf1abc59b87'"}
Please what can be the problem or solution?

@rfennell
Copy link
Author

If there is a missing Azure resources, all you can do is look in the Azure deployment logs to see why the resource was no deployed.

@ekanelee
Copy link

ekanelee commented Oct 27, 2023 via email

@rfennell
Copy link
Author

To get you up and running would suggest following the manual process in the blog post and Snipe documentation listed in the description of this gist

@rfennell
Copy link
Author

rfennell commented Oct 27, 2023

For details on the manual process to setup SnipeIT on Azure see my blog post and the SnipeIT documentation

These notes related to creating the Azure resources using ARM/BICEP

I have done test deployment using the files in this GITS and had no problems when using the following commands

At a PowerShell prompt, with BICEP installed

# connect to Azure subscription
az account set --subscription "My Subscription"
# create a resource group in your region of choice
az group create --name bicepsnipe --location "UK South"
# with the bicep and docker file saved locally
# run a deployment using the bicep file - replacing the parameters with your values
az deployment group create --resource-group bicepsnipe --template-file SnipeIT.bicep --parameters SnipeITStorageAccount_name=mysnipe SnipeITMySQLServer_name=mysnipe SnipeITDB_name=snipedb SnipeITServerFarm_name=snipefarm SnipeITWebsite_name=mysnipe SnipeITMySQLLogin=username SnipeITMySQLPassword=Pass@w0rd1 SnipeITAppKey=base64:YAirCSXhtIvv5jyLznElFTkMc/1xgfSG/OcTrh8DENY= SendGridAPIKey=SG.1222555555555555

This is assuming

If this command does not complete, you need to investigate the deployment logs for the resource group in the Azure Portal.

Once this completes you should be able to load your site e.g. https://mysnipe.azurewebsites.net/ and the SnipeIT configuration page will be shown

image

IMPORTANT The database initially will be pink, and reporting an error. This is because the file DigiCertGlobalRootCA.crt.pem needs to be uploaded to the share

In the Azure Portal, pick the storage account, open storage explorer and upload the file to the File Share called snipeit

Once this is done the database row should go green of the setup page is refeshed in the browser

Once the database tables have been created you can proceed with the instance setup as detailed in the SnipeIT documentation

@ekanelee
Copy link

ekanelee commented Oct 27, 2023 via email

@bm-fez
Copy link

bm-fez commented Oct 31, 2023

It was the azure database for mysql flexible server that wasn't deployed with an InternalServerError message and due to the dependencies attached to it, the webb app for containers wasn't deployed too. All other resources were deployed and i can't figure out the problem That's why I plead for your help Thanks

Thinking about the the most likely reason a resource did not deploy is probably a problem with it's name e.g. it is publicly exposed and already in use or it does not meet the naming conventions of the given service

@gatesry
Copy link

gatesry commented Nov 15, 2023

Thanks for putting this together! We followed your blog post and got everything almost working. Question for you, the APP_URL env variable seems to be causing redirect issues. Setting it to the default domain duplicates the URL value, and on page load https://gh-test.azurewebsites.net becomes https://gh-test.azurewebsites.net/gh-test.azurewebsites.net/setup

Coming from our on-prem docker install, we were able to fix this using localhost as the URL key, but open to suggestions on Azure PaaS.

Edit: After digging into this, I was able to set the APP_URL variable through the docker compose file, and everything works!

@rfennell
Copy link
Author

Strange, I had not seen these problems, but great that the Docker compose file got it sorted for you.

A factor maybe, in our instances we let the Web App use it's default URL and provide a 'real domain name' via Frontdoor

@gatesry
Copy link

gatesry commented Nov 22, 2023

Thanks, Richard. Curious what your use-case is for Frontdoor?

@rfennell
Copy link
Author

The key reason we use Frontdoor as it allows us to centralise the management of the publicly accessible Azure hosted systems. Specifically the domain are managed in Frontdoor not on each separate service and it also automatically manages short lived SSL Certificates.

Might be important to others, but it is a bonus for us that it also provides global load balancing and CDN caching.

So the quick answer is easier admin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment