Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding an example workflow for creating clusters on AKS and deploying a Spring app on that cluster #89

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions SpringExample/.github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: cosmosapp

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
aks:
name: "Deploy Spring ApplicationI"
concurrency: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gambtho/aks_create_action@main
with:
CLUSTER_NAME: ${{ secrets.CLUSTER_NAME }}
RESOURCE_GROUP_NAME: ${{ secrets.RESOURCE_GROUP_NAME }}
STORAGE_ACCOUNT_NAME: ${{ secrets.STORAGE_ACCOUNT_NAME }}
STORAGE_CONTAINER_NAME: ${{ secrets.STORAGE_CONTAINER_NAME }}
STORAGE_ACCESS_KEY: ${{ secrets.STORAGE_ACCESS_KEY }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
CREATE_ACR: true
- uses: azure/docker-login@v1
with:
login-server: ${{ secrets.CLUSTER_NAME }}.azurecr.io
username: ${{ secrets.ARM_CLIENT_ID }}
password: ${{ secrets.ARM_CLIENT_SECRET }}

# Container build and push to an Azure Container Registry(ACR)
- run: |
docker build . -t ${{ secrets.CLUSTER_NAME }}.azurecr.io/${{ secrets.APP_NAME }}:${{ github.sha }}
docker push ${{ secrets.CLUSTER_NAME }}.azurecr.io/${{ secrets.APP_NAME }}:${{ github.sha }}
name: "Docker push"
# Set the target Azure Kubernetes Service (AKS) cluster.
- uses: azure/aks-set-context@v1
with:
creds: '${{ secrets.AZURE_CREDS }}'
cluster-name: ${{ secrets.CLUSTER_NAME }}
resource-group: ${{ secrets.RESOURCE_GROUP_NAME }}
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDS }}
# Create namespace if it doesn't exist
- run: |
kubectl create namespace ${{ secrets.NAMESPACE }} --dry-run -o json | kubectl apply -f -

# Create image pull secret for ACR
- uses: azure/k8s-create-secret@v1
with:
container-registry-url: ${{ secrets.CLUSTER_NAME }}.azurecr.io
container-registry-username: ${{ secrets.ARM_CLIENT_ID }}
container-registry-password: ${{ secrets.ARM_CLIENT_SECRET }}
secret-name: ${{ secrets.SECRET_NAME }}
namespace: ${{ secrets.NAMESPACE }}
force: true
id: create-secret
# Deploy app to AKS
- uses: azure/k8s-deploy@v1
with:
manifests: |
k8s/deployment.yaml
images: |
${{ secrets.CLUSTER_NAME }}.azurecr.io/${{ secrets.APP_NAME }}:${{ github.sha }}
imagepullsecrets: |
${{ secrets.SECRET_NAME }}
namespace: ${{ secrets.NAMESPACE }}
17 changes: 17 additions & 0 deletions SpringExample/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
COPY src /create-cosmosdb-action/src
COPY pom.xml /create-cosmosdb-action/
RUN mvn -f /create-cosmosdb-action/pom.xml clean package

#
# Package stage
#
FROM openjdk:11-jre-slim
COPY --from=build /create-cosmosdb-action/target/action-0.0.1-SNAPSHOT.jar /usr/local/lib/action.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/action.jar"]

#/Users/marcushines/devpomelopment/create-cosmosdb-action
84 changes: 84 additions & 0 deletions SpringExample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Java-Example-App

This workflow can be used as an example for developers wanting to deploy Java apps using Github actions.

