Bicep to configure GitHub Action to build custom container, push to ACR and deploy on App Service

Denis Gontcharov 36 Reputation points
2022-12-07T21:47:16.663+00:00

I have a public GitHub repository with a minimal R application and a Dockerfile: https://github.com/gontcharovd/minimal-shiny-app

My goal is to:

  1. Build a Docker image
  2. Push the image to Azure Container Registry
  3. Deploy the image to Azure App Service

Essentially, it's exactly what's described in this Microsoft Learn article: https://learn.microsoft.com/en-us/azure/app-service/deploy-container-github-action?tabs=publish-profile

However, I would like to do this with GitHub Actions and Bicep (instead of Azure CLI) so that it's completely IaC.

For this, I wrote the following main.bicep file:

   param containerImage string = 'minimal-shiny-app'  
   param containerImageTag string = 'latest'  
   param location string = 'westeurope'  
     
   // define unique service names  
   var webAppName = 'webbApp${uniqueString(resourceGroup().id)}'  
   var webAppServicePlanName = 'webbAppServicePlan${uniqueString(resourceGroup().id)}'  
   var webSiteName = toLower(webAppName)  
   var containerRegistryName = 'containterregistry${uniqueString(resourceGroup().id)}'  
     
   // variables  
   var roleDefinitionID =  '7f951dda-4ed3-4680-a7ca-43fe172d538d'  // AcrPull  
   var linuxFxVersion = 'DOCKER|${containerRegistry.name}.azurecr.io/${containerImage}:${containerImageTag}'  
   var registryServerUrl = '${containerRegistry.name}.azurecr.io'  
   var roleAssignmentName= guid(roleDefinitionID, resourceGroup().id)  
     
   resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-06-01-preview' = {  
     name: containerRegistryName  
     location: location  
     sku: {  
       name: 'Basic'  
     }  
     properties: {  
       adminUserEnabled: true  
     }  
   }  
     
   resource webAppServicePlan 'Microsoft.Web/serverfarms@2020-06-01' = {  
     name: webAppServicePlanName  
     location: location  
     properties: {  
       reserved: true  
     }  
     sku: {  
       name: 'F1'  
     }  
     kind: 'linux'  
   }  
     
   resource webApp 'Microsoft.Web/sites@2022-03-01' = {  
     name: webSiteName  
     location: location  
     kind: 'app,linux,container'  
     identity: {  
       type: 'SystemAssigned'  
     }  
     properties: {  
       reserved: true  
       serverFarmId: webAppServicePlan.id  
       siteConfig: {  
         linuxFxVersion: linuxFxVersion  
         acrUseManagedIdentityCreds: true  
       }  
     }  
   }  
     
   resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {  
     name: roleAssignmentName  
     scope: resourceGroup()  
     properties: {  
       description: 'AcrPull'  
       principalId: webApp.identity.principalId  
       roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionID)  
       principalType: 'ServicePrincipal'  
     }  
   }  
     
   resource sourceControl 'Microsoft.Web/sites/sourcecontrols@2022-03-01' = {  
     name: 'web'  
     parent: webApp  
     properties: {  
       branch: 'main'  
       deploymentRollbackEnabled: false  
       gitHubActionConfiguration: {  
         containerConfiguration: {  
           imageName: containerImage  
           serverUrl: registryServerUrl  
           username: containerRegistry.name  
           password: 'thisIsNotARealPassword'  
         }  
         generateWorkflowFile: true  
         isLinux: true  
       }  
       isGitHubAction: true  
       isManualIntegration: false  
       repoUrl: 'https://github.com/gontcharovd/minimal-shiny-app'  
     }  
   }  


 

