/ DEVOPS

Github Actions ve Jekyll


okuma süresi yaklaşık 5 dakika

Şu anda okuduğunuz bu yazının barındığı platforma (bloga) yıllık alan adı ücreti dışında bir ücret ödemiyorum. Çünkü zaten çok nadir yazdığım ve ziyaretçisinin de az olduğu bir platforma neden ücret ödeyeyim ki diye düşündüm. Getirisi (maddi olarak) olmayan şeyin götürüsü (yine maddi) de olmamalı. Bu yazıda da Jekyll ve Github Actions ile bu blogun yayına çıkma serüveninden bahsedeceğim.

Statik Site Üreticileri

Static page generators diye tabir edilen bir yazılım ürünleri grubu var. Bu araçlar sizin verdiğiniz kaynak dosyaları derleyip HTML dosyaları üretiyorlar. Bu yazıyı okuduğunuza göre sizin de bildiğiniz ürünlerden biri olan Wordpress ise dinamik bir araçtır. Yani admin paneline girip yazınızda bir şeyi değiştirebilirsiniz, ve bu direkt yazıya yansıyacaktır. Ancak statik üreticileri kullanarak bir şeyler elde ediyorsanız siz kaynağı düzenlemelisiniz ve bu üretici yazılımla kaynaktan bir derlenmiş sonuç elde etmelisiniz. Yani bir şeyleri elle yapmanız gerekiyor (şimdilik).

Peki bu bize ne sunuyor? Aslında cevap çok basit, sitenizi sunmak için çok çok daha az kaynağa ihtiyacınız oluyor. Çünkü zaten siz önceden her şeyi yapıp nihai ürünü elde etmiş oluyorsunuz. Geriye sadece bunu sunmak kalıyor.

İşte bu noktada da sunucu maliyeti ortaya çıkıyor. Neyse ki Github‘un Github Pages isimli bir çözümü var, statik dosyalarımızı (html, css, js) Github depomuzdan direkt yayınlayabiliyoruz. Yani evet, sunucuya ücret ödemiyoruz. Ayrıca kaynağımızı Github yayınlıyor, yani güzel bir sağlayıcımız var diyebiliriz. Ayrıca kaynak zaten açık olduğu için bu yazıdaki bir yanlışlığı direkt düzeltme şansınız bile oluyor. Hatta bu yazının kaynağına giderek bu yazı için bir pull request oluşturursanız (bir şeyi düzeltmeniz ya da eksik bir şeyi tamamlamanızı dilerim) direkt bu blog üzerinde yazı güncellenecek. Dinamik olmayan dinamik bir blog burası.

Bu blog Jekyll adında bir statik site üreticisi tarafından derleniyor. Tema olarak da Ghost isimli bir CMS’in (Content Management System, Wordpress benzeri bir çözüm diyebiliriz) varsayılan temasının uyarlaması olan Jasper‘i kullanıyorum. Jekyll de Jasper de açık kaynaklı.

Bu yazıda sadece serüvenden bahsedeceğim. Bahsettiğim ürünler (jekyll, Github pages, ghost vb.) hakkında internette çok fazla kaynak zaten bulunuyor.

Yayına Alma

Github Pages bize birkaç farklı yöntem sunuyor aslında sitemizi yayınlamak için. Mesela gh-pages adında bir branch oluşturup dosyalarımızı orada tutmamızı sağlayabiliyor. Kendisi de oradan yayına alıyor. Ya da aynı şekilde master branch’ındaki docs/ klasörüne bakabiliyor. Ya da direkt master branchına bakıp ne gördüyse ordan yayına alabiliyor. Ben son bahsettiğim yöntemi kullanıyorum. Bunun çok basit bir sebebi var.

