microsoft / azure-container-apps

Roadmap and issues for Azure Container Apps
MIT License
372 stars 29 forks source link

Please help me correct my cronJob run inside containerapp.bicep #1265

Closed nholuongut closed 3 months ago

nholuongut commented 3 months ago

I have create cronJob on azure but can not work. Please help me correct my code again

Issue description

A clear and concise description of the observed issue.

Steps to reproduce

param webhookUrl string
param scheduleStartTime string = '07:00'
param scheduleEndTime string = '19:00'
param scheduleTimeZone string = 'Asia/Bangkok'
resource cronJob 'Microsoft.App/containerApps@2024-03-01' = {
  name: '${containerAppName}cronjob'
  location: location
  tags: tags
  identity: {
    type: 'SystemAssigned,UserAssigned'
    userAssignedIdentities: {
      '${managedId}': {}
    }
  }
  properties: {
    configuration: {
      registries: [
        {
          server: acrServer
          identity: managedId
        }
      ]
      activeRevisionsMode: 'Single'
      secrets: [
        {
          name: 'webhook-url'
          value: webhookUrl
        }
      ]
    }
    environmentId: environment.outputs.containerEnvId
    template: {
      containers: [
        {
          image: intoImage
          name: 'cron-container'
          env: [
            {
              name: 'WEBHOOK_URL'
              secretRef: 'webhook-url'
            }
          ]
          command: [
            '/bin/sh'
          ]
          args: [
            '-c',
            'curl -X POST $WEBHOOK_URL'
          ]
          resources: {
            cpu: '0.5'
            memoryInGb: '0.5'
          }
        }
      ]
      scale: {
        minReplicas: 0
        maxReplicas: 1
      }
      scheduleTriggerConfig: {
        cronExpression: '*/1 7-19 * * 1-5'
        parallelism: 1
        replicaCompletionCount: 1
      }
      timeZone: scheduleTimeZone 
    }
  }
}

output cronJobName string = cronJob.name

main.parameter.json

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "value": "${AZURE_LOCATION}"
    },
    "tags": {
      "value": {}
    },
    "containerAppName": {
      "value": "${APPLICATION_NAME}"
    },
    "intoWebAppFqdn": {
      "value": "${FQDN}"
    },
    "webhookUrl": {
      "value": "https://dev.com/cron/<redacted>"
    }
  }
}
anthonychu commented 3 months ago

@nholuongut I've updated your comment to format the code and redact a value that appears to be a secret. If it's indeed a secret, you should rotate it as you've shared it on a public repo.

Do you want to use a container app or a job? They are different resources. Your bicep seems to contain properties from both resources.

See the Bicep reference here:

nholuongut commented 3 months ago

Hello @anthonychu anthonychu

Thanks for your support.

Of course I have referred to that document as you sent.

