Skip to content

anotheroneofthese is deploying the project #185

anotheroneofthese is deploying the project

anotheroneofthese is deploying the project #185

Workflow file for this run

# Name of the workflow and a display name for the workflow
name: Deploy Project
run-name: ${{ github.actor }} is deploying the project
# Decides when the workflow gets triggered, this is a "coarse" definition for whole workflow
# Jobs can refine it further or use the defaults defined here
# List of all events that can be used for triggering workflows:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
on:
# Run on push to main branch and tags in the form v*.*.* eg.: v1.0.0
push:
branches:
- main
tags:
- v*.*.*
# Runs every time a pull request is created, updated, etc. can use "types" to run only on select PR activities
pull_request:
# Used to make sure that only one workflow in specified group runs at the same time
concurrency:
# Define concurrency group which will then be used to determine duplicate workflow runs
# The second property uses fallback values since not every run is a PR run
group: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}
cancel-in-progress: true
# Modify access granted to the workflow in the GITHUB_TOKEN
# Mainly used here to give checks a write permission so we can get a test run report
permissions:
contents: read
actions: read
checks: write
# List of jobs that this workflow will execute
jobs:
# Unique identifier for this job, make sure it's unique, you can use "name" property to give it more descriptive name
test-project:
# This name will be displayed in the GitHub UI when
name: Build and Test the Project
# Defines what runner to run this job on, if you want you can use an array to match runner name
# for example this can be written as [self-hosted, linux] and only runner matching all of these values will run it
runs-on: self-hosted-linux
# List of steps that this job needs to execute in sequential order, any changes done in one step will carry over to
# others, so be mindful of that when making changes to files
steps:
# Simple step which merely checks out the repository to the runner
- name: Checkout
# Specifies that this step should run a pre-defined action
uses: actions/checkout@v4
# This steps installs specified Java JDK
- name: Setup Java JDK
uses: actions/setup-java@v4
# Settings/Inputs/Parameters for the action
with:
# What JDK distribution to download and use
distribution: temurin # If you have no good reason go with Temurin distribution
java-version: 21
architecture: x64
# Sets up caching and restoring of dependencies for the specified package manager
# NB! If you decide to use a non-standard path for package repositories you need to set up caching yourself
# In that case use the "@actions/cache" action
cache: maven
# Since self hosted runner does not come with Maven, we need to install it
# Same for git, we need it to upload test results, hence why we initialize the repo
# Lastly gettext provides envsubst which is used in the "Verify the Project" step to replace env variables
- name: Install Maven and Initialize Repo
# Map of environment variables available for only this step, you can define it on job or workflow level too
env:
MAVEN_VERSION: 3.9.7 # So we can easily change the Maven version
run: | # Pipe allows to make the script multiline, if you need to run only one command you can skip it
sudo apt-get update -y
sudo apt-get install wget git gettext -y
wget https://downloads.apache.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz
sudo tar xzf apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt
sudo ln -s /opt/apache-maven-$MAVEN_VERSION/bin/mvn /usr/local/bin/mvn
echo "PATH=/opt/apache-maven-$MAVEN_VERSION/bin:$PATH" >> $GITHUB_ENV
git init
mvn -v
# This step imports secrets from Vault, it is recommended to use Vault as it allows checking and editing
# GitHub secrets wont permit you to see or re-use secrets, speak with Platform team to set up a namespace for you
# They should also give you an approle "user" which will allow you to get the secrets from github action
#
# The url must be in form: https://<URL>, while IDs are UUIDs
# When providing path to the secret you need to include "/data" after namespace and before the secret name
- name: Import Secrets
uses: hashicorp/vault-action@v3
with:
url: ${{ secrets.VAULT_URL }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: secret/v1/application/k8s/mlt/data/proxy *
# This step will actually build, test, and verify the project
# envsubst is used to provide proxy settings for Maven, proxy host address must be an IP address, not URL
- name: Verify the Project
run: |
envsubst < .m2/settings.xml > .m2/replaced.xml
mvn -B -e -s .m2/replaced.xml verify
# This step will use the test-reporter action to publish test results in the workflow run
- name: Publish Test Report
uses: dorny/test-reporter@v1
# If defines conditions that need to be fulfilled to run this step, in this case this step will always run
if: always()
with:
# Name for the report
name: JUnit Tests
# Where to look for report files, in this case look for any file named "TEST-...xml" anywhere in the project
path: ./**/TEST-*.xml
# What reporter created to use, since this project uses JUnit java-junit is used
reporter: java-junit
# Fail this step if there are test errors
fail-on-error: true
# Fail this step if no test results were found
fail-on-empty: true
# Last step will upload the JAR file as an artifact that can then be used in other jobs
- name: Upload the JAR File
uses: actions/upload-artifact@v4
with:
# Artifact ID
name: packaged-project
# Where to find artifact file(s)
# Add "project.build.finalName --> ${project.artifactId}" to pom.xml to drop the version suffix
path: target/wls.jar
# Fail if artifact is not found
if-no-files-found: error
# Allow overwriting of previous artifacts
overwrite: true
# This job will build a Docker image with relevant tags and labels, and publish it in Harbor
publish-image:
name: Build and Publish the Docker Image
# Defines that test-project job must finish successfully first, before this one can run
needs: test-project
# The if statement limits it to run only if action was triggered on main branch or one of the tags
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
runs-on: self-hosted-linux
# Outputs allows a job to output values that can be picked up by _downstream_ jobs that _depend_ on this job
outputs:
# The metadata step produces an image name that we need to use in deployment
image-name: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout
uses: actions/checkout@v4
# Sets up a Docker Build action which will produce an image
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker
# See this step description in the first job
- name: Import Secrets
uses: hashicorp/vault-action@v3
with:
url: ${{ secrets.VAULT_URL }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: secret/v1/application/k8s/mlt/data/harbor *
# Simple action that authenticates against the NLB's Harbor instance
# The url must be in form: https://<URL>, username and password should be for the github robot user
# Ask Platform team to create a robot user for you that has access to your project(s) in Harbor registry
- name: Log in to Harbor Registry
uses: docker/login-action@v3
with:
registry: ${{ env.HARBOR_URL }}
username: ${{ env.HARBOR_USERNAME }}
password: ${{ env.HARBOR_PASSWORD }}
- name: Extract Metadata for Docker
# Give this step an unique ID that can be used for referencing it later, here it's used to get the value of tags
id: meta
uses: docker/metadata-action@v5
with:
# Define the base that should be used for tags, can be multiple values if needed
images: harbor.nb.no/mlt/wls
# Defines list of tag types to use for generating the metadata
# the semver type will use GitHub tag in semver form and turn it into a proper tag for the image
# the ref type wil base its version either on branch or PR event and generate the tag for the image
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=ref,event=pr
# Downloads previously uploaded artifact with provided name
- name: Download the JAR File
uses: actions/download-artifact@v4
with:
name: packaged-project
# Builds and publishes the image in Harbor
- name: Build the Docker Image
uses: docker/build-push-action@v5
with:
# Makes the action push image to Harbor, equivalent to "--output-type=registry"
push: true
# Build context, makes the build process use actual files in the runner instead of using files from GitHub
context: .
# Override the path to the Dockerfile, since this project has it in the docker folder
file: ./docker/Dockerfile
# Set tags for the image using output from the meta step
tags: ${{ steps.meta.outputs.tags }}
# Set labels for the image using output from the meta step
labels: ${{ steps.meta.outputs.labels }}
# Deploys the image to kubernetes stage environment
deploy-to-stage:
name: Deploy to Kubernetes Stage
needs: publish-image
# Runs only on main branch
# Can be changed to also run on tags, to ensure that stage & prod use same image after a new version release
if: github.ref == 'refs/heads/main'
runs-on: self-hosted-linux
# Defines what environment this job references, this allows you to set deployment protections in the project
# Allows requiring a number of reviewers or specific reviewers, allow only specific branches or tags
# It also permits setting specific secrets and variables
environment: stage
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Import Secrets
uses: hashicorp/vault-action@v3
with:
url: ${{ secrets.VAULT_URL }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: secret/v1/application/k8s/mlt/data/k8s-stage *
# Installs and prepares a local kubectl instance
- name: Setup Kubectl
uses: azure/setup-kubectl@v4
# Script that sets some needed variables in deployment file, and then configures kubectl for deploying to stage
# Script itself is rather generic, especially for simple deployments so you can easily re-use it
# Just make sure to set correct context and namespace for your own needs
#
# K8S_HOST_URL - URL pointing to where you want the app hosted, we have two options for both stage and prod
# K8S_STAGE_SERVER - URL to the stage server in form https://<IP_ADDRESS>:<PORT>
# K8S_STAGE_NB_NO_CA - certificate auth data, get it from the Platform team
# K8S_STAGE_USER - name of the robot user that can deploy to your namespace, get it from the Platform team
# K8S_STAGE_NB_NO_TOKEN - credentials token for the robot user, get it from the Platform team
- name: Deploy to Stage
run: |
echo "Deploying to stage: ${{ needs.publish-image.outputs.image-name }}"
sed -i "s|<image_name>|${{ needs.publish-image.outputs.image-name }}|g" k8s/stage/wls.yml
sed -i "s|<host_url>|${{ env.K8S_HOST_URL }}|g" k8s/stage/wls.yml
kubectl config set-cluster stagecl --server=${{ env.K8S_STAGE_SERVER }}
kubectl config set clusters.stagecl.certificate-authority-data ${{ env.K8S_STAGE_NB_NO_CA }}
kubectl config set-credentials ${{ env.K8S_STAGE_USER }} --token=${{ env.K8S_STAGE_NB_NO_TOKEN }}
kubectl config set-context mlt --cluster=stagecl --user=${{ env.K8S_STAGE_USER }} --namespace=mlt
kubectl config use-context mlt
kubectl config view
kubectl version
kubectl apply -f k8s/stage/wls.yml
kubectl rollout restart deploy/wls
deploy-to-prod:
name: Deploy to Kubernetes Prod
needs: publish-image
# Runs only on tags
if: startsWith(github.event.ref, 'refs/tags/v')
runs-on: self-hosted-linux
environment: prod
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Import Secrets
uses: hashicorp/vault-action@v3
with:
url: ${{ secrets.VAULT_URL }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: secret/v1/application/k8s/mlt/data/k8s-prod *
- name: Setup Kubectl
uses: azure/setup-kubectl@v4
# Same concept as in stage deployment, just using production values
- name: Deploy to Prod
run: |
echo "Deploying to prod:${{ needs.publish-image.outputs.image-name }}"
sed -i "s|<image_name>|${{ needs.publish-image.outputs.image-name }}|g" k8s/prod/wls.yml
sed -i "s|<host_url>|${{ env.K8S_HOST_URL }}|g" k8s/prod/wls.yml
kubectl config set-cluster prodcl --server=${{ env.K8S_PROD_SERVER }}
kubectl config set clusters.prodcl.certificate-authority-data ${{ env.K8S_PROD_NB_NO_CA }}
kubectl config set-credentials ${{ env.K8S_PROD_USER }} --token=${{ env.K8S_PROD_NB_NO_TOKEN }}
kubectl config set-context mlt --cluster=prodcl --user=${{ env.K8S_PROD_USER }} --namespace=mlt
kubectl config use-context mlt
kubectl config view
kubectl version
kubectl apply -f k8s/prod/wls.yml
kubectl rollout restart deploy/wls