GitHub Actions for EKS Deployment
Create CI CD Pipeline for Scala App using GitHub Actions
GitHub Actions is a powerful automation tool that allows developers to create custom workflows to automate their software development processes. With GitHub Actions, developers can define a series of steps to run when specific events occur, such as code push, pull requests, and issue creation. These steps can include building and testing code, deploying applications, and sending notifications. Additionally, there are a wide variety of pre-built actions available in the GitHub Marketplace
that can be incorporated into workflows to further streamline the development process
In this blog post, we will be covering the following tasks.
Create a CI pipeline for scala app
- The CI pipeline workflow will run various unit tests on the code
Create CD pipeline for app deployment
The pipeline workflow will build an image
The pipeline workflow will push the image to ECR
The pipeline workflow will then deploy the latest image with commit tag to EKS cluster
Create CI pipeline for continuous integration
In your repository, create the
.github/workflows/
directory to store your workflow files.In the
.github/workflows/
directory, create a new file calledcheck-scala-app.yml
and add the following code.
# **What it does**: Checks that the code pushed passes all the required checks.
# **Why we have it**: To make sure pushed code can only be merged when all the required checks passed.
# **Author**: Saumya Pandey.
name: CI Check Scala App Service
on:
pull_request:
branches:
- staging
- develop
env:
ORG: Saumya Inc
PROJECT_NAME: Sample Scala App
AUTHOR: Saumya (SaumyaBhushan)
jobs:
check_scala_app_service:
env:
MODULE_NAME: scala_app_service
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SBT
uses: actions/cache@v2
with:
path: |
~/.ivy2/cache
~/.sbt
key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }}
- name: Run test cases and generate reports for Scala-App-Service
env:
URL: "jdbc:h2:mem:test;MODE=Oracle;"
DRIVER: "org.h2.Driver"
USERNAME:
PASSWORD:
run: |
sudo timedatectl set-timezone Asia/Kolkata
echo "...........Compiling the code .........."
sbt clean compile
- name: check Scala format
run : |
echo "...........Checking Scalafmt ........"
sbt scalafmtAll
- name: check Scalstyle
run: |
echo "...........Checking Scalastyle ........"
sbt scalastyle
- name: check copy paste detector
run: |
echo "...........Checking copy paste detector ........"
sbt cpd
- name: check scapegoat
run: |
echo "...........Checking Scapegoat ..........."
sbt scapegoat
- name: check test coverage and create coverage report
run: |
echo "...........Checking Test Coverage and Coverage Report.........."
sbt coverage test coverageReport
This is a GitHub Actions workflow file written in YAML. It is used to define a CI (continuous integration) process for a Scala app project. Let's break down each keyword and code line by line:
name
: This keyword specifies the name of the workflow, which is "CI Check Scala App Service".on
: This keyword specifies the events that trigger the workflow. In this case, it is triggered when a pull request is created or updated in the "staging" or "develop" branches.env
: This is used to set environment variables that can be accessed by the steps in the workflow.jobs
: This defines the set of jobs that will be executed by the workflow.check_scala_app_service
: This is the name of the job, which is "check_scala_app_service" in this case.runs-on
: This keyword specifies the type of machine that will run the job. In this case, it is "ubuntu-latest".steps
: This defines the set of steps that will be executed by the job. One workflow can have multiple stepsuses
: This step is used to checkout the source code of the project from the repository using the "actions/checkout@v2" action.uses
: This step uses the "actions/setup-java@v1" action to install JDK 11 on the machine.with
: This keyword specifies the configuration options for the "actions/setup-java@v1" action, which in this case is setting the "java-version" to 11.name
: This keyword specifies the name of the step, which is "Cache SBT" in this case.uses
: This step uses the "actions/cache@v2" action to cache the SBT dependencies.with
: This keyword specifies the configuration options for the "actions/cache@v2" action, which in this case is caching the "/.ivy2/cache" and "/.sbt" directories.key
: This keyword specifies the key for the cache, which is generated based on the OS and the hash of the "build.sbt" file.
run
: This keyword specifies the shell command that will be executed by the step. In this case, it sets the timezone, cleans and compiles the code using sbt.
The workflow performs several checks on the code, including compiling the code, checking the Scala format using
sbt scalafmtAll
, checking Scala style usingsbt scalastyle
, checking for copy-paste code usingsbt cpd
, checking for code quality issues usingsbt scapegoat
, and checking the test coverage and generating the coverage report usingsbt coverage test coverageReport
.
Create CD pipeline for Continuous Deployment
Similarly, as we did above go to your workflow directory .github/workflows/
, create new file deploy-scala-app.yml
# **What it does**: Build docker image and push it to Elastic Container Registry.
# **Why we have it**: Scala App needs to be build as an image and store at remote private registry
# **Author: Saumya Bhushan
name: Build and Deploy Scala App Service On Dev
on:
push:
branches:
- develop
jobs:
build-scala-app-service-on-develop:
env:
EKS_CLUSTER: test-eks-dev
name: push image to scala-app-service repo (ECR)
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
# Setup JDK 11
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SBT
uses: actions/cache@v2
with:
path: |
~/.ivy2/cache
~/.sbt
key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
# Generate Commit Id
- name: Generate Commit Id
id: hash-id
run: echo "::set-output name=git_hash::$(git rev-parse --short "$GITHUB_SHA")"
# Build the Docker image
- name: Package and Build Backend
run: |
echo "Building image..."
sbt docker:publishLocal
# Tag, and push image to Amazon ECR
- name: Build, tag, and push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: scala-app-service
IMAGE_TAG: ${{ steps.hash-id.outputs.git_hash }}
run: |
echo "Pushing image to ECR..."
docker tag sacla-app:1.0-SNAPSHOT $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
outputs:
output-id: ${{ steps.hash-id.outputs.git_hash }}
deploy-on-eks-develop:
needs: build-scala-app-service-on-develop
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: deploy to cluster
uses: kodermax/kubectl-aws-eks@master
env:
KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA_DEV }}
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: scala-app-service
IMAGE_TAG: ${{needs.build-registration-service-on-develop.outputs.output-id}}
KUBECTL_VERSION: "v1.23.0"
with:
args: set image deployment/$ECR_REPOSITORY $ECR_REPOSITORY=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -n scala-app-service
- name: restart the deployment
uses: kodermax/kubectl-aws-eks@master
env:
KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA_DEV }}
KUBECTL_VERSION: "v1.23.0"
with:
args: rollout restart deployment/scala-app-service -n scala-app-service
- name: verify deployment
uses: kodermax/kubectl-aws-eks@master
env:
KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA_DEV }}
with:
args: rollout status deployment/registration-service -n scala-app-service
This is a GitHub Actions workflow file written in YAML that automates the building and deployment of a Scala app service to an EKS cluster. The workflow is triggered on a push to the develop
branch. The workflow consists of two jobs: build-scala-app-service-on-develop
and deploy-on-eks-develop
.
The first job, build-scala-app-service-on-develop
, runs on an Ubuntu 18.04 runner and performs the following steps:
Checks out the code from the repository.
Sets up JDK 11.
Caches SBT to speed up builds.
Configures AWS credentials.
Logs in to Amazon ECR.
Generates a commit ID.
Builds a Docker image and tags it with the commit ID.
Pushes the Docker image to Amazon ECR.
Outputs the commit ID.
The second job, deploy-on-eks-develop
, runs on an Ubuntu latest runner and performs the following steps:
Checks out the code from the repository.
Configures AWS credentials.
Logs in to Amazon ECR.
Deploys the Docker image to the EKS cluster using
kubectl
.Restarts the deployment.
Verifies the deployment.
To run this CD workflow successfully you need to set the following credentials in secret tab :
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
KUBE_CONFIG_DATA_DEV
To set the value go to your repo and go to Settings
Tab
Then in the left panel go to Secrets and variables
and then click on Actions
Then from here click on New Repository Secret
Add the Secret Name
and Secret Value
and click on Add secret
. Similarly, add all the secret.
Now all your secrets are configured. Make the required changes in the deploy-scala-app.yml
such as EKS_CLUSTER
name, ECR_REPOSITORY
name KUBECTL_VERSION .
set image deployment/$ECR_REPOSITORY $ECR_REPOSITORY=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -n scala-app-service:
change thescala-app-service
to your namespace name where you need to deploy the imagerollout restart deployment/registration-service -n scala-app-service
: Here also change the deployment name and namespace name according to your setting.rollout status deployment/registration-service -n scala-app-service
: same as above
sbt docker:publishLocal
Now all set up whenever you make a change to your pull request or create a new pull request these workflows will run.
Note : CI workflow will run when there is a new pull request created from the staging or develop branch or if there is any change in the existing Pull Request created on this branch
CD workflow will run when code gets merged or pushed on develop branch
You can change the branch name according to your use case.
Hope you liked this blog. If you want to get more such blogs subscribe to my newsletter and follow me on hashnode and twitter.
References :
https://github.com/features/actions
https://www.scala-sbt.org/sbt-native-packager/formats/docker.html