ایجاد، پیاده‌سازی و اجرای اپلیکیشن در محیط‌های مختلف کار ساده‌ای نیست.

اگه بخوایم بدون استفاده از کانتینرهای داکر، برنامه‌مون رو اجرا کنیم، ممکنه حس کنیم بخشی از برنامه‌ ناقصه و چیزی کم داره!

حالا داکر به عنوان رهبر و پیشتاز در بحث کانتینرها به کمک همه‌ی ما اومده. این کانتینرها می‌تونن در هر جایی اجرا بشن، یعنی توسعه‌دهنده‌ها دیگه نگران اجرای برنامه‌ها در پلتفرم‌ها و سیستم‌عامل‌های مختلف نیستن.

داکر واقعاً به چه معناست؟ 

در کل Docker ابزاریست open source که برای توسعه، استقرار و اجرای برنامه‌های کاربردی توسط کانتینرها ازش استفاده می‌شه. 

یا می‌تونیم اینجوری تعریفش کنیم:

Docker فناوری‌‌‌ای است که به شما اجازه می‌ده image‌های برنامه‌تون رو با تمام قسمت‌های مورد نیازش مانند کتابخانه‌ها و وابستگی‌های دیگه ایجاد کنین.

توی این پست می‌خوایم دلایل استفاده از داکر در محیط توسعه‌ی برنامه‌ها رو با هم مرور کنیم و در ادامه یاد می‌گیریم چطوری در زبان‌های مختلف اون رو مورد استفاده قرار بدیم.

وقتی گروهی از افراد روی یک پروژه کار می‌کنن و عضو جدیدی به تیم اضافه می‌شه، بدون استفاده از داکر، ممکنه چند روز زمان ببره تا تنظیمات راه‌اندازی برای سیستم عامل جدید انجام بشه، اما با نصب داکر و اجرای ۳ تا ۵ دستور، عضو جدید تیم هم می‌تونه به راحتی تنظیمات سیستم‌عامل رو انجام بده و باز هم برنامه‌ها بدون مشکل کار می‌کنن و در حالت run قرار می‌گیرن. 

مزیت بعدی داکر اینه که اگر نسخه‌ی جدید از زبان مورد استفاده‌تون (مثل MYSQL ،PHP و... ) منتشر بشه، باز هم این امکان رو دارین تا به راحتی و بدون مشکل برنامه‌تون رو با داکر تست کنین. 

چرا و چگونه می‌توان از Docker برای توسعه استفاده کرد؟

در بخش قبل گفتیم داکر مزایای زیادی داره، اما مهم‌ترین مزیتش اینه که مبتنی بر کانتینر عمل می‌کنه.

با استفاده از داکر، نه تنها کدها، بلکه کل سیستم عامل و لایه‌های مرتبط با استقرار برنامه‌ها (مثل کتابخانه‌ها و توابع) رو منتقل و ایزوله می‌کنین.

در واقع داکر به توسعه‌دهنده اجازه میده تا ورژن مناسب سیستم عامل، ورژن مناسب زبان برنامه‌نویسی و سایر وابستگی‌ها رو بسته‌بندی کنه و همه رو در یک بسته ارسال بکنه.
داکر به دلیل سبک (کم حجم) بودن، قابلیت ایزوله‌سازی و مقیاس‌پذیری سرویس‌ها، نسبت به ماشین‌های مجازی برتری داره. 

داکر فقط برای استقرار نیست، بلکه برای توسعه‌ی برنامه‌ها نیز عالی‌ست. 

بسیاری از شرکت‌ها برای استقرار APIها و برنامه‌ها، اجرای کد توسعه‌دهندگان، تست محلی برای کاربران و… روی پلتفرم داکر سرمایه‌گذاری کردن. 

علاوه بر موارد بالا، برای توسعه‌ برنامه‌ها هم می‌شه از این پلتفرم استفاده کرد!

توی بخش بعدی می‌خوایم بگیم چرا و چگونه؟

 چرا از Docker برای توسعه استفاده می‌کنیم؟

به دلایل زیادی شما به عنوان یک توسعه‌دهنده می‌تونین با داکر، راحت‌تر از همیشه برنامه‌هاتون رو اجرا کنین!

۱- محیط‌های توسعه‌ی پایدار برای تمام اعضای پروژه وجود داره:

