DEV Community

Taha Yağız Güler
Taha Yağız Güler

Posted on

2NTECH-PROJE

2NTECH
Proje Amacı
Bu projede, Go dilinde yazılmış bir web uygulamasının geliştirilmesi, Docker kullanarak konteynerleştirilmesi, GitHub Actions ile CI/CD sürecinin kurulması, Kubernetes kullanılarak uygulamanın dağıtımının otomatik hale getirilmesi ve Argo CD ile sürekli dağıtım sürecinin entegrasyonu üzerine odaklandım. MERN stack yerine, Golang ile oluşturulmuş basit bir Web App tercih ettim çünkü MERN ile daha önce çalışmadım ve bu projede odaklanılması gereken ana konunun, Docker, Kubernetes ve CI/CD süreçleri olduğunu düşündüm.

Projenin GitHub reposuna buradan ulaşabilirsiniz.

1. Go Web Uygulaması Oluşturulması

Aşağıda, basit bir Go web uygulamasının test edilmiş örneği yer almaktadır:

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHomePage(t *testing.T) {
    req, err := http.NewRequest("GET", "/", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(homePage)

    handler.ServeHTTP(rr, req)

    if status := rr.Code; status != http.StatusOK {
        t.Errorf("homePage handler returned wrong status code: got %v want %v", status, http.StatusOK)
    }
}
Enter fullscreen mode Exit fullscreen mode
func TestHomeEndpoint(t *testing.T) {
    req, err := http.NewRequest("GET", "/home", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(homePage)

    handler.ServeHTTP(rr, req)

    if status := rr.Code; status != http.StatusOK {
        t.Errorf("home handler returned wrong status code: got %v want %v", status, http.StatusOK)
    }
}

func TestAboutPage(t *testing.T) {
    req, err := http.NewRequest("GET", "/about", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(aboutPage)

    handler.ServeHTTP(rr, req)

    if status := rr.Code; status != http.StatusOK {
        t.Errorf("aboutPage handler returned wrong status code: got %v want %v", status, http.StatusOK)
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Konteynerleştirme - Dockerfile Kullanımı
Bu süreçte, çok aşamalı bir Dockerfile kullanarak uygulamanın boyutunu optimize ettim. Dockerfile aşağıdaki gibi hazırlanmıştır:

FROM golang:1.23 AS base

WORKDIR /app

COPY go.mod .

RUN go mod download

COPY . .

RUN go build -o main .

# Final stage - Distroless image.

FROM gcr.io/distroless/base

COPY --from=base /app/main .

COPY --from=base /app/static ./static

# Expose the port on which the application will run
EXPOSE 8080

# Command to run the application
CMD ["./main"]
Enter fullscreen mode Exit fullscreen mode

3. Kubernetes ile Dağıtım
Uygulamanın Docker ile konteynerleştirilmesinin ardından, Kubernetes (K8s) kullanarak dağıtım yaptım. EKS (Amazon Elastic Kubernetes Service) kullanarak, Kubernetes kümesi oluşturdum ve Go uygulamasını bu kümeye dağıttım. AWS Kubernetes kümemi oluştururken eksctl kullandım ve Terraform ile yapmamın sebebi Bu kadar kısa bir işlem için buna gerek duymamam.
”Eğer Terraform ile ilgili projelerimi incelemek isterseniz, GitHub profilimi inceleyebilirsiniz.”

Aşağıda uygulamanın Kubernetes dağıtımı için kullanılan YAML dosyaları örnek olarak verilmiştir:

Deployment: Uygulamanın dağıtımını ve yönetimini sağlar.
Service: Uygulamanın dış dünyaya açılmasını sağlar.
Ingress: Trafiğin doğru yönlendirilmesini ve dış erişimi sağlar.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-web-app
  labels:
    app: go-web-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-web-app
  template:
    metadata:
      labels:
        app: go-web-app
    spec:
      containers:
      - name: go-web-app
        image: tyguler/go-web-app:v1
        ports:
        - containerPort: 8080
Enter fullscreen mode Exit fullscreen mode
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: go-web-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: go-web-app.local
    http:
      paths: 
      - path: /
        pathType: Prefix
        backend:
          service:
            name: go-web-app
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode
# Service
apiVersion: v1
kind: Service
metadata:
  name: go-web-app
  labels:
    app: go-web-app
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
  selector:
    app: go-web-app
  type: ClusterIP
Enter fullscreen mode Exit fullscreen mode

4. Helm ile Uygulama Yönetimi
Kubernetes üzerinde uygulama yönetimini kolaylaştırmak için Helm kullanmaya karar verdim. Helm, Kubernetes için bir paket yöneticisidir ve uygulamanın dağıtımını, yapılandırmasını ve sürüm yönetimini basitleştirir.

Helm chart'ları, Kubernetes kaynaklarını yönetmek için şablonlar sağlar ve bu şablonlar, her ortamda uygulanabilir hale gelir.

İlk olarak bir chart oluşturdum:
helm create go-web-app-chart
Sonrasında K8s YAML dosyalarını templates klasörüne kopyaladım ve imajları yönetebilmek için bir değişken atadım:
image: tyguler/go-web-app:{{ .Values.image.tag }}

Bu sayede chart içerisindeki Values.yaml dosyasından kontrol sağladım.
helm install go-web-app ./go-web-app-chart komutu ile tüm yapıyı test ettim ve sonrasında helm uninstall go-web-app komutu ile kaynakları temizledim.

5. GitHub Actions ile CI/CD Süreci
Uygulamanın otomatik olarak test edilmesi, derlenmesi ve dağıtımı için GitHub Actions kullandım. GitHub Actions, her commit sonrası otomatik olarak testlerin çalıştırılmasını, Docker imajlarının oluşturulmasını ve bunların DockerHub'a yüklenmesini sağlar. Bu işlem, sürekli entegrasyon (CI) sürecinin temelini oluşturur.

GitHub Actions iş akışı şu şekildedir:

name: CI

on:
  push:
    branches:
      - main
    paths-ignore:
      - 'README.md'
      - 'helm/**'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Set up Go 1.23
      uses: actions/setup-go@v2
      with:
        go-version: 1.23

    - name: Build
      run: go build -o go-web-app

    - name: Test
      run: go test ./... # ./... means all subdirectories

  code_quality:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: GolangCI-Lint
      uses: golangci/golangci-lint-action@v6
      with:
        version: latest

  push:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1

    - name: Login to DockerHub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}

    - name: Build and push
      uses: docker/build-push-action@v6
      with:
        context: .
        file: ./Dockerfile
        push: true
        tags: ${{ secrets.DOCKER_USERNAME }}/go-web-app:${{ github.run_id }}

  update-newtag-in-helm-chart:
    runs-on: ubuntu-latest

    needs: push

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Update Helm chart
      run: |
        # Update the Helm chart tag
        sed -i 's/tag: .*/tag: ${GITHUB_RUN_ID}/' ./go-web-app-chart/values.yaml

Enter fullscreen mode Exit fullscreen mode

6. Argo CD ile Sürekli Dağıtım Süreci
Son olarak, Argo CD ile sürekli dağıtım sürecini tamamladım. Argo CD, Kubernetes kümelerine otomatik dağıtım yaparak uygulamaların doğru sürümlerinin her zaman çalışmasını sağlar. Argo CD'nin kullanımını otomatikleştirdim ve Helm chart'ım ile sürekli dağıtımı Argo CD üzerinden gerçekleştirdim.

Argo CD'yi kurduktan sonra, Helm chart'ımı kaynak olarak ekledim ve Argo CD üzerinden manuel veya otomatik dağıtımlar gerçekleştirdim.

Image description

Sonuç
Proje, Docker, Kubernetes, Helm, GitHub Actions ve Argo CD entegrasyonuyla uygulama geliştirme ve dağıtım süreçlerini otomatikleştirmeme olanak tanıdı. Bu süreçlerin her birini doğru şekilde entegre etmek, sürekli entegrasyon (CI) ve sürekli dağıtım (CD) süreçlerini başarıyla kurmak, yazılım geliştirme ve dağıtımında verimliliği artırarak daha hızlı ve güvenilir sonuçlar elde edilmesini sağladı. Bu projede öğrendiğim en önemli şeylerden biri, farklı araç ve teknolojilerin birbirine nasıl entegre olacağını anlamak ve bu entegrasyonu etkin bir şekilde yönetebilmektir.

Karşılaşılan Zorluklar
Her ne kadar proje başarılı bir şekilde tamamlanmış olsa da, bazı zorluklarla karşılaştım. Bu zorluklar, proje sürecinin bazı noktalarında benim için önemli öğrenme fırsatları sundu.

  • GitHub Actions ile CI/CD sürecini kurarken, özellikle test aşamalarında karşılaştım. Docker imajlarının doğru bir şekilde yapılandırılması ve DockerHub'a yüklenmesi için gerekli olan adımlar zaman zaman hatalı gerçekleşti. Bu durumun üstesinden gelmek için GitHub Actions iş akışını dikkatlice optimize ettim ve her bir adımı doğru sırayla çalışacak şekilde yapılandırdım.

  • Argo CD ile sürekli dağıtım süreçlerini otomatikleştirmeye çalışırken, Helm chart'ları ile doğru entegrasyonu sağlamak bazen karmaşık hale geldi. Bu durumu çözmek için Argo CD'nin Helm entegrasyonunu dikkatlice araştırdım ve doğru Helm chart sürümünü kullandım. Ayrıca, Argo CD'nin düzgün çalışması için kaynakların doğru şekilde tanımlanması gerektiği konusunda birçok deneme yaptım.

  • Kubernetes kümesinin yönetimi, özellikle manuel yapılandırmalar ve değişikliklerin yapılması gerektiğinde zorlayıcı olabiliyor. EKS üzerinde kümeyi yönetmek, özellikle altyapı hataları veya ağ yapılandırma sorunları nedeniyle zaman zaman karmaşık hale geldi. Bu zorlukları aşmak için AWS belgelerine başvurdum ve en iyi uygulama örneklerini takip ettim.

Top comments (0)