Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 23

Traceable Docker Images: Tagging with Git Commit SHAs

Recommended resources

Merhaba! Önceki dersimizde, CI işlem hattımızı kullanarak PySpark ETL uygulamamızdan bir Docker imajı oluşturup bunu Docker Hub'a otomatik olarak göndermeyi başardık. Bu önemli bir adımdı, ancak imajımızı latest olarak etiketledik. Bu, geliştirme sırasında pratik olsa da, sürüm kontrolü ve güvenilir dağıtımlar için önemli bir eksiklik yaratır.

Bugün bu eksikliği gidereceğiz.

Bugünkü Öğrenme Hedefimiz: Docker imajlarını, onları oluşturan Git commit SHA'sı ile etiketleyerek tam sürüm izlenebilirliği sağlamak.

Neden latest Etiketinden Kaçınmalıyız?

latest etiketi, bir Docker imajı için "hareketli bir hedeftir". Her yeni imaj gönderildiğinde, latest etiketi en sonuncusunu işaret edecek şekilde güncellenir. Bu durum şu sorunlara yol açar:

  • Belirsizlik: Bir sunucuda çalışan :latest etiketli bir imaj gördüğünüzde, "Bu imaj tam olarak hangi kod versiyonunu içeriyor?" sorusunun net bir cevabı yoktur.
  • Güvenilmez Geri Almalar (Rollbacks): Bir dağıtımda sorun çıkarsa ve önceki sürüme dönmek isterseniz, bir önceki "latest" imajına geri dönmenin kolay bir yolu yoktur.
  • Hatalı Dağıtımlar: Kubernetes gibi orkestrasyon sistemleri, imajın imagePullPolicy ayarına bağlı olarak, aynı :latest etiketine sahip olsa bile her zaman en son imajı çekmeyebilir. Bu, farklı sunucularda kodun farklı sürümlerinin çalışmasına neden olabilir.

Çözüm: Git Commit SHA ile Sürümleme

Her git commit işlemi, o anki kod tabanınızın durumunu temsil eden benzersiz ve değişmez bir kimlik (SHA - Secure Hash Algorithm) oluşturur.

Git Log Output Showing Commit SHAs
Bu resimde, `git log --oneline` komutunun çıktısı görülmektedir. Her satırın başındaki `9fd7d12` gibi karakter dizileri, her bir commit için benzersiz olan kısa SHA kimlikleridir.

Bu benzersiz kimliği Docker imajlarımız için bir etiket olarak kullanarak, kod ile onu çalıştıran imaj arasında doğrudan ve değişmez bir bağ kurarız. Bir imajın sha-9fd7d12 olarak etiketlendiğini gördüğünüzde, o imajın içinde tam olarak 9fd7d12 commit'indeki kodun olduğunu bilirsiniz. Bu, CI/CD süreçlerinde izlenebilirlik (traceability) ve tekrarlanabilirlik (reproducibility) için temel bir prensiptir.

Nihai hedefimiz, container registry'mizin aşağıdaki gibi görünmesidir: Her commit, kendi benzersiz etiketine sahip bir imaj üretir.

GitHub Packages: Docker Image Tags with Git Commit SHAs
Bir container registry'de, her birinin etiketi olarak farklı bir Git commit SHA'sı olan Docker imajlarının listesi. Bu, her bir imajın hangi kod versiyonuna karşılık geldiğini net bir şekilde gösterir.

docker/metadata-action ile Tanışma

Bu sürümleme stratejisini GitHub Actions'da uygulamanın en standart ve güçlü yolu, Docker tarafından geliştirilen docker/metadata-action eylemini kullanmaktır. Bu eylemin tek bir görevi vardır: Git ve GitHub olaylarından (event) gelen bilgilere (commit SHA, branch adı, tag adı vb.) dayanarak Docker imajları için akıllı etiketler (tags) ve etiketler (labels) üretmek.

docker/metadata-action - GitHub

docker/metadata-action aracının ne işe yaradığını anlamak için resmi GitHub reposunun ana sayfasını inceleyelim. Bu kaynak, eylemin temel amacını ve nasıl kullanılacağına dair genel bir bakış sunar.

Sayfanın başındaki "About" bölümünü okuyarak bu eylemin ne için kullanıldığını kavrayın. Temel amaç, Git referanslarından ve GitHub olaylarından Docker için metadata (etiketler, etiketler) çıkarmaktır.


İş Akışına Versiyonlamayı Entegre Etme

Şimdi, önceki derste oluşturduğumuz build-and-push işini, commit SHA'sı ile etiketleme yapacak şekilde güncelleyelim. Bu iki adımlı bir süreçtir:

  1. Metadata (etiketler) üreten docker/metadata-action adımını eklemek.
  2. docker/build-push-action adımını, bu üretilen etiketleri kullanacak şekilde güncellemek.

Adım 1: Metadata Çıkarma Adımını Ekleme

build-and-push işinizin içine, login-action adımından sonra ve build-push-action adımından önce yeni bir adım ekleyin.




# .github/workflows/main.yml dosyanızdaki 'build-and-push' job'una ekleyin

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}




      # YENİ ADIM: Docker metadata'sını çıkar
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ secrets.DOCKER_USERNAME }}/pyspark-etl
          tags: |
            type=sha

Bu yeni adımın detayları:

  • id: meta: Bu adıma "meta" adında bir kimlik atar. Bu, sonraki adımlarda bu adımın çıktılarına (outputs) referans vermemizi sağlar.
  • images: ...: Etiketlerin hangi imaj adı için üretileceğini belirtir.
  • tags: type=sha: Bu en kritik kısımdır. metadata-action'a Git commit SHA'sını kullanarak bir etiket oluşturmasını söyler. Varsayılan olarak, sha- önekiyle birlikte 7 karakterlik kısa bir SHA üretir (örneğin, sha-abcdef1).

