Docker ile Mean Stack Oluşturmak

featured image

MEAN ifadesini mutlaka duymuşsunuzdur. MongoDB, Express, Angular ve Node.JS'in baş harflerinin birleşmesi ile oluşuyor efenim.

Zaman zaman bu stack'i kullanarak projelerimizi geliştiriyoruz. Geliştiriyoruz, geliştiriyoruz da geliştirme ortamını hazırlarken çok çileler çekiyoruz. İşte bu makalede bu çektiklerimizden kurtulmak adına bir Docker container'ı hazırlayacağız. Bu container sayesinde tek komutla MEAN stack üzerinde geliştirme yapmaya başlayabileceğiz.

gifpic-100

Öncelikle bir ayıp edip daha önce Docker'ı kurmadıysak hemen şuradan kuralım. Kurulumu tamamladığımıza inanıyorsak şu komutla emin olalım.

docker  -v
Docker version 17.12.0-ce, build c97c6d6

Başlayalım

Herhangi dizinde root dizininizi oluşturun. Örneğin ben, masaüstündeki app klasörüne docker-ile-mean-stack-olusturmak adıyla bir dizin oluşturuyorum. Tüm çalışmalarımı bu dizin altında yapacağım.

mkdir ~/Desktop/app/docker-ile-mean-stack-olusturmak
cd ~/Desktop/app/docker-ile-mean-stack-olusturmak

1.Angular Client Kurulumu

Angular'ın komut satırı arayüzü bilgisayarınızda kurulu değilse aşağıdaki komut ile kuralım.

npm install -g @angular/cli

Angular client için root folder'ı daha önce oluşturduğumuz docker-ile-mean-stack-olusturmak dizininin içine oluşturalım.

mkdir angular-client
cd angular-client

Angular projemizi, oluşturmuş olduğumuz angular-client klasörüne kuralım.

ng new my-app --directory ./
  • my-app parametresi proje adını belirler. Siz istediğinizi yazabilirsiniz.
  • --directory kısmı ise proje dosyalarının nereye kurulacağını belirler. Biz " ./ " ifadesi ile aynı dizine kurmasını istedik.

Her şey tamamsa, Angular projesini ayağa kaldıralım.

ng serve

http://localhost:4200 adresine gidelim. Her şey yolunda gittiyse aşağıdaki gibi bir ekranla karşılaşacaksınız.

angular client

Şimdi Ctrl+C ile bu çalışmayı durdurun.

Angular Client Dockerizing

Angular uygulamamızı kendi bilgisayarımızda çalıştırıyoruz sorun yok evet. Şimdi bu uygulamayı kendi bilgisayarımızdan değil de bir docker container'ı aracılığı ile nasıl çalıştıracağımıza bakalım.

angular-client klasörunde Dockerfile adında bir dosya oluşturun ve içeriğini şöyle değiştirin.

# Dockerhub üzerinden resmi Node 8 image'ını temel alarak bir image oluştur
FROM node:8

# Uygulamamızın bulunacağı klasörü oluştur
RUN mkdir -p /var/www/app

# Komutlarımızın çalıştırılacağı dizini seç
WORKDIR /var/www/app

# package.json dosyamızı çalışma dizinine kopyala
COPY package.json /var/www/app

# Bağımlılıkları kur
RUN npm install

# Tüm proje dosyalarını docker image'ına kopyala
COPY . /var/www/app

# Uygulamanın çalışacağı port
EXPOSE 4200

# Projeyi ayağa kaldıracak komutu çalıştır
CMD ["npm", "start"]

Docker Ignore

NPM bağımlılıklarımızın bulunduğu node_modules klasörünün docker image'ı içerisine gönderilmesini engellemek için .dockerignore adında bir dosya oluşturup içeriğini şöyle yapalım.

node_modules/

Start Script'i

Son olarak package.json dosyasındaki start script'ini şöyle değiştirelim.

"start": "ng serve -H 0.0.0.0"

Docker Build & Run

Aşağıdaki komut ile docker imaj'ımızı build edelim.

docker build -t angular-client:dev .

sonra ayağa kaldıralım

docker run -d --name angular-client -p 4200:4200 angular-client:dev

http://localhost:4200 adresine gidelim. Her şey yolunda gittiyse aşağıdaki gibi bir ekranla karşılaşacaksınız.

angular client

