Deploy Aplikasi AI di AWS Menggunakan Jenkins CI/CD dengan Metode DevSecOps

Artikel ini ditujukan untuk pembelajaran dan bukan untuk lingkungan produksi (ready production). Anda dapat menyesuaikannya lebih lanjut jika ingin menggunakan ini dalam lingkungan produksi. 

Metode DevSecOps

Sebelum memahami DevSecOps, Anda perlu mengenal DevOps terlebih dahulu. DevOps adalah metodologi yang mengoptimalkan komunikasi antara software developers dan tim operations dengan tujuan mempercepat waktu pengiriman melalui pipeline yang diotomatisasi (Jabbari et al. 2016). 

Seiring perkembangan teknologi dan meningkatnya serangan siber yang semakin canggih, perusahaan menghadapi tantangan besar dalam menjaga keamanan aplikasi. Sementara itu, bisnis tetap menuntut proses pengembangan dan operasional yang cepat. Oleh karena itu, para praktisi mulai memasukkan aspek keamanan dalam setiap langkah praktik DevOps, yang kemudian dikenal sebagai DevSecOps. 

Artikel ini mendokumentasikan proses deployment aplikasi berbasis AI di AWS menggunakan Jenkins CI/CD serta menerapkan metode DevSecOps. Diagram berikut menggambarkan tools yang digunakan dalam penerapan DevSecOps pada kasus ini. 

Diagram di bawah ini menggambarkan proses deploy dan penerapan DevSecOps yang digunakan, dengan penjelasan lebih rinci dijelaskan pada paragraf berikutnya. 

Persiapan Infrastruktur untuk Instalasi Docker

Dalam kasus ini, penulis menggunakan server AWS T3 Large Instance dengan OS Ubuntu 22.04. Sebuah keypair dibuat yang nantinya akan digunakan untuk proyek ini. Beberapa port TCP pada Security Group dibuka sesuai kebutuhan, dan storage yang digunakan untuk kasus ini adalah sebesar 30GB. 

 

Pada bagian Advanced, User Data ditambahkan menggunakan script berikut ini untuk menginstal Docker:  

