Skip to content

Commit

Permalink
Add Github Actions for pipeline (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuwzho authored Nov 13, 2024
1 parent 775b8cf commit 18b6261
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ This documentation guides how to deploy the PetClinic microservices.
1. Access the PetClinic application running in Azure Container Apps.

Using your browser either navigate to **https://\<IP_APPGW from prior step>** from above, or if you added the host file entry, to **<https://acahello.demoapp.com>**. *Because the cert is self-signed for this walkthrough, you will need to accept the security warnings presented by your browser.*


## Next step

:arrow_forward: [Setup CI/CD pipeline](./05-github-action.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Setup CI/CD Pipeline

With the application code already deployed to Azure Container Apps, the next step is to establish a CI/CD pipeline. This pipeline will automate the process of streaming subsequent code changes directly to Azure Container Apps. This setup ensures that every update is seamlessly integrated and deployed, enhancing efficiency and reducing manual effort.

## Expected Results

Setting up a GitHub Action for a CI/CD pipeline to deploy code changes to Azure Container Apps streamlines the development process, ensuring rapid and reliable delivery of updates.

## Steps

1. Create the Identity Used by GitHub Actions.
```bash
APPID_GITHUB_ACTION=$(az ad app create --display-name github-action --query appId -o tsv)
az ad sp create --id $APPID_GITHUB_ACTION
```

1. To allow the Application authenticate to Azure, set up the [federated identity credential](https://learn.microsoft.com/en-us/graph/api/resources/federatedidentitycredentials-overview?view=graph-rest-1.0).
First, update `[Your-GitHub-Organization]` and `[Your-Release-Branch]` to the [federated-credential.json](../modules/federated-credential.json).

```bash
az ad app federated-credential create --id $APPID_GITHUB_ACTION --parameters modules/federated-credential.json
```

1. Assign your application necessary role to run the CI/CD pipeline.

Retrieve your spoke resource group id
```bash
RESOURCEID_RESOURCEGROUP_SPOKE=$(az group show -n $RESOURCENAME_RESOURCEGROUP_SPOKE --query id -o tsv)
echo RESOURCEID_RESOURCEGROUP_SPOKE=$RESOURCEID_RESOURCEGROUP_SPOKE
```

Open [modules/role-definition.json](../modules/role-definition.json), update `Your-Spoke-Resource-Group-Id` to your `RESOURCEID_RESOURCEGROUP_SPOKE`.

```bash
ID_ROLEDEFINITION=$(az role definition create --role-definition @modules/role-definition.json --query id -o tsv)
az role assignment create --role $ID_ROLEDEFINITION --scope $RESOURCEID_RESOURCEGROUP_SPOKE --assignee $APPID_GITHUB_ACTION
```

1. Prepare variable settings in GitHub repository by setting the Azure information to repository.

```bash
AZURE_TENANT_ID=$(az account show --query tenantId -o tsv)
AZURE_SUBSCRIPTION_ID=$(az account show --query id -o tsv)
echo AZURE_CLIENT_ID=$APPID_GITHUB_ACTION && \
AZURE_TENANT_ID=$AZURE_TENANT_ID && \
AZURE_SUBSCRIPTION_ID=$AZURE_SUBSCRIPTION_ID && \
AZURE_RESOURCE_GROUP=$RESOURCENAME_RESOURCEGROUP_SPOKE
```
Navigate to the GitHub repository setting page, select `Security`/`Secrets and variables`/`Actions`. Set the `AZURE_CLIENT_ID` and `AZURE_TENANT_ID` to the secrets, `AZURE_SUBSCRIPTION_ID` and `AZURE_RESOURCE_GROUP` to the variables, according to above output.

![Set up Env](./github-action-env.png)

1. Create the workflow file.
Edit the [petclinic-deploy.yml](../modules/petclinic-deploy.yml), replace `[Your-Release-Branch-Name]` to your working branch. It should be consistent with the value set in step 2.
Move the [petclinic-deploy.yml](../modules/petclinic-deploy.yml) to [.github/workflows](../../../../../../.github/workflows/) folder, commit the changes and push to remote your working branch.

1. Navigate to GitHub Actions page and check the running state of the workflow.

![Github Actions](../docs/github-action-workflow.png)

## Next step

:arrow_forward: [Update Spring Cloud dependencies](./06-Update-Spring-Cloud-dependencies.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Update Spring Cloud dependencies

As the given PetClinic Microservices previously were deployed on Pivotal Cloud Foundry. They uses the Pivotal Spring Cloud dependencies to interact with Config Server and Service Registry. After migrate to Azure Container Apps, when interacting with [Java components](https://techcommunity.microsoft.com/t5/apps-on-azure-blog/announcing-the-general-availability-of-java-experiences-on-azure/ba-p/4238294), you can change the dependencies to the community version.

## Expected Results

The PetClinic Microservices uses community version dependencies to talk with Spring Cloud Config Server and Eureka Server.

## Steps

1. Remove the `spring-cloud-services-dependencies`.
Navigate to [src/pom.xml](../src/pom.xml) and remove the `spring-cloud-services-dependencies`

```diff
- <dependency>
- <groupId>io.pivotal.spring.cloud</groupId>
- <artifactId>spring-cloud-services-dependencies</artifactId>
- <version>${spring-cloud-services.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
```

1. Replace the Config Server dependency and Service Registry dependency.
Update the follow pom files:
- [src/spring-petclinic-api-gateway/pom.xml](../src/spring-petclinic-api-gateway/pom.xml)
- [src/spring-petclinic-customers-service/pom.xml](../src/spring-petclinic-customers-service/pom.xml)
- [src/spring-petclinic-vets-service/pom.xml](../src/spring-petclinic-vets-service/pom.xml)
- [src/spring-petclinic-visits-service/pom.xml](../src/spring-petclinic-visits-service/pom.xml)

```diff
<dependency>
- <groupId>io.pivotal.spring.cloud</groupId>
- <artifactId>spring-cloud-services-starter-config-client</artifactId>
+ <groupId>org.springframework.cloud</groupId>
+ <artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
- <groupId>io.pivotal.spring.cloud</groupId>
- <artifactId>spring-cloud-services-starter-service-registry</artifactId>
+ <groupId>org.springframework.cloud</groupId>
+ <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
```

1. Commit and push above changes to remote and trigger the pipeline.

1. Navigate to GitHub Actions page and check the running state of the workflow.

![Github Actions](../docs/github-action-workflow.png)

1. After the pipeline successfully finished, view your application.

Using your browser either navigate to **https://\<IP_APPGW>** from above, or if you added the host file entry, to **<https://acahello.demoapp.com>**. *Because the cert is self-signed for this walkthrough, you will need to accept the security warnings presented by your browser.*
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "GitHubAction",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:[Your-GitHub-Organization]/aca-landing-zone-accelerator:ref:refs/heads/[Your-Release-Branch]",
"description": "Github Action Auth",
"audiences": [
"api://AzureADTokenExchange"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# This workflow will deploy the PetClinic application to Azure Container Apps
name: PetClinic Deploy

on:
# When you directly push in the main branch
push:
branches:
- '[Your-Release-Branch-Name]'
paths:
- 'scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/**'
- '!scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/**.md'
- '.github/workflows/petclinic-deploy.yml'

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Login via Azure CLI
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Prepare env variables
uses: azure/CLI@v2
with:
azcliversion: latest
inlineScript: |
export ENVIRONMENT_NAME=$(az deployment group show -n acalza01-appplat -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.containerAppsEnvironmentName.value -o tsv)
export RESOURCEID_IDENTITY_ACR=$(az deployment group show -n acalza01-dependencies -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.containerRegistryUserAssignedIdentityId.value -o tsv)
export REGISTRYNAME_ACR=$(az deployment group show -n acalza01-dependencies -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.containerRegistryName.value -o tsv)
export LOGINSERVER_ACR=$(az deployment group show -n acalza01-dependencies -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.containerRegistryLoginServer.value -o tsv)
export RESOURCENAME_AGENTPOOL=$(az deployment group show -n acalza01-dependencies -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.containerRegistryAgentPoolName.value -o tsv)
export RESOURCEID_EUREKA=$(az deployment group show -n acalza01-appplat-java -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.eurekaId.value -o tsv)
export RESOURCEID_CONFIGSERVER=$(az deployment group show -n acalza01-appplat-java -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.configServerId.value -o tsv)
export RESOURCEID_MYSQL_DATABASE=$(az deployment group show -n acalza01-appplat-java -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.databaseId.value -o tsv)
export RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID=$(az deployment group show -n acalza01-appplat-java -g ${{ vars.AZURE_RESOURCE_GROUP }} --query properties.outputs.userAssignedIdentityClientId.value -o tsv)
echo ENVIRONMENT_NAME=$ENVIRONMENT_NAME >> $GITHUB_ENV
echo RESOURCEID_IDENTITY_ACR=$RESOURCEID_IDENTITY_ACR >> $GITHUB_ENV
echo REGISTRYNAME_ACR=$REGISTRYNAME_ACR >> $GITHUB_ENV
echo LOGINSERVER_ACR=$LOGINSERVER_ACR >> $GITHUB_ENV
echo RESOURCENAME_AGENTPOOL=$RESOURCENAME_AGENTPOOL >> $GITHUB_ENV
echo RESOURCEID_MYSQL_DATABASE=$RESOURCEID_MYSQL_DATABASE >> $GITHUB_ENV
echo RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID=$RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID >> $GITHUB_ENV
echo RESOURCEID_EUREKA=$RESOURCEID_EUREKA >> $GITHUB_ENV
echo RESOURCEID_CONFIGSERVER=$RESOURCEID_CONFIGSERVER >> $GITHUB_ENV
- name: Prepare image version variable
run: echo "IMAGE_TAG=ga-${{ github.run_number }}-$(date +%Y%m%d%H%M%S)" >> $GITHUB_ENV

- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven

- name: Build Jar with Maven
run: mvn clean package
working-directory: scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src

- name: Queue Build for application vets-service
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
pwd && \
az acr build -t spring-petclinic-vets-service:${{ env.IMAGE_TAG }} \
-r ${{ env.REGISTRYNAME_ACR }} scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/spring-petclinic-vets-service/target/docker \
--build-arg ARTIFACT_NAME=vets-service-3.0.1 \
--build-arg EXPOSED_PORT=8080 \
--agent-pool ${{ env.RESOURCENAME_AGENTPOOL }} --debug
- name: Queue Build for application visits-service
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az acr build -t spring-petclinic-visits-service:${{ env.IMAGE_TAG }} \
-r ${{ env.REGISTRYNAME_ACR }} scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/spring-petclinic-visits-service/target/docker \
--build-arg ARTIFACT_NAME=visits-service-3.0.1 \
--build-arg EXPOSED_PORT=8080 \
--agent-pool ${{ env.RESOURCENAME_AGENTPOOL }}
- name: Queue Build for application customers-service
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az acr build -t spring-petclinic-customers-service:${{ env.IMAGE_TAG }} \
-r ${{ env.REGISTRYNAME_ACR }} scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/spring-petclinic-customers-service/target/docker \
--build-arg ARTIFACT_NAME=customers-service-3.0.1 \
--build-arg EXPOSED_PORT=8080 \
--agent-pool ${{ env.RESOURCENAME_AGENTPOOL }}
- name: Queue Build for application api-gateway
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az acr build -t spring-petclinic-api-gateway:${{ env.IMAGE_TAG }} \
-r ${{ env.REGISTRYNAME_ACR }} scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/src/spring-petclinic-api-gateway/target/docker \
--build-arg ARTIFACT_NAME=api-gateway-3.0.1 \
--build-arg EXPOSED_PORT=8080 \
--agent-pool ${{ env.RESOURCENAME_AGENTPOOL }}
- name: Deploy image to Azure Container Apps
uses: azure/arm-deploy@v1
with:
subscriptionId: ${{ vars.AZURE_SUBSCRIPTION_ID }}
resourceGroupName: ${{ vars.AZURE_RESOURCE_GROUP }}
template: scenarios/aca-internal/bicep/sample-apps/cloud-foundry-spring-boot-application/modules/petclinic.bicep
parameters: 'managedEnvironmentsName=${{ env.ENVIRONMENT_NAME }} eurekaId=${{ env.RESOURCEID_EUREKA }} configServerId=${{ env.RESOURCEID_CONFIGSERVER }} mysqlDBId=${{ env.RESOURCEID_MYSQL_DATABASE }} mysqlUserAssignedIdentityClientId=${{ env.RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID }} acrRegistry=${{ env.LOGINSERVER_ACR }} imageTag=${{ env.IMAGE_TAG }} acrIdentityId=${{ env.RESOURCEID_IDENTITY_ACR }}'
failOnStdErr: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"description": "Used for Azure Container Apps deploy from code, including build image uses Azure Container Registry and deploy to Azure Container Apps",
"name": "ACR build and deploy to ACA",
"actions": [
"*/read",
"Microsoft.Resources/deployments/write",
"Microsoft.Resources/deployments/validate/action",
"Microsoft.ContainerRegistry/registries/listBuildSourceUploadUrl/action",
"Microsoft.ContainerRegistry/registries/runs/listLogSasUrl/action",
"Microsoft.ContainerRegistry/registries/builds/cancel/action",
"Microsoft.ContainerRegistry/registries/scheduleRun/action",
"Microsoft.App/containerApps/write",
"Microsoft.app/managedEnvironments/join/action",
"Microsoft.App/managedEnvironments/javaComponents/write",
"Microsoft.App/containerApps/listSecrets/action",
"Microsoft.ServiceLinker/linkers/write",
"Microsoft.ManagedIdentity/userAssignedIdentities/assign/action"
],
"notActions": [],
"dataActions": [],
"notDataActions": [],
"AssignableScopes": ["Your-Spoke-Resource-Group-Id"]
}

0 comments on commit 18b6261

Please sign in to comment.