I mean I have used .bicep to create App container and it was successful (I am using azure devops pipeline). And now I want to use the schedule job need to call the URL (https://abc.com/cron/SZDNJkX5lXX297gaphs1BNMG7TUbmck0Fxg-WdGTFW1leHD-oDKHO6BCHvz1qxHFyd4sa5ThJtQ) every minute Runtime from 07:00 - 19:00 time zone gmt +7 from monday to friday on week

And I have tried many of those case trucows but still not. Here is my latest code example. resource cronJob 'Microsoft.Web/containerApps@2024-03-01' = { name: '${containerAppName}cronjob' location: location tags: tags identity: { type: 'SystemAssigned' } properties: { configuration: { registries: [ { server: acrServer identity: managedId } ] activeRevisionsMode: 'Single' secrets: [ { name: 'webhook-url' value: webhookUrl } ] } environmentId: environment.outputs.containerEnvId template: { containers: [ { image: intoImage name: 'cron-container' env: [ { name: 'WEBHOOK_URL' secretRef: 'webhook-url' } ] command: [ '/bin/sh' ] args: [ '-c', 'curl -X POST $WEBHOOK_URL' ] resources: { cpu: '0.5' memoryInGb: '0.5' } } ] scale: { minReplicas: 0 maxReplicas: 1 } scheduleTriggerConfig: { cronExpression: '/1 7-19 * 1-5' parallelism: 1 replicaCompletionCount: 1 } timeZone: scheduleTimeZone } } }

nholuongut commented 3 months ago

Full detail with .bicep as bellow @anthonychu containerapp.bicep

param location string param tags object = {} param containerAppName string param abcFqdn string param infraSnetId string param logAnalytics object param storageAccountName string @secure() param storageAccountKey string param storageShareName string param dbHost string param dbUser string @secure() param dbPassword string param redisDeploymentOption string = 'container' param redisManagedFqdn string = '' @secure() param redisManagedPassword string = '' param abcImage string param acrServer string param managedId string param abcMinReplica int = 1 param abcMaxReplica int = 2 param envCertificateId string = "" param webhookUrl string param scheduleStartTime string = '07:00' param scheduleEndTime string = '19:00' param scheduleTimeZone string = 'Asia/Bangkok'

var dbPort = '3306' var volumename = 'abcstorage' var dbName = 'intodb'

var redisHostSecret = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : (redisDeploymentOption == 'local') ? 'localhost' : redisManagedFqdn var redisPassword = (redisDeploymentOption == 'managed') ? redisManagedPassword : 'null'

module environment 'modules/containerappsEnvironment.module.bicep' = { name: 'containerAppEnv-deployement' params: { tags: tags infraSnetId: infraSnetId location: location logAnalytics: logAnalytics storageAccountKey: storageAccountKey storageAccountName: storageAccountName storageShareName: storageShareName } }

resource redisContainer 'Microsoft.App/containerApps@2024-03-01' = if (redisDeploymentOption == 'container') { name: '${containerAppName}redis' location: location tags: tags properties: { configuration: { activeRevisionsMode: 'Single' ingress: { external: true targetPort: 6379 exposedPort: 6379 transport: 'tcp' } } environmentId: environment.outputs.containerEnvId template: { containers: [ { args: [] command: [] env: [] image: 'redis:latest' name: 'redis' probes: [] resources: { cpu: json('1.0') memory: '2.0Gi' } volumeMounts: [] } ] scale: { minReplicas: 1 } volumes:[] } } }

module abc 'abc.bicep' = { name: '${containerAppName}abc-deployment' params: { acrServer: acrServer containerAppName: containerAppName dbHost: dbHost dbPassword: dbPassword dbUser: dbUser environmentId: environment.outputs.containerEnvId abcImage: intoImage abcFqdn: abcFqdn location: location managedId: managedId redisHostSecret: redisHostSecret redisPassword: redisPassword storageName: environment.outputs.webStorageName dbName: dbName dbPort: dbPort abcAppMaxReplica: intoAppMaxReplica abcAppMinReplica: intoAppMinReplica tags: tags volumename: volumename envCertificateId: envCertificateId } }

resource cronJob 'Microsoft.App/containerApps@2024-03-01' = { name: '${containerAppName}cronjob' location: location tags: tags identity: { type: 'SystemAssigned,UserAssigned' userAssignedIdentities: { '${managedId}': {} } } properties: { configuration: { registries: [ { server: acrServer identity: managedId } ] activeRevisionsMode: 'Single' secrets: [ { name: 'webhook-url' value: webhookUrl } ] } environmentId: environment.outputs.containerEnvId template: { containers: [ { image: intoImage name: 'cron-container' env: [ { name: 'WEBHOOK_URL' secretRef: 'webhook-url' } ] command: [ '/bin/sh' ] args: [ '-c', 'curl -X POST $WEBHOOK_URL' ] resources: { cpu: '0.5' memoryInGb: '0.5' } } ] scale: { minReplicas: 0 maxReplicas: 1 } scheduleTriggerConfig: { cronExpression: '/1 7-19 * 1-5' parallelism: 1 replicaCompletionCount: 1 } timeZone: scheduleTimeZone } } }

output webFqdn string = AbcApp.outputs.webFqdn output redisFqdn string = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : '' output webLatestRevisionName string = abcWebApp.outputs.webLatestRevisionName output envSuffix string = environment.outputs.envSuffix output loadBalancerIP string = environment.outputs.loadBalancerIP output cronJobName string = cronJob.name

main.parameter.json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "value": "${AZURE_LOCATION}" }, "tags": { "value": {} }, "containerAppName": { "value": "${APPLICATION_NAME}" }, "abcWebAppFqdn": { "value": "${FQDN}" }, "infraSnetId": { "value": "${INFRA_SNET_ID}" }, "logAnalytics": { "value": {} }, "storageAccountName": { "value": "${STORAGE_ACCOUNT_NAME}" }, "storageAccountKey": { "value": "${STORAGE_ACCOUNT_KEY}" }, "storageShareName": { "value": "${STORAGE_SHARE_NAME}" }, "dbHost": { "value": "${DB_HOST}" }, "dbUser": { "value": "${DB_USER}" }, "dbPassword": { "value": "${DB_PASSWORD}" }, "redisDeploymentOption": { "value": "${REDIS_DEPLOYMENT_OPTION}" }, "redisManagedFqdn": { "value": "${REDIS_MANAGED_FQDN}" }, "redisManagedPassword": { "value": "${REDIS_MANAGED_PASSWORD}" }, "intoImage": { "value": "${ABC_IMAGE}" }, "acrServer": { "value": "${ACR_SERVER}" }, "managedId": { "value": "${MANAGED_ID}" }, "abcAppMinReplica": { "value": "${ABC_APP_MIN_REPLICA}" }, "abcAppMaxReplica": { "value": "${ABC_APP_MAX_REPLICA}" }, "envCertificateId": { "value": "${ENV_CERTIFICATE_ID}" }, "webhookUrl": { "value": "https://abc.com/cron/SZDNJkX5lXX297gaphs1BNMG7TUbmck0Fxg-WdGTFW1leHD-oDKHO6BCHvz1qxHFyd4sa5ThJtQ" } } }

