Introduce AzureContainerAppsRC task
This commit is contained in:
Родитель
dc1ccfba4d
Коммит
244e95fe84
|
@ -348,3 +348,12 @@ MigrationBackup/
|
|||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Ignore Tests folder copied over from stable task
|
||||
azurecontainerapps/Tests/
|
||||
|
||||
# Ignore .js files generated via tsc
|
||||
*.js
|
||||
|
||||
# Ignore .vsix files generated via tfx-cli
|
||||
*.vsix
|
314
README.md
314
README.md
|
@ -1,33 +1,305 @@
|
|||
# Project
|
||||
# Azure Container Apps Build and Deploy (Release Candidate)
|
||||
|
||||
> This repo has been populated by an initial template to help get you started. Please
|
||||
> make sure to update the content to build a great experience for community-building.
|
||||
## Important note
|
||||
|
||||
As the maintainer of this project, please make a few updates:
|
||||
The `AzureContainerAppsRC` task found in this repository is the _Release Candidate (RC)_ version of the
|
||||
`AzureContainerApps` task that ships out of the box with Azure Pipelines, which can be found
|
||||
[here](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureContainerAppsV0). The intended purpose
|
||||
of this Release Candidate task is to offer users immediate early access to features, bug fixes and patches that will
|
||||
eventually be rolled out in the official `AzureContainerApps` task at the end of every three week sprint.
|
||||
|
||||
- Improving this README.MD file to provide a great experience
|
||||
- Updating SUPPORT.MD with content about this project's support experience
|
||||
- Understanding the security reporting process in SECURITY.MD
|
||||
- Remove this section from the README
|
||||
## Description
|
||||
|
||||
This Azure Pipelines Task allows users to easily deploy their application source to an
|
||||
[Azure Container App](https://azure.microsoft.com/en-us/services/container-apps/) in their Azure Pipelines workflow by
|
||||
either providing a previously built image, a Dockerfile that an image can be built from, or using a builder to create a
|
||||
runnable application image for the user.
|
||||
|
||||
If no Dockerfile is found or provided in the provided application source, the following steps are performed by this task:
|
||||
|
||||
- Uses the Oryx++ Builder to build the application source using [Oryx](https://github.com/microsoft/Oryx) to produce a
|
||||
runnable application image
|
||||
- Pushes this runnable application image to the provided Azure Container Registry
|
||||
- Creates or updates a Container App based on this image
|
||||
|
||||
If a Dockerfile is found or discovered in the application source, the builder won't be used and the image will be built
|
||||
with a call to `docker build` and the Container App will be created or updated based on this image.
|
||||
|
||||
If a previously built image has already been pushed to the ACR instance and is provided to this task, no application
|
||||
source is required and the image will be used when creating or updating the Container App.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Prior to running this task, Azure resources and an Azure DevOps service connection are either required or optional
|
||||
depending on the arguments provided to this task.
|
||||
|
||||
### Azure DevOps Service Connection
|
||||
|
||||
To deploy to Azure, an Azure subscription has to be linked to Team Foundation Server or to Azure Pipelines using the
|
||||
Services tab in the settings section. Add the Azure subscription to use in the Build or Release Management definition by
|
||||
opening the Account Administration screen (gear icon on the top-right of the screen) and then click on the Services Tab.
|
||||
|
||||
Create the [ARM](https://azure.microsoft.com/en-in/documentation/articles/resource-group-overview/) service endpoint and
|
||||
use the **'Azure Resource Manager'** endpoint type; for more information on creating service connections, please follow
|
||||
[this document](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints).
|
||||
|
||||
### Azure CLI
|
||||
|
||||
This task requires that the Azure CLI is installed on the Azure Pipelines agent to execute a variety of commands
|
||||
throughout the execution of the task. For more information on how to install the Azure CLI on the agent, please see
|
||||
[this document](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli). If an agent is already running on the
|
||||
machine on which the Azure CLI is installed, ensure that you restart the agent so that all relevant environment
|
||||
variables are updated.
|
||||
|
||||
### Docker
|
||||
|
||||
This task requires that Docker is installed on the Azure Pipelines agent to push images to the provided Azure Container
|
||||
Registry. For more information on how to install Docker on the agent, please see
|
||||
[this document](https://docs.docker.com/get-docker/).
|
||||
|
||||
### Azure Container Registry
|
||||
|
||||
An [Azure Container Registry](https://azure.microsoft.com/en-us/products/container-registry/) must exist that the user
|
||||
is able to push container images to. This task will leverage the Azure Container Registry to either push a built
|
||||
runnable application image to and/or deploy a Container App from.
|
||||
|
||||
The name of the Azure Container Registry is required via the `acrName` argument.
|
||||
|
||||
The user can also provide values for the `acrUsername` and `acrPassword` arguments that will authenticate calls to the
|
||||
Azure Container Registry instance; if not provided, an access token will be generated via the Azure CLI that will
|
||||
authenticate the calls instead.
|
||||
|
||||
### Azure Container App environment
|
||||
|
||||
An [Azure Container App environment](https://docs.microsoft.com/en-us/azure/container-apps/environment) is recommended
|
||||
to have been previously created by the user to improve the performance of the task. If no environment has been
|
||||
created before, or if an environment cannot be found in the resource group that is being used to host the created
|
||||
Container App, then an environment will be created by as a part of the `az containerapp up` command, which may take
|
||||
additional time.
|
||||
|
||||
## Arguments
|
||||
|
||||
Below are the arguments that can be provided to this task.
|
||||
|
||||
| Argument name | Required | Description |
|
||||
| ------------------------- | -------- | ----------- |
|
||||
| `connectedServiceNameARM` | Yes | Service connection linked to the user's Azure Subscription where the Container App will be created/updated. This service connection _must_ have proper permissions to make these changes within the subscription (_e.g._, Contributor role). |
|
||||
| `appSourcePath` | No | Absolute path on the Azure Pipelines agent of the source application code to be built. |
|
||||
| `acrName` | Yes | The name of the Azure Container Registry that the runnable application image will be pushed to. |
|
||||
| `acrUsername` | No | The username used to authenticate push requests to the provided Azure Container Registry. If not provided, an access token will be generated via "az acr login" and provided to "docker login" to authenticate the requests. |
|
||||
| `acrPassword` | No | The password used to authenticate push requests to the provided Azure Container Registry. If not provided, an access token will be generated via "az acr login" and provided to "docker login" to authenticate the requests. |
|
||||
| `dockerfilePath` | No | Relative path (_without file prefixes, see example below_) to the Dockerfile in the provided application source that should be used to build the image that is then pushed to ACR and deployed to the Container App. If not provided, this action will check if there is a file named `Dockerfile` in the provided application source and use that to build the image. Otherwise, the Oryx++ Builder will be used to create the image. |
|
||||
| `imageToBuild` | No | The custom name of the image that is to be built, pushed to ACR and deployed to the Container App by this action. _Note_: this image name should include the ACR server; _e.g._, `<acr-name>.azurecr.io/<repo>:<tag>`. If this argument is not provided, a default image name will be constructed in the form `<acr-name>.azurecr.io/ado-task/container-app:<build-id>.<build-number>` |
|
||||
| `imageToDeploy` | No | The custom name of the image that has already been pushed to ACR and will be deployed to the Container App by this action. _Note_: this image name should include the ACR server; _e.g._, `<acr-name>.azurecr.io/<repo>:<tag>`. If this argument is not provided, the value provided (or determined) for the `imageToBuild` argument will be used. |
|
||||
| `containerAppName` | No | The name of the Container App that will be created or updated. If not provided, this value will be `ado-task-app-<build-id>-<build-number>`. |
|
||||
| `resourceGroup` | No | The resource group that the Container App will be created in, or currently exists in. If not provided, this value will be `<container-app-name>-rg`. |
|
||||
| `containerAppEnvironment` | No | The name of the Container App environment to use with the application. If not provided, an existing environment in the resource group of the Container App will be used, otherwise, an environment will be created in the formation `<container-app-name>-env`. |
|
||||
| `runtimeStack` | No | The platform version stack used in the final runnable application image that is deployed to the Container App. The value should be provided in the formation `<platform>:<version>`. If not provided, this value is determined by Oryx based on the contents of the provided application. Please refer to [this document](https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md) for more information on supported runtime stacks for Oryx. |
|
||||
| `targetPort` | No | The target port that the Container App will listen on. If not provided, this value will be "80" for Python applications and "8080" for all other supported platforms. |
|
||||
|
||||
## Usage
|
||||
|
||||
Below are a set of examples outlining how to use this task in different scenarios.
|
||||
|
||||
### Minimal
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new resource group named
|
||||
`<container-app-name>-rg`. The provided Azure Container Registry credentials will be used to authenticate any calls
|
||||
made against the 'sampleacr' instance.
|
||||
|
||||
### Container App name provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppName: 'test-container-app-123'
|
||||
```
|
||||
|
||||
This will create a new Container App named `test-container-app-123` in a new resource group named
|
||||
`test-container-app-123-rg`.
|
||||
|
||||
### Resource group provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
resourceGroup: 'test-container-app-rg'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `test-container-app-rg`.
|
||||
|
||||
### Container App name and resource group provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppName: 'test-container-app-123'
|
||||
resourceGroup: 'test-container-app-rg'
|
||||
```
|
||||
|
||||
If the `test-container-app-rg` resource group does not exist, this will create the resource group and create a new
|
||||
Container App named `test-container-app-123` within the resource group. If the resource group already exists, this will
|
||||
create a new Container App named `test-container-app-123` in the resource group, or update the Container App if it
|
||||
already exists within the resource group.
|
||||
|
||||
### Container App environment provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppEnvironment: 'test-container-app-123-env'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` with a new Container App environment named `test-container-app-123-env`.
|
||||
|
||||
### Runtime stack provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
runtimeStack: 'dotnetcore:7.0'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the runnable application image is using the .NET 7 runtime stack.
|
||||
|
||||
### Dockerfile provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
dockerfilePath: 'test.Dockerfile'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the runnable application image was created from the `test.Dockerfile`
|
||||
file found in the provided application source path directory.
|
||||
|
||||
_Note_: for values provided to `dockerfilePath`, no file prefixes should be included (_e.g._, `./test.Dockerfile` should be
|
||||
passed as just `test.Dockerfile`). The provided `appSourcePath` and `dockerfilePath` arguments will be concatenated inside
|
||||
of the Azure DevOps task.
|
||||
|
||||
### Image to build provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
imageToBuild: 'sampleacr.azurecr.io/app:latest'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the image built and pushed to ACR is named
|
||||
`sampleacr.azurecr.io/app:latest`
|
||||
|
||||
### Image to deploy provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
imageToDeploy: 'sampleacr.azurecr.io/app:latest'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where **no new image is built**, but an existing image in ACR named
|
||||
`sampleacr.azurecr.io/app:latest` will be deployed to the Container App.
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
This project welcomes contributions and suggestions from all users; however, we advise that any changes made to the
|
||||
`AzureContainerAppsRC` task be made instead to the
|
||||
[`AzureContainerApps` task](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureContainerAppsV0),
|
||||
which will later be migrated over to this Release Candidate task and published immediately.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Trademarks
|
||||
## Issues and feedback
|
||||
|
||||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
|
||||
trademarks or logos is subject to and must follow
|
||||
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
|
||||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||||
Any use of third-party trademarks or logos are subject to those third-party's policies.
|
||||
For any issues and feedback for the _Release Candidate_ `AzureContainerAppsRC` task, please create a new issue
|
||||
[in this `container-apps-deploy-pipelines-task` repository](https://github.com/azure/container-apps-deploy-pipelines-task/issues).
|
||||
|
||||
For any issues and feedback for the _official_ `AzureContainerApps` task, please create a new issue
|
||||
[in the `azure-pipelines-tasks` repository](https://github.com/microsoft/azure-pipelines-tasks/issues).
|
||||
|
||||
Do you think there might be a security issue? Have you been phished or identified a security vulnerability? Please don't
|
||||
report it here - let us know by sending an email to secure@microsoft.com.
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"loc.friendlyName": "Azure Container Apps Deploy (Release Candidate)",
|
||||
"loc.helpMarkDown": "[Learn more about this task](http://github.com/microsoft/azure-pipelines-tasks/blob/master/Tasks/AzureContainerAppsV0/README.md)",
|
||||
"loc.description": "An Azure DevOps Task to build and deploy Azure Container Apps.",
|
||||
"loc.instanceNameFormat": "Azure Container Apps Deploy (Release Candidate)",
|
||||
"loc.releaseNotes": "Released new AzureContainerApps task for building and deploying Azure Container Apps.",
|
||||
"loc.input.label.cwd": "Working Directory",
|
||||
"loc.input.help.cwd": "Current working directory where the script is run. Empty is the root of the repo (build) or artifacts (release), which is $(System.DefaultWorkingDirectory)",
|
||||
"loc.input.label.appSourcePath": "Application source path",
|
||||
"loc.input.help.appSourcePath": "Absolute path on the runner of the source application code to be built. If not provided, the 'imageToDeploy' argument must be provided to ensure the Container App has an image to reference.",
|
||||
"loc.input.label.connectedServiceNameARM": "Azure Resource Manager connection",
|
||||
"loc.input.help.connectedServiceNameARM": "Select an Azure Resource Manager service connection for the deployment",
|
||||
"loc.input.label.acrName": "Azure Container Registry name",
|
||||
"loc.input.help.acrName": "The name of the Azure Container Registry that the runnable application image will be pushed to.",
|
||||
"loc.input.label.acrUsername": "Azure Container Registry username",
|
||||
"loc.input.help.acrUsername": "The username used to authenticate push requests to the provided Azure Contrainer Registry. If not provided, an access token will be generated via 'az acr login' and provided to 'docker login' to authenticate the requests.",
|
||||
"loc.input.label.acrPassword": "Azure Container Registry password",
|
||||
"loc.input.help.acrPassword": "The password used to authenticate push requests to the provided Azure Contrainer Registry. If not provided, an access token will be generated via 'az acr login' and provided to 'docker login' to authenticate the requests.",
|
||||
"loc.input.label.dockerfilePath": "Dockerfile path",
|
||||
"loc.input.help.dockerfilePath": "Relative path to the Dockerfile in the provided application source that should be used to build the image that is then pushed to ACR and deployed to the Container App. If not provided, this task will check if there is a file named 'Dockerfile' at the root of the provided application source and use that to build the image. Otherwise, the Oryx++ Builder will be used to create the image.",
|
||||
"loc.input.label.imageToBuild": "Docker image to build",
|
||||
"loc.input.help.imageToBuild": "The custom name of the image that is to be built, pushed to ACR and deployed to the Container App by this task. Note: this image name should include the ACR server; e.g., <acr-name>.azurecr.io/<repo>:<tag>. If this argument is not provided, a default image name will be constructed in the form of <acr-name>.azurecr.io/ado-task/container-app:<build-id>.<build-number>.",
|
||||
"loc.input.label.imageToDeploy": "Docker image to deploy",
|
||||
"loc.input.help.imageToDeploy": "The custom name of the image that has already been pushed to ACR and will be deployed to the Container App by this task. Note: the image name should include the ACR server; e.g., <acr-name>.azurecr.io/<repo>:<tag>. If this argument is not provided, the value provided (or determined) for the 'imageToBuild' argument will be used.",
|
||||
"loc.input.label.containerAppName": "Azure Container App name",
|
||||
"loc.input.help.containerAppName": "The name of the Azure Container App that will be created or updated. If not provided, this value will be in the form of ado-task-app-<build-id>-<build-number>.",
|
||||
"loc.input.label.resourceGroup": "Azure resource group name",
|
||||
"loc.input.help.resourceGroup": "The resource group that the Azure Container App will be created in. If not provided, this value will be in the form of <container-app-name>-rg.",
|
||||
"loc.input.label.containerAppEnvironment": "Azure Container App environment",
|
||||
"loc.input.help.containerAppEnvironment": "The name of the Azure Container App environment to use with the application. If not provided, an existing environment in the resource group of the Container App will be used, otherwise, an environment will be created in the format of <container-app-name>-env.",
|
||||
"loc.input.label.runtimeStack": "Application runtime stack",
|
||||
"loc.input.help.runtimeStack": "The platform version stack that the application runs in when deployed to the Azure Container App. This should be provided in the form of <platform>:<version>. If not provided, this value is determined by Oryx based on the contents of the provided application. Please view the following document for more information on the supported runtime stacks for Oryx: https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md",
|
||||
"loc.input.label.targetPort": "Application target port",
|
||||
"loc.input.help.targetPort": "The designated port for the application to run on. If not provided, this value is 80 for Python applications, and 8080 for all other supposed platforms.",
|
||||
"loc.messages.AcrAccessTokenAuthFailed": "Unable to authenticate against ACR instance '%s.azurecr.io' with access token.",
|
||||
"loc.messages.AcrAccessTokenLoginMessage": "Logging in to Azure Container Registry using access token to be generated via Azure CLI.",
|
||||
"loc.messages.AcrUsernamePasswordAuthFailed": "Unable to authenticate against ACR instance '%s.azurecr.io' with username/password.",
|
||||
"loc.messages.AcrUsernamePasswordLoginMessage": "Logging in to Azure Container Registry using provided acrUsername and acrPassword arguments.",
|
||||
"loc.messages.BashCommandFailed": "`Unable to run provided bash command '%s'.",
|
||||
"loc.messages.CheckForAppSourceDockerfileMessage": "No dockerfilePath argument provided; checking for 'Dockerfile' at the root of app source path '%s' to build image from.",
|
||||
"loc.messages.ContainerAppEnvironmentUsedMessage": "Using the provided containerAppEnvironment value provided '%s' when deploying the Container App.",
|
||||
"loc.messages.CreateImageWithBuilderFailed": "Unable to create runnable application image using Oryx++ Builder.",
|
||||
"loc.messages.CreateImageWithBuilderMessage": "No Dockerfile was provided or found for the application source; attempting to create a runnable application image using the Oryx++ Builder.",
|
||||
"loc.messages.CreateImageWithDockerfileFailed": "Unable to create runnable application image using provided or discovered Dockerfile.",
|
||||
"loc.messages.CreateImageWithDockerfileMessage": "A Dockerfile was provided or found for the application source; attempting to build the image from Dockerfile '%s'.",
|
||||
"loc.messages.CreateOrUpdateContainerAppFailed": "Unable to create or update Azure Container App via 'az container app' command.",
|
||||
"loc.messages.DefaultContainerAppNameMessage": "No containerAppName argument was provided; setting the name of the Container App to create/update to '%s'.",
|
||||
"loc.messages.DefaultImageToBuildMessage": "No imageToBuild argument was provided; setting the image to be built to '%s'.",
|
||||
"loc.messages.DefaultImageToDeployMessage": "No imageToDeploy argument was provided; setting the image to deploy to '%s'.",
|
||||
"loc.messages.DefaultResourceGroupMessage": "No resourceGroup argument was provided; setting the resource group for deployment to '%s'.",
|
||||
"loc.messages.DefaultRuntimeStackMessage": "No runtimeStack argument was provided; using the runtime stack that was found for the app '%s'.",
|
||||
"loc.messages.DefaultTargetPortMessage": "No targetPort argument was provided; using the target port '%s' for the application.",
|
||||
"loc.messages.DetermineRuntimeStackFailed": "`Unable to determine runtime stack from application source '%s'.",
|
||||
"loc.messages.ErrorCodeFormat": "Error Code: [%s]",
|
||||
"loc.messages.ErrorMessageFormat": "Error: %s",
|
||||
"loc.messages.FoundAppSourceDockerfileMessage": "Found existing Dockerfile in provided application source at path '%s'; image will be built from this Dockerfile.",
|
||||
"loc.messages.InvalidArgumentsMessage": "Either appSourcePath or imageToDeploy must be provided, but not both.",
|
||||
"loc.messages.PackCliInstallFailed": "Unable to install pack CLI.",
|
||||
"loc.messages.PushImageToAcrFailed": "Unable to push image '%s' to ACR.",
|
||||
"loc.messages.SetDefaultBuilderFailed": "Unable to set the Oryx++ Builder as the default builder."
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
import * as path from 'path';
|
||||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import * as fs from 'fs';
|
||||
import { Utility } from './src/Utility';
|
||||
import { ContainerAppHelper } from './src/ContainerAppHelper';
|
||||
import { AzureAuthenticationHelper } from './src/AzureAuthenticationHelper';
|
||||
import { ContainerRegistryHelper } from './src/ContainerRegistryHelper';
|
||||
|
||||
export class azurecontainerapps {
|
||||
|
||||
public static async runMain(): Promise<void> {
|
||||
// Set up AzureAuthenticationHelper for managing logging in and out of Azure CLI using provided service connection
|
||||
const authHelper: AzureAuthenticationHelper = new AzureAuthenticationHelper();
|
||||
try {
|
||||
// Set up localization
|
||||
tl.setResourcePath(path.join(__dirname, 'task.json'));
|
||||
|
||||
const cwd: string = tl.getPathInput('cwd', true, false);
|
||||
tl.mkdirP(cwd);
|
||||
tl.cd(cwd);
|
||||
|
||||
// Set build variables used later for default values
|
||||
const buildId = tl.getVariable('Build.BuildId');
|
||||
const buildNumber = tl.getVariable('Build.BuildNumber');
|
||||
|
||||
// Set up array to store optional arguments for the 'az containerapp up' command
|
||||
const optionalCmdArgs: string[] = [];
|
||||
|
||||
// Get the path to the application source to build and run
|
||||
const appSourcePath: string = tl.getInput('appSourcePath', false);
|
||||
|
||||
// Get the previously built image to deploy
|
||||
let imageToDeploy: string = tl.getInput('imageToDeploy', false);
|
||||
|
||||
// Ensure that either the application source or a previously built image is provided, but not both
|
||||
if ((!appSourcePath && !imageToDeploy) || (!!appSourcePath && !!imageToDeploy)) {
|
||||
tl.error(tl.loc('InvalidArgumentsMessage'));
|
||||
throw Error(tl.loc('InvalidArgumentsMessage'));
|
||||
}
|
||||
|
||||
// Install the pack CLI
|
||||
await new ContainerAppHelper().installPackCliAsync();
|
||||
|
||||
// Set the Azure CLI to dynamically install missing extensions
|
||||
new Utility().setAzureCliDynamicInstall();
|
||||
|
||||
// Log in to Azure with the service connection provided
|
||||
const connectedService: string = tl.getInput('connectedServiceNameARM', true);
|
||||
authHelper.loginAzureRM(connectedService);
|
||||
|
||||
const acrName: string = tl.getInput('acrName', true);
|
||||
const acrUsername: string = tl.getInput('acrUsername', false);
|
||||
const acrPassword: string = tl.getInput('acrPassword', false);
|
||||
|
||||
// Login to ACR if credentials were provided
|
||||
if (!!acrUsername && !!acrPassword) {
|
||||
console.log(tl.loc('AcrUsernamePasswordLoginMessage'));
|
||||
new ContainerRegistryHelper().loginAcrWithUsernamePassword(acrName, acrUsername, acrPassword);
|
||||
optionalCmdArgs.push(
|
||||
`--registry-server ${acrName}.azurecr.io`,
|
||||
`--registry-username ${acrUsername}`,
|
||||
`--registry-password ${acrPassword}`);
|
||||
}
|
||||
|
||||
// Login to ACR with access token if no credentials were provided
|
||||
if (!acrUsername || !acrPassword) {
|
||||
console.log(tl.loc('AcrAccessTokenLoginMessage'));
|
||||
await new ContainerRegistryHelper().loginAcrWithAccessTokenAsync(acrName);
|
||||
}
|
||||
|
||||
// Get Dockerfile to build, if provided, or check if one exists at the root of the provided application
|
||||
let dockerfilePath: string = tl.getInput('dockerfilePath', false);
|
||||
if (!!appSourcePath && !dockerfilePath) {
|
||||
console.log(tl.loc('CheckForAppSourceDockerfileMessage', appSourcePath));
|
||||
const rootDockerfilePath = path.join(appSourcePath, 'Dockerfile');
|
||||
if (fs.existsSync(rootDockerfilePath)) {
|
||||
console.log(tl.loc('FoundAppSourceDockerfileMessage', rootDockerfilePath));
|
||||
dockerfilePath = rootDockerfilePath;
|
||||
}
|
||||
} else if (!!appSourcePath && !!dockerfilePath) {
|
||||
dockerfilePath = path.join(appSourcePath, dockerfilePath);
|
||||
}
|
||||
|
||||
// Get the name of the image to build if it was provided, or generate it from build variables
|
||||
let imageToBuild: string = tl.getInput('imageToBuild', false);
|
||||
if (!imageToBuild) {
|
||||
imageToBuild = `${acrName}.azurecr.io/ado-task/container-app:${buildId}.${buildNumber}`;
|
||||
console.log(tl.loc('DefaultImageToBuildMessage', imageToBuild));
|
||||
}
|
||||
|
||||
// Get the name of the image to deploy if it was provided, or set it to the value of 'imageToBuild'
|
||||
let shouldBuildAndPushImage = false;
|
||||
if (!imageToDeploy) {
|
||||
imageToDeploy = imageToBuild;
|
||||
shouldBuildAndPushImage = true;
|
||||
console.log(tl.loc('DefaultImageToDeployMessage', imageToDeploy));
|
||||
}
|
||||
|
||||
// Get the Container App name if it was provided, or generate it from build variables
|
||||
let containerAppName: string = tl.getInput('containerAppName', false);
|
||||
if (!containerAppName) {
|
||||
containerAppName = `ado-task-app-${buildId}-${buildNumber}`;
|
||||
console.log(tl.loc('DefaultContainerAppNameMessage', containerAppName));
|
||||
}
|
||||
|
||||
// Get the resource group to deploy to if it was provided, or generate it from the Container App name
|
||||
let resourceGroup: string = tl.getInput('resourceGroup', false);
|
||||
if (!resourceGroup) {
|
||||
resourceGroup = `${containerAppName}-rg`;
|
||||
console.log(tl.loc('DefaultResourceGroupMessage', resourceGroup));
|
||||
}
|
||||
|
||||
// Get the Container App environment if provided
|
||||
const containerAppEnvironment: string = tl.getInput('containerAppEnvironment', false);
|
||||
if (!!containerAppEnvironment) {
|
||||
console.log(tl.loc('ContainerAppEnvironmentUsedMessage', containerAppEnvironment));
|
||||
optionalCmdArgs.push(`--environment ${containerAppEnvironment}`);
|
||||
}
|
||||
|
||||
// Get the runtime stack if provided, or determine it using Oryx
|
||||
let runtimeStack: string = tl.getInput('runtimeStack', false);
|
||||
if (!runtimeStack && shouldBuildAndPushImage) {
|
||||
runtimeStack = await new ContainerAppHelper().determineRuntimeStackAsync(appSourcePath);
|
||||
console.log(tl.loc('DefaultRuntimeStackMessage', runtimeStack));
|
||||
}
|
||||
|
||||
// Get the target port if provided, or determine it based on the application type
|
||||
let targetPort: string = tl.getInput('targetPort', false);
|
||||
if (!targetPort && !dockerfilePath) {
|
||||
if (!!runtimeStack && runtimeStack.startsWith('python:')) {
|
||||
targetPort = '80';
|
||||
} else {
|
||||
targetPort = '8080';
|
||||
}
|
||||
|
||||
console.log(tl.loc('DefaultTargetPortMessage', targetPort));
|
||||
}
|
||||
|
||||
// Add the target port to the optional arguments array
|
||||
if (!!targetPort) {
|
||||
optionalCmdArgs.push(`--target-port ${targetPort}`);
|
||||
}
|
||||
|
||||
// If using the Oryx++ Builder to produce an image, create a runnable application image
|
||||
if (!dockerfilePath && shouldBuildAndPushImage) {
|
||||
console.log(tl.loc('CreateImageWithBuilderMessage'));
|
||||
|
||||
// Set the Oryx++ Builder as the default builder locally
|
||||
new ContainerAppHelper().setDefaultBuilder();
|
||||
|
||||
// Create a runnable application image
|
||||
new ContainerAppHelper().createRunnableAppImage(imageToDeploy, appSourcePath, runtimeStack);
|
||||
}
|
||||
|
||||
// If a Dockerfile was found or provided, create a runnable application image from that
|
||||
if (!!dockerfilePath && shouldBuildAndPushImage) {
|
||||
console.log(tl.loc('CreateImageWithDockerfileMessage', dockerfilePath));
|
||||
new ContainerAppHelper().createRunnableAppImageFromDockerfile(imageToDeploy, appSourcePath, dockerfilePath);
|
||||
}
|
||||
|
||||
// Push image to Azure Container Registry
|
||||
if (shouldBuildAndPushImage) {
|
||||
new ContainerRegistryHelper().pushImageToAcr(imageToDeploy);
|
||||
}
|
||||
|
||||
// Create or update Azure Container App
|
||||
new ContainerAppHelper().createOrUpdateContainerApp(containerAppName, resourceGroup, imageToDeploy, optionalCmdArgs);
|
||||
} catch (err) {
|
||||
tl.setResult(tl.TaskResult.Failed, err.message);
|
||||
} finally {
|
||||
// Logout of Azure if logged in during this task session
|
||||
authHelper.logoutAzure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
azurecontainerapps.runMain();
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "azure-container-apps-rc",
|
||||
"private": true,
|
||||
"description": "Azure Pipelines Task (Release Candidate) for building and deploying Azure Container Apps.",
|
||||
"main": "azurecontainerapps.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/Azure/container-apps-deploy-pipelines-task.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Azure/container-apps-deploy-pipelines-task/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Azure/container-apps-deploy-pipelines-task#readme",
|
||||
"dependencies": {
|
||||
"@types/node": "^16.11.39",
|
||||
"@types/q": "1.0.7",
|
||||
"azure-pipelines-task-lib": "^4.0.0-preview",
|
||||
"@types/mocha": "^5.2.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "4.0.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import * as path from 'path';
|
||||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import * as fs from 'fs';
|
||||
import { Utility } from './Utility';
|
||||
|
||||
export class AzureAuthenticationHelper {
|
||||
|
||||
private sessionLoggedIn: boolean = false;
|
||||
private cliPasswordPath: string = null;
|
||||
|
||||
/**
|
||||
* Re-uses the loginAzureRM code implemented by the AzureCLIV2 Azure DevOps Task.
|
||||
* https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/AzureCLIV2/azureclitask.ts#L106-L150
|
||||
* @param connectedService - an Azure DevOps Service Connection that can authorize the connection to Azure
|
||||
*/
|
||||
public loginAzureRM(connectedService: string): void {
|
||||
const authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
|
||||
const subscriptionID: string = tl.getEndpointDataParameter(connectedService, 'SubscriptionID', true);
|
||||
|
||||
if (authScheme.toLowerCase() === 'serviceprincipal') {
|
||||
const authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true);
|
||||
let cliPassword: string = null;
|
||||
const servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, 'serviceprincipalid', false);
|
||||
const tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, 'tenantid', false);
|
||||
|
||||
if (authType === 'spnCertificate') {
|
||||
tl.debug('certificate based endpoint');
|
||||
const certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, 'servicePrincipalCertificate', false);
|
||||
cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem');
|
||||
fs.writeFileSync(cliPassword, certificateContent);
|
||||
this.cliPasswordPath = cliPassword;
|
||||
} else {
|
||||
tl.debug('key based endpoint');
|
||||
cliPassword = tl.getEndpointAuthorizationParameter(connectedService, 'serviceprincipalkey', false);
|
||||
}
|
||||
|
||||
const escapedCliPassword = cliPassword.replace(/"/g, '\\"');
|
||||
tl.setSecret(escapedCliPassword.replace(/\\/g, '\"'));
|
||||
//login using svn
|
||||
new Utility().throwIfError(
|
||||
tl.execSync('az', `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`),
|
||||
'Azure login failed');
|
||||
} else if (authScheme.toLowerCase() === 'managedserviceidentity') {
|
||||
//login using msi
|
||||
new Utility().throwIfError(
|
||||
tl.execSync('az', 'login --identity'),
|
||||
'Azure login failed using Managed Service Identity');
|
||||
} else {
|
||||
throw `Auth Scheme "${authScheme}" is not supported`;
|
||||
}
|
||||
|
||||
this.sessionLoggedIn = true;
|
||||
if (!!subscriptionID) {
|
||||
//set the subscription imported to the current subscription
|
||||
new Utility().throwIfError(
|
||||
tl.execSync('az', 'account set --subscription "' + subscriptionID + '"'),
|
||||
'Error in setting up subscription');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-uses the logoutAzure code implemented by the AzureCLIV2 Azure DevOps Task.
|
||||
* https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/AzureCLIV2/azureclitask.ts#L175-L183
|
||||
*/
|
||||
public logoutAzure() {
|
||||
if (this.cliPasswordPath) {
|
||||
tl.debug('Removing spn certificate file');
|
||||
tl.rmRF(this.cliPasswordPath);
|
||||
}
|
||||
|
||||
if (this.sessionLoggedIn) {
|
||||
tl.debug('Attempting to log out from Azure');
|
||||
try {
|
||||
tl.execSync('az', ' account clear');
|
||||
} catch (err) {
|
||||
// task should not fail if logout doesn`t occur
|
||||
tl.warning(`The following error occurred while logging out: ${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import * as tr from 'azure-pipelines-task-lib/toolrunner';
|
||||
|
||||
export class CommandHelper {
|
||||
|
||||
/**
|
||||
* Re-uses logic from the translateDirectoryPath code implemented by the BashV3 Azure DevOps Task.
|
||||
* https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/BashV3/bash.ts#L7-L30
|
||||
* @param command - the command to execute in Bash
|
||||
* @param cwd - the current working directory; if not provided, the 'cwd' input will be used
|
||||
* @returns the string output from the command
|
||||
*/
|
||||
public async execBashCommandAsync(command: string, cwd?: string): Promise<string> {
|
||||
try {
|
||||
if (!cwd) {
|
||||
cwd = tl.getPathInput('cwd', true, false);
|
||||
}
|
||||
|
||||
const bashPath: string = tl.which('bash', true);
|
||||
const bashCmd = tl.tool(bashPath)
|
||||
.arg('-c')
|
||||
.arg(command);
|
||||
const bashOptions = <tr.IExecOptions> {
|
||||
cwd: cwd,
|
||||
failOnStdErr: true,
|
||||
errStream: process.stderr,
|
||||
outStream: process.stdout,
|
||||
ignoreReturnCode: false
|
||||
};
|
||||
let bashOutput = '';
|
||||
bashCmd.on('stdout', (data) => {
|
||||
bashOutput += data.toString();
|
||||
});
|
||||
await bashCmd.exec(bashOptions);
|
||||
return bashOutput.trim();
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('BashCommandFailed', command));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import { CommandHelper } from './CommandHelper';
|
||||
|
||||
const ORYX_CLI_IMAGE: string = 'cormtestacr.azurecr.io/oryx/cli:latest';
|
||||
const ORYX_BUILDER_IMAGE: string = 'cormtestacr.azurecr.io/builder:latest';
|
||||
|
||||
export class ContainerAppHelper {
|
||||
/**
|
||||
* Creates or updates an Azure Container App based from an image that was previously built.
|
||||
* @param containerAppName - the name of the Container App
|
||||
* @param resourceGroup - the resource group that the Container App is found in
|
||||
* @param imageToDeploy - the name of the runnable application image that the Container App will be based from
|
||||
* @param optionalCmdArgs - a set of optional command line arguments
|
||||
*/
|
||||
public createOrUpdateContainerApp(
|
||||
containerAppName: string,
|
||||
resourceGroup: string,
|
||||
imageToDeploy: string,
|
||||
optionalCmdArgs: string[]) {
|
||||
tl.debug(`Attempting to create/update Container App with name "${containerAppName}" in resource group "${resourceGroup}" based from image "${imageToDeploy}"`);
|
||||
try {
|
||||
let command = `containerapp up --name ${containerAppName} --resource-group ${resourceGroup} --image ${imageToDeploy}`;
|
||||
optionalCmdArgs.forEach(function (val: string) {
|
||||
command += ` ${val}`;
|
||||
});
|
||||
|
||||
tl.execSync('az', command);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('CreateOrUpdateContainerAppFailed'));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the Oryx++ Builder, creates a runnable application image from the provided application source.
|
||||
* @param imageToDeploy - the name of the runnable application image that is created and can be later deployed
|
||||
* @param appSourcePath - the path to the application source on the machine
|
||||
* @param runtimeStack - the runtime stack to use in the image layer that runs the application
|
||||
*/
|
||||
public createRunnableAppImage(
|
||||
imageToDeploy: string,
|
||||
appSourcePath: string,
|
||||
runtimeStack: string) {
|
||||
tl.debug(`Attempting to create a runnable application image using the Oryx++ Builder with image name "${imageToDeploy}"`);
|
||||
try {
|
||||
tl.execSync('pack', `build ${imageToDeploy} --path ${appSourcePath} --builder ${ORYX_BUILDER_IMAGE} --run-image mcr.microsoft.com/oryx/${runtimeStack} --env "CALLER_ID=azure-pipelines-v0"`);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('CreateImageWithBuilderFailed'));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using a Dockerfile that was provided or found at the root of the application source,
|
||||
* creates a runable application image.
|
||||
* @param imageToDeploy - the name of the runnable application image that is created and can be later deployed
|
||||
* @param appSourcePath - the path to the application source on the machine
|
||||
* @param dockerfilePath - the path to the Dockerfile to build and tag with the provided image name
|
||||
*/
|
||||
public createRunnableAppImageFromDockerfile(
|
||||
imageToDeploy: string,
|
||||
appSourcePath: string,
|
||||
dockerfilePath: string) {
|
||||
tl.debug(`Attempting to create a runnable application image from the provided/found Dockerfile "${dockerfilePath}" with image name "${imageToDeploy}"`);
|
||||
try {
|
||||
tl.execSync('docker', `build --tag ${imageToDeploy} --file ${dockerfilePath} ${appSourcePath}`);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('CreateImageWithDockerfileFailed'));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the runtime stack to use for the runnable application image.
|
||||
* @param appSourcePath - the path to the application source on the machine
|
||||
* @returns a string representing the runtime stack that can be used for the Oryx MCR runtime images
|
||||
*/
|
||||
public async determineRuntimeStackAsync(appSourcePath: string): Promise<string> {
|
||||
tl.debug('Attempting to determine the runtime stack needed for the provided application source');
|
||||
try {
|
||||
// Use 'oryx dockerfile' command to determine the runtime stack to use and write it to a temp file
|
||||
const dockerCommand: string = `run --rm -v ${appSourcePath}:/app ${ORYX_CLI_IMAGE} /bin/bash -c "oryx dockerfile /app | head -n 1 | sed 's/ARG RUNTIME=//' >> /app/oryx-runtime.txt"`;
|
||||
tl.execSync('docker', dockerCommand);
|
||||
|
||||
// Read the temp file to get the runtime stack into a variable
|
||||
let command: string = `head -n 1 ${appSourcePath}/oryx-runtime.txt`;
|
||||
const runtimeStack = await new CommandHelper().execBashCommandAsync(command);
|
||||
|
||||
// Delete the temp file
|
||||
command = `rm ${appSourcePath}/oryx-runtime.txt`;
|
||||
await new CommandHelper().execBashCommandAsync(command);
|
||||
|
||||
return runtimeStack;
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('DetermineRuntimeStackFailed', appSourcePath));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default builder on the machine to the Oryx++ Builder to prevent an exception from being thrown due
|
||||
* to no default builder set.
|
||||
*/
|
||||
public setDefaultBuilder() {
|
||||
tl.debug('Setting the Oryx++ Builder as the default builder via the pack CLI');
|
||||
try {
|
||||
tl.execSync('pack', `config default-builder ${ORYX_BUILDER_IMAGE}`);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('SetDefaultBuilderFailed'));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the pack CLI that will be used to build a runnable application image.
|
||||
* For more information about the pack CLI can be found here: https://buildpacks.io/docs/tools/pack/
|
||||
*/
|
||||
public async installPackCliAsync() {
|
||||
tl.debug('Attempting to install the pack CLI');
|
||||
try {
|
||||
const command: string = '(curl -sSL \"https://github.com/buildpacks/pack/releases/download/v0.27.0/pack-v0.27.0-linux.tgz\" | ' +
|
||||
'tar -C /usr/local/bin/ --no-same-owner -xzv pack)';
|
||||
await new CommandHelper().execBashCommandAsync(command);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('PackCliInstallFailed'));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import * as child from 'child_process';
|
||||
import { CommandHelper } from './CommandHelper';
|
||||
|
||||
export class ContainerRegistryHelper {
|
||||
/**
|
||||
* Authorizes Docker to make calls to the provided ACR instance using username and password.
|
||||
* @param acrName - the name of the ACR instance to authenticate calls to
|
||||
* @param acrUsername - the username for authentication
|
||||
* @param acrPassword - the password for authentication
|
||||
*/
|
||||
public loginAcrWithUsernamePassword(acrName: string, acrUsername: string, acrPassword: string) {
|
||||
tl.debug(`Attempting to log in to ACR instance "${acrName}" with username and password credentials`);
|
||||
try {
|
||||
child.execSync(
|
||||
`docker login --password-stdin --username ${acrUsername} ${acrName}.azurecr.io`,
|
||||
{ input: acrPassword });
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('AcrUsernamePasswordAuthFailed', acrName));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorizes Docker to make calls to the provided ACR instance using an access token that is generated via
|
||||
* the 'az acr login --expose-token' command.
|
||||
* @param acrName - the name of the ACR instance to authenticate calls to.
|
||||
*/
|
||||
public async loginAcrWithAccessTokenAsync(acrName: string) {
|
||||
tl.debug(`Attempting to log in to ACR instance "${acrName}" with access token`);
|
||||
try {
|
||||
const command: string = `CA_ADO_TASK_ACR_ACCESS_TOKEN=$(az acr login --name ${acrName} --output json --expose-token --only-show-errors | jq -r '.accessToken'); docker login ${acrName}.azurecr.io -u 00000000-0000-0000-0000-000000000000 -p $CA_ADO_TASK_ACR_ACCESS_TOKEN > /dev/null 2>&1`;
|
||||
await new CommandHelper().execBashCommandAsync(command);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('AcrAccessTokenAuthFailed', acrName));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an image to the ACR instance that was previously authenticated against.
|
||||
* @param imageToPush - the name of the image to push to ACR
|
||||
*/
|
||||
public pushImageToAcr(imageToPush: string) {
|
||||
tl.debug(`Attempting to push image "${imageToPush}" to ACR`);
|
||||
try {
|
||||
tl.execSync('docker', `push ${imageToPush}`);
|
||||
} catch (err) {
|
||||
tl.error(tl.loc('PushImageToAcrFailed', imageToPush));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import * as tl from 'azure-pipelines-task-lib/task';
|
||||
import { IExecSyncResult } from 'azure-pipelines-task-lib/toolrunner';
|
||||
|
||||
export class Utility {
|
||||
/**
|
||||
* Re-uses the throwIfError code implemented by the AzureCLIV2 Azure DevOps Task.
|
||||
* https://github.com/microsoft/azure-pipelines-tasks/blob/b82a8e69eb862d1a9d291af70da2e62ee69270df/Tasks/AzureCLIV2/src/Utility.ts#L79-L87
|
||||
* @param resultOfToolExecution - the result of the command that was previously executed
|
||||
* @param errormsg - the error message to display if the command failed
|
||||
*/
|
||||
public throwIfError(resultOfToolExecution: IExecSyncResult, errormsg?: string): void {
|
||||
if (resultOfToolExecution.code !== 0) {
|
||||
tl.error(tl.loc('ErrorCodeFormat', resultOfToolExecution.code));
|
||||
if (errormsg) {
|
||||
tl.error(tl.loc('ErrorMessageFormat', errormsg));
|
||||
}
|
||||
throw resultOfToolExecution;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Azure CLI to dynamically install extensions that are missing. In this case, we care about the
|
||||
* Azure Container Apps module being dynamically installed while it's still in preview.
|
||||
*/
|
||||
public setAzureCliDynamicInstall() {
|
||||
this.throwIfError(
|
||||
tl.execSync('az', 'config set extension.use_dynamic_install=yes_without_prompt'),
|
||||
'Unable to set the Azure CLI to dynamically install missing extensions');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
|
||||
"id": "04e660e2-4ef0-4169-9c5d-23c0579757f6",
|
||||
"name": "AzureContainerAppsRC",
|
||||
"friendlyName": "Azure Container Apps Deploy (Release Candidate)",
|
||||
"description": "An Azure DevOps Task to build and deploy Azure Container Apps.",
|
||||
"author": "Microsoft Corporation",
|
||||
"helpMarkDown": "[Learn more about this task](http://github.com/Azure/container-apps-deploy-pipelines-task)",
|
||||
"releaseNotes": "Released new AzureContainerAppsRC task for building and deploying Azure Container Apps.",
|
||||
"category": "Deploy",
|
||||
"visibility": [
|
||||
"Build",
|
||||
"Release"
|
||||
],
|
||||
"runsOn": [
|
||||
"Agent",
|
||||
"DeploymentGroup"
|
||||
],
|
||||
"version": {
|
||||
"Major": 0,
|
||||
"Minor": 1,
|
||||
"Patch": 7
|
||||
},
|
||||
"minimumAgentVersion": "2.144.0",
|
||||
"instanceNameFormat": "Azure Container Apps Deploy (Release Candidate)",
|
||||
"showEnvironmentVariables": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "cwd",
|
||||
"aliases": [
|
||||
"workingDirectory"
|
||||
],
|
||||
"type": "filePath",
|
||||
"label": "Working Directory",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"helpMarkDown": "Current working directory where the script is run. Empty is the root of the repo (build) or artifacts (release), which is $(System.DefaultWorkingDirectory)",
|
||||
"groupName": "advanced"
|
||||
},
|
||||
{
|
||||
"name": "appSourcePath",
|
||||
"type": "string",
|
||||
"label": "Application source path",
|
||||
"required": false,
|
||||
"helpMarkDown": "Absolute path on the runner of the source application code to be built. If not provided, the 'imageToDeploy' argument must be provided to ensure the Container App has an image to reference."
|
||||
},
|
||||
{
|
||||
"name": "connectedServiceNameARM",
|
||||
"aliases": [
|
||||
"azureSubscription"
|
||||
],
|
||||
"type": "connectedService:AzureRM",
|
||||
"label": "Azure Resource Manager connection",
|
||||
"required": true,
|
||||
"helpMarkDown": "Select an Azure Resource Manager service connection for the deployment",
|
||||
"properties": {
|
||||
"EndpointFilterRule": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "acrName",
|
||||
"type": "string",
|
||||
"label": "Azure Container Registry name",
|
||||
"required": true,
|
||||
"helpMarkDown": "The name of the Azure Container Registry that the runnable application image will be pushed to."
|
||||
},
|
||||
{
|
||||
"name": "acrUsername",
|
||||
"type": "string",
|
||||
"label": "Azure Container Registry username",
|
||||
"required": false,
|
||||
"helpMarkDown": "The username used to authenticate push requests to the provided Azure Contrainer Registry. If not provided, an access token will be generated via 'az acr login' and provided to 'docker login' to authenticate the requests."
|
||||
},
|
||||
{
|
||||
"name": "acrPassword",
|
||||
"type": "string",
|
||||
"label": "Azure Container Registry password",
|
||||
"required": false,
|
||||
"helpMarkDown": "The password used to authenticate push requests to the provided Azure Contrainer Registry. If not provided, an access token will be generated via 'az acr login' and provided to 'docker login' to authenticate the requests."
|
||||
},
|
||||
{
|
||||
"name": "dockerfilePath",
|
||||
"type": "string",
|
||||
"label": "Dockerfile path",
|
||||
"required": false,
|
||||
"helpMarkDown": "Relative path to the Dockerfile in the provided application source that should be used to build the image that is then pushed to ACR and deployed to the Container App. If not provided, this task will check if there is a file named 'Dockerfile' at the root of the provided application source and use that to build the image. Otherwise, the Oryx++ Builder will be used to create the image."
|
||||
},
|
||||
{
|
||||
"name": "imageToBuild",
|
||||
"type": "string",
|
||||
"label": "Docker image to build",
|
||||
"required": false,
|
||||
"helpMarkDown": "The custom name of the image that is to be built, pushed to ACR and deployed to the Container App by this task. Note: this image name should include the ACR server; e.g., <acr-name>.azurecr.io/<repo>:<tag>. If this argument is not provided, a default image name will be constructed in the form of <acr-name>.azurecr.io/ado-task/container-app:<build-id>.<build-number>."
|
||||
},
|
||||
{
|
||||
"name": "imageToDeploy",
|
||||
"type": "string",
|
||||
"label": "Docker image to deploy",
|
||||
"required": false,
|
||||
"helpMarkDown": "The custom name of the image that has already been pushed to ACR and will be deployed to the Container App by this task. Note: the image name should include the ACR server; e.g., <acr-name>.azurecr.io/<repo>:<tag>. If this argument is not provided, the value provided (or determined) for the 'imageToBuild' argument will be used."
|
||||
},
|
||||
{
|
||||
"name": "containerAppName",
|
||||
"type": "string",
|
||||
"label": "Azure Container App name",
|
||||
"required": false,
|
||||
"helpMarkDown": "The name of the Azure Container App that will be created or updated. If not provided, this value will be in the form of ado-task-app-<build-id>-<build-number>."
|
||||
},
|
||||
{
|
||||
"name": "resourceGroup",
|
||||
"type": "string",
|
||||
"label": "Azure resource group name",
|
||||
"required": false,
|
||||
"helpMarkDown": "The resource group that the Azure Container App will be created in. If not provided, this value will be in the form of <container-app-name>-rg."
|
||||
},
|
||||
{
|
||||
"name": "containerAppEnvironment",
|
||||
"type": "string",
|
||||
"label": "Azure Container App environment",
|
||||
"required": false,
|
||||
"helpMarkDown": "The name of the Azure Container App environment to use with the application. If not provided, an existing environment in the resource group of the Container App will be used, otherwise, an environment will be created in the format of <container-app-name>-env."
|
||||
},
|
||||
{
|
||||
"name": "runtimeStack",
|
||||
"type": "string",
|
||||
"label": "Application runtime stack",
|
||||
"required": false,
|
||||
"helpMarkDown": "The platform version stack that the application runs in when deployed to the Azure Container App. This should be provided in the form of <platform>:<version>. If not provided, this value is determined by Oryx based on the contents of the provided application. Please view the following document for more information on the supported runtime stacks for Oryx: https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md"
|
||||
},
|
||||
{
|
||||
"name": "targetPort",
|
||||
"type": "string",
|
||||
"label": "Application target port",
|
||||
"required": false,
|
||||
"helpMarkDown": "The designated port for the application to run on. If not provided, this value is 80 for Python applications, and 8080 for all other supposed platforms."
|
||||
}
|
||||
],
|
||||
"execution": {
|
||||
"Node10": {
|
||||
"target": "azurecontainerapps.js"
|
||||
},
|
||||
"Node16": {
|
||||
"target": "azurecontainerapps.js"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"AcrAccessTokenAuthFailed": "Unable to authenticate against ACR instance '%s.azurecr.io' with access token.",
|
||||
"AcrAccessTokenLoginMessage": "Logging in to Azure Container Registry using access token to be generated via Azure CLI.",
|
||||
"AcrUsernamePasswordAuthFailed": "Unable to authenticate against ACR instance '%s.azurecr.io' with username/password.",
|
||||
"AcrUsernamePasswordLoginMessage": "Logging in to Azure Container Registry using provided acrUsername and acrPassword arguments.",
|
||||
"BashCommandFailed": "`Unable to run provided bash command '%s'.",
|
||||
"CheckForAppSourceDockerfileMessage": "No dockerfilePath argument provided; checking for 'Dockerfile' at the root of app source path '%s' to build image from.",
|
||||
"ContainerAppEnvironmentUsedMessage": "Using the provided containerAppEnvironment value provided '%s' when deploying the Container App.",
|
||||
"CreateImageWithBuilderFailed": "Unable to create runnable application image using Oryx++ Builder.",
|
||||
"CreateImageWithBuilderMessage": "No Dockerfile was provided or found for the application source; attempting to create a runnable application image using the Oryx++ Builder.",
|
||||
"CreateImageWithDockerfileFailed": "Unable to create runnable application image using provided or discovered Dockerfile.",
|
||||
"CreateImageWithDockerfileMessage": "A Dockerfile was provided or found for the application source; attempting to build the image from Dockerfile '%s'.",
|
||||
"CreateOrUpdateContainerAppFailed": "Unable to create or update Azure Container App via 'az container app' command.",
|
||||
"DefaultContainerAppNameMessage": "No containerAppName argument was provided; setting the name of the Container App to create/update to '%s'.",
|
||||
"DefaultImageToBuildMessage": "No imageToBuild argument was provided; setting the image to be built to '%s'.",
|
||||
"DefaultImageToDeployMessage": "No imageToDeploy argument was provided; setting the image to deploy to '%s'.",
|
||||
"DefaultResourceGroupMessage": "No resourceGroup argument was provided; setting the resource group for deployment to '%s'.",
|
||||
"DefaultRuntimeStackMessage": "No runtimeStack argument was provided; using the runtime stack that was found for the app '%s'.",
|
||||
"DefaultTargetPortMessage": "No targetPort argument was provided; using the target port '%s' for the application.",
|
||||
"DetermineRuntimeStackFailed": "`Unable to determine runtime stack from application source '%s'.",
|
||||
"ErrorCodeFormat": "Error Code: [%s]",
|
||||
"ErrorMessageFormat": "Error: %s",
|
||||
"FoundAppSourceDockerfileMessage": "Found existing Dockerfile in provided application source at path '%s'; image will be built from this Dockerfile.",
|
||||
"InvalidArgumentsMessage": "Either appSourcePath or imageToDeploy must be provided, but not both.",
|
||||
"PackCliInstallFailed": "Unable to install pack CLI.",
|
||||
"PushImageToAcrFailed": "Unable to push image '%s' to ACR.",
|
||||
"SetDefaultBuilderFailed": "Unable to set the Oryx++ Builder as the default builder."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
|
||||
"id": "04e660e2-4ef0-4169-9c5d-23c0579757f6",
|
||||
"name": "AzureContainerAppsRC",
|
||||
"friendlyName": "ms-resource:loc.friendlyName",
|
||||
"description": "ms-resource:loc.description",
|
||||
"author": "Microsoft Corporation",
|
||||
"helpMarkDown": "ms-resource:loc.helpMarkDown",
|
||||
"releaseNotes": "ms-resource:loc.releaseNotes",
|
||||
"category": "Deploy",
|
||||
"visibility": [
|
||||
"Build",
|
||||
"Release"
|
||||
],
|
||||
"runsOn": [
|
||||
"Agent",
|
||||
"DeploymentGroup"
|
||||
],
|
||||
"version": {
|
||||
"Major": 0,
|
||||
"Minor": 1,
|
||||
"Patch": 7
|
||||
},
|
||||
"minimumAgentVersion": "2.144.0",
|
||||
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
|
||||
"showEnvironmentVariables": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "cwd",
|
||||
"aliases": [
|
||||
"workingDirectory"
|
||||
],
|
||||
"type": "filePath",
|
||||
"label": "ms-resource:loc.input.label.cwd",
|
||||
"defaultValue": "",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.cwd",
|
||||
"groupName": "advanced"
|
||||
},
|
||||
{
|
||||
"name": "appSourcePath",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.appSourcePath",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.appSourcePath"
|
||||
},
|
||||
{
|
||||
"name": "connectedServiceNameARM",
|
||||
"aliases": [
|
||||
"azureSubscription"
|
||||
],
|
||||
"type": "connectedService:AzureRM",
|
||||
"label": "ms-resource:loc.input.label.connectedServiceNameARM",
|
||||
"required": true,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.connectedServiceNameARM",
|
||||
"properties": {
|
||||
"EndpointFilterRule": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "acrName",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.acrName",
|
||||
"required": true,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.acrName"
|
||||
},
|
||||
{
|
||||
"name": "acrUsername",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.acrUsername",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.acrUsername"
|
||||
},
|
||||
{
|
||||
"name": "acrPassword",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.acrPassword",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.acrPassword"
|
||||
},
|
||||
{
|
||||
"name": "dockerfilePath",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.dockerfilePath",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.dockerfilePath"
|
||||
},
|
||||
{
|
||||
"name": "imageToBuild",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.imageToBuild",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.imageToBuild"
|
||||
},
|
||||
{
|
||||
"name": "imageToDeploy",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.imageToDeploy",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.imageToDeploy"
|
||||
},
|
||||
{
|
||||
"name": "containerAppName",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.containerAppName",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.containerAppName"
|
||||
},
|
||||
{
|
||||
"name": "resourceGroup",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.resourceGroup",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.resourceGroup"
|
||||
},
|
||||
{
|
||||
"name": "containerAppEnvironment",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.containerAppEnvironment",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.containerAppEnvironment"
|
||||
},
|
||||
{
|
||||
"name": "runtimeStack",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.runtimeStack",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.runtimeStack"
|
||||
},
|
||||
{
|
||||
"name": "targetPort",
|
||||
"type": "string",
|
||||
"label": "ms-resource:loc.input.label.targetPort",
|
||||
"required": false,
|
||||
"helpMarkDown": "ms-resource:loc.input.help.targetPort"
|
||||
}
|
||||
],
|
||||
"execution": {
|
||||
"Node10": {
|
||||
"target": "azurecontainerapps.js"
|
||||
},
|
||||
"Node16": {
|
||||
"target": "azurecontainerapps.js"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"AcrAccessTokenAuthFailed": "ms-resource:loc.messages.AcrAccessTokenAuthFailed",
|
||||
"AcrAccessTokenLoginMessage": "ms-resource:loc.messages.AcrAccessTokenLoginMessage",
|
||||
"AcrUsernamePasswordAuthFailed": "ms-resource:loc.messages.AcrUsernamePasswordAuthFailed",
|
||||
"AcrUsernamePasswordLoginMessage": "ms-resource:loc.messages.AcrUsernamePasswordLoginMessage",
|
||||
"BashCommandFailed": "ms-resource:loc.messages.BashCommandFailed",
|
||||
"CheckForAppSourceDockerfileMessage": "ms-resource:loc.messages.CheckForAppSourceDockerfileMessage",
|
||||
"ContainerAppEnvironmentUsedMessage": "ms-resource:loc.messages.ContainerAppEnvironmentUsedMessage",
|
||||
"CreateImageWithBuilderFailed": "ms-resource:loc.messages.CreateImageWithBuilderFailed",
|
||||
"CreateImageWithBuilderMessage": "ms-resource:loc.messages.CreateImageWithBuilderMessage",
|
||||
"CreateImageWithDockerfileFailed": "ms-resource:loc.messages.CreateImageWithDockerfileFailed",
|
||||
"CreateImageWithDockerfileMessage": "ms-resource:loc.messages.CreateImageWithDockerfileMessage",
|
||||
"CreateOrUpdateContainerAppFailed": "ms-resource:loc.messages.CreateOrUpdateContainerAppFailed",
|
||||
"DefaultContainerAppNameMessage": "ms-resource:loc.messages.DefaultContainerAppNameMessage",
|
||||
"DefaultImageToBuildMessage": "ms-resource:loc.messages.DefaultImageToBuildMessage",
|
||||
"DefaultImageToDeployMessage": "ms-resource:loc.messages.DefaultImageToDeployMessage",
|
||||
"DefaultResourceGroupMessage": "ms-resource:loc.messages.DefaultResourceGroupMessage",
|
||||
"DefaultRuntimeStackMessage": "ms-resource:loc.messages.DefaultRuntimeStackMessage",
|
||||
"DefaultTargetPortMessage": "ms-resource:loc.messages.DefaultTargetPortMessage",
|
||||
"DetermineRuntimeStackFailed": "ms-resource:loc.messages.DetermineRuntimeStackFailed",
|
||||
"ErrorCodeFormat": "ms-resource:loc.messages.ErrorCodeFormat",
|
||||
"ErrorMessageFormat": "ms-resource:loc.messages.ErrorMessageFormat",
|
||||
"FoundAppSourceDockerfileMessage": "ms-resource:loc.messages.FoundAppSourceDockerfileMessage",
|
||||
"InvalidArgumentsMessage": "ms-resource:loc.messages.InvalidArgumentsMessage",
|
||||
"PackCliInstallFailed": "ms-resource:loc.messages.PackCliInstallFailed",
|
||||
"PushImageToAcrFailed": "ms-resource:loc.messages.PushImageToAcrFailed",
|
||||
"SetDefaultBuilderFailed": "ms-resource:loc.messages.SetDefaultBuilderFailed"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.5 KiB |
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
# Azure Container Apps Build and Deploy (Release Candidate)
|
||||
|
||||
## Important note
|
||||
|
||||
The `AzureContainerAppsRC` task is the _Release Candidate (RC)_ version of the `AzureContainerApps` task that ships out
|
||||
of the box with Azure Pipelines, which can be found
|
||||
[here](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureContainerAppsV0). The intended purpose
|
||||
of this Release Candidate task is to offer users immediate early access to features, bug fixes and patches that will
|
||||
eventually be rolled out in the official `AzureContainerApps` task at the end of every three week sprint.
|
||||
|
||||
## Description
|
||||
|
||||
This Azure Pipelines Task allows users to easily deploy their application source to an
|
||||
[Azure Container App](https://azure.microsoft.com/en-us/services/container-apps/) in their Azure Pipelines workflow by
|
||||
either providing a previously built image, a Dockerfile that an image can be built from, or using a builder to create a
|
||||
runnable application image for the user.
|
||||
|
||||
If no Dockerfile is found or provided in the provided application source, the following steps are performed by this task:
|
||||
|
||||
- Uses the Oryx++ Builder to build the application source using [Oryx](https://github.com/microsoft/Oryx) to produce a
|
||||
runnable application image
|
||||
- Pushes this runnable application image to the provided Azure Container Registry
|
||||
- Creates or updates a Container App based on this image
|
||||
|
||||
If a Dockerfile is found or discovered in the application source, the builder won't be used and the image will be built
|
||||
with a call to `docker build` and the Container App will be created or updated based on this image.
|
||||
|
||||
If a previously built image has already been pushed to the ACR instance and is provided to this task, no application
|
||||
source is required and the image will be used when creating or updating the Container App.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Prior to running this task, Azure resources and an Azure DevOps service connection are either required or optional
|
||||
depending on the arguments provided to this task.
|
||||
|
||||
### Azure DevOps Service Connection
|
||||
|
||||
To deploy to Azure, an Azure subscription has to be linked to Team Foundation Server or to Azure Pipelines using the
|
||||
Services tab in the settings section. Add the Azure subscription to use in the Build or Release Management definition by
|
||||
opening the Account Administration screen (gear icon on the top-right of the screen) and then click on the Services Tab.
|
||||
|
||||
Create the [ARM](https://azure.microsoft.com/en-in/documentation/articles/resource-group-overview/) service endpoint and
|
||||
use the **'Azure Resource Manager'** endpoint type; for more information on creating service connections, please follow
|
||||
[this document](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints).
|
||||
|
||||
### Azure CLI
|
||||
|
||||
This task requires that the Azure CLI is installed on the Azure Pipelines agent to execute a variety of commands
|
||||
throughout the execution of the task. For more information on how to install the Azure CLI on the agent, please see
|
||||
[this document](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli). If an agent is already running on the
|
||||
machine on which the Azure CLI is installed, ensure that you restart the agent so that all relevant environment
|
||||
variables are updated.
|
||||
|
||||
### Docker
|
||||
|
||||
This task requires that Docker is installed on the Azure Pipelines agent to push images to the provided Azure Container
|
||||
Registry. For more information on how to install Docker on the agent, please see
|
||||
[this document](https://docs.docker.com/get-docker/).
|
||||
|
||||
### Azure Container Registry
|
||||
|
||||
An [Azure Container Registry](https://azure.microsoft.com/en-us/products/container-registry/) must exist that the user
|
||||
is able to push container images to. This task will leverage the Azure Container Registry to either push a built
|
||||
runnable application image to and/or deploy a Container App from.
|
||||
|
||||
The name of the Azure Container Registry is required via the `acrName` argument.
|
||||
|
||||
The user can also provide values for the `acrUsername` and `acrPassword` arguments that will authenticate calls to the
|
||||
Azure Container Registry instance; if not provided, an access token will be generated via the Azure CLI that will
|
||||
authenticate the calls instead.
|
||||
|
||||
### Azure Container App environment
|
||||
|
||||
An [Azure Container App environment](https://docs.microsoft.com/en-us/azure/container-apps/environment) is recommended
|
||||
to have been previously created by the user to improve the performance of the task. If no environment has been
|
||||
created before, or if an environment cannot be found in the resource group that is being used to host the created
|
||||
Container App, then an environment will be created by as a part of the `az containerapp up` command, which may take
|
||||
additional time.
|
||||
|
||||
## Arguments
|
||||
|
||||
Below are the arguments that can be provided to this task.
|
||||
|
||||
| Argument name | Required | Description |
|
||||
| ------------------------- | -------- | ----------- |
|
||||
| `connectedServiceNameARM` | Yes | Service connection linked to the user's Azure Subscription where the Container App will be created/updated. This service connection _must_ have proper permissions to make these changes within the subscription (_e.g._, Contributor role). |
|
||||
| `appSourcePath` | No | Absolute path on the Azure Pipelines agent of the source application code to be built. |
|
||||
| `acrName` | Yes | The name of the Azure Container Registry that the runnable application image will be pushed to. |
|
||||
| `acrUsername` | No | The username used to authenticate push requests to the provided Azure Container Registry. If not provided, an access token will be generated via "az acr login" and provided to "docker login" to authenticate the requests. |
|
||||
| `acrPassword` | No | The password used to authenticate push requests to the provided Azure Container Registry. If not provided, an access token will be generated via "az acr login" and provided to "docker login" to authenticate the requests. |
|
||||
| `dockerfilePath` | No | Relative path (_without file prefixes, see example below_) to the Dockerfile in the provided application source that should be used to build the image that is then pushed to ACR and deployed to the Container App. If not provided, this action will check if there is a file named `Dockerfile` in the provided application source and use that to build the image. Otherwise, the Oryx++ Builder will be used to create the image. |
|
||||
| `imageToBuild` | No | The custom name of the image that is to be built, pushed to ACR and deployed to the Container App by this action. _Note_: this image name should include the ACR server; _e.g._, `<acr-name>.azurecr.io/<repo>:<tag>`. If this argument is not provided, a default image name will be constructed in the form `<acr-name>.azurecr.io/ado-task/container-app:<build-id>.<build-number>` |
|
||||
| `imageToDeploy` | No | The custom name of the image that has already been pushed to ACR and will be deployed to the Container App by this action. _Note_: this image name should include the ACR server; _e.g._, `<acr-name>.azurecr.io/<repo>:<tag>`. If this argument is not provided, the value provided (or determined) for the `imageToBuild` argument will be used. |
|
||||
| `containerAppName` | No | The name of the Container App that will be created or updated. If not provided, this value will be `ado-task-app-<build-id>-<build-number>`. |
|
||||
| `resourceGroup` | No | The resource group that the Container App will be created in, or currently exists in. If not provided, this value will be `<container-app-name>-rg`. |
|
||||
| `containerAppEnvironment` | No | The name of the Container App environment to use with the application. If not provided, an existing environment in the resource group of the Container App will be used, otherwise, an environment will be created in the formation `<container-app-name>-env`. |
|
||||
| `runtimeStack` | No | The platform version stack used in the final runnable application image that is deployed to the Container App. The value should be provided in the formation `<platform>:<version>`. If not provided, this value is determined by Oryx based on the contents of the provided application. Please refer to [this document](https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md) for more information on supported runtime stacks for Oryx. |
|
||||
| `targetPort` | No | The target port that the Container App will listen on. If not provided, this value will be "80" for Python applications and "8080" for all other supported platforms. |
|
||||
|
||||
## Usage
|
||||
|
||||
Below are a set of examples outlining how to use this task in different scenarios.
|
||||
|
||||
### Minimal
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new resource group named
|
||||
`<container-app-name>-rg`. The provided Azure Container Registry credentials will be used to authenticate any calls
|
||||
made against the 'sampleacr' instance.
|
||||
|
||||
### Container App name provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppName: 'test-container-app-123'
|
||||
```
|
||||
|
||||
This will create a new Container App named `test-container-app-123` in a new resource group named
|
||||
`test-container-app-123-rg`.
|
||||
|
||||
### Resource group provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
resourceGroup: 'test-container-app-rg'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `test-container-app-rg`.
|
||||
|
||||
### Container App name and resource group provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppName: 'test-container-app-123'
|
||||
resourceGroup: 'test-container-app-rg'
|
||||
```
|
||||
|
||||
If the `test-container-app-rg` resource group does not exist, this will create the resource group and create a new
|
||||
Container App named `test-container-app-123` within the resource group. If the resource group already exists, this will
|
||||
create a new Container App named `test-container-app-123` in the resource group, or update the Container App if it
|
||||
already exists within the resource group.
|
||||
|
||||
### Container App environment provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
containerAppEnvironment: 'test-container-app-123-env'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` with a new Container App environment named `test-container-app-123-env`.
|
||||
|
||||
### Runtime stack provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
runtimeStack: 'dotnetcore:7.0'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the runnable application image is using the .NET 7 runtime stack.
|
||||
|
||||
### Dockerfile provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
dockerfilePath: 'test.Dockerfile'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the runnable application image was created from the `test.Dockerfile`
|
||||
file found in the provided application source path directory.
|
||||
|
||||
_Note_: for values provided to `dockerfilePath`, no file prefixes should be included (_e.g._, `./test.Dockerfile` should be
|
||||
passed as just `test.Dockerfile`). The provided `appSourcePath` and `dockerfilePath` arguments will be concatenated inside
|
||||
of the Azure DevOps task.
|
||||
|
||||
### Image to build provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
imageToBuild: 'sampleacr.azurecr.io/app:latest'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where the image built and pushed to ACR is named
|
||||
`sampleacr.azurecr.io/app:latest`
|
||||
|
||||
### Image to deploy provided
|
||||
|
||||
```yml
|
||||
steps:
|
||||
|
||||
- task: AzureContainerAppsRC@V0
|
||||
displayName: Build and deploy Container App
|
||||
inputs:
|
||||
connectedServiceNameARM: 'azure-subscription-service-connection'
|
||||
appSourcePath: '$(System.DefaultWorkingDirectory)/folder-containing-app-source'
|
||||
acrName: 'sampleacr'
|
||||
acrUsername: $(ACR_USERNAME_SECRET)
|
||||
acrPassword: $(ACR_PASSWORD_SECRET)
|
||||
imageToDeploy: 'sampleacr.azurecr.io/app:latest'
|
||||
```
|
||||
|
||||
This will create a new Container App named `ado-task-app-<build-id>-<build-number>` in a new
|
||||
resource group named `<container-app-name>-rg` where **no new image is built**, but an existing image in ACR named
|
||||
`sampleacr.azurecr.io/app:latest` will be deployed to the Container App.
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions from all users; however, we advise that any changes made to the
|
||||
`AzureContainerAppsRC` task be made instead to the
|
||||
[`AzureContainerApps` task](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureContainerAppsV0),
|
||||
which will later be migrated over to this Release Candidate task and published immediately.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Issues and feedback
|
||||
|
||||
For any issues and feedback for the _Release Candidate_ `AzureContainerAppsRC` task, please create a new issue
|
||||
[in the `container-apps-deploy-pipelines-task` repository](https://github.com/azure/container-apps-deploy-pipelines-task/issues).
|
||||
|
||||
For any issues and feedback for the _official_ `AzureContainerApps` task, please create a new issue
|
||||
[in the `azure-pipelines-tasks` repository](https://github.com/microsoft/azure-pipelines-tasks/issues).
|
||||
|
||||
Do you think there might be a security issue? Have you been phished or identified a security vulnerability? Please don't
|
||||
report it here - let us know by sending an email to secure@microsoft.com.
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"manifestVersion": 1,
|
||||
"id": "AzureContainerAppsRC",
|
||||
"name": "Azure Container Apps Deploy (Release Candidate)",
|
||||
"version": "0.1.7",
|
||||
"publisher": "microsoft-oryx",
|
||||
"public": true,
|
||||
"targets": [
|
||||
{
|
||||
"id": "Microsoft.VisualStudio.Services"
|
||||
}
|
||||
],
|
||||
"description": "An Azure DevOps Task to build and deploy Azure Container Apps.",
|
||||
"categories": [
|
||||
"Azure Pipelines"
|
||||
],
|
||||
"Tags": [
|
||||
"Azure",
|
||||
"Container Apps",
|
||||
"Deployment",
|
||||
"Release"
|
||||
],
|
||||
"branding": {
|
||||
"color": "#FFFFFF",
|
||||
"theme": "light"
|
||||
},
|
||||
"links": {
|
||||
"home": {
|
||||
"uri": "https://github.com/azure/container-apps-deploy-pipelines-task"
|
||||
},
|
||||
"support": {
|
||||
"uri": "https://github.com/azure/container-apps-deploy-pipelines-task/issues"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"default": "icon.png"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"uri": "https://github.com/azure/container-apps-deploy-pipelines-task"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"path": "azurecontainerapps"
|
||||
}
|
||||
],
|
||||
"contributions": [
|
||||
{
|
||||
"id": "container-apps-deploy-pipelines-task",
|
||||
"type": "ms.vss-distributed-task.task",
|
||||
"targets": [
|
||||
"ms.vss-distributed-task.task"
|
||||
],
|
||||
"properties": {
|
||||
"name": "azurecontainerapps"
|
||||
}
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"details": {
|
||||
"path": "overview.md"
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче