Docker Serisi’nin 3. bölümüne hoşgeldiniz! İlk bölümde sanallaştırmanın ne olduğundan, container teknolojisinden ve temel Docker kavramlarından; ikinci bölümde Docker Engine ve Docker komutlarından bahsetmiştim. Bu bölümdeyse özetle şu konulara değineceğim:
- Kalıcı Veri Depolama
- Çevresel Değişkenler
- Bağlantı Noktaları
- Dockerfile
- Kendi İmajınızı Hazırlamak
- Docker Store & Registry
- Kendi Docker Registry’nizi Kurun
Hızlıca başlayalım! 🙂
Kalıcı Veri Depolama
İkinci bölümün docker run komutuyla ilgili olan kısmında container’lara dışarıdan dosya ve dizin bağlanabileceğinden bahsetmiştim. Normalde, ölçeklenebilirliğin ön planda olduğu gerçek ortam container’ları dışarıdan bağımsız çalışabilecek şekilde tasarlanmalıdır. Aslında bakarsanız ölçeklenebilirliğin maksimize edilmesi için uygulamanızın, 12 Faktör prensibine uygun tasarlanmış olması gerekir. Bu prensiplere uyarak örneğin uygulamanızdan N tane container başlatarak ölçeklenebilirliği rahatlıkla sağlayabilirsiniz.
Ölçeklenebilirliğin çok sorun olmadığı durumlarda ya da geliştirme/test ortamlarında dosya/dizin bağlamak size büyük
kolaylık sağlar. Örneğin uygulama kayıtlarınızı (log) merkezi bir servis yerine yerel dosya sistemine yazıyorsanız,
ilgili dizini ev sahibi makineye bağlamak akılcı olacaktır. Ya da uygulamalarınızı Tomcat’e dizin açarak yüklüyorsanız
webapps
dizinini ev sahibi makineye bağlamak isteyebilirsiniz.
Container’larda kalıcı veri depolama (persistence) söz konusu olduğunda 3 tip depolamadan bahsetmek mümkün:
Ev sahibi makineden dizin/dosya bağlayarak depolamak
Bu yöntemde ev sahibi makineyi paylaşımlı dizin gibi düşünebiliriz. Bir kaç örnek senaryo sayarsam:
- nginx kurarken
/etc/nginx/nginx.conf
’u ev sahibi makineden bağlayarak üzerinde değişiklik yapmayı kolaylaştırmak - nginx imajında hiç bir değişiklik yapmaksızın ev sahibi makinede tuttuğum statik web uygulamamın dizinini
/var/www/html
dizinine bağlayarak doğrudan sunmak - Ev sahibi makinede tuttuğum, PHP ile geliştirdiğim kod tabanımı container ile paylaşarak yaptığım değişikliklerin sonucunu container üstünden anında görmek
- Ev sahibi makinede bulunan bir dizindeki tüm dosyaları, container’ın içinde çalışacak bir program ile işleyip aynı dizine yeniden yazmak
- Ev sahibi makinede çalışan Docker Engine’in çalışma dizinini, container’a bağlayarak Docker Engine’de bazı işlemler yapmak (ör: docker-cleanup)
Peki dosya ya da dizinleri nasıl bağlıyoruz? Yukarıdaki bir kaç örneği gerçekleyelim:
Dışarıdan /etc/nginx/nginx.conf’u bağlamak:
docker run -d --name nginx1 -v /home/alper/nginx/nginx.conf:/etc/nginx/nginx.conf -p 8000:80 nginx
Dışarıdan statik web uygulamasının dizinini bağlamak:
docker run -d --name nginx2 -v /home/alper/web:/var/www/html -p 8001:80 nginx
Dışarıdan dizin bağlayıp içindeki dosyaları işlemek:
docker run --rm -v /home/alper/test:/test ubuntu sed ‘/kanat/d’ /test/deneme.txt
Depolayıcı container’lar kullanmak
Kalıcı veri depolamanın Docker’ca yolu, depolayıcı container’lar kullanmaktan geçiyor. Depolayıcı container’ların avantajları kabaca şöyle:
- İlgili alanı birden fazla container ile paylaşabilirsiniz.
- Bir container’a birden fazla depolayıcı container bağlayabilirsiniz.
- Depolayıcı container’lar, beraber çalıştıkları container’lar ölse dahi silinmez; tekrar tekrar kullanılabilirler.
Depolayıcı container yaratmak için;
docker create -v /dbdata --name dbstore training/postgres /bin/true
Depolayıcı container’ı bağlamak için;
docker run -d --volumes-from dbstore --name db1 training/postgres
yazabilirsiniz. Bu sayede db1
adındaki container’ınızın içindeki /dbdata
dizini, aslında dbstore
container’ından
bağlanmış olacaktır. Diyelim ki; disk alanını yedeklemek istiyoruz. Yeni bir container ile aynı depolayıcı container’ı
bağlayarak bu işlemi gerçekleştirebiliriz:
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
Bu komutun yaptıklarını kısaca özetlersek;
- Çalıştıktan sonra silinecek şekilde, Ubuntu imajından yeni bir container yarat (
docker run --rm
) - Bu container’a dbstore adlı depolayıcı container’ından dışarı açılan dizinleri bağla (
--volumes-from dbstore
) - Ev sahibi makine üstünde bulunduğum dizini, container içerisindeki
/backup
dizinine bağla. (-v $(pwd):/backup
) - Container üstündeki
/dbdata
dizinini sıkıştırarak ev sahibi makine üstünde/backup/backup.tar
olarak kaydet.
Paylaşımlı Disk Alanları Kullanmak
Docker, 1.8.0 sürümünden itibaren disk alanları için sürücü desteğiyle beraber geliyor. Az sonra bahsedeceğim komutlara
ek olarak; Azure, Google Compute Engine, NFS vb. sürücüleri parametre olarak geçerek (ör: --volume-driver=flocker
)
farklı servislerden disk alanlarını da container’larınıza
bağlayabilirsiniz. Herhangi bir sürücü belirtmezseniz
öntanımlı olan yerel disk sürücüsü (--volume-driver=local
) kullanılır ve disk alanı makinenizde oluşturulur.
Yerel disk alanı yaratmak için:
docker volume create --name=shared-disk
[Yükledikten sonra] flocker sürücüsü ile yaratmak için:
docker volume create -d flocker -o size=20GB --name=shared-disk
Oluşturduğunuz disk alanını container’daki bir bölüme bağlamak için:
docker run -d --name=t1 -v shared-disk:/usr/local/tomcat/webapps -P tomcat
docker run -d --name=t2 -v shared-disk:/usr/local/tomcat/webapps -P tomcat
Yukarıdaki şekilde 2 tane Tomcat sunucusu başlatıp aynı disk alanını ikisine birden bağlayabiliyoruz.
Çevresel Değişkenler
İster web uygulaması olsun, ister bir API uygulaması; bir uygulamanın en önemli kısımlarından biri yapılandırma kısmıdır. Bazen bu yapılandırma, uygulamada kullanılan 3. parti servislerin erişim bilgileridir, bazense uygulamanın nasıl davranacağını belirleyen kritik roldeki bir anahtardır. Yalnızca bir anahtarın değerini değiştirerek gerçek bir veritabanı yerine örnek verilerle çalışmasını sağlayabilir ya da uygulama içindeki bir özelliği komple açıp kapatabilirsiniz.
Eski tip yazılım paketleme yöntemlerinde; uygulama içerisinde tutulan yapılandırma dosyalarının değerleriyle oynayıp birden fazla paket çıkarmak oldukça yaygın. Docker’da ise imajınızı gerçek ortama göre hazırlayıp dışarıdan vereceğiniz çevresel değişkenlerle her şeyi yönetebilirsiniz.
Tanımlayacağınız çevresel değişkenler, container içerisinde işletim sistemi seviyesinde ve tüm uygulamalarda erişilebilir durumda olacaktır. Bu sayede yapılandırma dosyalarında ya da çalıştırma betiklerinde çevresel değişkenlerinizi kullanabilirsiniz. Bu sayede son derece esnek imajlar yaratmanız mümkün.
Çevresel değişkenlerle ilgili serinin ilerleyen bölümlerinde gerçekçi örnekler vereceğim için şimdilik Tomcat ve MySQL özelinde 2 örnekle bu kısmı noktalıyorum:
Tomcat Manager Uygulaması Şifresini Belirlemek
docker run -d -p 8080:8080 -e TOMCAT_PASS=”mypass” tutum/tomcat
Burada tutum’un imajını kullanma sebebim; orjinal Tomcat imajlarında çevresel değişkenler ile şifre belirleme özelliğinin bulunmuyor oluşundan kaynaklanıyor.
MySQL Yönetici Şifresini Belirlemek
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
Docker Hub’dan (yeni adıyla Docker Store) indirdiğiniz imajların hangi çevresel değişkenleri kullandığını anlamak için ilgili sayfalarına bakabilirsiniz. Maalesef bazı imajlarda bu detaylar yeterince belgelendirilmediği için imajların kaynak kodlarındaki Dockerfile dosyalarını incelemeniz gerekebilir.
Bağlantı Noktaları
Bağlantı noktaları (port) dış dünya ile container’larınızın iletişimini sağlar. Bir web uygulaması geliştirdiğimizi varsayarsak, container’daki 80. bağlantı noktasını ev sahibi makinedeki herhangi bir bağlantı noktasına bağlamadan uygulamamıza erişemeyiz.
Docker, çalışma zamanında özellikle belirtmediğiniz sürece, öntanımlı olarak herhangi bir bağlantı noktasını dışarıya
açmayacaktır. İmaj hazırlanırken bağlantı noktalarının tanımları da Dockerfile içine
yazılır. Ancak yine de container’ı çalıştırırken, -p
ya da -P
ile ev sahibi makineye bağlamazsanız dışarıdan
erişilmez olacaktır.
Container’ın tanımladığı bağlantı noktalarını docker ps
komutuyla görebilirsiniz: 0.0.0.0:80->80/tcp
, 443/tcp
Bu
çıktıya baktığımızda 80. bağlantı noktasının ev sahibi makinedeki tüm ağlara bağlandığını, 443. bağlantı noktasının
ise bağlanmadığını görüyoruz. Sadece bağlanmış olanları görmek için docker port container_adi
(örnek:
docker port nginx
) komutunu da kullanabiliriz.
80 (HTTP) ve 443 (HTTPS) Bağlantı Noktalarını Bağlayalım
Aşağıdaki komutla ev sahibi makinenin 80. ve 443. bağlantı noktalarını, container’daki 80. ve 443. bağlantı noktalarına bağlayabiliriz:
docker run -d --name nginx -p 80:80 -p 443:443 nginx
Bağlantı Noktalarını Rastgele Bağlayalım
Java ile yazılmış bir Spring Boot uygulamanız olduğunu varsayalım. Spring Boot’un avantajlarından biri, Tomcat’i
uygulamayla birlikte JAR olarak paketleyebiliyorsunuz. Şimdi uygulamamızı Docker imajı haline getirdiğimizi ve
yukarıdaki yöntemle başlattığımızı düşünelim. Aynı ev sahibi makine üstünde bir bağlantı noktasını yalnızca bir
container kullanabilir. Bu nedenle yeniden yukarıdaki yöntemi kullanmak isterseniz yalnızca -p 81:80 -p 444:443
yazarak başlatabilirsiniz.
Ölçeklendirilebilirliğin önemli olduğu durumlarda bağlantı noktasını sürekli elle artırarak yeni container açmak pek
kabul edilebilir bir yöntem değil. Bu nedenle doğru olan yöntem -P
parametresini kullanarak container’da tanımlanmış
tüm bağlantı noktalarının ev sahibi makinedeki rastgele bağlantı noktalarına atanmasını sağlamaktır. Serinin ileriki
bölümlerinden “Günlük Kullanım Bölüm 1” içerisinde bu yöntemden daha detaylı bahsedeceğim.
Rastgele bağlantı noktası ataması için aşağıdaki komutu kullanabilirsiniz:
docker run -d --name nginx -P nginx
Dockerfile
Dockerfile ile ilgili en detaylı ve güncel bilgiyi kendi sitesinde bulabilirsiniz. Bu kısımda kısaca Dockerfile’ı neden ve nasıl kullanmanız gerektiğini anlatmaya çalışacağım. Dockerfile, özetle bir Docker imajını tarif eder. Hangi imajı baz alacağımızı, baz aldığımız imajın üstünde çalıştıracağımız komutları, oluşturacağımız dizinleri, dış kullanıma açılabilecek çevresel değişkenleri, bağlantı noktalarını ve disk alanlarını bu dosyada belirtiyoruz. Yine bir örnek üstünden ilerleyelim:
Her Dockerfile, FROM
satırıyla başlar. İmajımızı, node:6.2-slim
imajını baz alarak yaratacağız. -slim
’i imajı
mümkün olduğunca küçültmek amacıyla kullanıyorum. İmajı ilk inşa ettiğimiz noktada ne kadar küçükten başlatabilirsek o
kadar iyi. Bu nedenle Alpine Linux,
*-slim vb. seçenekleriniz varsa mutlaka
kullanın. Örneğin Java’yla yazılmış uygulamanızı Debian ya da Ubuntu imajını baz alıp üstüne Java kurarak oluşturmak
yerine, doğrudan java imajlarını tercih
etmelisiniz.
Zorunlu olmasa da, Docker Store vb. yerlerde sorgulanabilmesi ve sorumlunun açıkça
görülebilmesi açısından MAINTAINER
satırını kullanmanız iyi olur.
ADD
komutuyla, bulunduğum dizini container’ın /srv
dizinine kopyalıyorum. Uygulamamı bu dizinde tutuyor olacağım.
Bu tercih tamamen size kalmış. İsterseniz /app
vb. bir dizin de kullanabilirsiniz. Ya da Tomcat imajını baz
alıyorsanız doğrudan uygulamanızı /usr/share/tomcat/webapps
gibi bir dizin altına da kopyalayabilirsiniz. Bir sonraki
satırda (WORKDIR
) ise bundan sonraki komutların çalıştırılacağı dizini /srv
olarak belirtiyorum.
Dockerfile’daki her satır diğer komutlardan bağımsız çalışır.
WORKDIR /srv
yerinecd /srv
yazarsanız bu sonraki komutların yine/
dizininde çalışmasına sebep olacaktır.
Serinin ilk bölümündeki “İmaj ne demek?” kısmında bahsettiğim gibi,
Docker imajları katmanlardan oluşur. Dockerfile’da yazdığınız, imaja bir şey ekleyen (ADD
, COPY
, RUN
vb.) her
satır, imaja yeni bir katman ekler; dolayısıyla boyutunu artırır. Bu nedenle, dosyanın yukarıdan aşağıya doğru
okunduğunu unutmayarak, değişmeyecek kısımları mümkün olduğunca yukarıya eklemeli ve komutları zincirlemelisiniz. 8.
satırdaki apt
komutlarının zincirlenmesi, işletim sistemi güncellemelerinin tek bir katmanda yer almasını sağlıyor.
9–12. satırlar arasında uygulamanın çalışması için gereken bağımlılıkları kurup (RUN
), uygulamayı derliyoruz.
satırda
NODE_ENV
adında bir çevresel değişken tanımlayıp (NODE_ENV
) öntanımlı değeriniproduction
yapıyoruz. Bu, yukarıda bahsettiğim gerçek ortama yönelik imaj oluşturma prensibiyle de örtüşüyor. Çalışma zamanında-e NODE_ENV=development
parametresiyle öntanımlı değeri ezebiliyoruz.satırda, 3000. bağlantı noktasının dışarıdan kullanılabileceğini (
EXPOSE
) belirtiyorum. Yukarıda belirttiğim gibi, çalışma zamanında-p 3000:3000
ya da-P
gibi bir parametreyle bu bağlantı noktasını ev sahibi makineye bağlamam gerekiyor.
Son olarak 17. satırdaki CMD
komutuyla öntanımlı olarak, daha önce WORKDIR
ile belirlediğimiz dizindeki (/srv
)
app.js
dosyasının çalıştırılacağını belirtiyoruz. Bu satırda CMD
yerine ENTRYPOINT
kullanarak da aynı işi
yapabilirdik ama CMD daha esnek olduğundan onu tercih edebiliriz. Serinin
ikinci bölümünde bahsettiğim gibi docker run
komutlarının sonunda cat
vb. terminal komutlarını çağırabiliyoruz. Bunu CMD
’e borçluyuz. ENTRYPOINT
kullanıyor olsaydık, imaj için
belirlenen komut dışında bir komutu çağıramıyor olacaktık.
Dockerfile’la ilgili bu kısmı diğer kullanışlı bazı komutları açıklayarak kapatayım:
LABEL
Oluşturulacak imajın sahip olacağı öntanımlı etiketleri belirler. Ölçeklenebilirliğin önemli olduğu durumlarda
docker run
ile etiket vermektense bu şekilde etiketler tanımlamak daha mantıklı ve kolay.
LABEL type="node" purpose="api" role="core" description="REST API"
VOLUME
Yukarıdaki Kalıcı Veri Depolama kısmında bahsettiğim gibi container’lara
dışarıdan disk alanları bağlayabiliyoruz. Dockerfile’a ekleyeceğiniz VOLUME
komutlarıyla container içindeki disk
alanlarının dışarıdan bağlanabileceğini belirtmiş oluyorsunuz.
VOLUME [“/data”]
VOLUME /data
USER
Container içinde çalışan süreçler siz aksini belirtmediğiniz sürece root
kullanıcısıyla çalıştırılır. Bu da
Docker’daki olası bir açığın kötüye kullanılmasıyla istenmeyen sonuçlara sebebiyet verebilir. Bu tip durumların önüne
geçmek için özellikle proje bağımlılıklarını kurmadan önce USER
komutunu vermiş olmanız iyi olur. Bu sayede
bağımlılıkların dosya/dizin sahipliği de bu kullanıcıya ait olur.
ARG
Çevresel durumların yetişmediği bazı durumlarda imajlarınızı parametrik üretmek isterseniz ARG
komutuyla değişkenler
ve öntanımlı değerlerini tanımlayabilirsiniz. Bu tanımlar docker build
komutunda, imajınız yaratılırken kullanılır.
ARG user1=someuser
ARG buildno=1
şeklinde değişkenler tanımladığınızı varsayarsak; örneğin buildno’yu imaj oluşturulurken değiştirmek isterseniz:
docker build --build-arg buildno=2 -t tunix/alperkan.at .
şeklinde yapabilirsiniz.
HEALTHCHECK
Docker 1.12 ile eklenen bu özellik sayesinde container’ın olması gerektiği gibi çalışıp çalışmadığını kontrol eden bir komutun belirli sıklıkta ve belirli zaman dilimlerinde çalışmasını sağlayabilirsiniz. Bu metrikleri takip eden başka servislerle yeni bir container başlatılmasını, mevcut container’ın yeniden başlatılmasını sağlayabilir ya da çeşitli alarm sistemlerini tetikleyebilirsiniz.
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
Kendi İmajınızı Hazırlamak
Diyelim ki elinizde, Docker’laştırmak istediğiniz bir projeniz var; ne yapmalısınız? Bu sorunun cevabını vermek için Monitise MEA’da açık kaynak olarak GitHub’a koyduğumuz Gerrit Dashboard Server projesini örnek olarak kullanacağım.
Projeyi kendi makinenize indirdikten sonra;
npm install
gulp
komutlarıyla bağımlılıkları kurup projeyi derleyin. Son komutla, Node.js ile yazılmış
projenin derlenmiş hali dist
dizinine yerleştiriliyor. Bu dizini,
node imajlarından birini baz alan bir
container’ın içine kopyalayıp çalıştırmalıyım.
Dockerfile’a bakarsak;
Gerrit Dashboard Server projesinden Docker imajı üretme işini Travis CI üstünde yapıyoruz. Öncelikle imajın doğru şekilde üretildiğinden emin olmak için kendi makinemizde kurulu olan Docker Engine üstünde deneyelim:
docker build -t gerrit-dashboard-server:1.0.2 .
İşlem başarılı bir şekilde sonuçlandığında docker images
komutunu verdiğinizde imajın oluşturulduğunu
doğrulayabilmelisiniz.
İmajı dağıtıma çıkarmadan önce kullanılabilecek parametrelerle birlikte doğru şekilde çalıştığından emin olun.
Oluşturduğunuz imajı başka bir makineye kopyalamak için 2 seçeneğiniz var:
- Docker Engine’den arşivlenmiş şekilde dışa aktarmak
- Docker Store benzeri bir servise yüklemek
Docker Engine’den arşivlenmiş şekilde dışa aktarmak için;
docker save -o ~/Desktop/gerritdashboard-1.0.2.tar \
gerrit-dashboard-server:1.0.2
komutunu kullanabilirsiniz. Oluşan tar dosyasını diğer makineye kopyaladıktan sonra yeniden içeri aktarım yapmak içinse;
docker load -i gerritdashboard-1.0.2.tar
komutunu kullanabilirsiniz.
Docker Store & Registry
Docker imajlarını saklamanın en kolay yollarından birisi Docker Store’a yüklemek. Çoğunlukla baz imajları indirmek için en temel kaynak olarak kullandığımız Docker Hub (yeni adıyla Docker Store) aslında kendi imajlarımıza da ev sahipliği yapabilecek bir depo. Genele açık imajlarınızı sınırsızca yükleyebileceğiniz servis, özel imajlarınız için 5 adede kadar ücretsiz olanak sağlıyor. Sonrası içinse ücretli üyeliklerden birine geçilmesi gerekiyor.
Eğer oluşturduğunuz imajı herkese açık olarak yüklemenizde bir sakınca yoksa Docker Hub’a ücretsiz olarak yükleyebilirsiniz. Bunun için öncelikle servise kayıt olmalısınız. Kayıt olduktan sonra kullanıcı bilgilerinizle giriş yapın ve yeni bir Docker imaj deposu (repository) oluşturun. Bunun için tercih edebileceğiniz 2 yol var:
Manuel Depo
Giriş yaptıktan sonra sağ üstteki Create menüsünden Create Repository’e basın. Formdaki alanları doldurduktan sonra Create tuşuna basın. Şimdi imajı yükleme zamanı! 🤘🏻
Yükleme yapabilmek için bilgisayarınızdan Docker Hub’a giriş yapmak için;
docker login
komutunu verin. E-posta adresinizi ve şifrenizi yazıp doğrulamadan geçtikten sonra ev dizininizdeki
~/.docker/config.json
dosyasına ilgili servise ait giriş bilgileri (yetki kodu ve e-posta adresiniz) yazılacaktır.
Bu işlem, aynı servisi kullandığınız sürece tek seferliktir; tekrarlamanız gerekmez.
Yukardaki son örneğimizden devam edelim. İmajımızı
gerrit-dashboard-server:1.0.2
adıyla oluşturmuştuk. Docker Engine, imajı uzaktaki bir servise yükleyeceğimizde nereye
yükleyeceğini imajın adından buluyor.
Bu nedenle imajı yeniden oluşturmamıza gerek yok; etiketleri kullanarak işlemi gerçekleştirebiliriz. Docker Hub servisi
için imajı etiketleyelim:
docker tag gerrit-dashboard-server:1.0.2 docker.io/tunix/gerritdashboard-server:1.0.2
Artık imajı Docker Hub’a yükleyebiliriz:
docker push docker.io/tunix/gerritdashboard-server:1.0.2
İşlem node imajını baz alıp üstüne sadece kendi katmanlarımızı eklediğimizden hızlıca tamamlanacaktır. Artık Docker Engine yüklü olan herhangi bir makinede;
docker pull docker.io/tunix/gerritdashboard-server:1.0.2
komutuyla imajı indirip kullanmaya başlayabilirsiniz.
Otomatik Depo
Giriş yaptıktan sonra sağ üstteki Create menüsünden Create Automated Build’a basın. Karşınıza yukarıdaki gibi GitHub ya da Bitbucket arasında seçim yapmanız gereken bir ekran gelecek. Seçiminizi yaptığınızda ilgili servisin sitesine gidip kod depolarınıza erişim hakkı vermeniz gerekecektir. Bu adımı gerçekleştirdikten sonra kod depolarınızı seçmeniz için aşağıdaki gibi bir ekran göreceksiniz:
Seçiminizi yaptığınızda karşınıza otomatik depo oluşturmanın son adımı olan form çıkacaktır; formu doldurup Create tuşuna bastığınızda deponuz oluşturulacak ve ilk derleme işlemi için beklemeye başlayacaktır. Aslında kod deposu seçimini yaptığınızda arkaplanda seçim yaptığınız depoya bir webhook (ağ kancası? 😂) eklenir. Kod deposuna yeni kod parçacığı gönderdiğinizde Docker Hub’da otomatik olarak bir derlenme süreci tetiklenecek ve oluşturulan imajınız sayfada yer alacaktır.
Docker Registry
Docker Hub bu servisi verirken arkaplanda Docker Registry (yeni adıyla Docker Distribution) adı verilen açık kaynak kodlu bir yazılımı kullanıyor. Eğer imajlarınızı yüklemek için bir registry’e para vermek istemiyorsanız kendi registry’nizi kurabilirsiniz. Ancak böyle bir tercihte bulunacaksanız kurulum yapacağınız sunucunun yönetimini ve maliyetlerini de göz önünde bulundurun. Öte yandan proje kodlarını git vb. bir SKS (sürüm kontrol sistemi) üstünde tuttuğunuz sürece geriye dönüp imajı yeniden yaratmanız mümkün olabileceğinden riskiniz o kadar da yüksek değil. Yine de kodunuzun o anki hali değilse bile bulunduğu ortamın ve bağımlılıkların sıkıntı çıkarabileceğini unutmayın. 🤔
Kendi Docker Registry’nizi Kurun
Monitise MEA’da hibrid bir geliştirme ve test ortamımız var. Klasik şekilde bir VM üstüne kurulu Tomcat’e yüklenen sayısız projemiz olduğu gibi, yeni projelerimizde Docker’ı kullanma seçeneğini her zaman göz önünde bulunduruyoruz. Gerçek ortamda Docker’ı hiç kullanmayan projelerde dahi bazı durumlarda geliştirme ve test ortamı için Docker’ı tercih edebiliyoruz. Dolayısıyla bu projelerin Docker imajlarını üretmemiz ve sunucular arasında taşımaya ihtiyacımız var ve Docker Registry burada devreye giriyor.
Özetle, Docker Registry bir API’dan ve disk üstünde imaj katmanlarını yöneten bir sistemden oluşuyor. API v1 iken Docker Registry adını taşırken, v2 ile birlikte Docker Distribution adını aldı. Her ikisi de Docker Store’dan indirilebilir durumda. Kurmak için;
docker run -d -p 5000:5000 --name registry registry:2
komutunu vermeniz yeterli. Bu durumda aşağıdaki öntanımlı değerler geçerli olur:
- İmajlarınız container içindeki
/var/lib/registry
dizini altına yazılır. Öntanımlı olarak filesystem sürücüsü kullanılır. Alternatifler şurada. - Registry’nize, herhangi bir SSL sertifikasına sahip olmadığından, HTTP üstünden ulaşırsınız.
- Registry’niz herkesin yüklemesine ve indirmesine açık şekilde çalışır; kullanıcıların önce giriş yapmaları gerekmez. Kullandığınız ağın dışarıya açık olmaması durumunda bu şekilde de çalışabilirsiniz.
Registry kurulumuyla ilgili en güncel bilgiyi şuradan bulabilirsiniz.
Benim tavsiyem; registry için ev sahibi makineye ek disk vermeniz ve container’daki /var/lib/registry
dizinini ev
sahibi makinedeki /registry
dizinine bağlamanız yönünde. Ayrıca registry’i kullanan tüm makinelerde ek ayar
(--insecure-registry
) yapmamak için sunucuya geçerli bir sertifika kurmanızda fayda var.
LetsEncrypt gibi güzelliklerin olduğu günümüzde yapmazsanız ayıp! 😉 Tabii sertifika işini
registry’nin önüne bir HTTP sunucusu (nginx, Apache vb.) koyarak da
çözebilirsiniz. Hatta HTTP sunucusu yerine https-proxy’i de
kullanabilirsiniz.
Son durumda registry kurulumu için aşağıdaki gibi bir komuta ihtiyacınız var:
docker run -d --name registry \
-p 5000:5000 \
--restart=always \
-v /registry:/var/lib/registry \
registry:2
https-proxy kullanmak isteyenlere bonus olarak örnek komutu ekleyeyim:
docker run -d --name registry-ssl \
-e KEY=”$(cat registry.key)” \
-e CERT=”$(cat registry.crt)” \
-p 443:443 \
-e PORT=5000 \
--restart=always \
--link registry:www \
yajo/https-proxy
registry container’ını yaratırken kullandığınız ismin, https-proxy’i yaratırken kullandığınız komuttaki –link bölümündeki registry ismiyle aynı olduğundan emin olun.
Diyelim ki; registry’inize ulaştığınız adres docker.example.com
olsun. Bu durumda imajlarınızı buraya yüklemek için
docker.example.com/tunix/alperkan.at:1.0.2
gibi isimlendirmelisiniz. docker push
komutuyla imajınızı yüklerken,
Docker Engine otomatik olarak HTTPS protokolünü tercih edecektir. Bu nedenle SSL adımını atladıysanız ve kendi
makinenizden yükleme yapıyorsanız Docker Engine ayarlarında yeni registry’inizi “Insecure Registries” bölümünden
ekleyin. Linux’da bu arayüz geliyor mu emin değilim ama şuradaki adımları
takip edebilirsiniz.
Bu bölümünün de sonuna geldik. Bir sonraki bölümde Docker Compose’dan ve özellikle birden fazla parçaya ihtiyaç duyan projelerinizi Docker ile nasıl kolayca ayağa kaldırabileceğinizden bahsedeceğim.
Gidişâta göre bu planda zaman zaman değişiklikler yapacak olsam da serinin tüm bölümlerinin planına şuradan ulaşabilirsiniz.