nholuongut commented 3 months ago

@anthonychu The idea as I understand it is to use container-apps-jobs to run cronJob for container app and the requirement for this cronJob is: => the schedule job need to call the URL (https://abc.com/cron/SZDNJkX5lXX297gaphs1BNMG7TUbmck0Fxg-WdGTFW1leHD-oDKHO6BCHvz1qxHFyd4sa5ThJtQ) every minute Runtime from 07:00 - 19:00 time zone gmt +7 from monday to friday on week

nholuongut commented 3 months ago

Hello @anthonychu Here you are?

anthonychu commented 3 months ago

Sounds like you want to use jobs. Your current Bicep is for a container app (Microsoft.App/containerApps@2024-03-01). It also contains unsupported properties such as timeZone (cron expressions in scheduled Container Apps jobs are in UTC only). Please see this documentation for the correct resource type and properties: https://learn.microsoft.com/en-us/azure/templates/microsoft.app/jobs?pivots=deployment-language-bicep

Here's an example of a job that does what you want:

param location string = 'westus'
param managedEnvironmentName string = 'my-managed-environment'
param logAnalyticsWorkspaceName string = 'my-log-analytics-workspace'
param jobName string = 'my-job'

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
  name: logAnalyticsWorkspaceName
  location: location
  properties: any({
    retentionInDays: 30
    features: {
      searchVersion: 1
    }
    sku: {
      name: 'PerGB2018'
    }
  })
}

resource env 'Microsoft.App/managedEnvironments@2024-03-01' = {
  name: managedEnvironmentName
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalyticsWorkspace.properties.customerId
        sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
      }
    }
  }
}

resource job 'Microsoft.App/jobs@2024-03-01' = {
  name: jobName
  location: location
  properties: {
    environmentId: env.id
    configuration: {
      replicaTimeout: 120
      triggerType: 'Schedule'
      scheduleTriggerConfig: {
        cronExpression: '*/1 7-19 * * 1-5'
      }
    }
    template: {
      containers: [
        {
          name: 'my-container'
          image: 'curlimages/curl:latest'
          resources: {
            cpu: json('0.25')
            memory: '0.5Gi'
          }
          args: [
            '-v'
            'https://www.azure.com'
          ]
        }
      ]
    }
  }
}
nholuongut commented 3 months ago

Hi @anthonychu

How about if i want correct all code for my containerapp.bicep here. If yes, Please help me correct again?


param location string param tags object = {} param containerAppName string param abcFqdn string param infraSnetId string param logAnalytics object #=> I have define logAnalytics here param storageAccountName string https://github.com/secure() param storageAccountKey string param storageShareName string param dbHost string param dbUser string https://github.com/secure() param dbPassword string param redisDeploymentOption string = 'container' param redisManagedFqdn string = '' https://github.com/secure() param redisManagedPassword string = '' param abcImage string param acrServer string param managedId string param abcMinReplica int = 1 param abcMaxReplica int = 2 param envCertificateId string = "" param webhookUrl string param scheduleStartTime string = '07:00' param scheduleEndTime string = '19:00' param scheduleTimeZone string = 'Asia/Bangkok' param logAnalyticsWorkspaceName string = 'cronjob-analytics-workspace' # > duplicate again?
param jobName string = 'cronJobDev'