این یعنی تمام توسعه‌دهندگان از سیستم‌عامل، کتابخانه‌ها و زبان runtime مشابهی استفاده می‌کنن و نوع سیستم‌عامل میزبان هم مهم نیس.

۲-محیط توسعه دقیقا با محیط تولید یکسانه:

این یعنی با استقرار برنامه‌ها می‌تونین مطمئن باشین که برنامه به درستی کار می‌کنه. 

۳-اگه زمان کامپایل برنامه‌تون خیلی طول می‌کشه، می‌تونید اون رو داخل داکر build کنین:

این‌کار برای همه‌ی توسعه‌دهندگانی که از سیستم‌عامل‌های ویندوز و مک استفاده می‌کنن، قابل اجراست.

۴-برای توسعه‌‌ی برنامه‌ها تنها به داکر نیاز دارین:

برای این‌کار نیازی نیست زبان‌های مختلفی رو در سیستم‌تون نصب کنین: 

آیا نیاز دارین اسکریپت Ruby رو اجرا کنین، ولی Ruby‌ رو نصب نکردین؟
می‌تونین اون رو در یک image‌ docker‌ برنامه‌ی Ruby، اجرا کنین.

۵-این امکان رو دارین تا از نسخه‌های چند زبانه استفاده کنین: 

مثلا اگر نیاز دارین برنامه‌ی پایتون‌تون رو در Python 3 اجرا کنین، ولی فقط Python 2 در سیستم نصبه، می‌تونین اون رو با ایمیج Python 3 اجرا کنین.

یا مثلا اگه بخواین برنامه‌ی جاواتون رو با Java 1.6‌ کامپایل کنین، ولی‌ Java 1.7‌ در سیستم شما نصبه، می‌تونین اون رو در یک image docker‌ برنامه‌ی Java 1.6 کامپایل کنین. 

۶-با استفاده از داکر استقرار برنامه‌ها به راحتی انجام می‌گیره:

اگر برنامه در کانتینر شما اجرا شد، روی سرور هم اجرا می‌شه.
فقط کافیه کد‌تون رو بسته‌بندی کنین و به همراه image قبلی روی سرور مستقر کنین، یا این‌که image docker‌ جدیدی رو در کدهاتون اعمال کنین و image جدید رو اجرا کنین.

۷-روی سیستم من اجرا بشه، یعنی در هر محیط دیگه هم اجرا می‌شه:

کانتینرها قابل حمل‌ هستن و وقتی برنامه برای اجرا در کانتینر آماده‌ست و بدون مشکل در سیستم شما اجرا می‌شه، در یک محیط توسعه، مرحله‌بندی (staging) و تولید (production) هم به همون روش اجرا می‌‌شه. 

۸-برنامه‌ با نسخه‌‌ی جدید زبان برنامه‌نویسی/ بانک اطلاعاتی سازگار خواهد بود:

تصور کنین، اخیرا نسخه‌ی جدیدی از زبانی که استفاده می‌کنین، منتشر شده. مثلا از PHP 5.6 استفاده می‌کردین و حالا نسخه‌ی 7.0 اون منتشر شده.
دقیقا نمی‌دونین چقدر زمان نیازه تا برنامه‌ با نسخه جدید سازگار بشه؛ فقط کافیه دو کانتینر مختلف docker رو اجرا کنین. یکی از کانتینرها نسخه‌ی فعلی رو اجرا می‌کنه و دیگری نسخه جدید رو. حتی می‌تونین دو نسخه از برنامه رو در کنار هم تست کنین تا عملکرد رو اندازه‌گیری کنین. 

چگونه می‌توان از Docker برای توسعه استفاده کرد؟

استفاده از داکر برای توسعه‌ی برنامه‌ها، تفاوت زیادی با کاری که معمولا برای توسعه انجام می‌دادین، ایجاد نمی‌کنه، به جز دو مورد زیر: 

  • تضمین می‌کنه که کدها و تمام وابستگی‌های مربوط به اون، در دایرکتوری پروژه وجود داره.
  • دستورات بیلد و اجرای برنامه رو تغییر میدین، تا برنامه رو در کانتینر داکری خودتون اجرا کنین. 

در این بخش با ما همراه باشین تا بگیم، چطوری این کار در زبان‌های مختلف قابل انجامه.

