সফটওয়্যার কন্টেইনারাইজেশন মানে এটি মানক ইউনিটগুলিতে প্যাকেজ করা যাতে ডেভেলপমেন্ট এবং ডিপ্লয়মেন্ট সহজ হয়। কন্টেইনারগুলো আপনার অ্যাপ্লিকেশনের কোডসহ এর সমস্ত নির্ভরতা বান্ডেল করে। একটি কন্টেইনার সম্পূর্ণরূপে স্বতন্ত্র হতে পারে; এতে আপনার সফটওয়্যার, একটি রানটাইম এনভায়রনমেন্ট এবং সিস্টেম লাইব্রেরিগুলির একটি প্যাকেজ থাকে। কন্টেইনার ডেভেলপারদের এবং অপারেশন টিমগুলিকে নিশ্চিত করতে সাহায্য করে যে সফটওয়্যারটি পরিবেশ নির্বিশেষে একইভাবে চলে। কোডকে ইনফ্রাস্ট্রাকচার থেকে পৃথক করে, "কন্টেইনারাইজড" অ্যাপ্লিকেশনগুলো লোকাল এনভায়রনমেন্ট, টেস্ট এনভায়রনমেন্ট এবং প্রোডাকশনে একইভাবে রান করে।
ডকার (Docker) সফটওয়্যার ডেভেলপ এবং ডিপ্লয় করার সবচেয়ে জনপ্রিয় প্ল্যাটফর্মগুলির এক। ডকার সফটওয়্যারকে একটি "ইমেজ" হিসেবে প্যাকেজ করে, যা ডকার ইমেজে এক্সিকিউট হলে রানটাইমে একটি কন্টেইনারে রূপান্তরিত হয়। এই বিচ্ছিন্নতা ডেভেলপারদের একসাথে একই হোস্টে অনেক কন্টেইনার চালাতে দেয়।
রেলস ডেভেলপাররা একটি বিদ্যমান অ্যাপ্লিকেশন কন্টেইনারাইজ করার সময় অনন্য চ্যালেঞ্জের সম্মুখীন হন। এই নিবন্ধে একটি কার্যকর রেলস অ্যাপ কন্টেইনারাইজ করার পদ্ধতি এবং রাস্তায় থাকা গুরুত্বপূর্ণ ধারণা ও陷阱গুলির ব্যাখ্যা করা হবে। এটি কন্টেইনার বা ডকারের মৌলিক বর্ণনা নয়; বরং এটি প্রোডাকশন অ্যাপ্লিকেশন কন্টেইনারাইজ করার সময় ডেভেলপাররা যে সমস্যাগুলোর সম্মুখীন হন তার ব্যাখ্যা।
পূর্বশর্ত
আপনি যদি অনুসরণ করতে চান, তবে আপনার কাছে একটি রেলস অ্যাপ্লিকেশন থাকতে হবে যা ইতিমধ্যে ডকারাইজড নয় (এই হলো 'কন্টেইনারাইজড'-র ডকার-নির্দিষ্ট শব্দ)। আমি রেলসওয়ার্ক (RailsWork) ব্যবহার করব, একটি সম্পূর্ণ ফিচারযুক্ত সাইড প্রজেক্ট যা আমি সম্প্রতি লঞ্চ করেছি। এটি রেলস দিয়ে লিখিত একটি জব-বোর্ড যা হারোকুতে (Heroku) ডিপ্লয় করা হয়েছে, কিন্তু কন্টেইনারাইজড নয়।
এর বাইরে, আপনাকে ডকার ইনস্টলড থাকতে হবে। একটি জনপ্রিয় পদ্ধতি হলো ডকার ডেস্কটপ (Docker Desktop) ব্যবহার করা, যা অফিসিয়াল ওয়েবসাইট থেকে ডাউনলোড করা যায়।