Deploying this bicep file results in the following cryptic error:

   ERROR: {"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n  \"Code\": \"BadRequest\",\r\n  \"Message\": \"<Error xmlns=\\\"http://schemas.microsoft.com/windowsazure\\\" xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"><Code>BadRequest</Code><Message>Repository 'UpdateSiteSourceControl' operation failed with System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl).</Message><ExtendedCode>05007</ExtendedCode><MessageTemplate>Repository '{0}' operation failed with {1}.</MessageTemplate><Parameters xmlns:a=\\\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\\\"><a:string>UpdateSiteSourceControl</a:string><a:string>System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)</a:string></Parameters><InnerErrors i:nil=\\\"true\\\"/><Details i:nil=\\\"true\\\"/><Target i:nil=\\\"true\\\"/></Error>\",\r\n  \"Target\": null,\r\n  \"Details\": [\r\n    {\r\n      \"Message\": \"<Error xmlns=\\\"http://schemas.microsoft.com/windowsazure\\\" xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"><Code>BadRequest</Code><Message>Repository 'UpdateSiteSourceControl' operation failed with System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl).</Message><ExtendedCode>05007</ExtendedCode><MessageTemplate>Repository '{0}' operation failed with {1}.</MessageTemplate><Parameters xmlns:a=\\\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\\\"><a:string>UpdateSiteSourceControl</a:string><a:string>System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)</a:string></Parameters><InnerErrors i:nil=\\\"true\\\"/><Details i:nil=\\\"true\\\"/><Target i:nil=\\\"true\\\"/></Error>\"\r\n    },\r\n    {\r\n      \"Code\": \"BadRequest\"\r\n    },\r\n    {\r\n      \"ErrorEntity\": {\r\n        \"Code\": \"BadRequest\",\r\n        \"Message\": \"<Error xmlns=\\\"http://schemas.microsoft.com/windowsazure\\\" xmlns:i=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"><Code>BadRequest</Code><Message>Repository 'UpdateSiteSourceControl' operation failed with System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl).</Message><ExtendedCode>05007</ExtendedCode><MessageTemplate>Repository '{0}' operation failed with {1}.</MessageTemplate><Parameters xmlns:a=\\\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\\\"><a:string>UpdateSiteSourceControl</a:string><a:string>System.NullReferenceException: Object reference not set to an instance of an object.&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionConfigurationExtensions.ContainerUsername(GitHubActionConfiguration gitHubActionConfiguration)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;CreateOrUpdateGitHubActionSecret&gt;d__19.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.GitHubActionRepositoryProvider.&lt;UpdateSiteSourceControl&gt;d__16.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.&lt;&gt;c__DisplayClass347_1.&lt;&lt;UpdateSiteSourceControl&gt;b__1&gt;d.MoveNext()&#xD;\\n--- End of stack trace from previous location where exception was thrown ---&#xD;\\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#xD;\\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#xD;\\n   at Microsoft.Web.Hosting.AsyncHelper.RunSync[TResult](Func`1 func)&#xD;\\n   at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)</a:string></Parameters><InnerErrors i:nil=\\\"true\\\"/><Details i:nil=\\\"true\\\"/><Target i:nil=\\\"true\\\"/></Error>\"\r\n      }\r\n    }\r\n  ],\r\n  \"Innererror\": null\r\n}"}]}}  

Besides the error I have a few questions:

  1. Why are username and password required parameters in containerConfiguration if the authentication is performed through RBAC with a Managed identity?
  2. How can this password be known before the ACR is created? It's defined and deployed in this bicep file and there is no parameter to set the password in Microsoft.ContainerRegistry/registries@2021-06-01-preview.
  3. Is it even possible to configure everything in bicep? Or will there always be some manual configuration required in GitHub?
Azure Container Registry
Azure Container Registry
An Azure service that provides a registry of Docker and Open Container Initiative images.
367 questions
Azure App Service
Azure App Service
Azure App Service is a service used to create and deploy scalable, mission-critical web apps.
6,634 questions
0 comments No comments
{count} votes