با توضیح طولانی در زبان Ruby‌ شروع می‌کنیم و در ادامه به سایر زبان‌ها هم نگاهی کوتاه می‌اندازیم:

Ruby

بیایید با مثال ساده‌ Hello world‌ در زبان Ruby شروع کنیم که حتی برای اجرای اون احتیاجی به نصب Ruby‌ ندارین!

کد زیر رو کپی کنین و اون رو در فایلی به نام hello.rb‌ قرار بدین:

puts 'Hello Ruby!'

حالا این دستور رو اجرا کنین:

docker run --rm -v "$(pwd)":/app -w /app ruby ruby hello.rb

با اجرای این دستور باید عبارت !Hello Ruby‌ ‌رو در صفحه‌ی نمایش‌تون مشاهده کنین. 

اضافه کردن وابستگی‌ در Ruby

حالا بیاین یک وابستگی دیگه رو اضافه کنیم تا ببینیم vendor‌ کردن وابستگی‌ها چطوری کار می‌کنه.

بدون این‌که مجبور باشین وابستگی‌ها رو توی کانتینر نصب کنین، می‌تونین وابستگی‌ها رو داخل کانتینر اجرا کنین،

خب ببینیم چطوری؟

کد زیر رو در فایلی به نام Gemfile کپی کنین:

source 'https://rubygems.org'
gem 'hello-world'

فایل hello.rb رو به حالت زیر تغییر بدین:

require 'hello-world'
puts 'Hello Ruby!'

اگر دستور bundle install‌ رو برای نصب وابستگی جدید gems، اجرا کنین و بعدش دستور 
ruby hello.rb رو اجرا کنین، این کار به درستی انجام می‌شه - اما اگر بخواین اون رو داخل کانتینر docker‌ اجرا کنین، با خطا مواجه می‌شین، چون iron_mq gem داخل کانتینر نصب نشده. 

می‌تونین اون رو درون کانتینر نصب کنین؛ اما در این حالت باید کانتینر رو مدیریت کنین، وضعیت کانتینر رو به خاطر بسپارین و… .

bundle کردن وابستگی‌ در Ruby

برای رفع مشکل قسمت قبل، باید تمام کدها و وابستگی‌هاتون رو در در یک package کوچک قرار بدین.

با دستور زیر، وابستگی‌ها در دایرکتوری پروژه نصب می‌شن و هر چیزی که به کامپایل
نیاز داشته باشه، روی معماری مناسب بیلد می‌شه:

docker run --rm -v "$(pwd)":/app -w /app ruby bundle install --standalone --deployment

برای استفاده از این bundle جدید، تغییر کوچکی در hello.rb انجام می‌‌شه، به اولین خط دستور زیر (require_relative) توجه کنین:

require_relative 'vendor/bundle/bundler/setup'
require 'hello-world'

puts 'Hello Ruby!'

و حالا دوباره برای وابستگی جدیدمون، دستور docker run رو اجرا می‌کنیم:

 docker run --rm -v "$(pwd)":/app -w /app ruby ruby hello.rb

اجرای دستورات در ورژن‌های دیگر Ruby

خب! حالا چطوری این دستورات رو در ورژن دیگه‌ای از Ruby مثل Ruby 1.9، اجرا کنین؟

کافیه دستورات رو در کانتینر دیگه‌ای اجرا کنین:

docker run --rm -v "$(pwd)":/app -w /app ruby:2.4 ruby hello.rb

Web Apps

اگر در حال ایجاد یک برنامه‌ی تحت وب هستین، به بازکردن پورت‌ها نیاز دارین.

کافیه از پرچم p PORT:PORT - در دستور docker run استفاده کنین. 

به عنوان مثال، کد زیر رو کپی کنین و اون رو در فایلی به نام webapp.rb قرار بدین:

require_relative'vendor/bundle/bundler/setup'
require 'sinatra'
set :port, 8080
set :bind, '0.0.0.0' # required to bind to all interfaces
get '/' do
    "Hello World!"
End

وابستگی و bundle در WebApps

-مشابه توضیحاتی که در زبان Ruby‌ گفته شد،  ’gem ‘sinatra رو به  Gemfile ای که ساخته بودین اضافه کنین.

دستور bundle install رو دوباره اجرا کنین و بعد هم دستور زیر رو اجرا کنین:

