Docker ile CI(Continious Integration) Ortamı Nasıl Kurulur?

CI denildiğinde aklımıza gelen araçların başında sanırım Jenkins gelir. Eğer kodları bir statik kod analizinden geçirmek istiyorsak ayrıca bir de SonarQube gibi bir araca ihtiyacımız vardır. Bu yazıda amacım docker kullanarak kolayca Jenkins ve SonarQube ikilisini kullanarak bir CI ortamı oluşturmak.

Örnek bir pipeline oluşturmak istiyorum. Bu pipeline içerisindeki adımları aşağıdaki gibi belirleyebiliriz;

Not: Bu örnek uygulama maven projesi olarak oluşturulmuştur.

  1. Kodların checkout edilmesi
  2. Projenin build(maven) edilmesi
  3. Projedeki unit testlerin çalıştırılması
  4. Statik kod analizinin çalıştırılması

Bu işlemleri yapabilmek için ihtiyacım olanları aşağıdaki gibi sıralayabilirim;

  1. Docker kurulu bir bilgisayar
  2. Jenkins için docker image
  3. Projeyi build ederken kullanacağım maven docker image
  4. Statik kod analizini işleyip görselleştirmek için SonarQube docker image

Docker kurulu olan bilgisayar olduğunu varsayarak devam edersek 2. adıma geçebilirim. Bu adımda kullanacağım docker image “jenkinsci/blueocean”. Fakat benim kodları çekebilmem için gerek duyduğum SSH işlemleri için docker image’nda bazı değişiklikler yapmam gerekti. Container içerisinden kolayca SSH bağlantısı yapabilmem için SSH private key’i image’e ekleyip aynı zamanda bağlanacağım adresi de “known_hosts”a eklemem gerekli.

Buna bağlı olarak docker file aşağıdaki gibi oluşuyor;

FROM jenkinsci/blueocean
ARG ssh_prv_key
ARG ssh_pub_key
USER root
RUN mkdir -p /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan -p 2022 [host-name] > /root/.ssh/known_hosts
RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa && \
    echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub && \
    chmod 600 /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/id_rsa.pub
USER jenkins

Aşağıdaki bölüm [host-name] ile belirtilen adresi “known_hosts” dosyasına eklemeyi sağlar.

RUN mkdir -p /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan -p 2022 [host-name] > /root/.ssh/known_hosts

Aşağıdaki bölüm ise “$ssh_prv_key” ve “$ssh_pub_key” parametreleri ile verilen SSH private ve public keylerini “.ssh” dizinine eklemeyi sağlar.

RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa && \
    echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub && \
    chmod 600 /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/id_rsa.pub

Docker image build etmek için aşağıdaki komutu kullanabilirsiniz;

docker build -t custom-jenkins-blueocean --build-arg ssh_prv_key="$(cat /[your-path]/id_rsa)" --build-arg ssh_pub_key="$(cat /[your-path]/id_rsa.pub)" --squash .

Yeni oluşturduğumuz image üzerinden bir container çalıştırmak için aşağıdaki komutu kullanabilirsiniz;

docker volume create jenkins-data
docker run --name my-jenkins -u root --rm -d -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock custom-jenkins-blueocean
docker logs -f my-jenkins

Jenkins çalıştıktan sonra admin olarak açıldığından emin olmak için admin password istiyor. Bu bilgiyi alabilmek için aşağıdaki adımları izleyebilirsiniz;

docker exec -it my-jenkins bash
vi /var/jenkins_home/secrets/initialAdminPassword

Sonraki adımda jenkins için default plug-inleri kurmasını belirtip geçebiliriz. Artık Jenkins kullanıma hazır durumda.

Artık Jenkins ortamının hazır olduğunu gördük. Bundan sonraki adım projemizi CI/CD işlerini yapacak pipeline oluşturmak. Test etmek için aşağıdaki repoyu kullanabilirsiniz;

https://github.com/dilaverdemirel/simple-java-maven-app?source=post_page—–354cfd364c7b———————-

Bu repo içerisindeki Jenkinsfile bizim pipeline’nımızı otomatik oluşturmamızı sağlayacak.

pipeline {
    agent {
        docker {
            image 'maven:3-alpine'
            args '-v /root/.m2:/root/.m2'
        }
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn -B -DskipTests clean package'
            }
        }
        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }
        stage('Deliver') {
            steps {
                sh './jenkins/scripts/deliver.sh'
            }
        }
    }
}

Scripti incelediğimizde;

 agent {
        docker {
            image 'maven:3-alpine'
            args '-v /root/.m2:/root/.m2'
        }
    }

yukarıdaki bölüm pipeline scriptinde tanımlı olan “stage”leri çalıştıracağımız ortamı bize sağlar. Stage’ler bir “maven:3-alpine” image ile oluşturulan docker conrainer içerisinde çalıştırılır. “maven:3-alpine” image bize Maven 3 kurulu bir ortam sağlar. Amacımız maven projesi olarak oluşturulmuş olan projemizi build/test/deliver adımlarından geçirip belirlediğimiz kontrolleri ve işleri yapmamız. Bunun için maven tooluna ihtiyacımız vardı, bunu da “maven:3-alpine” image ile hallettik.
Bu sayede bir maven kurulumu yapmadan yine docker ile projeyi build ve test ettik.
Bu noktada eğer custom bir maven repository kullanıyorsanız maven “settings.xml” dosyasını değiştirmeniz gerekecektir. Bunun için ise aşağıdaki docker file’ı kullanabilirsiniz;

#Dockerfile
FROM maven:3.6.1-jdk-8-slim
COPY settings.xml /usr/share/maven/conf/

Dockerfile’in olduğu dizinde maven için gerekli olan “settings.xml” dosyası da olmalıdır. Aşağıdaki komut ile image build edebilirsiniz;

docker build -t maven-jdk-8-slim .

Oluşturduğunuz custom image’ı kullanmak için “Jenkinsfile” içerisindeki agent bölümünü aşağıdaki gibi değiştirmelisiniz;

  agent {
        docker {
            image 'maven-jdk-8-slim'
            args '-v /root/.m2:/root/.m2'
        }
    }

Sonuç olarak docker ile jenkins ortamını kurduk ve yine maven docker image ile projemizi build ettik. Docker dışında farklı bir araç kurulumunu manuel olarak yapmadık.