İçerik
Bu yazıda Kubernetes CI/CD süreçlerinin nasıl işlediğine dair temel bilgileri bulabileceksiniz. Kubernetes üzerinde Gitlab ve Gitlab Runner kurulumunu yapacağız. Ardından SonarQube kurulumu ve son olarak Harbor Registry kurulumunu yapacağız. Tüm bu araçlar Kubernetes üzerinde çalışacak. Gitlab Runner üzerinden build, code analysis ve deployment süreçlerini yazacağız.
Bu süreçlerin geliştirilmesi ve değiştirilmesi tamamen projenize bağlıdır. Test aşaması ekleyebilirsiniz ya da bir çok open-source tool araya koyabilirsiniz. Bu yazıda sadece temel seviyede ilgili CI/CD kavramını ve nasıl sistemin kurulduğuna değiniyorum. Kıvılcım benden ateşi körüklemek sizden :]
CI/CD Nedir?
CI Continuous Integration (Sürekli Entegrasyon), CD ise Continuous Delivery (Sürekli Teslimat) ya da (Continuous Deployment) Sürekli Dağıtım kısaltmasını ifade etmektedir.
Continuous Integration (Sürekli Entegrasyon)
Sürekli entegrasyon mimarisi yapılan değişiklikler/geliştirmeler sonucu oluşan yeni sürümün, bir boru hattı (pipeline) vasıtasıyla, mevcut sürüm ile sürekli şekilde otomatik olarak birleştirilmesini sağlar. Burada önemli olan nokta sürecin bir boru hattı (pipeline) üzerinden yürütülüyor olmasıdır.
Boru hattı (pipeline) dediğimiz şey aslında süreçleri uç uca eklemek ve ihtiyaçlarımız doğrultusunda akışlara yön vererek otomatize edilmiş bir düzen oluşturmaktır.
CI pipeline içerisinde kabul kriterlerimiz için boru hatları oluşturur ve bunları bir araya getirerek yeni paketin ancak bir dizi otomatik kontrol sonrasında hedef sürüm ile birleştirilmesini sağlayabiliriz.
Continuous Delivery (Sürekli Teslimat)
Sürekli teslimat ise istenilen bir sürümün istenilen bir ortama elle tetiklemek suretiyle deploy edilebilmesidir. Yani biz istemedikçe deployment sağlanmaz, deployment istediğimizde süreci manuel olarak başlatırız.
Normalde ilgili bir sürümü deploy etmek için manuel gerçekleştirdiğimiz tüm adımları komut dosyaları vs. aracılığıyla otomatize ederiz.
Yani görselleştirmek gerekirse artık akışımız aşağıdaki şekilde olacaktır
Continuous Deployment (Sürekli Dağıtım)
Sürekli dağıtım ise CI sonrasında ilgili ortamlara deploymentin otomatik olarak yapılmasıdır. CI pipeline’i CD pipeline’a bağlarız ve bu sayede güncel sürümün yayınlanmasını istediğimiz ortamlara otomatik deploy ederiz.
Örnek üzerinden ilerleyecek olursak;
dev branch’te bir güncelleme olduğunda internal ya da staging ortamlarına deploy olmasını, master branch’te bir güncelleme olduğunda pre-prod ya da prod ortamlarına deploy olmasını sağlayabiliriz.
CD pipeline içerisinde migrationların çalışması, trafiğin yeni sürüme iletilmesi için swap/routing işlemleri, cdn önbellek temizliği, log rotation vs. hedef ortamın ve mimarinizin dinamiklerine göre dilediğiniz işlevleri dahil edebilirsiniz.
Harbor Registry Kurulumu
Daha önce Harbor registry’nin nasıl kurulduğuna dair bir yazı hazırlamıştım. Aşağıdaki bağlantıdan ulaşabilirsiniz.
SonarQube Kurulumu
Aşağıdaki yazımda SonarQube kurulumunu ve Jenkins’e entegrasyonunu anlatmıştım. İlgili yazımdaki SonarQube kurulumunu sadece yapmanız yeterli olacaktır.
Gitlab/Gitlab Runner Kurulumu
Daha önce aynı şekilde bu kurulumu anlatan bir yazı yazmıştım. Aşağıdaki yazıyı baz alarak kurulumunuzu tamamlayabilirsiniz. Kurulumu yaparken gözden kaçırmamanız gereken en önemli nokta yazımda bulunan aşağıdaki helm komutunu
--set gitlab-runner.install=false \
aşağıdaki gibi değiştirmelisiniz.
--set gitlab-runner.install=true \
Böylelikle Kubernetes üzerinde Gitlab’ı kurarken beraberinde Gitlab Runner’ı da kurmuş olacağız.
CI/CD Süreçleri
Aşağıdaki süreçler test için oluşturduğum Dockerfile, .gitlab-ci.yml, index.html, myweb.yaml dosyalarını kapsamaktadır. Bu dosyaları Gitlab reponuzun içerisine yüklediğinizi ve/veya oluşturduğunuzu varsayıyorum. Anlatım bu kıstasa göre olacaktır.
Bu repo içerisindeki dosyaların temel işlevleri aşağıdaki gibidir.
- Apache ile birlikte index.html dosyamızın da içerisinde bulunduğu bir image oluşturmak
- Bu image’ı versiyonlayıp Harbor Registry’e yüklemek.
- Oluşan her değişiklikte myweb.yaml dosyamızı kubectl aracılığı ile Kubernetes üzerinde deploy etmek.
- .gitlab-ci.yml ile birlikte SonarQube aracını CI/CD sürecine dahil etmek.
NOT: Bu süreçte “Argo-CD” gibi araçlarda kullanılabilir. Başta belirttiğim gibi size göre kusursuz bir sistemi yaratmak kendi elinizde. Bu anlatım sadece temel seviyede yol gösterici niteliğindedir.
Gitlab Reposunun Oluşturulması
Gitlab / Gitlab Runner kurulumunuzu yaptıktan sonra arayüze web üzerinden erişin. Daha sonra projeniz için reponuzu oluşturun. Bunu oluşturduğunuzu varsayarak görsel anlatım yapmıyorum. Klasik Gitlab arayüzü ve aşamaları.
Web Dosyasının Oluşturulması
Oluşturacağımız Dockerfile dosyasında Apache üzerinden yayınlayacağımız index.html dosyası aşağıdaki gibidir.
<center>
<h1>Sezer.in</h1>
<h1>v1.0</h1>
<br><hr>
<p>CI/CD Süreçleri - Kubernetes - Gitlab/Gitlab Runner - SonarQube - Harbor Registry</p>
</center>
Dockerfile Dosyasının Oluşturulması
Repomuzun içerisinde oluşturacağımız Dockerfile dosyamızın içeriği aşağıdaki gibi olacaktır.
FROM httpd:2.4
COPY ./index.html /usr/local/apache2/htdocs
Kubernetes Üzerinde ImagePullSecret Oluşturulması
Şifre korumalı bir Registry üzerinde çalışıyorsanız ve Deployment’larınızda bu Registry üzerinden Image çekiyorsanız mutlaka Deployment dosyanızda bu Image’ın hangi bilgileri kullanarak Registry’e login olacağını belirtmeniz gerekir. Bu şekilde Kubernetes podları oluştururken Private Registry adresinizden sorunsuz Image’ları çekebilecek.
Bununla ilgili yazımı bu bağlantıda bulabilirsiniz.
Kubernetes Deployment Dosyasının Oluşturulması
Repomuzun içerisinde oluşturacağımız myweb.yaml dosyamızın içeriği aşağıdaki gibi olacaktır.
Yaml kodlarımız arasında bulunan Registry adresini kendi adresiniz ile değiştirin. Ayrıca imagePullSecrets kısmındaki veriyi de üstte anlattığım daha önce oluşturduğunuz ImagePullSecret adınızla değiştirmeyi unutmayın. Yine de .gitlab-ci.yml dosyasının içerisinde ImagePullSecret oluşturma aşamasını da ekledim. Manuel yapmanıza gerek kalmadan bu kısmı da Pipeline üzerinden yönetebilirsiniz.
apiVersion: v1
kind: Namespace
metadata:
name: myweb
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myweb
name: myweb
namespace: myweb
spec:
replicas: 3
selector:
matchLabels:
app: myweb
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: myweb
spec:
containers:
- image: harbor.sezer.test:443/library/test-image:latest
imagePullPolicy: Always
name: myweb
env:
- name: BUILD_DATE
value: 'THIS_STRING_IS_REPLACED_DURING_BUILD'
imagePullSecrets:
- name: sezertestsecret
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myweb
name: myweb
namespace: myweb
spec:
ports:
- nodePort: 32223
port: 80
protocol: TCP
targetPort: 80
selector:
app: myweb
type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myweb
namespace: myweb
spec:
ingressClassName: nginx
rules:
-
host: myweb.test
http:
paths:
-
backend:
service:
name: myweb
port:
number: 80
path: /
pathType: Prefix
Gitlab İçin Cluster Yetkisi Tanımlanması
Gitlab Runner’ın Kubernetes üzerinde deployment yapabilmesi için Cluster yetkisinin olması gerekiyor. Aşağıdaki komutla Gitlab’a yetki tanımlayabilirsiniz.
kubectl create clusterrolebinding gitlab-cluster-admin --clusterrole=cluster-admin --group=system:serviceaccounts --namespace=gitlab
Pipeline İçin Variable Tanımlamaları
Pipeline üzerinde kullanacağımız bazı variable’lar var. Bunları tanımlamak için Gitlab Web arayüzüne girdikten sonra reponuzun içerisindeki Settings > CI/CD menüsüne gidin. İlgili sayfada Variables sekmesini göreceksiniz. Tanımlamalarınız aşağıdaki gibi olmalı.
- DOCKER_REGISTRY_HOST => Image’ı çektiğiniz Registry adresi
- DOCKER_REGISTRY_PASSWORD => Registry şifresi
- DOCKER_REGISTRY_USER => Registry kullanıcı adı
- KUBE_CONFIG => Kubernetes Cluster’ınıza bağlanmak için kullandığınız .kube/config dosyanız
- SONAR_HOST_URL => SonarQube kurulumu yaptığınız URL
- SONAR_TOKEN => SonarQube üzerinden projenize oluşturduğunuz Token
Tüm tanımları aşağıya görsel olarak ekledim.
Gitlab Runner Pipeline Dosyasının Oluşturulması
Repomuzun içerisinde oluşturacağımız .gitlab-ci.yml dosyası bizim için tüm işleri yapacak Pipeline kodlarını içeren dosyadır.
stages:
- build
- sonarqubecheck
- deploy
before_script:
- |
for i in $(seq 1 30)
do
docker info && break
echo "Waiting for docker to start"
sleep 1s
done
docker_build_version_push:
stage: build
image: docker:latest
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_TLS_VERIFY: 1
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
script:
- docker build -t harbor.sezer.test:443/library/test-image:latest -t harbor.sezer.test:443/library/test-image:$CI_PIPELINE_IID .
- docker login $DOCKER_REGISTRY_HOST -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
- docker push harbor.sezer.test:443/library/test-image:latest && docker push harbor.sezer.test:443/library/test-image:$CI_PIPELINE_IID
- docker rmi $(docker images -a -q) -f
sonarqube_check:
stage: sonarqubecheck
image:
name: sonarsource/sonar-scanner-cli:latest
entrypoint: [""]
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0"
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- sonar-scanner
allow_failure: true
only:
- main
deploy_to_k8s:
stage: deploy
image: alpine:latest
script:
- apk update && apk add --no-cache curl
- curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
- chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl
- mkdir -p $HOME/.kube
- echo -n $KUBE_CONFIG | base64 -d > $HOME/.kube/config
- sed -ie "s/THIS_STRING_IS_REPLACED_DURING_BUILD/$(date)/g" myweb.yaml
- kubectl apply -f myweb.yaml
- kubectl create secret docker-registry sezertestsecret -n myweb --docker-server=$DOCKER_REGISTRY_HOST --docker-username=$DOCKER_REGISTRY_USER --docker-password=$DOCKER_REGISTRY_PASSWORD --dry-run=client -o yaml | kubectl apply -f -
Sonuç
Artık repomuza herhangi bir push yaptığımızda otomatik olarak Pipeline devreye girecek. Böylelikle projemizi derlemiş, versiyonlamış, analiz etmiş ve Cluster üzerinde dağıtmış olduk.