var dbPort = '3306' var volumename = 'abcstorage' var dbName = 'intodb'

var redisHostSecret = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : (redisDeploymentOption == 'local') ? 'localhost' : redisManagedFqdn var redisPassword = (redisDeploymentOption == 'managed') ? redisManagedPassword : 'null'

module environment 'modules/containerappsEnvironment.module.bicep' = { name: 'containerAppEnv-deployement' params: { tags: tags infraSnetId: infraSnetId location: location logAnalytics: logAnalytics storageAccountKey: storageAccountKey storageAccountName: storageAccountName storageShareName: storageShareName } }

resource redisContainer 'Microsoft.App/containerApps@2024-03-01' = if (redisDeploymentOption == 'container') { name: '${containerAppName}redis' location: location tags: tags properties: { configuration: { activeRevisionsMode: 'Single' ingress: { external: true targetPort: 6379 exposedPort: 6379 transport: 'tcp' } } environmentId: environment.outputs.containerEnvId template: { containers: [ { args: [] command: [] env: [] image: 'redis:latest' name: 'redis' probes: [] resources: { cpu: json('1.0') memory: '2.0Gi' } volumeMounts: [] } ] scale: { minReplicas: 1 } volumes:[] } } }

module abc 'abc.bicep' = { name: '${containerAppName}abc-deployment' params: { acrServer: acrServer containerAppName: containerAppName dbHost: dbHost dbPassword: dbPassword dbUser: dbUser environmentId: environment.outputs.containerEnvId abcImage: intoImage abcFqdn: abcFqdn location: location managedId: managedId redisHostSecret: redisHostSecret redisPassword: redisPassword storageName: environment.outputs.webStorageName dbName: dbName dbPort: dbPort abcAppMaxReplica: intoAppMaxReplica abcAppMinReplica: intoAppMinReplica tags: tags volumename: volumename envCertificateId: envCertificateId } }

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: logAnalyticsWorkspaceName location: location properties: any({ retentionInDays: 30 features: { searchVersion: 1 } sku: { name: 'PerGB2018' } }) }

resource env 'Microsoft.App/managedEnvironments@2024-03-01' = { name: managedEnvironmentName location: location properties: { appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { customerId: logAnalyticsWorkspace.properties.customerId sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey } } } }

resource job 'Microsoft.App/jobs@2024-03-01' = { name: jobName location: location properties: { environmentId: env.id configuration: { replicaTimeout: 120 triggerType: 'Schedule' scheduleTriggerConfig: { cronExpression: '/1 7-19 * 1-5' } } template: { containers: [ { name: 'my-container' image: 'curlimages/curl:latest'

how about correct with my info

      # image: intoImage
      # name: 'cron-container'

      resources: {
        cpu: json('0.25')
        memory: '0.5Gi'
      }
      args: [
        '-v'
        'https://www.azure.com'
      ]
    }
  ]
}

} }

output webFqdn string = AbcApp.outputs.webFqdn output redisFqdn string = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : '' output webLatestRevisionName string = abcWebApp.outputs.webLatestRevisionName output envSuffix string = environment.outputs.envSuffix output loadBalancerIP string = environment.outputs.loadBalancerIP output cronJobName string = cronJob.name #how about this command output

nholuongut commented 3 months ago

Hi @anthonychu anthonychu I have updated my code and deployed successfully but i still no see my cronjob. If yes, Please help me correct again?

This is latest my code:

param location string param tags object = {} param containerAppName string param intoWebAppFqdn string param infraSnetId string param logAnalytics object param storageAccountName string @secure() param storageAccountKey string param storageShareName string param dbHost string param dbUser string @secure() param dbPassword string param redisDeploymentOption string = 'container' param redisManagedFqdn string = '' @secure() param redisManagedPassword string = '' param intoImage string param acrServer string param managedId string param abcAppMinReplica int = 1 param abcAppMaxReplica int = 2 param envCertificateId string = "" param managedEnvironmentName string = 'managed-environment' param logAnalyticsWorkspaceName string = 'log-analytics-workspace' param jobName string = 'cronJobDev'