Bu type=sha özelliğinin nasıl çalıştığını daha detaylı anlamak için metadata-action'ın dokümantasyonuna göz atabilirsiniz.

docker/metadata-action - GitHub

Şimdi metadata-action'ın en önemli girdisi olan tags'ı ve özellikle type=sha'nın nasıl çalıştığını inceleyelim. Bu, öğrenme hedefimizle doğrudan ilgilidir.

Sayfada tags input başlığını bulun ve okuyun. Ardından, type=sha alt başlığına odaklanın. Bu bölüm, SHA etiketlerinin nasıl oluşturulduğunu, long formatının nasıl kullanılacağını ve prefix'in ne anlama geldiğini açıklar.

Adım 2: Build ve Push Adımını Güncelleme

Şimdi docker/build-push-action adımını, meta adımının ürettiği etiketleri kullanacak şekilde değiştirmeliyiz. Artık etiketi manuel olarak (:latest) yazmayacağız.

Eski Hali:

      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@v5
        with:



          # ... diğer parametreler
          tags: ${{ secrets.DOCKER_USERNAME }}/pyspark-etl:latest

Yeni Hali:

      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Değişikliklerin açıklaması:

  • tags: ${{ steps.meta.outputs.tags }}: Bu ifade, id'si meta olan adımın (steps.meta) çıktılarına (outputs) erişir ve tags adlı çıktıyı alır. metadata-action bu çıktıya, type=sha kuralına göre oluşturduğu sha-abcdef1 gibi bir değer atar.
  • labels: ${{ steps.meta.outputs.labels }}: İyi bir uygulama olarak, metadata-action tarafından oluşturulan standart OCI (Open Container Initiative) etiketlerini de imajımıza ekliyoruz. Bu, imaj hakkında sürüm, oluşturulma tarihi gibi ek bilgiler içerir.

Tamamlanmış İş Akışı ve Uygulama

Güncellenmiş build-and-push işiniz aşağıdaki gibi görünmelidir. Bu örnek, OneUptime tarafından hazırlanan bir blog yazısındaki en iyi uygulamaları yansıtmaktadır ve bizim projemiz için de geçerlidir.

How to Build and Push Docker Images with GitHub Actions

Bu blog yazısı, bizim yaptığımıza çok benzer bir şekilde, metadata-action kullanarak bir GitHub Actions iş akışının nasıl oluşturulacağını gösteren eksiksiz bir örnek sunar.

Makaledeki "Basic Build and Push to GHCR" başlığı altındaki YAML kod bloğunu inceleyin. Özellikle "Step 4: Generate tags and labels from Git metadata" ve "Step 5: Build and push the Docker image" adımlarının bizim yaptığımız değişikliklerle nasıl örtüştüğüne dikkat edin. Ayrıca, "Tagging Strategy" tablosu, farklı etiket türlerinin kullanım amaçlarını özetlemektedir.

Güncellenmiş build-and-push Job:

  build-and-push:
    runs-on: ubuntu-latest
    needs: test-and-lint # Önceki job'unuzun adıyla değiştirin
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ secrets.DOCKER_USERNAME }}/pyspark-etl
          tags: |
            type=sha

      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Sıra Sizde:

  1. Projenizin .github/workflows/main.yml dosyasını yukarıdaki gibi güncelleyin.
  2. Bu değişikliği commit'leyip GitHub repository'nize push edin.
  3. Repository'nizin Actions sekmesine gidin ve iş akışının çalışmasını izleyin.
  4. İş akışı başarıyla tamamlandıktan sonra Docker Hub hesabınıza gidin. pyspark-etl repository'nizde latest yerine, az önce yaptığınız commit'in SHA'sı ile etiketlenmiş yeni bir imaj görmelisiniz.

Sonuç

Tebrikler! Artık CI işlem hattınız, her kod değişikliği için benzersiz ve izlenebilir bir Docker imajı üretiyor. latest etiketinin belirsizliğinden kurtulup, hangi kodun hangi imajda olduğunu tam olarak bildiğiniz sağlam bir sürümleme sistemine geçiş yaptınız.

Temel Çıkarımlar:

  • latest etiketi üretim ortamlarında izlenebilirlik sorunları yaratır ve kullanılmamalıdır.
  • Git commit SHA'ları, kod ve Docker imajları arasında değişmez bir sürüm bağlantısı kurmak için mükemmel bir yöntemdir.
  • docker/metadata-action, GitHub Actions'da Docker etiketlerini ve yaftalarını Git bağlamından dinamik olarak oluşturmak için standart bir araçtır.
  • GitHub Actions'daki id ve steps.<id>.outputs mekanizması, adımlar arasında veri aktarımı için kullanılır.

Gelecek Dersin Önizlemesi:
Şu ana kadar CI/CD işlem hattımız kodu test ediyor, imajı oluşturuyor ve versiyonlayarak bir registry'e yüklüyor. Ancak bu imaj henüz hiçbir yerde çalışmıyor. Bir sonraki dersimizde, bu container'ize edilmiş PySpark işini bir Kubernetes kümesinde çalıştırmak için gereken manifest dosyasını (Kubernetes Job) yazmayı öğreneceğiz. Bu, Sürekli Dağıtım'a (Continuous Deployment) giden yolda ilk adımımız olacak.