docker run -i -t --rm -v "$(pwd)":/app -w /app -p 8080:8080 ruby ruby webapp.rb

تمام نکاتی که تا اینجا گفتیم، در سایر زبان‌ها هم صدق می‌کنه، فقط ممکنه یکسری تفاوت‌های جزئی وجود داشته باشه.

در ادامه‌ی این پست به طور خلاصه این نکات رو در زبان‌های Java ،Node وGo بررسی می‌کنیم.

برای بررسی بیش‌تر این جزئیات، می‌تونین source code کامل زبان‌های مختلف رو در این لینک، مشاهده کنین.  

Java

مشابه مثال Ruby، وابستگی‌ها رو در دایرکتوری پروژه‌تون قرار بدین و بعد برنامه رو در کانتینر، کامپایل و اجرا کنین. (در  repo ، وابستگی‌های این مثال موجوده).

کد زیر رو کپی کنین و اون رو در فایلی به نام Hello.java قرار بدین:

import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.json.JSONArray;
import org.json.JSONObject;

public class Hello {
  public static void main(String[]
           args) throws Exception {
  System.out.println("Hello Java!");
  }
}

دستورات داکر در Java برای کامپایل و اجرا

کد کامپایل در کانتینر به صورت زیر است:

docker run --rm -v "$(pwd)":/app -w /app iron/java:dev sh -c 'javac -cp "json-java.jar:gson-2.2.4.jar" Hello.java'

و قطعه کد اجرا در کانتینر نیز به صورت زیر است:

docker run --rm -v "$(pwd)":/app -w /app iron/images:java-1.8 sh -c 'java -cp gson-2.2.4.jar:json-java.jar:. Hello'

Node

npm در node برای نصب دایرکتوری‌های پروژه، پیش‌فرض‌های لازم رو به طور خودکار نصب می‌کنه.

اول باید وابستگی مورد نیاز رو با دستور زیر نصب کنین:

docker run --rm -it -v $PWD:/app -w /app node npm install hello-world-npm

حالا برنامه رو در فایلی به نام hello.js کپی کنین:     

const helloWorld = require('hello-world-npm');
console.log(helloWorld());
console.log("Hello Node!");

و بعدش دستور زیر رو اجرا کنین: 

docker run --rm -it -v $PWD:/app -w /app node hello.js

Go

کد زیر رو در فایلی به نام hello.go کپی کنین:

package main
import (
    "fmt"
    hello "github.com/treeder/go-hello-world"
)
func main() {
    fmt.Println(hello.Hello())
    fmt.Println("Hello Go!")
}

دستورات داکر در Go برای اجرای وابستگی

حالا  برای بدست آوردن، بیلد و اجرای وابستگی‌ها می‌تونین دستورات زیر رو اجرا کنین:

docker run --rm -i -v $PWD:/app -w /app golang go mod init github.com/treeder/goexample
docker run --rm -i -v $PWD:/app -w /app golang go mod vendor
docker run --rm -i -v $PWD:/app -w /app golang go build -mod vendor -o myapp
docker run --rm -i -v $PWD:/app -w /app golang ./myapp

…

- در مثال‌های قبل، بعد از اجرای فلگ (rm-)، کانتینر حذف می‌شه.

برای این‌که به هر دلیلی کانتینر رو نگه دارین، می‌تونین از کد زیر استفاده کنین:

 docker run — name goapp -v $GOPATH:/gopath -v “$(pwd)”:/app -w /app golang sh -c ‘go build -o hello && ./hello’ || docker start -ia goapp.

نکته آخر 

چه موقع باید از docker استفاده کنیم؟ 

  • به عنوان کنترل ورژن برای سیستم عامل برنامه‌تون.
  • وقتی می‌خواین کد یکسان و پیکربندی سرور یکسانی رو هم در لپ تاپ شخصی و هم در سرور داشته باشین.
  • و هر زمان که برنامه‌های شما باید مراحل مختلف توسعه رو پشت سر بگذارد.

در این پست با داکر و روش‌ استفاده از اون در زبان‌های مختلف آشنا شدیم! امیدواریم با مطالعه‌ی مطالب این پست بتونین از Docker به راحتی استفاده کنین و بیش‌ترین بهره رو ازش ببرین.  

مرسی از همراهی‌تون!