var dbPort = '3306' var volumename = 'abcstorage' var dbName = 'abcdb'

var redisHostSecret = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : (redisDeploymentOption == 'local') ? 'localhost' : redisManagedFqdn var redisPassword = (redisDeploymentOption == 'managed') ? redisManagedPassword : 'null'

module environment 'modules/containerappsEnvironment.module.bicep' = { name: 'containerAppEnv-deployement' params: { tags: tags infraSnetId: infraSnetId location: location logAnalytics: logAnalytics storageAccountKey: storageAccountKey storageAccountName: storageAccountName storageShareName: storageShareName } }

resource redisContainer 'Microsoft.App/containerApps@2024-03-01' = if (redisDeploymentOption == 'container') { name: '${containerAppName}redis' location: location tags: tags properties: { configuration: { activeRevisionsMode: 'Single' ingress: { external: true targetPort: 6379 exposedPort: 6379 transport: 'tcp' } } environmentId: environment.outputs.containerEnvId template: { containers: [ { args: [] command: [] env: [] image: 'redis:latest' name: 'redis' probes: [] resources: { cpu: json('1.0') memory: '2.0Gi' } volumeMounts: [] } ] scale: { minReplicas: 1 } volumes:[] } } }

module abcWebApp 'abcwebapp.bicep' = { name: '${containerAppName}abcapp-deployment' params: { acrServer: acrServer containerAppName: containerAppName dbHost: dbHost dbPassword: dbPassword dbUser: dbUser environmentId: environment.outputs.containerEnvId abcImage: intoImage abcWebAppFqdn: intoWebAppFqdn location: location managedId: managedId redisHostSecret: redisHostSecret redisPassword: redisPassword storageName: environment.outputs.webStorageName dbName: dbName dbPort: dbPort abcAppMaxReplica: intoAppMaxReplica abcAppMinReplica: intoAppMinReplica tags: tags volumename: volumename envCertificateId: envCertificateId } }

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: logAnalyticsWorkspaceName location: location properties: any({ retentionInDays: 30 features: { searchVersion: 1 } sku: { name: 'PerGB2018' } }) }

resource env 'Microsoft.App/managedEnvironments@2024-03-01' = { name: managedEnvironmentName location: location properties: { appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { customerId: logAnalyticsWorkspace.properties.customerId sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey } } } }

resource job 'Microsoft.App/jobs@2024-03-01' = { name: jobName location: location properties: { environmentId: env.id configuration: { replicaTimeout: 120 triggerType: 'Schedule' scheduleTriggerConfig: { cronExpression: '/1 7-19 * 1-5' } } template: { containers: [ { name: 'cronjob-container' image: 'curlimages/curl:latest' resources: { cpu: json('0.25') memory: '0.5Gi' } args: [ '-v' 'https://www.azure.com' ] } ] } } }

output webFqdn string = abcWebApp.outputs.webFqdn output redisFqdn string = (redisDeploymentOption == 'container') ? redisContainer.properties.configuration.ingress.fqdn : '' output webLatestRevisionName string = abcWebApp.outputs.webLatestRevisionName output envSuffix string = environment.outputs.envSuffix output loadBalancerIP string = environment.outputs.loadBalancerIP output jobNameOutput string = job.name

nholuongut commented 3 months ago

Hi @anthonychu

This is latest code with my cron Job but still not work. Hazz

cronjonapp.parameters.json cronjonapp.json

anthonychu commented 3 months ago

What's the error? Bicep looks okay. Your job name must be all lowercase characters. You should see this error in your deployment:

Invalid ContainerAppsJob name 'cronJob-Dev'. A name must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character and cannot have '--'. The length must not be more than 32 characters. (Code: ContainerAppInvalidName)

nholuongut commented 3 months ago

I have updated with cron-dev but still can't create after deployed. hazz ![Uploading Screen Shot 2024-08-21 at 09.38.34.png…]()

simonjj commented 3 months ago

@nholuongut, thank you for reaching out. Please don't post secrets on Github. There is a library of templates available under https://azure.github.io/awesome-azd and the schema is available here https://learn.microsoft.com/en-us/azure/templates/microsoft.app/jobs?pivots=deployment-language-bicep

We have to delete this issue now due to the exposed secrets.