diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..f02131ce --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: Java CI with Gradle + +on: + pull_request: + branches: [ main ] + +env: + DATREE_TOKEN: ${{ secrets.DATREE_TOKEN }} + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + cache: gradle + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build + - name: SonarQube Scan + uses: sonarsource/sonarqube-scan-action@master + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + - name: SonarQube Quality Gate check + uses: sonarsource/sonarqube-quality-gate-action@master + # Force to fail step after specific time + timeout-minutes: 5 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - name: Install Datree + run: curl https://get.datree.io | /bin/bash + + - name: Run Datree's policy check + run: datree test kube.yaml + + diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml new file mode 100644 index 00000000..d6773d69 --- /dev/null +++ b/.github/workflows/cicd.yml @@ -0,0 +1,84 @@ +name: Java CICD with Gradle + +on: + push: + branches: [ main ] + +env: + DATREE_TOKEN: ${{ secrets.DATREE_TOKEN }} + KUBECONFIG: /home/alerts_deekshith/kubeconfig/config_now + +jobs: + build: + + runs-on: self-hosted + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + cache: gradle + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build + - name: SonarQube Scan + uses: sonarsource/sonarqube-scan-action@master + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + - name: SonarQube Quality Gate check + uses: sonarsource/sonarqube-quality-gate-action@master + # Force to fail step after specific time + timeout-minutes: 5 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - name: Install Datree + run: curl https://get.datree.io | /bin/bash + + - name: Run Datree's policy check + run: datree test kube.yaml + + - name: Login to Nexus registy + uses: docker/login-action@v1 + with: + registry: 34.125.31.157:8083 + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: docker build & docker push + run: | + docker build -t 34.125.31.157:8083/javaapp:${{ github.run_number }} . + docker push 34.125.31.157:8083/javaapp:${{ github.run_number }} + docker rmi 34.125.31.157:8083/javaapp:${{ github.run_number }} + + - name: deploying manifest file on k8s cluster + run: | + sed -i "s;imagename;34.125.31.157:8083/javaapp:${{ github.run_number }};g" kube.yaml + kubectl apply -f kube.yaml + sleep 30 + kubectl get po + + - name: verification + run: | + sleep 60 + kubectl run curl --image=curlimages/curl -i --rm --restart=Never -- curl myapp:8080 + + - name: Send email + if: always() + uses: dawidd6/action-send-mail@v2 + with: + server_address: smtp.gmail.com + server_port: 465 + username: ${{ secrets.EMAIL_USERNAME }} + password: ${{ secrets.EMAIL_PASSWORD }} + subject: ${{ github.job }} job of ${{ github.repository }} has ${{ job.status }} + # email body as text + body: ${{ github.job }} job in worflow ${{ github.workflow }} of ${{ github.repository }} has ${{ job.status }} + # comma-separated string, send email to + to: deekshith.snsep@gmail.com + # from email name + from: deekshith.snsep@gmail.com diff --git a/Dockerfile b/Dockerfile index e6c19db0..f9c20863 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# this is multi stage FROM openjdk:11 as base WORKDIR /app COPY . . @@ -7,4 +8,4 @@ RUN ./gradlew build FROM tomcat:9 WORKDIR webapps COPY --from=base /app/build/libs/sampleWeb-0.0.1-SNAPSHOT.war . -RUN rm -rf ROOT && mv sampleWeb-0.0.1-SNAPSHOT.war ROOT.war \ No newline at end of file +RUN rm -rf ROOT && mv sampleWeb-0.0.1-SNAPSHOT.war ROOT.war diff --git a/JenkinsfileFilter b/JenkinsfileFilter new file mode 100644 index 00000000..1c68c70e --- /dev/null +++ b/JenkinsfileFilter @@ -0,0 +1,23 @@ +pipeline { + agent { + docker { + image 'openjdk:11' + } + } + + stages { + stage('Building') { + steps { + sh 'chmod +x gradlew' + sh "./gradlew build | tee output.log" + } + } + stage('Monitoring the logs') { + steps { + script { + sh '! grep "Task" output.log' + } + } + } + } +} diff --git a/JenkinsfileSharedLibrary b/JenkinsfileSharedLibrary new file mode 100644 index 00000000..0a04c9fb --- /dev/null +++ b/JenkinsfileSharedLibrary @@ -0,0 +1,26 @@ +#!/usr/bin/env groovy + +@Library('shared-library@master') _ //master or whatever branch + + +pipeline { + agent { + docker { + image 'openjdk:11' + } + } + + stages { + stage('Building') { + steps { + sh 'chmod +x gradlew' + sh "./gradlew build " + } + } + stage ('Check logs') { + steps { + filterLogs ('Task', 15) + } + } + } +} diff --git a/Jenkinsfile_demo b/Jenkinsfile_demo new file mode 100644 index 00000000..3db03236 --- /dev/null +++ b/Jenkinsfile_demo @@ -0,0 +1,96 @@ +pipeline{ + agent any + environment{ + VERSION = "${env.BUILD_ID}" + } + stages{ + stage("sonar qube analysis"){ + agent{ + docker { + image 'openjdk:11' + } + } + steps{ + script{ + withSonarQubeEnv(credentialsId: 'sonar-token') { + sh ''' + chmod +x gradlew + ./gradlew sonarqube + ''' + } + + timeout(5) { + def qg = waitForQualityGate() + if (qg.status != 'OK') { + error "Pipeline aborted due to quality gate failure: ${qg.status}" + } + } + } + } + } + + stage("building docker image and pushing it to nexus"){ + steps{ + script{ + + withCredentials([string(credentialsId: 'nexus_pass', variable: 'docker_pass')]) { + sh ''' + + docker build -t 35.188.44.251:8083/springapp:${VERSION} . + docker login -u admin -p $docker_pass 35.188.44.251:8083 + docker push 35.188.44.251:8083/springapp:${VERSION} + docker rmi 35.188.44.251:8083/springapp:${VERSION} + docker image prune -f + ''' + } + } + } + } + + + stage('manual approval'){ + steps{ + script{ + timeout(10) { + mail bcc: '', body: "
Project: ${env.JOB_NAME}
Build Number: ${env.BUILD_NUMBER}
Go to build url and approve the deployment request
URL de build: ${env.BUILD_URL}", cc: '', charset: 'UTF-8', from: '', mimeType: 'text/html', replyTo: '', subject: "${currentBuild.result} CI: Project name -> ${env.JOB_NAME}", to: "issamraz1993@gmail.com"; + input(id: "Deploy Gate", message: "Deploy ${params.project_name}?", ok: 'Deploy') + } + } + } + } + + + + stage('Deploying application on k8s cluster') { + steps { + script{ + withCredentials([kubeconfigFile(credentialsId: 'kubernetes-config', variable: 'KUBECONFIG')]) { + dir('kubernetes/') { + + sh 'helm upgrade --install --set image.repository="35.188.44.251:8083/springapp" --set image.tag="${VERSION}" myjavaapp myapp/ ' + } + } + } + } + } + + + stage('verifying app deployment'){ + steps{ + script{ + withCredentials([kubeconfigFile(credentialsId: 'kubernetes-config', variable: 'KUBECONFIG')]) { + sh ''' + + chmod +x healthcheck.sh + ./healthcheck.sh + ''' + + } + } + } + } + + + } + +} diff --git a/build.gradle b/build.gradle index 1e8ba502..2b60d6a0 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ test { sonarqube { properties { - property 'sonar.host.url', 'http://34.125.75.197:9000' + property 'sonar.host.url', 'http://34.125.201.58:9000' property 'sonar.login', '******' } } diff --git a/healthcheck.sh b/healthcheck.sh new file mode 100644 index 00000000..c0244ee6 --- /dev/null +++ b/healthcheck.sh @@ -0,0 +1,10 @@ +echo "executing health check it might take a while" +sleep 120 +kubectl run curl --image=curlimages/curl -i --rm --restart=Never -- curl myjavaapp-myapp:8080 + +if [ $? -eq 0 ] +then + echo "The Deployment is success...Application Health is Good" +else + helm rollback myjavaapp +fi diff --git a/kube.yaml b/kube.yaml new file mode 100644 index 00000000..d0058111 --- /dev/null +++ b/kube.yaml @@ -0,0 +1,81 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: myapp + labels: + helm.sh/chart: myapp-0.2.0 + app.kubernetes.io/name: myapp + app.kubernetes.io/instance: myapp + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + type: NodePort + ports: + - port: 8080 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: myapp + app.kubernetes.io/instance: myapp +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + labels: + helm.sh/chart: myapp-0.2.0 + app.kubernetes.io/name: myapp + app.kubernetes.io/instance: myapp + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: myapp + app.kubernetes.io/instance: myapp + template: + metadata: + labels: + app.kubernetes.io/name: myapp + app.kubernetes.io/instance: myapp + spec: + imagePullSecrets: + - name: registry-secret + containers: + - name: myapp + image: imagename + command: ["/bin/sh"] + args: ["-c","sh /usr/local/tomcat/bin/startup.sh;while true; do echo hello; sleep 10;done"] + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 60 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 60 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + resources: + requests: + memory: 0.25Gi + cpu: 0.5 + limits: + memory: 0.25Gi + cpu: 0.5 diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000..3f7e5334 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,3 @@ +sonar.projectKey=CICD_Java_gradle_application +sonar.java.binaries=. +sonar.exclusions=build/** diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 017ca718..414eacf6 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -4,7 +4,240 @@ web app -

Sample Web application

+

Sample Web application has been deployed with Github action

- \ No newline at end of file + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + + + + + + web app + + +

Sample Web application has been deployed with Github action

+ + + + +