#!/bin/bash
# Add Docker’s official GPG key:
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
“deb [arch=$(dpkg –print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo “$VERSION_CODENAME”) stable” | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Install the Docker packages:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Setelah selesai, klik tombol Create Instance, dan dalam waktu sekitar 3-5 menit, server akan berjalan sesuai persyaratan yang diinginkan. 

Selanjutnya, lakukan SSH ke dalam server dan ikuti perintah pada gambar di bawah ini untuk melakukan validasi bahwa Docker telah terinstal dengan benar. 

Menginstal Jenkins, SonarQube, dan Lainnya

Menginstal Jenkins

Akses server melalui SSH, kemudian buat direktori bernama `jenkins_home` lalu jalankan Docker dengan script di bawah ini. 

mkdir jenkins_home

docker run –name jenkins -d -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/usr/bin/docker -v ./jenkins_home:/var/jenkins_home -u 1000:$(getent group docker | cut -d’:’ -f3) –restart unless-stopped jenkins/jenkins:lts

Setelah instalasi selesai, akses Jenkins menggunakan public IP address dengan port 8080. 

Permintaan Administrator password seperti gambar di atas akan muncul. Anda bisa mendapatkan password dengan perintah berikut. 

docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Masukkan password yang telah didapat, kemudian instal plugin rekomendasi.   

Menginstal Plugins Jenkins

Pertama, masuk ke menu Manage Jenkins > Plugins > Available Plugins dan instal beberapa plugin yang dibutuhkan seperti di bawah ini. 

Menginstal Node Exporter

Buat file `docker-compose.yml` pada server Jenkins dengan menggunakan script di bawah ini. 

 


services:
node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node_exporter
command: “–path.rootfs=/host”
ports:
– 9100:9100
pid: host
restart: unless-stopped
volumes:
– /:/host:ro,rslaveroot

 

 

Jalankan script dengan perintah `docker compsoe up -d`. 

Menginstall SonarQube

Instalasi SonarQube untuk code quality dilakukan menggunakan script di bawah ini. 

docker run -itd –name sonar -p 9000:9000 –restart unless-stopped sonarqube:lts-community

Setelah instalasi selesai, akses IP dan port, kemudian login menggunakan username ‘admin’ dan password ‘admin’. 

Setelah itu, Anda akan diminta untuk mengubah password, dan kemudian diarahkan ke dashboard SonarQube seperti gambar di bawah. 

Proses Konfigurasi New Project SonarQube

Pada dashboard utama, pilih menu Manually dan buat konfigurasi seperti dibawah ini. Klik tombol Set Up setelah semuanya dikonfigurasi. 

Menginstal Trivy

Trivy berfungsi untuk melakukan scanning code projects dan membangun artefak untuk masalah keamanan seperti kerentanan, kesalahan konfigurasi IaC, kredensial, dan banyak lagi 

Instalasi Trivy dilakukan dengan melakukan copy script di bawah ini ke server. 

sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO – https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add –
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy

Penggunaan Trivy bisa dilakukan dengan perintah berikut. 

trivy image <imageid>

Trivy nantinya akan diintegrasikan dengan pipeline Jenkins. 

Proses Konfigurasi Java dan Node.js

Langkah pertama adalah pergi ke menu Manage Jenkins > Tools dan instal JDK (17) serta Node.js (18). 

Setelah konfigurasi selesai, klik Apply dan Save. 

Konfigurasi Sonar Server

Langkah pertama adalah  mengakses public IP dan port Sonar server (9090), kemudian pilih menu `Administration > Security > Users > Klik Tokens > Update Token > Berikan Nama > dan Generate`. 

Selanjutnya, pergi ke Jenkins Dashboard > Manage Jenkins > Credentials > System > Global credentials > Add Credentials > Add Secret Text. 

 Setelah menambahkan sonar-token pada Jenkins, pergi ke menu Dashboard > Manage Jenkins > System > SonarQube Servers. Lakukan konfigurasi seperti pada gambar di bawah ini, kemudian klik apply dan save. 

Konfigurasi Sonar Scanner

Pada dashboard Jenkins, pergi ke menu `Manage Jenkins > Tools > SonarQube Scanner Installation`. Lakukan konfigurasi seperti gambar di bawah ini. 

Proses Konfigurasi Webhook pada SonarQube

Pada dashboard SonarQube, pergi ke `Configuration > Webhooks > Create`. Masukkan URL berikut ke bagian URL. 

http://jenkins-public-ip-kamu:8080/sonarqube-webhook/

Proses Konfigurasi OWASP Dependency Check

Pada dashboard Jenkins, pergi ke menu` Manage Jenkins > Tools > Dependency-Check Installations`. Lakukan konfigurasi seperti di bawah ini, lalu klik apply dan save. 

Mengintegrasikan Jenkins Notifikasi ke Email

Proses diawali dengan login ke Gmail, kemudian klik profil Gmail, dan pergi ke `Manage Your Google Account > Security > App Password (Sandi Aplikasi)`. 

Selanjutnya, buat satu key baru dan simpan. 

Kemudian, pergi ke dashboard Jenkins dan masuk ke menu Manage Jenkins > Systems > E-mail Notification.  Masukkan SMTP server, username, password (token yang di-generate di atas), dan SMTP Port. Aktifkan SSL dan TLS, kemudian apply, lakukan test koneksi, dan save. 

Setelah itu, pergi ke menu Manage Jenkins > Credentials > System > Global > Add Credentials > Username with Ppassword. Isi data dan klik create. 

Kembali lagi ke menu Manage Jenkins > System > Extended E-mail Notification. Lakukan konfigurasi seperti gambar di bawah, kemudian save. 

Proses Konfigurasi Docker Registry dan Docker Credentials

Penulis telah menyiapkan Docker repository yang berfungsi untuk menyimpan image. Anda dapat membuat Docker repository dengan registrasi di hub.docker.com. Selanjutnya, buat satu registry yang nantinya akan digunakan untuk menyimpan image. Pada contoh ini, penulis menggunakan `neilsamaa/nutrivis` karena ini akan berpengaruh pada pemberian nama pada image yang dibangun. 

Selanjutnya kembali ke dashboard Jenkins dan masuk ke menu Manage Jenkins > Credentials > System > Global > Username and Ppassword. Masukkan username dan password dari DockerHub. 

Membuat Job dengan Pipeline pada Jenkins

Mulai dengan mengklik `New Item` pada dashboard, kemudian masukkan nama project dan pilih `Pipeline`, lalu klik ok. 

Masuk ke bagian Configure, copy dan paste pipeline-nya, kemudian save. 

pipeline{
    agent any
    tools{
        jdk ‘jdk17’
        nodejs ‘node18’
    }
    environment {
// CREDENTIALS
DOCKER_CREDENTIALS=”docker-credentials”
// TOOLS
        SCANNER_HOME=tool ‘sonar-scanner’
// ENV
TYPES_EXPRESS_NAME=”NutriVis”
TYPES_EXPRESS_PORT=”7777″
TYPES_EXPRESS_CLAUDEAI_API_KEY=”xxx”
TYPES_EXPRESS_CLAUDEAI_PROMPT=”As the nutritionist assessing the food image, simply identify the foods depicted without providing detailed descriptions. Express each item with a single word that best represents it. If you recognize multiple food items in the image, kindly connect them with the word ‘and’. For example, if you recognize fried chicken breast, fried tofu, and boiled eggs, say ‘chicken and tofu and egg’. Please include the details of every food item you recognize and express it in English.”
TYPES_EXPRESS_API_NINJAS_NUTRITION_API_KEY=”xxx”
    }
    stages {
        stage(‘clean workspace’){
            steps{
                cleanWs()
            }
        }
        stage(‘Checkout from Git’){
            steps{
                git branch: ‘backend-production’, url: ‘https://github.com/neilsamaa/iC-Project-1.git’
            }
        }
        stage(“Sonarqube Analysis”){
            steps{
                withSonarQubeEnv(‘sonar-server’) {
                    sh ”’ $SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=NutriVis \
                    -Dsonar.projectKey=NutriVis ”’
                }
            }
        }
        stage(“quality gate”){
           steps {
                script {
                    waitForQualityGate abortPipeline: false, credentialsId: ‘sonar-token’ 
                }
            } 
        }
        stage(‘Install Dependencies’) {
            steps {
                sh “npm install”
            }
        }
        stage(‘OWASP FS SCAN’) {
            steps {
                dependencyCheck additionalArguments: ‘–scan ./ –disableYarnAudit –disableNodeAudit’, odcInstallation: ‘DP-Check’
                dependencyCheckPublisher pattern: ‘**/dependency-check-report.xml’
            }
        }
        stage(‘TRIVY FS SCAN’) {
            steps {
                sh ‘docker run –rm -v $(pwd):/root/scan aquasec/trivy fs /root/scan > trivyfs.txt 2>&1’
                // sh ‘docker run –rm aquasec/trivy fs . > trivyfs.txt’
                // sh “trivy fs . > trivyfs.txt”
            }
        }
stage(“Docker Build & Push”) {
            steps {
                withCredentials([usernamePassword(credentialsId: “${DOCKER_CREDENTIALS}”, passwordVariable: ‘DOCKER_REGISTRY_PASSWORD’, usernameVariable: ‘DOCKER_REGISTRY_USER’)]) {
                    sh ”’
docker build -t neilsamaa/nutrivis:latest -f Dockerfile .
                    echo $DOCKER_REGISTRY_PASSWORD | docker login –username $DOCKER_REGISTRY_USER –password-stdin
                    docker push neilsamaa/nutrivis:latest
                    ”’
                }
            }
        }
        stage(“TRIVY”){
            steps{
                sh ‘docker run –rm aquasec/trivy image neilsamaa/nutrivis:latest > trivyimage.txt’
                // sh “trivy image neilsamaa/nutrivis:latest > trivyimage.txt” 
            }
        }
        stage(‘Deploy to container’) {
steps {
sh ”’
    docker pull neilsamaa/nutrivis:latest
docker run -itd –name nutrivis \
-e TYPES_EXPRESS_NAME=”$TYPES_EXPRESS_NAME” \
-e TYPES_EXPRESS_PORT=”$TYPES_EXPRESS_PORT” \
-e TYPES_EXPRESS_CLAUDEAI_API_KEY=”$TYPES_EXPRESS_CLAUDEAI_API_KEY” \
-e TYPES_EXPRESS_CLAUDEAI_PROMPT=”$TYPES_EXPRESS_CLAUDEAI_PROMPT” \
-e TYPES_EXPRESS_API_NINJAS_NUTRITION_API_KEY=”$TYPES_EXPRESS_API_NINJAS_NUTRITION_API_KEY” \
-p 7777:7777 neilsamaa/nutrivis:latest
”’
}
}
    }
post {
     always {
        emailext attachLog: true,
            subject: “‘${currentBuild.result}'”,
            body: “Project: ${env.JOB_NAME}<br/>” +
                “Build Number: ${env.BUILD_NUMBER}<br/>” +
                “URL: ${env.BUILD_URL}<br/>”,
            to: ‘mirzamaulanaazmi@gmail.com’,
            attachmentsPattern: ‘trivyfs.txt,trivyimage.txt’
        }
    }
}

 

Setelah disimpan, klik tombol Build Now untuk melakukan trigger build secara manual.  

Proses Setup Webhook GitHub untuk Trigger Build Otomatis Apabila Ada Perubahan pada Code Repository

Pada halaman dashboard, klik profile `Admin > Configure > API Token`, kemudian generate token dan simpan. 

Kembali ke Job Pipeline project sebelumnya, aktifkan Trigger Builds dan masukan authentication token, kemudian simpan. 

Selanjutnya, pergi ke GitHub Setting pada repo code aplikasi, dan masuk ke menu Webhook. Masukkan payload dengan format http://user:token@ip-public:port/job/xxx/build?token=xxx. 

http://admin:11ff9ae4e7db9643da98b8d40a4024c90c@13.229.183.49:8080/job/iC-Projects-1/build?token=asdasdasd

Hasil Output

Hasil Code Quality Menggunakan SonarQube

Hasil Email Notifikasi Ketika Proses Build Selesai

Log Build

Log Trivy Image Scan Vulnerability

Log Trivy Filesystem Scan Vulnerability 

Menginstal Prometheus dan Grafana

💡 Prometheus dan Grafana berguna untuk melakukan monitoring pada project ini. 

  

Mulai dengan membuat satu server lagi seperti pada langkah pertama, dan untuk family instance yang digunakan bisa menggunakan T3 Medium.  

Pertama, buat direktori dengan perintah di bawah ini. 

mkdir -p prometheus/config

mkdir grafana

Kemudian buat file `prometheus.yml` di dalam direktori `prometheus/config` dengan menggunakan kode dibawah ini. 

global:
scrape_interval: 10s # By default, scrape targets every 15 seconds.
evaluation_interval: 15s
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
# external_labels:
# monitor: ‘codelab-monitor’

scrape_configs:
– job_name: ‘prometheus’
scrape_interval: 5s
static_configs:
– targets: [‘localhost:9090’]

# job for node_exporter
– job_name: ‘node-monitoring’
static_configs:
– targets: [‘node-monitoring:9100’]

– job_name: ‘node-jenkins’
static_configs:
– targets: [‘13.229.82.99:9100’]

# job for jenkins
– job_name: ‘jenkins-exporter’
metrics_path: ‘/prometheus/’
static_configs:
– targets: [‘13.229.82.99:8080’]

Selanjutnya, buat file `docker-compose.yml` dengan perintah di bawah ini. 

nano docker-compose.yml

Tempelkan kode ini ke dalamnya: 

services:
prometheus:
user: “1000:1000”
image: prom/prometheus:latest
container_name: prometheus
ports:
– “9090:9090”
volumes:
– /home/ubuntu/prometheus/config:/etc/prometheus:ro
– /home/ubuntu/prometheus:/prometheus
restart: unless-stopped
command:
– “–config.file=/etc/prometheus/prometheus.yml”

grafana:
user: “1000:1000”
image: grafana/grafana:latest
container_name: grafana
ports:
– “3000:3000”
volumes:
– /home/ubuntu/grafana:/var/lib/grafana
restart: unless-stopped

node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node-monitoring
#ports:
# – 9100:9100
command: “–path.rootfs=/host”
pid: host
restart: unless-stopped
volumes:
– /:/host:ro,rslave

Simpan dan jalankan dengan perintah berikut. 

docker compose up -d

Akses dapat dilakukan dengan IP dan port 9090 dengan /targets. Terlihat semua state up yang menandakan sudah berjalan dan berhasil mendapatkan metrics-nya. 

Setup Grafana

Pertama, akses web Grafana dengan IP public dan port 3000. Login dengan kredensial default yaitu user ‘admin’, pass ‘admin’. Anda akan diminta untuk melakukan update password dan diarahkan ke dashboard utama. 

Selanjutnya, klik Datasource. 

Pilih Prometheus untuk Ddatasource.  

Masukkan URL Prometheus. Pada contoh di bawah, penulis menggunakan `http://prometheus:9090` karena penulis menggunakan Docker. Selanjutnya, klik save dan test. 

 

Pada pojok kanan atas, pilih Import Dashboard. 

Masukkan kode 1860, pilih datasource-nya, kemudian load dan import. 

Dashboard berhasil di-import dan tampilannya kurang lebih seperti ini. 

Anda juga bisa menambahkan dashboard untuk monitoring Jenkins overview dengan melakukan import kode dashboard 9964. 

Itulah seluruh proses deploy AI App menggunakan Jenkins CI/CD dengan menerapkan metode DevSecOps. Adapun penerapan yang dilakukan pada kasus ini merupakan percontohan. Anda bisa mencoba sendiri dengan mengikuti dokumentasi ini atau menyesuaikan penggunaan tools dan konfigurasi sesuai dengan kebutuhan Anda. 

Facebook
Twitter
LinkedIn
WhatsApp

Write Your Own Article!