Ne değişti? Az önce de bu ekranla karşılaşmıştık? Evet ama diğerini kendi bilgisayarından çalıştırmıştın, burada ise docker container'ın çalışıyor.

gifpic-100

Angular container'ı tamam. Geçelim Express'e.

2.Express Server Kurulumu

Express server'ın bulunacağı kök dizini oluşturalım.

cd ~/Desktop/app/docker-ile-mean-stack-olusturmak
mkdir express-server

Express generator'ı kuralım.

sudo npm install -g express-generator

Express projesini oluşturup ayağa kaldıralım.

express .
npm install

http://localhost:3000 adresine gidelim. Her şey yolunda gittiyse aşağıdaki gibi bir ekranla karşılaşacaksınız.

express server

Şimdi Ctrl+C ile bu çalışmayı durdurun.

Express Server Dockerizing

# Dockerhub üzerinden resmi Node 8 image'ını temel alarak bir image oluştur
FROM node:8

# Uygulamamızın bulunacağı klasörü oluştur
RUN mkdir -p /var/www/app

# Komutlarımızın çalıştırılacağı dizini seç
WORKDIR /var/www/app

# package.json dosyamızı çalışma dizinine kopyala
COPY package.json /var/www/app

# Bağımlılıkları kur
RUN npm install

# nodemon'u kur
RUN npm install -g nodemon

# Tüm proje dosyalarını docker image'ına kopyala
COPY . /var/www/app

# Uygulamanın çalışacağı port
EXPOSE 3000

# Projeyi ayağa kaldıracak komutu çalıştır
CMD ["npm", "start"]

Docker Ignore

NPM bağımlılıklarımızın bulunduğu node_modules klasörünün, docker image'ı içerisine gönderilmesini engellemek için .dockerignore adında bir dosya oluşturup içeriğini şöyle yapalım.

node_modules/

Start Script'i

Son olarak package.json dosyasındaki start script'ini şöyle değiştirerek nodemon kullanmak istediğimizi belirtelim.

"start": "nodemon ./bin/www"

Docker Build & Run

Aşağıdaki komut ile docker imaj'ımızı build edelim.

docker build -t express-server:dev .

sonra ayağa kaldıralım

docker run -d --name express-server -p 3000:3000 express-server:dev

http://localhost:3000 adresine gidelim. Her şey yolunda gittiyse aşağıdaki gibi bir ekranla karşılaşacaksınız.

express server

Yine aynı şekilde bir şey değişmemiş gibi görünüyor. Öyle de olması gerekiyor zaten. Yaptığımız değişikliğin amacı, uygulamanın bilgisayarımızdan çalışması yerine docker container'ı üzerinden çalışmasını sağlamaktı. Her şey yolunda efem.

alemlere akak mi

MongoDB container

Bu noktada herhangi dockerfile oluşturmaya ihtiyacımız yok. Zaten Docker Hub üzerinde bulunan görüntüyü alıp kullanacağız.

docker run -d --name mongodb -p 27017:27017 mongo

Docker Compose

Angular, Express ve MongoDB container'larımızı ayrı ayrı oluşturduk. Peki bunları nasıl bir çatı altında toplayıp birbirleriyle iletişim kurabilir hale getireceğiz? El-cevap: Docker Compose.

Kurulum için sizi şöyle alalım.

docker-compose -v
docker-compose version 1.11.2, build dfed245

Öncelikle daha önce ayağa kaldırdığımız docker containerlar ile çakışma olmaması için container'larımızı durduralım.

docker stop angular-client && docker stop express-server && docker stop mongodb

Şimdi kök dizinimize gidelim.

cd ~/Desktop/app/docker-ile-mean-stack-olusturmak

Ve burada docker-compose.yml adlı dosyayı oluşturalım.

touch docker-compose.yml

İçeriğini aşağıdaki gibi yapalım.

version: '2'

services: # Tüm Docker container'larımız 'services' altında olacak
  angular: # Angular client için tanımlama
    build: angular-client # imaj adı
    ports: # port yönlendirmeleri
      - '4200:4200'
    volumes:
      - ./angular-client/:/var/www/app

  express: # Express server için tanımlama
    build: express-server # imaj adı
    ports: # port yönlendirmeleri
      - '3000:3000'
    volumes:
      - ./express-server/:/var/www/app
    links:
      - database

  database: # Mongo server için tanımlama
    image: mongo # imaj adı
    ports: # port yönlendirmeleri
      - '27017:27017'