একবার অ্যাপ ডাউনলোড হলে, ইনস্টলার চালান। এটি চালানোর পর, এটি আপনাকে অ্যাপ্লিকেশনটি আপনার অ্যাপ্লিকেশন ফোল্ডারে টেনে আনতে বলবে। তারপর আপনাকে আপনার অ্যাপ্লিকেশন ফোল্ডার থেকে অ্যাপটি লঞ্চ করতে হবে এবং এটি যে সুবিধাগুলো চাইবে সেগুলো দিতে হবে। শেষ চেক হিসেবে ডকার সঠিকভাবে ইনস্টল হয়েছে কিনা তা নিশ্চিত করতে, আপনার টার্মিনাল থেকে আপনার মেশিনে চলমান কন্টেইনারগুলো লিস্ট করার চেষ্টা করুন নিচের কমান্ড চালিয়ে:
docker ps
যদি ডকার ইনস্টলড থাকে (এবং আপনি কোনো কন্টেইনার চালাচ্ছেন না), তবে আপনি শুধু হেডার সহ একটি খালি লিস্ট পাবেন যা এরকম দেখাবে:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Dockerfile
গভীরে যাওয়ার আগে স্পষ্ট টার্মিনোলজি দিয়ে শুরু করা গুরুত্বপূর্ণ।
আপনার রেলস অ্যাপ্লিকেশন "ডকারাইজড" হলে, এটি একটি কন্টেইনারে চলে। একটি কন্টেইনার স্বতন্ত্র, প্রতিস্থাপনযোগ্য এবং প্রায়শই পুনর্নির্মিত হয়।
একটি কন্টেইনার একটি ইমেজ থেকে তৈরি হয়। একটি ইমেজ হলো একটি ফাইল সিস্টেমের ভার্চুয়াল স্ন্যাপশট যা মেটাডেটার সাথে জোড়া।
একটি Dockerfile হলো সোর্স কোড যা বর্ণনা করে একটি ইমেজ কীভাবে তৈরি করা উচিত। Dockerfile-গুলো প্রায়শই একটি ডকারাইজড অ্যাপের রিপোজিটറിയ리에 থাকে এবং বাকি অ্যাপের সাথে ভার্সন কন্ট্রোলে ট্র্যাক করা হয়।
Dockerfile তৈরি করা শুনতে চেয়ে সহজ! ডকার আমাদের বিশেষ সিনট্যাক্স দেয় যা কিছু কন্টেইনারাইজ করার কঠিন কাজ থেকে আমাদের মুক্তি দেয়। প্রথমে, আপনি যে অ্যাপটি কন্টেইনারাইজ করতে চান তার রুট ডিরেক্টরিতে যান। এখন কাজ শুরু করার জন্য প্রস্তুত, যদি আপনি গিট (git) ব্যবহার করেন তবে একটি নতুন ব্রাঞ্চ তৈরি করা ভালো আইডিয়া। আপনি নিচের কমান্ড চালিয়ে dockerize-this-app নামে সহজেই একটি নতুন ব্রাঞ্চ তৈরি করতে পারেন:
git checkout -b dockerize-this-app
এরপর, একটি Dockerfile তৈরি করুন এবং একটি রুবি অ্যাপ্লিকেশনের ভিত্তিতে ইমেজ তৈরি করার নির্দেশ দিন। এটি কমান্ড লাইন থেকে নিচের কমান্ড চালিয়ে করা যায়:
echo "FROM ruby:3.0.0" > Dockerfile
এখানে, আমরা শুধু Dockerfile তৈরি করছি এবং একটি লাইন যোগ করছি যা নির্দেশ করে রুবি কন্টেইনার ইমেজ কোথায় পাওয়া যাবে। আমার প্রজেক্টে রুবি ৩.০.০ ব্যবহার করা হয়েছে, তাই আমি উপযুক্ত ইমেজটি ব্যবহার করেছি। আপনি যদি রুবির ভিন্ন ভার্সন ব্যবহার করেন, তাও সমস্যা নেই। ডকারে সমস্ত সাপোর্টেড ইমেজের তালিকা আছে।
এরপর, ম্যানুয়ালি ডকারকে একটি ডকার ইমেজ তৈরি করার নির্দেশ দিন:
docker build -t rails_work .
এখানে, আপনি rails_work-কে ইমেজের জন্য আপনার পছন্দের যেকোনো নাম দিয়ে প্রতিস্থাপন করতে পারেন। এবং শেষে পিরিয়ড (.) অন্তর্ভুক্ত করা নিশ্চিত করুন!
যদি আপনি দেখতে চান ইমেজটি তৈরি হয়েছে কিনা, তবে নিচের কমান্ড দিয়ে আপনার সিস্টেমের ইমেজগুলো লিস্ট করুন:
docker image list
এই ইমেজটি প্রায় খালি; এতে বর্তমানে আমাদের অ্যাপ্লিকেশন নেই। আমরা নিচের লাইনগুলো Dockerfile-এ যোগ করে অ্যাপের কোড যোগ করার নির্দেশ দিতে পারি:
ADD . /rails_work
WORKDIR /rails_work
RUN bundle install
এটি আপনার অ্যাপ্লিকেশন থেকে ফাইলগুলো কপি করে এবং অ্যাপ্লিকেশনের নির্ভরতা ইনস্টল করে। (এখানে, আপনি rails_work-কে আপনার অ্যাপের নাম দিয়ে প্রতিস্থাপন করবেন।)
এই পয়েন্টে, আপনাকে আবার ইমেজ তৈরি করার কমান্ড চালাতে হবে:
docker image list
এখানে একটি সমস্যার সম্ভাবনা রয়েছে, বিশেষ করে যদি আপনি এটি একটি বিদ্যমান প্রোডাকশন অ্যাপ্লিকেশনের জন্য করছেন। বান্ডলার (Bundler) ফিরিয়ে দিতে পারে যে ইমেজটি যে বান্ডলার ভার্সন ব্যবহার করার চেষ্টা করছে সেটি Gemfile.lock ফাইলটি তৈরি করা বান্ডলার ভার্সন থেকে ভিন্ন। اگر এটি ঘটে, তবে আপনার দুটি স্পষ্ট বিকল্প রয়েছে:
- ইমেজ যে ভার্সনটি ব্যবহার করছে সেটি পরিবর্তন করুন।
Gemfile.lockসম্পূর্ণরূপে মুছে দিন। যদি আপনি এটি করেন, তবে নিশ্চিত করুন যে আপনার যে জেম (Gem) ভার্সনগুলো নির্দিষ্ট ভার্সনে পিন করা দরকার সেগুলো পিন করা আছে, কারণ লকফাইলটি সম্পূর্ণরূপে পুনর্জন্মাবে।
যদি আপনার bundle install এখনও ফেল করে, তবে আপনার Dockerfile-এ কিছু অতিরিক্ত ইনস্টলেশন দরকার হতে পারে:
RUN apt-get update && apt-get install -y shared-mime-info
যদি আপনি এখনও সমস্যা অনুভব করেন, তবে আপনি ভুল রুবি ইমেজ বেস হিসেবে বেছে নেওয়ার সম্ভাবনা রয়েছে, তাই সেখান থেকে তদন্ত শুরু করা উচিত।
এখানে এনভায়রনমেন্ট ভেরিয়েবল সেট করার একটি ভালো সুযোগ:
ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true
এরপর, পোর্ট ৩০০০ এক্সপোজ (expose) করার একটি লাইন যোগ করুন, যা ডিফল্টভাবে রেলস চলার জায়গা:
EXPOSE 3000
শেষে, কন্টেইনারকে স্টার্ট হলে একটি ব্যাশ শেল (bash shell) খুলতে নির্দেশ দিন:
CMD ["bash"]
মোটামুটি, আপনার Dockerfileটি এইভাবে দেখাবে (rails_work নামটি বাদ দিয়ে):
FROM ruby:3.0.0
ADD . /rails_work
WORKDIR /rails_work
RUN bundle install
ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true
EXPOSE 3000
CMD ["bash"]
ডকার কমান্ডها ব্যাখ্যা
সর্বাধিক সাধারণ Dockerfile কমান্ডগুলোর পূর্ণ বোঝাপড়া থাকা অবশ্যই সাহায্যকর হবে।
- FROM -> এটি বেস হিসেবে কোন ইমেজ ব্যবহার করা হবে তা সংজ্ঞায়িত করে।
- RUN -> এটি কন্টেইনারের ভিতরে কমান্ড এক্সিকিউট করে।
- ENV -> এটি এনভায়রনমেন্ট ভেরিয়েবল সংজ্ঞায়িত করে।
- WORKDIR -> এটি কন্টেইনার যে ডিরেক্টরি ব্যবহার করছে সেটি পরিবর্তন করে।
- CMD -> কন্টেইনার স্টার্ট হলে কোন প্রোগ্রাম চলবে তা নির্দিষ্ট করে।
Docker Compose
ডকারের ডকুমেন্টেশন অনুযায়ী, "Compose" হলো তাদের টুল যা একাধিক ডকার কন্টেইনার সহ অ্যাপ্লিকেশন তৈরি (এবং শুরু) করতে ব্যবহৃত হয়। অ্যাপ্লিকেশনের প্রয়োজনীয় কন্টেইনারগুলো চালু করার জন্য যা যা দরকার সেটি YAML-এ আউটলাইন করা হয়। কেউ docker-compose up চালালে, কন্টেইনারগুলো তৈরি হয়! Docker-compose আমাদের ডিক্লেরেটিভলি (declaratively) আমাদের কন্টেইনার কনফিগারেশন বর্ণনা করতে দেয়।
আপনার Docker Compose ফাইল তৈরি করার আগে, ডকারকে বোঝাতে হবে কী ফাইলগুলো বিল্ড হওয়া ইমেজ থেকে বাদ দিতে হবে। .dockerignore নামে একটি ফাইল তৈরি করুন। (পিরিয়েডটি লক্ষ্য করুন!) এই ফাইলে নিচের কন্টেন্ট পেস্ট করুন:
.git
.dockerignore
.env
যদি আপনার Gemfile বিল্ড প্রসেস দ্বারা মেইনটেইন করা হয়, তবে উপরের বাদ দেওয়া লিস্টে Gemfile.lock যোগ করুন।
এরপর, docker-compose.yml নামে একটি ফাইল তৈরি করুন। এখানে আমরা আমাদের কন্টেইনার কনফিগারেশন বর্ণনা করব। আমরা ফাইলের কন্টেন্ট হিসেবে নিচের কোড দিয়ে শুরু করব:
version: '3.8'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres:/var/lib/postgresql/data
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/Rails-Docker
ports:
- "3000:3000"
depends_on:
- db
volumes:
postgres:
এই ফাইল দুটি সার্ভিস তৈরি করে: একটি db নামে এবং অন্যটি web নামে। db কন্টেইনারটি পোস্টগ্রেস (postgres) জন্য বने একটি প্রি-মেড ইমেজ থেকে তৈরি হবে, এবং আপনাকে POSTGRES_USER এবং POSTGRES_PASSWORD এর প্রাসঙ্গিক মানগুলো বদলাতে হবে। আপনাকে প্রোডাকশন সিক্রেটগুলো এই ফাইলে না রাখার জন্য সতর্ক থাকতে হবে - আরও তথ্যের জন্য নিচের "Managing Secrets" সেকশন দেখুন।
web কন্টেইনারটি আমাদের Dockerfile থেকে বিল্ড হয় এবং তারপর পোর্ট ৩০০০-এ IP অ্যাড্রেস 0.0.0.0-এ একটি রেলস সার্ভার শুরু করে। ইন্টারন্যাল পোর্ট ৩০০০ তারপর প্রকৃত পোর্ট ৩০০০-এ ম্যাপ করা হয়।
এবং শেষে, আমাদের জন্য ডেটা পার্সিস্ট (persist) করার একটি পোস্টগ্রেস ভলিউম রয়েছে।
সিক্রেট ম্যানেজ করা
বিল্ড-টাইমে অথেন্টিকেশন প্রোডাকশন অ্যাপ্লিকেশনের জন্য একটি সমস্যা হতে পারে। কখনও কখনও আপনার অ্যাপ্লিকেশন একটি প্রাইভেট রিপোজিটরি থেকে জেম (Gem) খুঁজে বের করতে পারে, অথবা আপনাকে ডাটাবেস শংসাপত্র সংরক্ষণ করতে হতে পারে।
Dockerfile-এ সরাসরি থাকা যেকোনো তথ্য চিরকাল কন্টেইনার ইমেজে বেকড (baked) থাকে, এবং এটি একটি সাধারণ সিকিউরিটি পিটফল (pitfall)।
আপনি যদি রেলসের ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করেন, তবে ডকারকে (বা যেকোনো হোস্টকে) এক্সেস দেয়া অপেক্ষাকৃত সহজ। Docker Compose ফাইলে, আপনি শুধু RAILS_MASTER_KEY এনভায়রনমেন্ট ভেরিয়েবল প্রদান করুন। দিয়ে गये compose টার্গেটের জন্য, আপনি environment হেডারের অধীনে কীটি নির্দিষ্ট করুন, যা আপনাকে তৈরি করতে হবে যদি আপনি ইতিমধ্যে না করে থাকেন। উপরের docker-compose ফাইলটি তাহলে নিচেরভাবে হবে:
version: '3.8'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres:/var/lib/postgresql/data
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/Rails-Docker
ports:
- "3000:3000"
depends_on:
- db
environment:
- RAILS_MASTER_KEY=this_would_be_the_key
volumes:
postgres:
এখন, আপনি একটি চৌরস্তায় আছেন। আপনি সম্ভবত এই ফাইলটি সোর্স কন্ট্রোলে কমিট করতে চান, কিন্তু আপনি নিশ্চিতভাবেই আপনার মাস্টার কী বা ডাটাবেস পাসওয়ার্ড সোর্স কন্ট্রোলে ট্র্যাক করতে চান না, কারণ এটি আরেকটি বিপজ্জনক সিকিউরিটি সমস্যা হবে। সর্বোত্তম সমাধান হবে dotenv জেম ব্যবহার করা যাতে আপনি এই শংসাপত্রগুলো প্রক্সি (proxy) দিয়ে এক্সেস করতে পারেন, সেগুলো একটি আলাদা ফাইলে সংরক্ষণ করে যা সোর্স কন্ট্রোলে ট্র্যাক করা হয় না।
ডকারাইজড অ্যাপ্লিকেশন চালানো
শেষে, আপনি নিচের কমান্ড দিয়ে ডকারাইজড অ্যাপ্লিকেশনটি चला सकते हैं:
docker compose up
বিশ্বাস করা কঠিন, কিন্তু এটিই সব! ডকার-কম্পোজ (docker-compose) কন্টেইনার চালু করা সহজ করে দেয়, বিশেষ করে কমান্ড-লাইন আর্গুমেন্টের ক্ষেত্রে।
আপনি যদি চলমান কন্টেইনারদের তালিকা চান, তবে নিচের কমান্ড চালান:
docker ps
আপনার রেলস কন্টেইনারের নাম যদি web হয়, তবে আপনি এর উপরে কমান্ড এক্সিকিউট করতে পারেন একদম সরলভাবে। উদাহরণস্বরূপ, আপনি যদি একটি রেলস কনসোল চালাতে চান, তবে আপনাকে শুধু নিচের কমান্ড চালাতে হবে:
docker exec -it web rails console
আপনি যদি কন্টেইনারের ভিতরে একটি ব্যাশ শেল (bash shell) চান, তবে নিচের কমান্ড চালান:
docker exec -it web bash
এখানে বর্ণিতগুলোর মতো আরও কিছু পিটফল (Pitfalls)
প্রোডাকশনে ডকারাইজড রেলস অ্যাপ্লিকেশনের সাথে একটি সাধারণ সমস্যা হলো লগ (logs) নিয়ে। এগুলো দীর্ঘমেয়াদে কন্টেইনার সিস্টেমে থাকা উচিত নয়। ডকার প্রস্তাব করে যে লগগুলো সহজে STDOUT-এ রিডাইরেক্ট করা যাক। এটি config/application.rb-এ এক্সপ্লিসিটলি কনফিগার করা যায়।
একটি অন্য সাধারণ সমস্যা হলো মেইলার (mailers) নিয়ে। আপনার অ্যাপ্লিকেশন যদি মেইলার ব্যবহার করে, তবে আপনাকে অবশ্যই কানেকশন সেটিংস এক্সপ্লিসিটলি ডিফাইন করতে হবে। SMTP একটি পরিপূর্ণ ডেলিভারি মেথড এবং সাধারণত ডিফল্টসহ ভালো কাজ করে, কিন্তু আমাদের সার্ভার লোকেশন এবং অন্যান্য সেটিংস আমাদের কন্টেইনার কনফিগারেশন সাথে মেলাতে হবে।
আপনার যদি ওয়ার্কার বা ব্যাকগ্রাউন্ড জব থাকে, যেমন sidekiq, তবে সেটিকে অবশ্যই এর নিজস্ব কন্টেইনারে চালাতে হবে।
উপসংহার
একটি প্রোডাকশন রেলস অ্যাপ্লিকেশন কন্টেইনারাইজ করা চ্যালেঞ্জের একটি সেট लेकर আসে, যা আপনি নিঃসন্দেহে দেখেছেন। আপনার অ্যাপ্লিকেশন জ्यों-ज्यों বড় হয়েছে, ত्यों-ত्यों এতে সম্ভবত অনেক নির্ভরতা জমা হয়েছে যা এই মাইগ্রেশনকে চ্যালেঞ্জিং করে তোলে। যেটি হোক ব্যাকগ্রাউন্ড ওয়ার্কার, মেইলার, অথবা সিক্রেট - অধিকাংশ পিটফল হ্যান্ডেল করার সুস্থাপিত প্যাটার্ন রয়েছে। একবার প্রোডাকশন অ্যাপ্লিকেশন ডকারের সাথে কাজ করার প্রারম্ভিক কাজ সম্পন্ন হলে, ভবিষ্যতে পরিবর্তন এবং ডিপ্লয়ের সহজতা নিবেশকে অর্থবহ করে তুলবে।