# The workflow:
This example workflow will:
1. Create a k8's cluster on AKS
2. Build your applications image
3. Create and push your image to ACR (Azure Container Registry
4. Pull your image from ACR, and deploy your application on AKS

Workflows are defined in a `.yaml` file. The workflow file can be named anything, but it _must_ be inside a directory `./.github/workflows/`

# Using variables and secrets in your `.yaml` workflow
You can define secrets and variables by navigating to your github repository's `settings` page. You can define a new secrets variables by selecting "New Repository Secret"
Once you define your secrets, you can reference them with the syntax `${{ secrets.VARIABLE_NAME }}`

You can now pass these values as arguments to your workflow actions, without having to define them in plain text. To use this workflow, make sure to define the required secrets in your Github repository.
If you do not currently have the values needed to run this example, they can be created by running the script `./setup.sh -c <<cluster name> -g <<resource group name>> -s <<subscription id>> -r <<region>>
`. The script will output the values needed. You can define these as secrets and pass them
as arguments like seen below:

```yaml
steps:
- uses: actions/checkout@v2
- uses: gambtho/aks_create_action@main
with:
CLUSTER_NAME: ${{ secrets.CLUSTER_NAME }}
RESOURCE_GROUP_NAME: ${{ secrets.RESOURCE_GROUP_NAME }}
STORAGE_ACCOUNT_NAME: ${{ secrets.STORAGE_ACCOUNT_NAME }}
STORAGE_CONTAINER_NAME: ${{ secrets.STORAGE_CONTAINER_NAME }}
STORAGE_ACCESS_KEY: ${{ secrets.STORAGE_ACCESS_KEY }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
CREATE_ACR: true
```

# aks-set-context
This example workflow leverages the `aks-set-context` action, which requires the use of azure credentials.
The purpose of this action is to set cluster context before other actions like `azure/k8s-deploy`, `azure/k8s-create-secret` or any kubectl commands (in script) that can be run subsequently in the workflow.

To generate the credentials needed for this action
run the following command, and copy the output into your Github actions secret variables:

`az ad sp create-for-rbac --sdk-auth`

```yaml
uses: azure/aks-set-context@v1
with:
creds: '${{ secrets.AZURE_CREDENTIALS }}' # Azure credentials
resource-group: '<resource group name>'
cluster-name: '<cluster name>'
```


az ad sp create-for-rbac --sdk-auth


# Defining your deployment
You will define your k8's deployment in a yaml file, as you would other kubernetes deployments. For more details on Kubernetes deployments,
see https://kubernetes.io/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/

The file path of your deployment will be passed as a `manifests` argument to the following `azure/k8s-deploy@v1` action. In the example the path is `k8/deployment.yaml`. Be sure to update this
if your pathname differs.

```yaml
- uses: azure/k8s-deploy@v1
with:
manifests: |
k8s/deployment.yaml
images: |
${{ secrets.CLUSTER_NAME }}.azurecr.io/${{ secrets.APP_NAME }}:${{ github.sha }}
imagepullsecrets: |
${{ secrets.SECRET_NAME }}
namespace: ${{ secrets.NAMESPACE }}

```





26 changes: 26 additions & 0 deletions SpringExample/k8s/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cosmosapp
labels:
purpose: example-app
app: cosmosapp
spec:
replicas: 1
selector:
matchLabels:
app: cosmosapp
template:
metadata:
labels:
app: cosmosapp
spec:
containers:
- name: cosmosapp
image: mahinescluster.azurecr.io/cosmosapp # Replace with your image
imagePullPolicy: Always
ports:
- containerPort: 80
env:
- name: YOUR_ENV_VARIABLE
value: "71ac8979-e82e-4ec6-819d-a1ed4a0e332a"
65 changes: 65 additions & 0 deletions SpringExample/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.createcosmos</groupId>
<artifactId>action</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>action</name>
<description>Demo project for Creating CosmosDB using AKS</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-documentdb</artifactId>
<version>2.6.4</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-cosmos</artifactId>
<version>4.19.0</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.3.6</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-secrets</artifactId>
<version>4.3.1</version>
</dependency>

</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
72 changes: 72 additions & 0 deletions SpringExample/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash

usage="$(basename "$0") [-h] [-c CLUSTER_NAME] [-g RESOURCE_GROUP_NAME] [-s SUBSCRIPTION_ID] [-r REGION]
Creates a service principal and storage account for using terraform on Azure
where:
-h show this help text
-c desired cluster name
-g desired resource group name
-s subscription id for cluster
-r region for cluster"

while getopts h:c:g:s:r: flag
do
case "${flag}" in
h) echo "$usage"; exit;;
c) cluster_name=${OPTARG};;
g) resource_group_name=${OPTARG};;
s) subscription=${OPTARG};;
r) region=${OPTARG};;
:) printf "missing argument for -%s\n" "$OPTARG" >&2; echo "$usage" >&2; exit 1;;
\?) printf "illegal option: -%s\n" "$OPTARG" >&2; echo "$usage" >&2; exit 1;;
esac
done

# mandatory arguments
if [ ! "$cluster_name" ] || [ ! "$resource_group_name" ] || [ ! "$subscription" ] || [ ! "$region" ]; then
echo "all arguments must be provided"
echo "$usage" >&2; exit 1
fi

echo "Arguments provided:"
echo "Cluster Name: $cluster_name";
echo "Resource Group Name: $resource_group_name";
echo "Subscription: $subscription";
echo "Region: $region";

STORAGE_ACCOUNT_NAME=$(echo "${resource_group_name}" | tr '[:upper:]' '[:lower:]')$RANDOM
CONTAINER_NAME=$(echo "${cluster_name}" | tr '[:upper:]' '[:lower:]')tstate

az account set --subscription $subscription &> /dev/null
# Create resource group
az group create --location $region --resource-group $resource_group_name &> /dev/null

#Create service principal and give it access to group
SP_OUTPUT=$(az ad sp create-for-rbac --name $resource_group_name --role contributor --scopes /subscriptions/$subscription/resourceGroups/$resource_group_name --sdk-auth)
echo $SP_OUTPUT
ARM_CLIENT_ID=$(echo $SP_OUTPUT | jq -r .clientId)
ARM_CLIENT_SECRET=$(echo $SP_OUTPUT | jq -r .clientSecret)
ARM_TENANT_ID=$(echo $SP_OUTPUT | jq -r .tenantId)


# Create storage account
az storage account create --resource-group $resource_group_name --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob

# Get storage account key
ACCOUNT_KEY=$(az storage account keys list --resource-group $resource_group_name --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)

# Create blob container
az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME --account-key $ACCOUNT_KEY

echo "____________________________________________________________"
echo "____________________________________________________________"
echo "the following should be passed to the action"
echo "CLUSTER_NAME: $cluster_name";
echo "RESOURCE_GROUP_NAME: $resource_group_name";
echo "STORAGE_ACCOUNT_NAME: $STORAGE_ACCOUNT_NAME"
echo "STORAGE_CONTAINER_NAME: $CONTAINER_NAME"
echo "STORAGE_ACCESS_KEY: $ACCOUNT_KEY"
echo "ARM_CLIENT_ID: $ARM_CLIENT_ID"
echo "ARM_CLIENT_SECRET: $ARM_CLIENT_SECRET"
echo "ARM_SUBSCRIPTION_ID: $subscription"
echo "ARM_TENANT_ID: $ARM_TENANT_ID"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.createcosmos.action;

import com.createcosmos.action.resource.App;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ActionApplication {

public static void main(String[] args) {
SpringApplication.run(ActionApplication.class, args);
App exampleApp = new App();
exampleApp.run();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.createcosmos.action.resource;


public class App {

public void run() {
System.out.println("App is running...");
}
}
1 change: 1 addition & 0 deletions SpringExample/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.createcosmos.action;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ActionApplicationTests {

@Test
void contextLoads() {
}

}