Yukarıdaki tanımlamada açıklamadığımız iki kısım var; volumes: Container'ı ayağa kaldırdıktan sonra yazdığınız kodlar neyse öyle kalır. Yani kodunuzda bir değişiklik yaptığınızda bu değişikliği göremezsiniz. Bu durum değiştirmiş olduğunuz dosyanın bilgisayarınızdaki dizinden docker içine kopyalanmadığı için oluşuyor. Volumes tanımlaması ile bilgisayarınızdaki ve docker içerisindeki proje dizinlerini birbirine eşitlemiş oluyorsunuz. Böylece herhangi değişiklik yaptığınızda bu değişim hemen yansıyor.

links: Container'ların birbiri ile haberleşebilmesi için kullanılır. Biz burada express-server'ın mongodb'ye de erişebilmesini istediğimiz için bu tanımlamayı yaptık.

Şimdi komutu verelim ve kurduğumuz yapıyı ayağa kaldıralım.

docker-compose up

Komutu çalıştırdıktan sonra şöyle loglar üretiyor.

docker compose up

Eveeeeeeet. Oldu da bitti maşallah.

ismail abi ficcicu

Teset edelim bakalım. Angular Client şurada http://localhost:4200 Express Server ise şurada http://localhost:3000

Projemizde herhangi bir değişiklik yapmadığımız için yine aynı çıktıyı göreceksiniz.

Şimdi Angular tarafında birkaç değişiklik yapalım bakalım.

angular-client/src/app/app.component.html

<div style="text-align:center">
  <h1>Welcome to Docker MEAN Stack</h1>
  <img
    width="300"
    alt="Angular Logo"
    src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
  />

  <div>
    <div class="info">Created by <strong>Mehmet Seven</strong></div>
    <a href="https://github.com/meseven" target="_blank">
      <img
        src="https://assets-cdn.github.com/images/modules/logos_page/GitHub-Mark.png"
        class="logo"
      />
      @meseven
    </a>
    <a href="https://twitter.com/mehmeteseven" target="_blank">
      <img
        src="https://www.sketchappsources.com/resources/source-image/twitterlogo_1x.png"
        class="logo"
      />
      @mehmeteseven
    </a>
  </div>
</div>

angular-client/src/app/app.component.css

* {
  font-family: Arial;
}

a {
  color: #000;
  text-decoration: none;
  font-weight: 600;
  font-size: 13px;
}

.info {
  margin-bottom: 25px;
}

.logo {
  width: 30px;
  vertical-align: middle;
  margin-left: 20px;
}

Hemen bakalım: http://localhost:4200

mean stack

Evet. Cillop!

dance

Node.JS MongoDB Bağlantısı

Sorun yaşayabileceğinizi düşündüğüm bu konuyu da izah etmek istiyorum

express-server/ dizinine gidelim ve

npm install mongoose

diyerek mongoose'u kuralım.

Ardından express-server/app.js dosyasına şu kodları ekleyelim.

var mongoURI = 'mongodb://database/my-db';
mongoose.connect(mongoURI, function (err) {
  if (err) console.log('db connection err');
  console.log('mongodb: connected');
});

Evet, bu şekilde veritabanımıza bağlanıyoruz. Ancak şu mongoURI değişkeninde database diye bir şey var. Neyin nesidir? Hani docker-compose.yml dosyamızda database diye bir tanımlama yapmıştık ya. Ha işte, bu ona karşılık geliyor. En sondaki my-db ifadesi ise veritabanı adınızı belirtiyor.

Dockerfile dosyalarınızda bir değişiklik yaptığınızda, değişikliklerin yansıması için docker-compose up --build komutunu çalıştırabilirsiniz.

Amma bık bık konuştun kardeşim, yeter, bana direkt stack'i ver dersen de hazırladığımız stack şu GitHub reposunda. Alıp tüm projelerinizde gönül rahatlığıyla kullanmaya başlayabilirsiniz. Pull Requestleriniz baş tacımızdır. Bekleriz efem.

Konuyu bir de videolu olarak anlattım.

Kapanış

Mevzu bittiğine göre bana yine yol göründü.

operler

Bu arada, o gemi bir gün gelecek.