Accepted answer
  1. ajkuma 21,321 Reputation points Microsoft Employee
    2022-12-09T17:38:11.557+00:00

    @Denis Gontcharov , Thanks for the great question!

    As I understand, you’re trying to generate the GitHub action YAML from the Bicep.
    Instead, I would suggest not to go with that flow, as the Bicep code is already executed from the GitHub Action.

    You may checkout about NubesGen - https://github.com/microsoft/NubesGen.
    (NubesGen is a Web application that generates a cloud infrastructure using Terraform or Bicep)

    If you wish, you may leverage NubesGen - Navigate to www.nubesgen.com and generate a WebApp with docker and to check "Add GitOps" to generate the appropriate GitHub action.

    To answer your specific questions:

    1. In the referenced code, you are not creating managed identities or assigning roles to managed identities. Thus username/password is required.
      -The Bicep generated by NubesGen is using username and password, but without exposing them.

    2.No, it can’t know the password.
    -That's why the Biceps generated by NubesGen is doing a lookup on the ACR resource.

    1. It depends on what you want to achieve. If your goal is to create an ACR, an App Service Plan and an App Service from a Bicep, yes you can achieve that with Bicep.
      In this case, as I mentioned earlier, the GitHub Action should be committed by the you (or user) on the GitHub repo, not by Azure. There will be a one-time manual operation to link GitHub with your Azure subscription (either through Service Principal or OIDC).

    -NubesGen CLI helps you setup this easily.

    Alternatively, if your requirement fits, you may consider using the ACR Image build module from the bicep registry.

    https://github.com/Azure/bicep-registry-modules/tree/main/modules/deployment-scripts/build-acr#examples

    This way you can simply point App Service to the ACR and not rely on the GitHub Action Configuration.

    More info: NubesGen -An Open Source tool to automate Azure deployments

    --
    To benefit the community find the right answers, please do mark the post which was helpful by clicking on Accept Answer’ & ‘Up-Vote’.

    1 person found this answer helpful.
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Denis Gontcharov 36 Reputation points
    2022-12-25T14:14:10.737+00:00

    I got it working using Bicep code generated by NubesGen and by using the ACR Image build module from the bicep registry. Here is the working code:

    param location string = 'westeurope'  
      
    // define unique service names  
    var webAppName = 'webbApp${uniqueString(resourceGroup().id)}'  
    var webAppServicePlanName = 'webbAppServicePlan${uniqueString(resourceGroup().id)}'  
    var webSiteName = toLower(webAppName)  
    var containerRegistryName = 'containterregistry${uniqueString(resourceGroup().id)}'  
      
    // variables  
    var containerImage = 'compressor/minimal'  
    var linuxFxVersion = 'DOCKER|${buildContainerImage.outputs.acrImage}'  
      
    resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-06-01-preview' = {  
      name: containerRegistryName  
      location: location  
      sku: {  
        name: 'Basic'  
      }  
      properties: {  
        adminUserEnabled: true  
      }  
    }  
      
    resource webAppServicePlan 'Microsoft.Web/serverfarms@2020-06-01' = {  
      name: webAppServicePlanName  
      location: location  
      properties: {  
        reserved: true  
      }  
      sku: {  
        tier: 'Free'  
        name: 'F1'  
      }  
      kind: 'linux'  
    }  
      
    resource webApp 'Microsoft.Web/sites@2022-03-01' = {  
      name: webSiteName  
      location: location  
      properties: {  
        reserved: true  
        serverFarmId: webAppServicePlan.id  
        httpsOnly: true  
        clientAffinityEnabled: false  
        siteConfig: {  
          linuxFxVersion: linuxFxVersion  
          ftpsState: 'FtpsOnly'  
          http20Enabled: true  
          minTlsVersion: '1.2'  
          appSettings: [  
            {  
              name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE'  
              value: 'false'  
            }  
            {  
              name: 'DOCKER_REGISTRY_SERVER_URL'  
              value: 'https://${containerRegistry.name}.azurecr.io'  
            }  
            {  
              name: 'DOCKER_REGISTRY_SERVER_USERNAME'  
              value: containerRegistry.name  
            }  
            {  
              name: 'DOCKER_REGISTRY_SERVER_PASSWORD'  
              value: listCredentials(containerRegistry.id, containerRegistry.apiVersion).passwords[0].value  
            }  
            {  
              name: 'WEBSITES_PORT'  
              value: '8080'  
            }  
          ]  
        }  
      }  
    }  
      
    module buildContainerImage 'br/public:deployment-scripts/build-acr:1.0.1' = {  
      name: 'buildContainerImage'  
      params: {  
        AcrName: containerRegistry.name  
        location: location  
        gitRepositoryUrl:  'https://github.com/gontcharovd/minimal-shiny-app'  
        gitRepoDirectory:  '.'  
        imageName: containerImage  
      }  
    }  
      
    
    0 comments No comments