Aslında Github jekyll’i kendi içinde zaten destekliyor. Yani jekyll’i kendisi derleyip yayına alabiliyor ve bunun için sizin nerdeyse hiçbir şey yapmanıza gerek yok. Bu konu hakkında da internette yeterince kaynak var. E o zaman bu yazı neden var? Çünkü benim senaryomda Github’un direkt desteklemesi ve kendisinin derleyip yayına alması yetersiz kaldı. Ben bazı ek Jekyll eklentileri kullanmak durumunda kaldım. Ve Github, Jekyll eklentilerini desteklemiyor :(. Ve ortaya çıkardığı sitede bazı sayfalar yanlış üretilebiliyor ya da hiç üretilmiyordu. Dolayısıyla benim bu üretme işlemini kendim yapmam gerekiyordu ama her yazı yayınladığımda bilgisayarımda derlemek de işkence olabiliyor. Çünkü farklı bir cihazdan bir şey yayınlamam gerekse önce Ruby’yi indirmem gerekecek (Jekyll’in geliştirildiği programlama dili) daha sonra bağımlı olduğu paketleri kurmam gerekecek.

Github’un Jekyll’i tanımaması ve kendi kendine derlemeye çalışmaması için ana dizine .nojekyll adında bir dosya oluşturmamız gerekiyor. Bunu oluşturduğumuz zaman da sadece üçüncü seçenekte bahsettiğimiz gibi kullanmamıza izin veriyor Github Pages’i.

Tam bu işleri otomatize etmek için aslında CI/CD toollarını kullanıyoruz. Önce Travis’i kullanıyordum. Daha sonra Github, Actions isimli çözümünü piyasaya sürünce ona geçirmeyi düşündüm altyapıyı. Altyapı diyorsam da üç-beş komuttan ibaret her şey. Epey vakit geçtikten sonra bunu gerçekleştirdim. Github Actions hakkında Türkçe kaynaklar çok zengin değil ama Github’un kendi dökümanının giriş kısmını okusanız bile bu yazıyı yayına çıkarmak için hazırladığım Action’u anlayabilirsiniz. Actions’u bir eylem gerçekleştiğinde (mesela yeni bir yazı yazdığınızda) belli komutları (bizim önceden tanımladığımız) çalıştıran bir bilgisayar gibi düşünebilirsiniz.

Bize yazı yazdığımız zaman blogumuzu Jekyll ile üretecek ve daha sonrasında da bunu yine depoya gönderecek bir action lazım. Çünkü Github Pages yine depodan okuyacak ve yayınlayacak.

Burada parça parça inceleyeceğimiz action dosyamızın tamamına ve şu anda çalışan güncel versiyonuna ulaşmak için tıklayınız. (İleride action’u güncellersem burayı güncelleyeceğimin garantisini veremem…)

Action dosyalarımız YAML formatında, dolayısıyla okumak kolay. Adım adım incelemeye başlayalım.

1
2
3
4
5
6
7
name: Build Blog

on: 
  push:
    branches: master
    paths: 
      - "source/**"

Burada ilk satırda actionumuza bir isim veriyoruz. Bu action blogumuzu oluşturacağı için ben Build Blog dedim. Daha sonraki satırlarda da push işlemi gerçekleştiğinde, yani depoya bir şeyler geldiğinde çalışacağını belirtmişim. Ancak bu depoda sadece yazılar yok, bu action da blogu derliyorsa yazılar haricindeki değişikliklerde çalışmamalı. O yüzden biz de branches ve paths parametrelerini tanımlıyoruz ve sadece master branchındaki source/ klasörüne dosya gönderilirse çalış diyerek kısıtlıyoruz. Burası tam da bizim blogumuzun kaynağının bulunduğu klasör.

1
2
3
4
5
6
jobs:
  build:

    runs-on: ubuntu-latest

    steps:

Devam eden bu satırlarda da jobs yani actionumuzun görevlerini tanımlamaya başlıyoruz. Ben ilk göreve build adını vermişim. Ve bu görevin ubuntu ortamında çalışmasını istemişim. Actionsa bizim için komutlar çalıştıran bilgisayar diyebiliriz demiştik. Burada bizim bilgisayarımız ubuntu işletim sistemine sahip olsun istedik. Daha sonra da steps kısımında bu görevde çalışacak adımları teker teker tanımlayacağız.

1
2
3
4
5
    - name: Install Ruby
      run:  sudo apt install ruby-full
    
    - name: Insall Bundler
      run: sudo gem install bundler

İlk iki adımımızı hazırladık, aslında bu iki adım da aynı amacı güdüyor. Bağımlılıkları kurmak. İlk adım ruby dilini sisteme kuruyor, ikinci adım da ruby için bir paket yöneticisi olan bundler’i kuruyor. Bunları tek adımda kurdurmak da mümkün tabi ancak actions’un akış diyagramında ayrı ayrı görmek ve bir hata alınırsa daha kolay müdahale edebilmek adına daha iyi oluyor.

1
2
3
4
    - name: Install dependencies
      run: |
        cd source
        bundle install  

3. adımımızda da bundler ile ihtiyaç duyduğumuz paketleri kurduruyoruz (jekyll ve kullandığı diğer eklentileri). Bu adımımız farkettiyseniz iki ayrı komut içeriyor. Çünkü bundlerin kullanacağı Gemfile dosyamız source klasöründe. Dolayısıyla önce dizini değiştirmemiz gerekiyor.

1
2
3
4
    - name: Build blog
      run: |
        cd source
        bundle exec jekyll build

Sonunda blogumuzun dosyalarını üreteceğimiz adıma geldik. Bu adımda da yine kaynak dosyalarının bulunduğu dizine geçtik ve bundler üzerinde jekyll build komutunu çalıştırdık. Bu komut çalıştıktan sonra Jekyll yine aynı dizinde _site/ klasörü oluşturuluyor ve kaynaktan ürettiği dosyaları oraya koyuyor. Biz de bir sonraki adımlarda bu dosyaları Github Pages’e vereceğiz ki sitemiz yayına alınabilsin.

1
2
3
4
    - name: Install SSH Client
      uses: webfactory/ssh-agent@v0.2.0
      with:
        ssh-private-key: $

Tabi ürettiğimiz dosyaları yine depoya göndereceğimiz için Github’a kendimizi tanıtmamız ve yetkili birisi olduğumuza kendisini ikna etmemiz gerekiyor. Bunun için hazırlanmış olan farklı bir actionu çağırıyoruz ve ilgili parametreyi veriyoruz. Bizim için o action gerekli işlemleri yapıyor. Evet, action-in-action.

1
2
3
4
    - name: Initialize Git
      run: |
        git config --global user.email "bot@bisguzar.com"
        git config --global user.name "Deploy Bot"

Bu adımda da klasik git ayarlamalarımızı yapıyoruz.

1
2
3
4
5
6
7
    - name: Deploy Source
      run: |
        cp -r source/_site/* ./
        rm -r source/_site
        git add .
        git commit -m "🤖 Built and deployed automatically by actions." 
        git push

Blogumuzu yayına aldığımız asıl adı burası. Burada sırasıyla Jekyll’in ürettiği dosyaları ana dizine kopyaladık. Çünkü daha önce de bahsettiğim gibi, Github Pages ana dizinden yayına alıyor. Daha sonrasında üretilen dosyaları sildik, çünkü aynı anda iki yerde olmalarına ne gerek var? Bunlardan sonra da değişikliklerimizi git’e bildirdik, mesajımızı yazdık ve depoya gönderdik.

1
2
    - name: Finish
      run: echo "All done!"

Evet, bu da son adımımız. Her şey bitti, sorun yaşamadık demek. Sadece ekrana “All done!” yazdırıyor.

Bu yazı yayına çıkarken çalışan action’u adım adım incelemek için tıklayın, ve evet, bunu sonradan ekliyorum. Çünkü actionun çalışması için önce yazıyı göndermem gerekiyordu.

Cover photo by unsplash-logoYancy Min

bisguzar

Buğra İşgüzar

Buğra, bilgisayar bilimlerine meraklı bir sağlıkçı. Kurcalamayı ve kurcaladıklarını anlatmayı çok sever.

Profiline Git