Github Actions ile Ücretsiz CI/CD (ASP.NET Core 3.1 & Docker)

Selamlar arkadalaşlar,

Karantidayken ne yapsam diye düşünürken birden aklıma github‘un yayınlamış olduğu ci/cd çözümü olan Github Actions ‘u denemek geldi.

Bu çalışmada senaryomuz ise şöyle; basit bir asp.net core web projesi oluşturup bunu github‘a yükleyeceğiz ardından her atılan her commit‘te yeni bir docker imajı oluşturup bu yeni imajı sunucumuza deploy edeceğiz.

Çalışmayı yapabilmek için visual studio ile bir asp.net core web projesi oluşturup github repository’ime yükledim.

Ardından projede kullanacağım dockerfile‘ı ana dizine ekleyip projeyle alakalı dosyaları ise src altında bir dizine taşıdım.

Burda önemli olan nokta ise kullandığımız sln dosyası ile dockerfile‘ın kök dizinde olması gerekliliği. Bunu sağlayabilmek için sln dosyasındaki “Project(“{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}”) = “WebApplication1”, “WebApplication1\WebApplication1.csproj”, “{0311290B-BE99-4D8F-8D9C-A125FFCAA0DA}” satırını “Project(“{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}”) = “WebApplication1”, “src\WebApplication1.csproj”, “{0311290B-BE99-4D8F-8D9C-A125FFCAA0DA}” olarak güncelliyorum ve sln dosyasını kök dizine atıyorum.

Kullandığm dockerfile‘ın içeriği ise şöyledir (Kopyalamak için buraya kullanın: https://github.com/ismkdc/github-actions-example/blob/master/dockerfile):

FROM mcr.microsoft.com/dotnet/core/sdk:3.1.201-alpine AS build-env
WORKDIR /app
COPY . .

RUN dotnet restore
RUN dotnet build -c Release -o /out
RUN dotnet publish -c Release -o /out

# Runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.3-alpine
WORKDIR /app
COPY --from=build-env /out .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
*ENTRYPOINT [“dotnet”, “WebApplication1.dll”]  satırındaki dll ismini kendi projenize göre düzenlemeniz gerekmektedir.

 

dockerfile hakkında kısaca bilgi vermek gerekirse; dockerfile, oldukça basit tutulmaya çalışılıp multi-stage (https://docs.docker.com/develop/develop-images/multistage-build/) bir şekilde daha hafif olan alpine linux (https://alpinelinux.org/) imajlar baz alınarak hazırlanmıştır.

 

Şimdi ise sıra geldi Github Action‘uzumu hazırlamaya:

Bunun için github repomuzu ziyaret edip tabler’den Actions tab’ine tıklıyoruz. Bu tab altında bizim için önceden hazırlanmış kullanabileceğimiz bir çok hazır Action bulunmakta. Biz bu Actionları pas geçip Set up a workflow yourself butonuna basarak kendi yaml dosyamızı hazırlayacağız.
Kullanacağımız Action içeriği ise şöyledir (Kopyalamak için buraya kullanın: https://github.com/ismkdc/github-actions-example/blob/master/.github/workflows/main.yml):
name: Publish Docker
on:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/[email protected]
    - name: Publish to Registry
      uses: elgohr/[email protected]
      with:
        name: ismkdc/github-actions-example
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
        snapshot: true
  release:
    needs: build
    runs-on: ubuntu-latest
    steps:
    - name: executing remote ssh commands using password
      uses: appleboy/[email protected]
      with:
        host: ${{ secrets.SSH_HOST }}
        username: ${{ secrets.SSH_USERNAME }}
        password: ${{ secrets.SSH_PASSWORD }}
        port: ${{ secrets.SSH_PORT }}
        script: |
          docker rm -f $(docker ps -aq -f name=github-actions-example)
          docker rmi $(docker images | grep 'ismkdc/github-actions-example' | awk '{print $3}')
          docker pull ismkdc/github-actions-example:dev
          docker run --name github-actions-example -p 5000:80 --restart=always -d ismkdc/github-actions-example

Oluşturduğumuz bu Actionu kısaca açıklamak gerekirse; Action, build adımında projemizi build edip bir docker imajı oluşturuyor ve bu oluşan imajı docker registry‘e push ediyor. Ardından sunucumuza ssh ile bağlanıp güncel imajı indirip bu imajdan bir container ayağa kaldırıyor. Burda dikkat edilmesi gereken nokta bu yaml içerisinde tanımlı değişkenleri repository‘imze tanımlamamız.

Repository‘e değişkenleri tanımlamak için repository içerisindeki Settings menüsü altından sol taraftaki Secrets menüsünü kullanmamız gerekiyor. Bu menüye girdikten sonra tanımlamamız gereken toplam 6 adet değişken mevcut. Bunlardan 2’si docker hub için diğer 4’ü ise ssh için gerekli.

Sırasıyla açıklamak gerekirse;

DOCKER_USERNAME: docker hub üzerindeki kullanıcı adımız.

DOCKER_PASSWORD: docker hub üzerindeki Access Tokenimiz (Token almak için: https://hub.docker.com/settings/security)

SSH_HOST: bağlanacağımız sunucunun ip adresi

SSH_USERNAME: bağlanacağımız sunucudaki kullanıcı adımız

SSH_PASSWORD: bağlanacağımız sunucudaki parolamız

SSH_PORT: bağlanacağımız sunucunun ssh portu (default 22)

Hepsini oluşturduktan sonra yukarıdaki gibi bir tabloyla karşılaşmamız gerekiyor.

Burada dikkat etmeniz gereken diğer bir durum ise ssh ile bağlantı yapacak kullacının yetkilerinin sadece docker kullanabilecek şekilde sınırlandırılmış olması gerektiğidir.

Herşeyi tamamladıktan sonra artık pipeline‘ımızı deneyebiliriz.

Commit‘imizi attıktan sonra otomatik deployment için bekleyemeye başlıyoruz. Bu bekleme esnasında Actions tab’i altında pipeline‘ımızın ilerleme durumunu kontrol edebiliriz.

 

Vee.. Uygulamamız yayında!

 

Artık atılan her commit için uygulamamız pipeline tarafından otomatik olarak deploy ediliyor olmuş oldu. Tabi bazı durumlarda her commit yayına gitsin istemeyiz bu tür durumlarda master yerine başka bir branch‘i işaretleyerek sadece ilgili branch‘e giden kodlar için pipeline‘ımızın tetiklenmesini sağlamalıyız. Bunun için ise main.yml dosyasındaki branches:- master kısmını ilgili branch ismiye değiştirmemiz yeterlidir.

Artı olarak yine prod env için bu pipeline üzerine yazılmış olan testlerin çalıştırılıp eğer testlerin hepsi geçmezse pipeline‘ın fail etmesi durumunu eklememiz gerekir.

Çalışmanın son hali: https://github.com/ismkdc/github-actions-example