Lock service deployment
During peak periods such as campaigns, holidays, or system outages, it becomes crucial to maintain stability and avoid unexpected changes or disruptions to services. Implementing a service locking mechanism using Port's Github Action helps to enforce this stability by temporarily preventing deployments during these critical times.
The CI/CD deployment check described in this guide will follow these steps:
- New code is pushed to the
main
branch of a Git repository - A GitHub workflow is triggered by the push event
- The Github workflow queries Port's Entity API and returns a response for the service
- If the value of the
locked_in_prod
field istrue
, the deployment check will fail - If the value of the
locked_in_prod
field isfalse
, the deployment check will succeed
Prerequisites​
- This guide assumes you have a Port account and that you have finished the onboarding process
- You will need a GitHub repository in which you can trigger a workflow that we will use in this guide
Below you can find the JSON for the Service
blueprint required for the guide:
Service blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Github",
"schema": {
"properties": {
"readme": {
"title": "README",
"type": "string",
"format": "markdown",
"icon": "Book"
},
"url": {
"title": "URL",
"format": "url",
"type": "string",
"icon": "Link"
},
"language": {
"icon": "Git",
"type": "string",
"title": "Language",
"enum": [
"GO",
"Python",
"Node",
"React"
],
"enumColors": {
"GO": "red",
"Python": "green",
"Node": "blue",
"React": "yellow"
}
},
"slack": {
"icon": "Slack",
"type": "string",
"title": "Slack",
"format": "url"
},
"code_owners": {
"title": "Code owners",
"description": "This service's code owners",
"type": "string",
"icon": "TwoUsers"
},
"type": {
"title": "Type",
"description": "This service's type",
"type": "string",
"enum": [
"Backend",
"Frontend",
"Library"
],
"enumColors": {
"Backend": "purple",
"Frontend": "pink",
"Library": "green"
},
"icon": "DefaultProperty"
},
"lifecycle": {
"title": "Lifecycle",
"type": "string",
"enum": [
"Production",
"Experimental",
"Deprecated"
],
"enumColors": {
"Production": "green",
"Experimental": "yellow",
"Deprecated": "red"
},
"icon": "DefaultProperty"
},
"locked_in_prod": {
"icon": "DefaultProperty",
"title": "Locked in Prod",
"type": "boolean",
"default": false
},
"locked_reason_prod": {
"icon": "DefaultProperty",
"title": "Locked Reason Prod",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
Our Service blueprint has a property called locked_in_prod
with a boolean value. We will use the value of this field to determine whether new deployments of the service are allowed.
Now that you have your blueprint created, let's manually create a Notification Service
entity in our software catalog:
{
"identifier": "notification-service",
"title": "Notification Service",
"icon": "Github",
"properties": {
"url": "https://github.com/my-repo",
"language": "Python",
"slack": "https://app.slack.com/client",
"type": "Backend",
"lifecycle": "Production",
"locked_in_prod": true
},
"relations": {}
}
Reading the lock status during deployment​
In order to use the locked_in_prod
field in your CI/CD pipeline, you will use Port's GitHub Action.
Let's go ahead and create a GitHub workflow file in a GitHub repository meant for the Notification Service
:
- Create a GitHub repository (or use an existing one)
- Create a
.github
directory- Inside it create a
workflows
directory
- Inside it create a
Inside the /.github/workflows
directory create a file called check-service-lock.yml
with the following content:
GitHub workflow configuration (click to expand)
name: Check Service Lock Status
on:
push:
branches:
- "main"
jobs:
get-entity:
runs-on: ubuntu-latest
outputs:
entity: ${{ steps.port-github-action.outputs.entity }}
steps:
- id: port-github-action
name: Get entity from Port
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
identifier: notification-service
blueprint: service
operation: GET
check-lock-status:
runs-on: ubuntu-latest
needs: get-entity
steps:
- name: Get entity lock status
run: echo "LOCK_STATUS=$(echo '${{needs.get-entity.outputs.entity}}' | jq -r .properties.locked_in_prod)" >> $GITHUB_ENV
- name: Check lock status 🚧
if: ${{ env.LOCK_STATUS == 'true' }}
run: |
echo "Service in production is locked, stopping deployment"
exit 1
run-deployment:
runs-on: ubuntu-latest
needs: [check-lock-status]
steps:
- name: Run deployment
run: echo "Service in production is not locked, continuing deployment"
For security reasons it is recommended to save the PORT_CLIENT_ID
and PORT_CLIENT_SECRET
as GitHub Secrets, and access them as shown in the example above.
If you try to push code to your repository when the locked_in_prod
field is set to true
, the deployment workflow will stop:
When you will look at the step that failed, you will see that the failure is due to the value of the locked field:
If you set the value of the locked_in_prod
field to false
, the workflow will perform the deployment without any issue: