1. ভূমিকা
সর্বশেষ হালনাগাদ: ২০২৪-১১-০১
কীভাবে একটি পুরোনো পিএইচপি অ্যাপ্লিকেশনকে গুগল ক্লাউডের জন্য আধুনিকীকরণ করা যায়?
(📽️ এই কোডল্যাবটির একটি ৭ মিনিটের পরিচিতিমূলক ভিডিও দেখুন)
অন-প্রেমিসে চলমান লিগ্যাসি অ্যাপ্লিকেশন থাকাটা একটি সাধারণ ব্যাপার, যেগুলোকে আধুনিকীকরণ করা প্রয়োজন। এর অর্থ হলো সেগুলোকে স্কেলেবল, সুরক্ষিত এবং বিভিন্ন পরিবেশে স্থাপনযোগ্য করে তোলা।
এই কর্মশালায় আপনি যা শিখবেন:
- পিএইচপি অ্যাপ্লিকেশনটিকে কন্টেইনারাইজ করুন ।
- ম্যানেজড ডাটাবেস সার্ভিসে ( ক্লাউড এসকিউএল ) স্থানান্তরিত হন।
- ক্লাউড রান -এ ডিপ্লয় করুন (এটি GKE/Kubernetes-এর একটি জিরো-অপস বিকল্প)।
- আইডেন্টিটি অ্যান্ড অ্যাক্সেস ম্যানেজমেন্ট (IAM) এবং সিক্রেট ম্যানেজারের মাধ্যমে অ্যাপ্লিকেশনটি সুরক্ষিত করুন ।
- ক্লাউড বিল্ডের মাধ্যমে একটি CI/CD পাইপলাইন নির্ধারণ করুন। ক্লাউড বিল্ডকে GitHub বা GitLab-এর মতো জনপ্রিয় গিট প্রোভাইডারদের কাছে হোস্ট করা আপনার গিট রিপোর সাথে সংযুক্ত করা যেতে পারে এবং উদাহরণস্বরূপ, মেইন-এ যেকোনো পুশ-এর মাধ্যমে এটিকে ট্রিগার করা যায়।
- অ্যাপ্লিকেশনটির ছবিগুলো ক্লাউড স্টোরেজে হোস্ট করুন। এটি মাউন্টিংয়ের মাধ্যমে করা হয় এবং অ্যাপটি পরিবর্তন করার জন্য কোনো কোডের প্রয়োজন নেই।
- জেমিনি-র মাধ্যমে জেন এআই কার্যকারিতা চালু করুন, যা ক্লাউড ফাংশন (সার্ভারবিহীন) দ্বারা পরিচালিত হয়।
- SLO-গুলো সম্পর্কে জানুন এবং আপনার নতুন করে সাজানো অ্যাপটি পরিচালনা করতে শিখুন ।
এই পদক্ষেপগুলো অনুসরণ করে, আপনি পর্যায়ক্রমে আপনার পিএইচপি অ্যাপ্লিকেশনকে আধুনিক করে তুলতে পারেন এবং এর স্কেলেবিলিটি, নিরাপত্তা ও ডেপ্লয়মেন্টের নমনীয়তা উন্নত করতে পারেন। অধিকন্তু, গুগল ক্লাউডে স্থানান্তরিত হলে আপনি এর শক্তিশালী পরিকাঠামো এবং পরিষেবাগুলো ব্যবহার করে একটি ক্লাউড-নেটিভ পরিবেশে আপনার অ্যাপ্লিকেশনটির নির্বিঘ্ন চলাচল নিশ্চিত করতে পারবেন।
আমরা বিশ্বাস করি যে, এই সহজ ধাপগুলো অনুসরণ করে আপনি যা শিখবেন, তা ভিন্ন ভাষা/স্ট্যাক এবং বিভিন্ন ব্যবহারের ক্ষেত্রে আপনার নিজের অ্যাপ্লিকেশন ও প্রতিষ্ঠানে প্রয়োগ করতে পারবেন।
অ্যাপ সম্পর্কে
যে অ্যাপ্লিকেশনটি ( কোড , এমআইটি লাইসেন্সের অধীনে) আপনি ফর্ক করবেন, সেটি MySQL অথেনটিকেশন সহ একটি সাধারণ PHP 5.7 অ্যাপ্লিকেশন। অ্যাপটির মূল উদ্দেশ্য হলো এমন একটি প্ল্যাটফর্ম তৈরি করা যেখানে ব্যবহারকারীরা ছবি আপলোড করতে পারবেন এবং অ্যাডমিনিস্ট্রেটররা অনুপযুক্ত ছবিগুলোতে ট্যাগ যুক্ত করতে পারবেন। অ্যাপ্লিকেশনটিতে দুটি টেবিল রয়েছে:
- ব্যবহারকারীগণ । অ্যাডমিনসহ পূর্ব-সংকলিত অবস্থায় আসে। নতুনরা নিবন্ধন করতে পারেন।
- ছবি । সাথে কয়েকটি নমুনা ছবি রয়েছে। লগ ইন করা ব্যবহারকারীরা নতুন ছবি আপলোড করতে পারবেন। আমরা এখানে কিছু জাদু যোগ করব।
আপনার লক্ষ্য
আমরা পুরোনো অ্যাপ্লিকেশনটিকে আধুনিকীকরণ করে গুগল ক্লাউডে আনতে চাই। আমরা এর টুলস ও পরিষেবাগুলো ব্যবহার করে স্কেলেবিলিটি উন্নত করব, নিরাপত্তা জোরদার করব, ইনফ্রাস্ট্রাকচার ম্যানেজমেন্ট স্বয়ংক্রিয় করব এবং ক্লাউড এসকিউএল, ক্লাউড রান, ক্লাউড বিল্ড, সিক্রেট ম্যানেজার ও আরও অনেক পরিষেবার মাধ্যমে ইমেজ প্রসেসিং, মনিটরিং এবং ডেটা স্টোরেজের মতো উন্নত ফিচারগুলো ইন্টিগ্রেট করব।

এর চেয়েও গুরুত্বপূর্ণ বিষয় হলো, আমরা এটি ধাপে ধাপে করতে চাই, যাতে আপনি প্রতিটি ধাপের পেছনের চিন্তাধারা সম্পর্কে জানতে পারেন, এবং সাধারণত প্রতিটি ধাপ পরবর্তী ধাপগুলোর জন্য নতুন সম্ভাবনার দ্বার উন্মোচন করে (উদাহরণস্বরূপ: মডিউল ২ -> ৩, এবং ৬ -> ৭)।
এখনও বিশ্বাস হচ্ছে না? ইউটিউবে এই ৭ মিনিটের ভিডিওটি দেখুন।
আপনার যা যা লাগবে
- ব্রাউজারসহ একটি কম্পিউটার, যা ইন্টারনেটের সাথে সংযুক্ত।
- কিছু GCP ক্রেডিট । এর জন্য পরবর্তী ধাপ দেখুন।
- আপনি ক্লাউড শেল ব্যবহার করবেন। এতে আপনার প্রয়োজনীয় সমস্ত কমান্ড আগে থেকেই ইনস্টল করা আছে এবং একটি IDE-ও রয়েছে।
- গিটহাব অ্যাকাউন্ট । আপনার নিজের গিট রিপো দিয়ে মূল কোড 🧑🏻💻 gdgpescara/app-mod-workshop-এর একটি ব্রাঞ্চ তৈরি করতে এটি প্রয়োজন। আপনার নিজস্ব CI/CD পাইপলাইন (স্বয়ংক্রিয় কমিট -> বিল্ড -> ডিপ্লয়) চালু রাখার জন্যও এটি দরকার।
নমুনা সমাধান এখানে পাওয়া যাবে:
- লেখকের রিপো: https://github.com/Friends-of-Ricc/app-mod-workshop
- প্রতিটি অধ্যায়ের জন্য মূল ওয়ার্কশপ রিপোটি
.solutions/ফোল্ডারের অধীনে থাকে।
এই কর্মশালাটি ক্লাউড শেল-এ (ব্রাউজারে) সম্পন্ন করার জন্য ডিজাইন করা হয়েছে।
তবে, আপনার স্থানীয় কম্পিউটার থেকেও এটি চেষ্টা করা যেতে পারে।
২. ক্রেডিট সেট আপ এবং ফর্ক

GCP ক্রেডিট রিডিম করুন এবং আপনার GCP এনভায়রনমেন্ট সেট আপ করুন [ঐচ্ছিক]
এই কর্মশালাটি চালানোর জন্য আপনার একটি বিলিং অ্যাকাউন্ট প্রয়োজন, যাতে কিছু ব্যালেন্স আছে। যদি আপনার আগে থেকেই নিজস্ব বিলিং ব্যবস্থা থাকে, তবে আপনি এই ধাপটি বাদ দিতে পারেন।
আপনার GCP ক্রেডিট লিঙ্ক করার জন্য একটি একদম নতুন Google Gmail অ্যাকাউন্ট (*) তৈরি করুন । GCP ক্রেডিট রিডিম করার জন্য আপনার প্রশিক্ষকের কাছে লিঙ্কটি চেয়ে নিন অথবা এখানে ক্রেডিটগুলি ব্যবহার করুন: bit.ly/PHP-Amarcord-credits ।
নতুন তৈরি করা অ্যাকাউন্ট দিয়ে সাইন ইন করুন এবং নির্দেশাবলী অনুসরণ করুন।

(
আমার একটি নতুন জিমেইল অ্যাকাউন্টের প্রয়োজন কেন?
আমরা দেখেছি যে, অনেকে কোডল্যাবে ব্যর্থ হয়েছেন কারণ তাদের অ্যাকাউন্টে (বিশেষ করে কর্মক্ষেত্র বা শিক্ষার্থীদের ইমেল) আগে থেকেই GCP ব্যবহারের অভিজ্ঞতা ছিল এবং প্রাতিষ্ঠানিক নীতিমালার কারণে তা করা সম্ভব ছিল না। আমরা একটি নতুন জিমেইল অ্যাকাউন্ট তৈরি করার অথবা এমন একটি বিদ্যমান জিমেইল অ্যাকাউন্ট (gmail.com) ব্যবহার করার পরামর্শ দিই, যেটিতে আগে GCP ব্যবহারের কোনো অভিজ্ঞতা নেই।
ক্রেডিটটি রিডিম করতে বাটনটিতে ক্লিক করুন।

নিচের ফর্মটি আপনার নাম ও পদবি দিয়ে পূরণ করুন এবং শর্তাবলীতে সম্মত হন।
বিলিং অ্যাকাউন্টটি এখানে প্রদর্শিত হওয়ার আগে আপনাকে কয়েক সেকেন্ড অপেক্ষা করতে হতে পারে: https://console.cloud.google.com/billing
কাজটি সম্পন্ন হলে Google Cloud Console খুলুন এবং উপরের বাম দিকের ড্রপডাউন মেনুতে থাকা 'No organization' দেখানো অংশে থাকা Project Selector-এ ক্লিক করে একটি নতুন প্রজেক্ট তৈরি করুন। নিচে দেখুন।

আপনার কোনো প্রজেক্ট না থাকলে, নিচের স্ক্রিনশটে দেখানো অনুযায়ী একটি নতুন প্রজেক্ট তৈরি করুন। এর উপরের ডান কোণায় একটি "NEW PROJECT" অপশন রয়েছে।

নতুন প্রজেক্টটিকে নিম্নোক্তভাবে GCP ট্রায়াল বিলিং অ্যাকাউন্টের সাথে লিঙ্ক করা নিশ্চিত করুন।

আপনি গুগল ক্লাউড প্ল্যাটফর্ম ব্যবহার করার জন্য সম্পূর্ণ প্রস্তুত। আপনি যদি নতুন হন অথবা ক্লাউড পরিবেশে সবকিছু করতে চান, তাহলে নিচে দেখানো অনুযায়ী উপরের বাম কোণায় থাকা বাটনটির মাধ্যমে ক্লাউড শেল এবং এর এডিটর অ্যাক্সেস করতে পারেন।

উপরের বাম দিকে আপনার নতুন প্রজেক্টটি সিলেক্ট করা আছে কিনা তা নিশ্চিত করুন:
নির্বাচিত নয় (খারাপ):

নির্বাচিত (ভালো):

গিটহাব থেকে অ্যাপটি ফর্ক করুন
- ডেমো অ্যাপটিতে যান: https://github.com/gdgpescara/app-mod-workshop
- কাঁটাচামচ 🍴-এ ক্লিক করুন।
- আপনার যদি গিটহাব অ্যাকাউন্ট না থাকে, তাহলে আপনাকে একটি নতুন অ্যাকাউন্ট তৈরি করতে হবে।
- আপনার ইচ্ছামতো সম্পাদনা করুন।

- অ্যাপ কোডটি ক্লোন করতে ব্যবহার করুন
-
git clonehttps://github.com/YOUR-GITHUB-USER/YOUR-REPO-NAME
- আপনার পছন্দের এডিটর দিয়ে ক্লোন করা প্রজেক্ট ফোল্ডারটি খুলুন। আপনি যদি ক্লাউড শেল বেছে নেন, তাহলে নিচে দেখানো অনুযায়ী " ওপেন এডিটর " এ ক্লিক করে এটি করতে পারেন।

নিচের চিত্রে যেমন দেখানো হয়েছে, গুগল ক্লাউড শেল এডিটর-এ আপনার প্রয়োজনীয় সবকিছুই রয়েছে।

'ওপেন ফোল্ডার'-এ ক্লিক করে এবং ফোল্ডারটি নির্বাচন করে এটি দৃশ্যত করা যেতে পারে, সম্ভবত আপনার হোম ফোল্ডারে থাকা app-mod-workshop ফোল্ডারটি।
৩. মডিউল ১: একটি SQL ইনস্ট্যান্স তৈরি করুন
গুগল ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করুন
আমাদের পিএইচপি অ্যাপটি একটি MySQL ডাটাবেসের সাথে সংযুক্ত হবে এবং তাই কোনো ঝামেলা ছাড়াই মাইগ্রেশনের জন্য এটিকে গুগল ক্লাউডে রেপ্লিকেট করা প্রয়োজন। ক্লাউড এসকিউএল এক্ষেত্রে একটি আদর্শ সমাধান, কারণ এটি আপনাকে ক্লাউডে একটি সম্পূর্ণ পরিচালিত MySQL ডাটাবেস চালানোর সুযোগ দেয়। অনুসরণ করার ধাপগুলো হলো:
- ক্লাউড এসকিউএল পেজে যান: https://console.cloud.google.com/sql/instances
- "ইনস্ট্যান্স তৈরি করুন" এ ক্লিক করুন
- এপিআই সক্রিয় করুন (প্রয়োজন হলে)। এতে কয়েক সেকেন্ড সময় লাগতে পারে।
- MySQL নির্বাচন করুন।
- (আমরা আপনাকে সবচেয়ে সস্তা সংস্করণটি দেওয়ার চেষ্টা করছি, যাতে এটি বেশিদিন টেকে):
- সংস্করণ: এন্টারপ্রাইজ
- প্রিসেট: ডেভেলপমেন্ট (আমরা স্যান্ডবক্স চেষ্টা করেছিলাম এবং সেটি আমাদের জন্য কাজ করেনি)
- Mysql ভার্সন: 5.7 (বাহ, পুরনো দিনের কথা মনে পড়ে গেল!)
- ইনস্ট্যান্স আইডি:
appmod-phpappবেছে নিন (যদি আপনি এটি পরিবর্তন করেন, তবে ভবিষ্যতের স্ক্রিপ্ট এবং সমাধানগুলিও সেই অনুযায়ী পরিবর্তন করতে মনে রাখবেন)। - পাসওয়ার্ড: আপনার যা ইচ্ছা, কিন্তু এটি CLOUDSQL_INSTANCE_PASSWORD হিসেবে লিখে রাখুন।
- অঞ্চল: অ্যাপের বাকি অংশের জন্য আপনি যা বেছে নিয়েছেন, সেটিই রাখুন (যেমন, মিলান =
europe-west8) - জোনভিত্তিক প্রাপ্যতা: একক জোন (আমরা ডেমোর জন্য টাকা বাঁচাচ্ছি)
ক্লাউড এসকিউএল ডাটাবেস ডেপ্লয় করতে ক্রিয়েট ইনস্ট্যান্স বাটনে ক্লিক করুন; ⌛ এটি সম্পন্ন হতে প্রায় ১০ মিনিট সময় লাগে⌛ । এই সময়ের মধ্যে ডকুমেন্টেশন পড়া চালিয়ে যান; আপনি পরবর্তী মডিউল ("কন্টেইনারাইজ ইওর পিএইচপি অ্যাপ") সমাধান করাও শুরু করতে পারেন, কারণ প্রথম অংশে এই মডিউলের উপর এর কোনো নির্ভরতা নেই (যতক্ষণ না আপনি ডিবি কানেকশন ঠিক করছেন)।
দ্রষ্টব্য : এই ইনস্ট্যান্সটির জন্য আপনার প্রতিদিন প্রায় ৭ ডলার খরচ হবে। ওয়ার্কশপের পরে এটি বন্ধ করে দিতে ভুলবেন না।
ক্লাউড SQL-এ image_catalog ডেটাবেস এবং ব্যবহারকারী তৈরি করুন
অ্যাপ প্রজেক্টটিতে একটি db/ ফোল্ডার রয়েছে, যার মধ্যে দুটি sql ফাইল আছে:
- 01_schema.sql : এতে ব্যবহারকারী এবং ছবির ডেটা ধারণকারী দুটি টেবিল তৈরির SQL কোড রয়েছে।
- 02_seed.sql : পূর্বে তৈরি করা টেবিলগুলিতে ডেটা যুক্ত করার জন্য SQL কোড ধারণ করে।
image_catalog ডাটাবেসটি তৈরি হয়ে গেলে এই ফাইলগুলো পরে ব্যবহার করা হবে। আপনি নিম্নলিখিত ধাপগুলো অনুসরণ করে এটি করতে পারেন:
- আপনার ইনস্ট্যান্সটি খুলুন এবং ডেটাবেস ট্যাবে ক্লিক করুন:
- "ডেটাবেস তৈরি করুন" এ ক্লিক করুন
- এর নাম দিন
image_catalog(যেমনটি PHP অ্যাপ কনফিগে আছে)।

এরপর আমরা ডাটাবেস ইউজার তৈরি করি। এর মাধ্যমে আমরা image_catalog ডাটাবেসে প্রমাণীকরণ করতে পারি।
- এখন ইউজার্স ট্যাবে ক্লিক করুন
- 'ব্যবহারকারী অ্যাকাউন্ট যোগ করুন'-এ ক্লিক করুন।
- ব্যবহারকারী: চলুন একটি তৈরি করি:
- ব্যবহারকারীর নাম:
appmod-phpapp-user - পাসওয়ার্ড: এমন কিছু বেছে নিন যা আপনি মনে রাখতে পারবেন, অথবা "জেনারেট" এ ক্লিক করুন।
- " যেকোনো হোস্টকে অনুমতি দিন (%) " রাখুন।
- যোগ করুন-এ ক্লিক করুন।
সুপরিচিত আইপিগুলোর জন্য ডেটাবেসটি উন্মুক্ত করুন।
উল্লেখ্য যে, ক্লাউড এসকিউএল-এর সমস্ত ডেটাবেস 'আইসোলেটেড' বা বিচ্ছিন্ন অবস্থায় থাকে। এটি অ্যাক্সেস করার জন্য আপনাকে স্পষ্টভাবে একটি নেটওয়ার্ক সেট আপ করতে হবে।
- আপনার ইনস্ট্যান্সে ক্লিক করুন
- 'কানেকশন' মেনুটি খুলুন
- "নেটওয়ার্কিং" ট্যাবে ক্লিক করুন।
- 'অনুমোদিত নেটওয়ার্ক'-এর নিচে ক্লিক করুন। এবার একটি নেটওয়ার্ক (যেমন, একটি সাবনেট) যোগ করুন।
- আপাতত, অ্যাপটি চালু রাখার জন্য একটি দ্রুত কিন্তু অনিরাপদ সেটিংস বেছে নেওয়া যাক - পরে আপনি এটিকে আপনার বিশ্বস্ত আইপি-গুলোর মধ্যে সীমাবদ্ধ করতে চাইতে পারেন:
- নাম: "পৃথিবীর প্রত্যেকেই - নিরাপত্তাহীনতায় ভোগে"।
- নেটওয়ার্ক: "
0.0.0.0/0"(দ্রষ্টব্য: এই অংশটিই অনিরাপদ!) - সম্পন্ন ক্লিক করুন
- সংরক্ষণ করুন।
আপনার এইরকম কিছু দেখা উচিত:

দ্রষ্টব্য : কর্মশালাটি O(ঘন্টায়) শেষ করার জন্য এই সমাধানটি একটি ভালো আপোস। তবে, প্রোডাকশনের জন্য আপনার সমাধানটি সুরক্ষিত করতে SECURITY ডকটি দেখে নিন!
এবার ডিবি সংযোগটি পরীক্ষা করার পালা!
দেখা যাক, আমরা আগে তৈরি করা image_catalog ইউজারটি কাজ করে কি না।
ইনস্ট্যান্সের ভিতরে "ক্লাউড এসকিউএল স্টুডিও"-তে প্রবেশ করুন এবং নিচে দেখানো অনুযায়ী প্রমাণীকরণের জন্য ডেটাবেস, ইউজার এবং পাসওয়ার্ড লিখুন:

এখন যেহেতু আপনি প্রবেশ করেছেন, আপনি SQL এডিটরটি খুলে পরবর্তী বিভাগে যেতে পারেন।
কোডবেস থেকে ডাটাবেস ইম্পোর্ট করুন
SQL এডিটর ব্যবহার করে image_catalog টেবিলগুলো তাদের ডেটাসহ ইম্পোর্ট করুন। রিপো-তে থাকা ফাইলগুলো ( 01_schema.sql এবং তারপর 02_seed.sql ) থেকে SQL কোড কপি করুন এবং ক্রমানুসারে একের পর এক এক্সিকিউট করুন।
এর পরে আপনি image_catalog-এ users এবং images নামে দুটি টেবিল পাবেন, যা নিচে দেখানো হয়েছে:

আপনি এডিটরে নিম্নলিখিতটি চালিয়ে এটি পরীক্ষা করতে পারেন: select * from images;
এছাড়াও ক্লাউড এসকিউএল ইনস্ট্যান্সের পাবলিক আইপি অ্যাড্রেসটি লিখে রাখতে ভুলবেন না, পরে আপনার এটির প্রয়োজন হবে। আইপি পেতে, ক্লাউড এসকিউএল ইনস্ট্যান্সের মূল পৃষ্ঠার ওভারভিউ পেজে যান। (ওভারভিউ > এই ইনস্ট্যান্সে সংযোগ করুন > পাবলিক আইপি অ্যাড্রেস)।
৪. মডিউল ২: আপনার পিএইচপি অ্যাপকে কন্টেইনারাইজ করুন

আমরা এই অ্যাপটি ক্লাউডের জন্য তৈরি করতে চাই।
এর মানে হলো কোডটিকে কোনো এক ধরনের ZIP ফাইলে প্যাকেজ করা, যেটিতে ক্লাউডে এটি চালানোর জন্য প্রয়োজনীয় সমস্ত তথ্য থাকে।
এটি প্যাকেজ করার কয়েকটি উপায় আছে:
- ডকার খুবই জনপ্রিয়, কিন্তু সঠিকভাবে সেট আপ করা বেশ জটিল।
- বিল্ডপ্যাক । তুলনামূলকভাবে কম জনপ্রিয়, কিন্তু কী বিল্ড করতে হবে এবং কী চালাতে হবে তা এটি স্বয়ংক্রিয়ভাবে অনুমান করে নেয়। প্রায়শই এটি কোনো সমস্যা ছাড়াই কাজ করে!
এই কর্মশালার প্রেক্ষাপটে, আমরা ধরে নেব যে আপনি ডকার ব্যবহার করেন।
আপনি যদি ক্লাউড শেল ব্যবহার করার সিদ্ধান্ত নিয়ে থাকেন, তবে এটি পুনরায় খোলার এটাই সময় (ক্লাউড কনসোলের উপরের ডানদিকে ক্লিক করুন)।

এটি পৃষ্ঠার নীচে একটি সুবিধাজনক শেল খুলবে, যেখানে আপনি সেট-আপ ধাপে কোডটি ফোর্ক করে রেখেছিলেন।

ডকার
আপনি যদি নিয়ন্ত্রণ রাখতে চান, তবে এটিই আপনার জন্য সঠিক সমাধান। নির্দিষ্ট লাইব্রেরি কনফিগার করার প্রয়োজন হলে এবং কিছু অপ্রত্যাশিত আচরণ যুক্ত করার দরকার হলে (যেমন আপলোডে chmod ব্যবহার, আপনার অ্যাপে কোনো নন-স্ট্যান্ডার্ড এক্সিকিউটেবল ফাইল যোগ করা, ইত্যাদি) এটি বিশেষভাবে কার্যকর।
যেহেতু আমরা শেষ পর্যন্ত আমাদের কন্টেইনারাইজড অ্যাপ্লিকেশনটি ক্লাউড রান-এ ডেপ্লয় করতে চাই, তাই নিম্নলিখিত ডকুমেন্টেশনটি দেখুন। আপনি কীভাবে এটিকে পিএইচপি ৮ থেকে পিএইচপি ৫.৭-এ ব্যাক পোর্ট করবেন? সম্ভবত আপনি এর জন্য জেমিনি ব্যবহার করতে পারেন। বিকল্পভাবে, আপনি এই প্রি-বেকেড ভার্সনটি ব্যবহার করতে পারেন:
# Use the official PHP image: https://hub.docker.com/_/php
FROM php:5.6-apache
# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
# Install PHP's extension for MySQL
RUN docker-php-ext-install -j "$(nproc)" opcache mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
RUN set -ex; \
{ \
echo "; Cloud Run enforces memory & timeouts"; \
echo "memory_limit = -1"; \
echo "max_execution_time = 0"; \
echo "; File upload at Cloud Run network limit"; \
echo "upload_max_filesize = 32M"; \
echo "post_max_size = 32M"; \
echo "; Configure Opcache for Containers"; \
echo "opcache.enable = On"; \
echo "opcache.validate_timestamps = Off"; \
echo "; Configure Opcache Memory (Application-specific)"; \
echo "opcache.memory_consumption = 32"; \
} > "$PHP_INI_DIR/conf.d/cloud-run.ini"
# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . .
# Setup the PORT environment variable in Apache configuration files: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080
# Tell Apache to use 8080 instead of 80.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
# Note: This is quite insecure and opens security breaches. See last chapter for hardening ideas.
# Uncomment at your own risk:
#RUN chmod 777 /var/www/html/uploads/
# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Expose the port
EXPOSE 8080
সর্বশেষ Dockerfile সংস্করণটি এখানে পাওয়া যাবে।
আমাদের অ্যাপ্লিকেশনটি স্থানীয়ভাবে পরীক্ষা করার জন্য, config.php ফাইলটি এমনভাবে পরিবর্তন করতে হবে যাতে আমাদের PHP অ্যাপটি Google CloudSQL-এ উপলব্ধ MYSQL ডেটাবেসের সাথে সংযোগ স্থাপন করতে পারে। আপনি পূর্বে যা সেট আপ করেছেন তার উপর ভিত্তি করে, শূন্যস্থানগুলি পূরণ করুন :
<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
-
DB_HOSTহলো ক্লাউড SQL-এর পাবলিক আইপি অ্যাড্রেস, যা আপনি SQL কনসোলে খুঁজে পাবেন:

-
DB_NAMEঅপরিবর্তিত থাকা উচিত:image_catalog -
DB_USERহবেappmod-phpapp-user -
DB_PASSহলো আপনার বেছে নেওয়া একটি বিষয়। এটিকে সিঙ্গেল কোটের মধ্যে সেট করুন এবং প্রয়োজন অনুযায়ী এস্কেপ (escape) ব্যবহার করুন।
এছাড়াও, জেমিনির সাহায্যে কয়েকটি 🇮🇹 ইতালীয় রচনা ইংরেজিতে অনুবাদ করতে পারেন !
ঠিক আছে, এখন যেহেতু আপনার কাছে Dockerfile আছে এবং আপনি আপনার পিএইচপি অ্যাপটিকে ডেটাবেসের সাথে সংযোগ করার জন্য কনফিগারও করে ফেলেছেন, চলুন এটি চেষ্টা করে দেখা যাক!
আপনার কাছে ডকার না থাকলে তা ইনস্টল করুন ( লিঙ্ক )। আপনি যদি ক্লাউড শেল ব্যবহার করেন তবে এটির প্রয়োজন নেই (ভাবুন তো, ব্যাপারটা কী দারুণ!)।
এখন উপযুক্ত ডকার বিল্ড এবং রান কমান্ড ব্যবহার করে আপনার কন্টেইনারাইজড পিএইচপি অ্যাপটি বিল্ড ও রান করার চেষ্টা করুন।
# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .
# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker
সবকিছু ঠিকঠাক কাজ করলে, লোকাল হোস্টে সংযুক্ত হলে আপনি নিম্নলিখিত ওয়েব পেজটি দেখতে পাবেন! এখন আপনার অ্যাপটি ৮০৮০ পোর্টে চলছে, "ওয়েব প্রিভিউ" আইকনে (চোখসহ একটি ব্রাউজার) ক্লিক করুন এবং তারপর ৮০৮০ পোর্টে প্রিভিউ করুন (অথবা অন্য যেকোনো পোর্টের জন্য "চেঞ্জ পোর্ট"-এ ক্লিক করুন )।

আপনার ব্রাউজারে ফলাফল পরীক্ষা করা হচ্ছে
এখন আপনার অ্যাপ্লিকেশনটি দেখতে অনেকটা এইরকম হবে:

আর আপনি যদি Admin/admin123 দিয়ে লগইন করেন, তাহলে এইরকম কিছু দেখতে পাবেন।

দারুণ!!! ইতালীয় লেখাটা ছাড়া বাকি সব ঠিকঠাক কাজ করছে! 🎉🎉🎉
আপনার ডকারাইজেশন ঠিক থাকলেও যদি ডেটাবেসের ক্রেডেনশিয়াল ভুল থাকে, তাহলে আপনি এইরকম কিছু দেখতে পারেন:

আবার চেষ্টা করুন, আপনি কাছাকাছি আছেন!
আর্টিফ্যাক্ট রেজিস্ট্রি-তে সংরক্ষণ [ঐচ্ছিক]
এতক্ষণে আপনার একটি কার্যকরী কন্টেইনারাইজড পিএইচপি অ্যাপ্লিকেশন তৈরি হয়ে যাওয়ার কথা, যা ক্লাউডে ডেপ্লয় করার জন্য প্রস্তুত। এরপর, আমাদের ডকার ইমেজটি সংরক্ষণ করার জন্য ক্লাউডে একটি জায়গা প্রয়োজন, যাতে ক্লাউড রান-এর মতো গুগল ক্লাউড পরিষেবাগুলিতে এটি ডেপ্লয়মেন্টের জন্য সহজলভ্য হয়। এই স্টোরেজ সলিউশনটিকে আর্টিফ্যাক্ট রেজিস্ট্রি বলা হয়, যা একটি সম্পূর্ণ পরিচালিত গুগল ক্লাউড পরিষেবা। এটি অ্যাপ্লিকেশন আর্টিফ্যাক্ট, যেমন—ডকার কন্টেইনার ইমেজ, ম্যাভেন প্যাকেজ, এনপিএম মডিউল এবং আরও অনেক কিছু সংরক্ষণের জন্য ডিজাইন করা হয়েছে।
চলুন, উপযুক্ত বাটনটি ব্যবহার করে গুগল ক্লাউড আর্টিফ্যাক্ট রেজিস্ট্রি-তে একটি রিপোজিটরি তৈরি করি।

নিদর্শনগুলো সংরক্ষণের জন্য একটি বৈধ নাম, ফরম্যাট এবং উপযুক্ত অঞ্চল নির্বাচন করুন।

আপনার স্থানীয় ডেভেলপমেন্ট এনভায়রনমেন্ট ট্যাগে ফিরে যান এবং সদ্য তৈরি করা আর্টিফ্যাক্ট রেজিস্ট্রি রিপোজিটরিতে অ্যাপ কন্টেইনার ইমেজটি পুশ করুন। এটি করার জন্য নিম্নলিখিত কমান্ডগুলি সম্পূর্ণ করুন।
- ডকার ট্যাগ উৎস_ছবি[:TAG] লক্ষ্য_ছবি[:TAG]
- docker push TARGET_IMAGE[:TAG]
ফলাফলটি নিচের স্ক্রিনশটের মতো দেখতে হবে।

হুররে 🎉🎉🎉 আপনি পরবর্তী স্তরে যেতে পারবেন। তার আগে, আপলোড/লগইন/লগআউট চেষ্টা করে এবং অ্যাপের এন্ডপয়েন্টগুলোর সাথে পরিচিত হতে ২ মিনিট সময় ব্যয় করতে পারেন। পরে আপনার এগুলো কাজে লাগবে।
সম্ভাব্য ত্রুটি
যদি আপনি কন্টেইনারাইজেশন ত্রুটি পান, তাহলে ত্রুটিটি ব্যাখ্যা করতে এবং সমাধান করতে Gemini ব্যবহার করে দেখুন, এবং এর জন্য নিম্নলিখিত তথ্যগুলো প্রদান করুন:
- আপনার বর্তমান ডকারফাইল
- প্রাপ্ত ত্রুটি
- [প্রয়োজনে] নির্বাহ করা হচ্ছে এমন PHP কোড।
আপলোড পারমিশন । এছাড়াও /upload.php এন্ডপয়েন্টটি ব্যবহার করে একটি ছবি আপলোড করার চেষ্টা করুন। আপনি নিচের এররটি পেতে পারেন। যদি তাই হয়, তাহলে আপনাকে Dockerfile এ chmod/chown ফিক্স করতে হবে।
সতর্কীকরণ : move_uploaded_file(uploads/image (3).png): স্ট্রিম খুলতে ব্যর্থ: অনুমতি নেই, /var/www/html/upload.php ফাইলের ১১ নম্বর লাইনে।
PDOException "ড্রাইভার খুঁজে পাওয়া যায়নি" (বা "Errore di connessione: could not find driver") । ডেটাবেসের সাথে সংযোগ করার জন্য, নিশ্চিত করুন যে আপনার Dockerfile-এ mysql-এর জন্য সঠিক PDO লাইব্রেরি ( pdo_mysql ) রয়েছে। এখান থেকে সমাধানগুলো থেকে অনুপ্রেরণা নিন।
আপনার অনুরোধটি ব্যাকএন্ডে ফরোয়ার্ড করা সম্ভব হয়নি। পোর্ট ৮০৮০-তে কোনো সার্ভারের সাথে সংযোগ স্থাপন করা যায়নি। এর মানে হলো, আপনি সম্ভবত ভুল পোর্ট ব্যবহার করছেন। নিশ্চিত করুন যে আপনি সেই পোর্টটিই ব্যবহার করছেন যেখান থেকে Apache/Nginx প্রকৃতপক্ষে পরিষেবা দিচ্ছে। এটি একটি সহজ কাজ নয়। সম্ভব হলে, সেই পোর্টটি ৮০৮০ করার চেষ্টা করুন (এতে Cloud Run-এর সাথে কাজ করা সহজ হয়)। আপনি যদি পোর্ট ৮০ রাখতে চান (যেমন, কারণ Apache সেভাবেই চায়), তবে এটি চালানোর জন্য একটি ভিন্ন কমান্ড ব্যবহার করুন:
$ docker run -it -p 8080:80 # force 80
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
৫. মডিউল ৩: ক্লাউড রান-এ অ্যাপটি স্থাপন করুন

ক্লাউড রান কেন?
ন্যায্য প্রশ্ন! কয়েক বছর আগে হলে আপনি নিশ্চয়ই গুগল অ্যাপ ইঞ্জিনই বেছে নিতেন।
সহজ কথায় বলতে গেলে, বর্তমানে ক্লাউড রানের একটি নতুন টেক স্ট্যাক রয়েছে, এটি স্থাপন করা সহজ, সাশ্রয়ী এবং ব্যবহার না করলে স্বয়ংক্রিয়ভাবে শূন্যে নেমে আসে। যেকোনো স্টেটলেস কন্টেইনার চালানোর নমনীয়তা এবং বিভিন্ন গুগল ক্লাউড পরিষেবার সাথে এর ইন্টিগ্রেশনের কারণে, এটি ন্যূনতম ওভারহেড ও সর্বোচ্চ দক্ষতার সাথে মাইক্রোসার্ভিস এবং আধুনিক অ্যাপ্লিকেশন স্থাপনের জন্য আদর্শ।
আরও নির্দিষ্টভাবে বলতে গেলে, ক্লাউড রান হলো গুগল ক্লাউড দ্বারা পরিচালিত একটি সম্পূর্ণ ম্যানেজড প্ল্যাটফর্ম, যা আপনাকে সার্ভারবিহীন পরিবেশে স্টেটলেস কন্টেইনারাইজড অ্যাপ্লিকেশন চালাতে সক্ষম করে। এটি স্বয়ংক্রিয়ভাবে সমস্ত পরিকাঠামো পরিচালনা করে, আগত ট্র্যাফিক মেটাতে শূন্য থেকে স্কেল করে এবং নিষ্ক্রিয় থাকলে ডাউন হয়ে যায়, যা এটিকে সাশ্রয়ী এবং কার্যকর করে তোলে। ক্লাউড রান যেকোনো ভাষা বা লাইব্রেরিকে সমর্থন করে, যতক্ষণ পর্যন্ত তা একটি কন্টেইনারে প্যাকেজ করা থাকে, যা ডেভেলপমেন্টে দারুণ নমনীয়তা প্রদান করে। এটি অন্যান্য গুগল ক্লাউড পরিষেবাগুলির সাথে ভালোভাবে ইন্টিগ্রেট করে এবং সার্ভার পরিকাঠামো পরিচালনার প্রয়োজন ছাড়াই মাইক্রোসার্ভিস, এপিআই, ওয়েবসাইট এবং ইভেন্ট-ড্রাইভেন অ্যাপ্লিকেশন তৈরির জন্য উপযুক্ত।
পূর্বশর্ত
এই কাজটি সম্পন্ন করার জন্য আপনার লোকাল মেশিনে gcloud ইনস্টল করা থাকা উচিত। যদি না থাকে, তবে এখানকার নির্দেশাবলী দেখুন। এর পরিবর্তে, আপনি যদি গুগল ক্লাউড শেল ব্যবহার করেন, তবে কোনো পদক্ষেপ নেওয়ার প্রয়োজন নেই।
মোতায়েন করার আগে...
আপনি যদি আপনার স্থানীয় পরিবেশে কাজ করেন, তাহলে নিম্নলিখিত উপায়ে গুগল ক্লাউডে প্রমাণীকরণ করুন।
-
$ gcloud auth login –update-adc # not needed in Cloud Shell
এটি আপনার ব্রাউজারে একটি OAuth লগইনের মাধ্যমে আপনাকে প্রমাণীকরণ করবে। নিশ্চিত করুন যে আপনি Chrome-এর মাধ্যমে সেই একই ব্যবহারকারী (যেমন vattelapesca@gmail.com) দিয়ে লগইন করছেন, যিনি বিলিং চালু রেখে Google Cloud-এ লগইন করেছেন।
নিম্নলিখিত কমান্ডের মাধ্যমে ক্লাউড রান এপিআই (Cloud Run API) সক্রিয় করুন:
-
$ gcloud services enable run.googleapis.com cloudbuild.googleapis.com
এই পর্যায়ে ক্লাউড রান-এ ডেপ্লয় করার জন্য সবকিছু প্রস্তুত।
gcloud-এর মাধ্যমে আপনার অ্যাপটি ক্লাউড রান-এ স্থাপন করুন।
ক্লাউড রানে অ্যাপটি ডেপ্লয় করার কমান্ডটি হলো gcloud run deploy । আপনার লক্ষ্য অর্জনের জন্য বেশ কিছু অপশন সেট করতে হয়। ন্যূনতম অপশনগুলো হলো নিম্নরূপ (যা আপনি কমান্ড লাইনের মাধ্যমে দিতে পারেন, অথবা টুলটি ইন্টারেক্টিভ প্রম্পটের মাধ্যমে আপনাকে জিজ্ঞাসা করবে):
- আপনার অ্যাপের জন্য যে ক্লাউড রান সার্ভিসটি আপনি ডেপ্লয় করতে চান, তার নাম । একটি ক্লাউড রান সার্ভিস আপনাকে একটি ইউআরএল ফেরত দেবে, যা আপনার অ্যাপের জন্য একটি এন্ডপয়েন্ট প্রদান করে।
- গুগল ক্লাউড রিজিয়ন যেখানে আপনার অ্যাপটি চলবে (
--regionREGION) - কন্টেইনার ইমেজ যা আপনার অ্যাপকে আবৃত করে রাখে।
- এনভায়রনমেন্ট ভেরিয়েবল , যেগুলো আপনার অ্যাপ চলার সময় ব্যবহার করতে হয়।
- Allow-Unauthenticated ফ্ল্যাগটি প্রত্যেককে কোনো অতিরিক্ত প্রমাণীকরণ ছাড়াই আপনার অ্যাপ অ্যাক্সেস করার অনুমতি দেয়।
আপনার কমান্ড লাইনে এই অপশনটি কীভাবে প্রয়োগ করবেন তা দেখতে ডকুমেন্টেশন দেখুন (অথবা সম্ভাব্য সমাধানের জন্য নিচে স্ক্রোল করুন)।
স্থাপন হতে কয়েক মিনিট সময় লাগবে। সবকিছু ঠিক থাকলে আপনি গুগল ক্লাউড কনসোলে এইরকম কিছু দেখতে পাবেন।


ক্লাউড রান থেকে দেওয়া URL-টিতে ক্লিক করুন এবং আপনার অ্যাপ্লিকেশনটি পরীক্ষা করুন। প্রমাণীকরণ সম্পন্ন হলে আপনি এইরকম কিছু দেখতে পাবেন।

কোনো আর্গুমেন্ট ছাড়া 'gcloud run deploy'
আপনি হয়তো লক্ষ্য করেছেন যে, gcloud run deploy আপনাকে সঠিক প্রশ্নগুলো জিজ্ঞাসা করে এবং আপনার রেখে যাওয়া ফাঁকা জায়গাগুলো পূরণ করে দেয়। এটা অসাধারণ!
তবে, কয়েকটি মডিউলে আমরা এই কমান্ডটি একটি ক্লাউড বিল্ড ট্রিগারে যুক্ত করতে যাচ্ছি, তাই আমরা ইন্টারেক্টিভ প্রশ্ন ব্যবহার করতে পারব না। আমাদের কমান্ডের প্রতিটি অপশন পূরণ করতে হবে। সুতরাং, আপনাকে gcloud run deploy --option1 blah --foo bar --region your-fav-region এই আদর্শ কমান্ডটি তৈরি করতে হবে। আপনি এটি কীভাবে করবেন?
- gcloud প্রশ্ন করা বন্ধ না করা পর্যন্ত ২, ৩ ও ৪ নম্বর ধাপগুলো পুনরাবৃত্তি করুন:
- [লুপ] এখন পর্যন্ত পাওয়া অপশনগুলো সহ
gcloud run deploy - [LOOP] সিস্টেমগুলো অপশন X চায়।
- [লুপ] পাবলিক ডক্স-এ সার্চ করুন কিভাবে CLI থেকে
--my-option [my-value]অপশনটি যোগ করে X সেট আপ করতে হয়। - এখন ধাপ ২-এ ফিরে যান, যদি না gcloud আর কোনো প্রশ্ন ছাড়াই সম্পন্ন হয়।
- এই gcloud run deploy ব্লাহ ব্লাহ ব্লাহ অসাধারণ! কমান্ডটি কোথাও সেভ করে রাখুন, পরে ক্লাউড বিল্ড ধাপে আপনার এটি লাগবে!
একটি সম্ভাব্য সমাধান এখানে রয়েছে। ডকুমেন্টেশন এখানে আছে।
হুররে 🎉🎉🎉 আপনি সফলভাবে গুগল ক্লাউডে আপনার অ্যাপটি স্থাপন করেছেন এবং আধুনিকীকরণের প্রথম ধাপটি সম্পন্ন করেছেন।
৬. মডিউল ৪: সিক্রেট ম্যানেজারের সাহায্যে পাসওয়ার্ড পরিষ্করণ

পূর্ববর্তী ধাপে আমরা ক্লাউড রান-এ আমাদের অ্যাপটি সফলভাবে ডেপ্লয় এবং রান করতে পেরেছিলাম। তবে, আমরা একটি নিরাপত্তাজনিত ত্রুটি অনুসরণ করে কাজটি করেছিলাম: কিছু গোপনীয় তথ্য সুস্পষ্টভাবে (ক্লিয়ারটেক্সট) সরবরাহ করা ।
প্রথম ধাপ: ENV ব্যবহার করার জন্য আপনার config.php ফাইলটি আপডেট করুন।
আপনি হয়তো লক্ষ্য করেছেন যে আমরা config.php ফাইলের কোডে সরাসরি DB পাসওয়ার্ডটি রেখেছি। পরীক্ষার জন্য এবং অ্যাপটি কাজ করছে কিনা তা দেখার জন্য এটি ঠিক আছে। কিন্তু প্রোডাকশন এনভায়রনমেন্টে আপনি এই ধরনের কোড কমিট বা ব্যবহার করতে পারবেন না। পাসওয়ার্ড (এবং অন্যান্য DB কানেকশন প্যারামিটার) ডাইনামিকভাবে রিড করা উচিত এবং রানটাইমে অ্যাপে সরবরাহ করা উচিত। config.php ফাইলটি পরিবর্তন করুন যাতে এটি ENV ভেরিয়েবল থেকে db প্যারামিটারগুলো রিড করে। যদি এটি ব্যর্থ হয়, তবে আপনার ডিফল্ট ভ্যালু সেট করার কথা বিবেচনা করা উচিত। এটি এই কারণে ভালো যে, যদি আপনি ENV লোড করতে ব্যর্থ হন, তাহলে পেজের আউটপুট আপনাকে বলে দেবে যে এটি ডিফল্ট ভ্যালু ব্যবহার করছে কিনা। খালি জায়গাগুলো পূরণ করুন এবং config.php ফাইলের কোডটি প্রতিস্থাপন করুন।
<?php
// Database configuration with ENV variables. Set default values as well
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// Note getenv() is PHP 5.3 compatible
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
যেহেতু আপনার অ্যাপটি কন্টেইনারাইজড, তাই অ্যাপটিতে ENV ভেরিয়েবল সরবরাহ করার একটি উপায় রাখতে হবে। এটি কয়েকটি উপায়ে করা যেতে পারে:
- বিল্ড করার সময়, আপনার পূর্ববর্তী Dockerfile-এ ENV DB_VAR=ENV_VAR_VALUE সিনট্যাক্স ব্যবহার করে ৪টি প্যারামিটার যোগ করুন। এটি ডিফল্ট মান সেট করবে যা রানটাইমে ওভাররাইড করা যাবে। উদাহরণস্বরূপ, 'DB_NAME' এবং 'DB_USER' শুধুমাত্র এখানেই সেট করা যেতে পারে।
- রান টাইমে। আপনি ক্লাউড রানের জন্য এই ভেরিয়েবলগুলো CLI অথবা UI, উভয় থেকেই সেট করতে পারেন । আপনার ৪টি ভেরিয়েবল রাখার জন্য এটিই সঠিক জায়গা (যদি না আপনি ডকারফাইলে সেট করা ডিফল্টগুলো রাখতে চান)।
লোকালহোস্টে, আপনি আপনার ENV ভেরিয়েবলগুলো একটি .env ফাইলে রাখতে পারেন ( সলিউশনস ফোল্ডারটি দেখুন)।
এছাড়াও নিশ্চিত করুন যে আপনার .gitignore এ .env যুক্ত করা আছে: আপনি নিশ্চয়ই আপনার গোপনীয় তথ্য গিটহাবে পুশ করতে চাইবেন না!
echo .env >> .gitignore
এরপরে, আপনি ইনস্ট্যান্সটি স্থানীয়ভাবে পরীক্ষা করতে পারেন:
docker run -it -p 8080:8080 --env-file .env my-php-app-docker
এখন আপনি নিম্নলিখিত বিষয়গুলো অর্জন করেছেন:
- আপনার অ্যাপ আপনার ENV থেকে ভেরিয়েবলগুলো ডায়নামিকভাবে পড়বে।
- আপনি আপনার কোড থেকে ডিবি পাসওয়ার্ডটি সরিয়ে দেওয়ায় নিরাপত্তা উন্নত করেছেন।
আপনি এখন ক্লাউড রান-এ একটি নতুন সংস্করণ ডেপ্লয় করতে পারেন। চলুন UI-তে গিয়ে এনভায়রনমেন্ট ভেরিয়েবলগুলো ম্যানুয়ালি সেট করে নিই:
- https://console.cloud.google.com/run- এ যান
- আপনার অ্যাপে ক্লিক করুন
- 'নতুন সংস্করণ সম্পাদনা ও স্থাপন করুন'-এ ক্লিক করুন
- প্রথম ট্যাব "Container(s)"-এ, নিচের ট্যাব "Variables and secrets"-এ ক্লিক করুন।
- "+ ভেরিয়েবল যোগ করুন"-এ ক্লিক করুন এবং প্রয়োজনীয় সমস্ত ভেরিয়েবল যোগ করুন। এর ফলে ফলাফলটি দেখতে এইরকম হবে:


এটা কি নিখুঁত? না। আপনার পাসটি এখনও বেশিরভাগ অপারেটরের কাছে দৃশ্যমান। গুগল ক্লাউড সিক্রেট ম্যানেজারের মাধ্যমে এর সমাধান করা যেতে পারে।
দ্বিতীয় পুনরাবৃত্তি: গোপন ব্যবস্থাপক
আপনার পাসওয়ার্ডগুলো আপনার নিজের কোড থেকেই উধাও হয়ে গেছে: জয়! কিন্তু দাঁড়ান - আমরা কি এখনও নিরাপদ?
আপনার পাসওয়ার্ডগুলো এখনও গুগল ক্লাউড কনসোলে অ্যাক্সেস আছে এমন যে কেউ দেখতে পারে। প্রকৃতপক্ষে, আপনি যদি ক্লাউড রান YAML ডেপ্লয়মেন্ট ফাইলটি অ্যাক্সেস করেন, তবে আপনি এটি পুনরুদ্ধার করতে পারবেন। অথবা, আপনি যদি ক্লাউড রানের কোনো নতুন সংস্করণ সম্পাদনা বা ডেপ্লয় করার চেষ্টা করেন, তাহলে নিচের স্ক্রিনশটগুলোতে দেখানো অনুযায়ী পাসওয়ার্ডটি ভ্যারিয়েবলস অ্যান্ড সিক্রেটস (Variables & Secrets) বিভাগে দেখা যাবে।
গুগল ক্লাউড সিক্রেট ম্যানেজার হলো এপিআই কী, পাসওয়ার্ড, সার্টিফিকেট এবং অন্যান্য গোপনীয় তথ্যের মতো সংবেদনশীল তথ্য ব্যবস্থাপনার জন্য একটি নিরাপদ ও কেন্দ্রীভূত পরিষেবা।
এটি আপনাকে সূক্ষ্ম অনুমতি এবং শক্তিশালী এনক্রিপশনের মাধ্যমে গোপনীয় তথ্য সংরক্ষণ, পরিচালনা এবং অ্যাক্সেস করতে সক্ষম করে। গুগল ক্লাউডের আইডেন্টিটি অ্যান্ড অ্যাক্সেস ম্যানেজমেন্ট (IAM)-এর সাথে সমন্বিত, সিক্রেট ম্যানেজার আপনাকে নিয়ন্ত্রণ করতে দেয় যে কে নির্দিষ্ট গোপনীয় তথ্য অ্যাক্সেস করতে পারবে, যা ডেটা নিরাপত্তা এবং নিয়ন্ত্রক সম্মতি নিশ্চিত করে।
এটি স্বয়ংক্রিয় সিক্রেট রোটেশন এবং ভার্সনিংও সমর্থন করে, যা সিক্রেট লাইফসাইকেল ম্যানেজমেন্টকে সহজ করে এবং গুগল ক্লাউড পরিষেবা জুড়ে অ্যাপ্লিকেশনগুলির নিরাপত্তা বাড়ায়।
সিক্রেট ম্যানেজার অ্যাক্সেস করতে, হ্যামবার্গার মেনু থেকে সিকিউরিটি সার্ভিসেস-এ যান এবং নিচের স্ক্রিনশটে দেখানো অনুযায়ী ডেটা প্রোটেকশন সেকশনের অধীনে এটি খুঁজুন।

সেখানে পৌঁছানোর পর নিচের ছবি অনুযায়ী সিক্রেট ম্যানেজার এপিআই (Secret Manager API) সক্রিয় করুন।

- এখন " Create a secret "-এ ক্লিক করুন: চলুন এর একটি যৌক্তিক নাম দেওয়া যাক:
- নাম:
php-amarcord-db-pass - গোপন মান: ' আপনার ডিবি পাসওয়ার্ড ' ("আপলোড ফাইল" অংশটি উপেক্ষা করুন)।
- এই গোপন লিঙ্কটি টীকাযুক্ত করুন, এটি দেখতে
projects/123456789012/secrets/php-amarcord-db-passএর মতো হওয়া উচিত। এটি আপনার গোপনীয়তার অনন্য নির্দেশক (টেরাফর্ম, ক্লাউড রান এবং অন্যান্যদের জন্য)। সংখ্যাটি হলো আপনার অনন্য প্রজেক্ট নম্বর।
পরামর্শ : আপনার সিক্রেটগুলোর জন্য একটি সামঞ্জস্যপূর্ণ নামকরণ পদ্ধতি ব্যবহার করার চেষ্টা করুন, বাম থেকে ডানে বিশেষায়িত করে, যেমন: cloud-devrel-phpamarcord-dbpass
- সংস্থা (কোম্পানির সাথে)
- দল (সংস্থার অভ্যন্তরে)
- (দলের মধ্যে) আবেদন
- ভেরিয়েবলের নাম (অ্যাপের মধ্যে)
এর মাধ্যমে আপনি একটিমাত্র অ্যাপের সমস্ত গোপনীয় তথ্য সহজে খুঁজে বের করার জন্য রেজেক্স (regex) ব্যবহার করতে পারবেন।
একটি নতুন ক্লাউড রান রিভিশন তৈরি করুন
এখন যেহেতু আমাদের একটি নতুন সিক্রেট আছে, তাই আমাদের DB_PASS ENV ভেরিয়েবলটি সরিয়ে দিয়ে তার জায়গায় নতুন সিক্রেটটি বসাতে হবে। সুতরাং:
- গুগল ক্লাউড কনসোল ব্যবহার করে ক্লাউড রান -এ অ্যাক্সেস
- অ্যাপটি বেছে নিন।
- "নতুন সংস্করণ সম্পাদনা ও স্থাপন করুন"-এ ক্লিক করুন
- "Variables & Secrets" ট্যাবটি খুঁজুন।
- DB_PASS ENV ভেরিয়েবলটি রিসেট করতে "+ Reference a Secret" বাটনটি ব্যবহার করুন।
- উল্লেখিত সিক্রেটগুলোর জন্য একই 'DB_PASS' ব্যবহার করুন এবং সর্বশেষ সংস্করণটি ব্যবহার করুন।

একবার সম্পন্ন হলে, আপনি নিম্নলিখিত ত্রুটিটি পাবেন।

এটি কীভাবে ঠিক করা যায় তা খুঁজে বের করার চেষ্টা করুন। এটি সমাধান করার জন্য আপনাকে IAM ও অ্যাডমিন বিভাগে প্রবেশ করে অনুমতি প্রদানের বিষয়টি পরিবর্তন করতে হবে। ডিবাগিং আনন্দদায়ক হোক!
একবার বিষয়টি বুঝে গেলে, ক্লাউড রান-এ ফিরে যান এবং একটি নতুন সংস্করণ পুনরায় স্থাপন করুন। ফলাফলটি নিচের চিত্রের মতো দেখতে হবে:

পরামর্শ : ডেভেলপার কনসোল (UI) অনুমতি সংক্রান্ত সমস্যাগুলো চিহ্নিত করতে দারুণ কার্যকর। আপনার ক্লাউড এনটিটিগুলোর সমস্ত লিঙ্ক ভালোভাবে দেখে নিতে সময় নিন!
৭. মডিউল ৫: ক্লাউড বিল্ড দিয়ে আপনার CI/CD সেটআপ করুন

CI/CD পাইপলাইন কেন প্রয়োজন?
এতক্ষণে আপনি হয়তো কয়েকবার gcloud run deploy টাইপ করে ফেলেছেন এবং একই প্রশ্নের উত্তর বারবার দিয়েছেন।
gcloud run deploy ব্যবহার করে ম্যানুয়ালি আপনার অ্যাপ ডেপ্লয় করতে করতে ক্লান্ত? কেমন হতো যদি আপনার গিট রিপোজিটরিতে প্রতিবার কোনো নতুন পরিবর্তন পুশ করার সাথে সাথে আপনার অ্যাপটি স্বয়ংক্রিয়ভাবে ডেপ্লয় হয়ে যেত?
একটি CI/CD পাইপলাইন ব্যবহার করতে আপনার দুটি জিনিস লাগবে:
- একটি ব্যক্তিগত গিট রিপোজিটরি : সৌভাগ্যবশত, আপনি ধাপ ২-এ ওয়ার্কশপ রিপোজিটরিটি আপনার গিটহাব অ্যাকাউন্টে ইতিমধ্যে ফোর্ক করে ফেলেছেন। যদি না করে থাকেন, তাহলে ফিরে যান এবং সেই ধাপটি সম্পূর্ণ করুন। আপনার ফোর্ক করা রিপোজিটরিটি দেখতে এইরকম হবে:
https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop - ক্লাউড বিল্ড । এই চমৎকার এবং সাশ্রয়ী পরিষেবাটি আপনাকে প্রায় সবকিছুর জন্যই বিল্ড অটোমেশন কনফিগার করার সুযোগ দেয়: টেরাফর্ম, ডকারাইজড অ্যাপস, ইত্যাদি।
এই অংশে ক্লাউড বিল্ড সেট আপ করার উপর আলোকপাত করা হবে।
ক্লাউড বিল্ডে প্রবেশ করুন!
আমরা এটি করার জন্য ক্লাউড বিল্ড ব্যবহার করব:
- আপনার সোর্স বিল্ড করুন (Dockerfile ব্যবহার করে)। এটিকে একটি 'বড় .zip ফাইল' হিসেবে ভাবুন, যার মধ্যে এটি বিল্ড ও রান করার জন্য প্রয়োজনীয় সবকিছু রয়েছে (আপনার 'বিল্ড আর্টিফ্যাক্ট')।
- এই আর্টিফ্যাক্টটি আর্টিফ্যাক্ট রেজিস্ট্রি (AR)-তে পুশ করুন।
- তারপর AR থেকে Cloud Run-এ 'php-amarcord' অ্যাপটির জন্য একটি ডেপ্লয়মেন্ট জারি করুন।
- এটি বিদ্যমান অ্যাপটির একটি নতুন সংস্করণ ("রিভিশন") তৈরি করবে (নতুন কোডসহ একটি লেয়ার হিসেবে ভাবুন) এবং পুশ সফল হলে ট্র্যাফিককে নতুন সংস্করণে পাঠিয়ে দেওয়ার জন্য আমরা এটিকে কনফিগার করব।
এটি আমার php-amarcord অ্যাপের কয়েকটি বিল্ডের উদাহরণ:

আমরা এই সবকিছু কীভাবে করি?
- একটি নিখুঁত YAML ফাইল তৈরি করে:
cloudbuild.yaml - একটি ক্লাউড বিল্ড ট্রিগার তৈরি করার মাধ্যমে।
- ক্লাউড বিল্ড UI- এর মাধ্যমে আমাদের গিটহাব রিপোতে সংযোগ করে।
ট্রিগার তৈরি করুন (এবং রিপোজিটরি সংযুক্ত করুন)
- https://console.cloud.google.com/cloud-build/triggers- এ যান
- "ক্রিয়েট ট্রিগার"-এ ক্লিক করুন।
- সংকলন করুন:
- নাম: অর্থপূর্ণ কিছু, যেমন
on-git-commit-build-php-app - ইভেন্ট: ব্রাঞ্চে পুশ করুন
- উৎস: "নতুন রিপোজিটরি সংযুক্ত করুন"

- এটি ডানদিকে একটি উইন্ডো খুলবে: "রিপোজিটরি সংযোগ করুন"
- উৎস প্রদানকারী: 'গিটহাব' (প্রথম)
- "চালিয়ে যান"
- অথেন্টিকেট করলে ক্রস-অথেনটিকেশনের জন্য গিটহাবে একটি উইন্ডো খুলবে। নির্দেশাবলী অনুসরণ করুন এবং ধৈর্য ধরুন। আপনার অনেকগুলো রিপো থাকলে এতে কিছুটা সময় লাগতে পারে।
- "রিপো নির্বাচন করুন" আপনার অ্যাকাউন্ট/রিপো নির্বাচন করুন এবং "আমি বুঝতে পেরেছি..." অংশে টিক দিন।
- যদি আপনি "আপনার কোনো রিপোজিটরিতে GitHub অ্যাপ ইনস্টল করা নেই" এই ত্রুটিটি পান, তাহলে "Install Google Cloud Build"-এ ক্লিক করুন এবং নির্দেশাবলী অনুসরণ করুন।
ক্লিক সংযোগ 
- বাহ! আপনার রিপো এখন সংযুক্ত হয়েছে।
- আবার ট্রিগার অংশে ফেরা যাক...
- কনফিগারেশন: স্বয়ংক্রিয়ভাবে শনাক্তকৃত (*)
- উন্নত: পরিষেবা অ্যাকাউন্ট "[PROJECT_NUMBER]- compute@developer.gserviceaccount.com " নির্বাচন করুন।
- xxxxx হলো আপনার প্রজেক্ট আইডি
- ডিফল্ট কম্পিউট সার্ভিস অ্যাকাউন্টটি ল্যাব পর্যায়ে ব্যবহারের জন্য ঠিক আছে - এটি প্রোডাকশনে ব্যবহার করবেন না! ( আরও জানুন )।
- বাকি সবকিছু যেমন আছে তেমনই রেখে দিন।
- 'Create' বাটনে ক্লিক করুন।
(*) এটিই সবচেয়ে সহজ উপায়, কারণ এটি Dockerfile বা cloudbuild.yaml পরীক্ষা করে। তবে, কোন ধাপে কী করতে হবে, সেই সিদ্ধান্ত নেওয়ার আসল ক্ষমতা cloudbuild.yaml ই আপনাকে দেয়।
আমার ক্ষমতা আছে!
এখন, আপনি ক্লাউড বিল্ড সার্ভিস অ্যাকাউন্টটি না দিলে ট্রিগারটি কাজ করবে না (সার্ভিস অ্যাকাউন্ট কী? এটি হলো একটি "রোবট"-এর ইমেল, যে আপনার হয়ে কোনো কাজ করে – এক্ষেত্রে ক্লাউডে বিভিন্ন জিনিস তৈরি করার কাজ করে!)।
আপনি আপনার SA-কে ক্ষমতা না দিলে সে বিল্ড এবং ডিপ্লয় করতে ব্যর্থ হবে। সৌভাগ্যবশত, এটা বেশ সহজ!
- 'ক্লাউড বিল্ড' > ' সেটিংস' -এ যান।
- "[প্রকল্প_নম্বর]- compute@developer.gserviceaccount.com " পরিষেবা অ্যাকাউন্ট
- এই বাক্সগুলিতে টিক দিন:
- ক্লাউড রান
- গোপন ব্যবস্থাপক
- পরিষেবা অ্যাকাউন্ট
- ক্লাউড বিল্ড
- এছাড়াও "পছন্দের পরিষেবা অ্যাকাউন্ট হিসাবে সেট করুন" বিকল্পটিতে টিক দিন।

ক্লাউড বিল্ড YAML ফাইলটি কোথায়?
আমরা আপনাকে কিছু সময় ব্যয় করে আপনার নিজস্ব ক্লাউড বিল্ড YAML তৈরি করতে দৃঢ়ভাবে উৎসাহিত করছি।
তবে, যদি আপনার সময় না থাকে, বা আপনি সময় বের করতে না চান, তাহলে আপনি এই সলিউশন ফোল্ডারটি থেকে কিছু অনুপ্রেরণা পেতে পারেন: .solutions
এখন আপনি গিটহাবে একটি পরিবর্তন পুশ করতে পারেন এবং ক্লাউড বিল্ডকে তার কাজটি করতে দেখতে পারেন।
ক্লাউড বিল্ড সেট আপ করা বেশ জটিল হতে পারে। এক্ষেত্রে নিম্নলিখিত পক্ষগুলোর মধ্যে কিছু আলোচনা ও মতবিনিময় আশা করা যায়:
- Checking logs in https://console.cloud.google.com/cloud-build/builds;region=global
- Finding your error.
- Fixing in the code, and re-issuing git commit / git push.
- Sometimes the error is not in code, but in some configuration. In that case, you can issue a new build from UI (cloud build > "Triggers" > Run)

Note that if you use this solution, there is still some work to do. For instance, you need to set the ENV variables for the newly created dev/prod endpoints:

আপনি এটা দুইভাবে করতে পারেন:
- Via UI - by setting ENV variables again
- Via CLI by crafting the "perfect" script for you. An example can be found here: gcloud-run-deploy.sh . You need to tweak a few things, for instance the endpoint and project number; You can find your project number in the Cloud Overview .
How do i commit code to github?
It's beyond the scope of this workshop to teach you the best way to git push to github. However, in case your are stuck and you're in Cloud Shell, there are two ways:
- CLI . Add an ssh key locally and add a remote with git@github.com :YOUR_USER/app-mod-workshop.git (instead of http)
- VSCode . If you use the Cloud Shell editor, ou can use the Source control (ctrl-shift-G) tab, click on "sync changes" and follow instructions. You should be able to authenticate your github account to vscode and the pull/push from there become a breeze.

Remember to git add clodubuild.yaml among other files, or it won't work.
Deep vs Shallow "dev/prod parity" [optional]
If you copied the model version from here , you're going to have two identical DEV and PROD versions. This is cool, and in line with the rule 10 of The Twelve-Factor App .
However, we are using two different Web endpoints to have an app pointing to the same Database. This is good enough for a workshop; however, in real life, you want to spend some time to create a proper prod environment. This means having two databases (one for dev and one for prod) and also choosing where to have them for disaster recovery / high availability. This goes beyond the scope of this workshop, but it's some food for thought.
If you have time to do a "deep" version of production, please keep in mind all the resources you need to duplicate, like:
- Cloud SQL Database (and probably SQL instance).
- GCS bucket
- Cloud Function.
- You might use Gemini 1.5 Flash as a model in dev (cheaper, faster), and Gemini 1.5 Pro (more powerful).
In general, every time you do something about the app, think critically: should production has this same value or not? And if not, duplicate your effort. This of course is a lot easier with Terraform, where you can inject your environment (-dev, -prod) as a suffix to your resources.
8. Module 6: Move to Google Cloud Storage

স্টোরেজ

Currently the app stored the state in a docker container. If the machine breaks, the app explodes, or simply if you push a new revision , a new revision will be scheduled, with a new, empty storage: 🙈
How do we fix it? there are a number of approaches.
- Store images in the DB. That's what i've ended up doing with my previous PHP app. It's the simplest solution as it doesn't add complexity to it. But it adds latency and load to your DB for sure!
- Migrate your Cloud Run app to a storage-friendly solution: GCE + Persistent disk ? Maybe GKE + Storage ? Note: what you gain in control, you lose in agility.
- Move to GCS . Google Cloud Storage offers best in class Storage for the whole of Google Cloud and it's the most Cloud idiomatic solution. However, it requires us with getting dirty with PHP libraries . Do we have PHP 5.7 libraries for GCS ? Does
PHP 5.7even supportComposer(seems like PHP 5.3.2 is the earliest version supported by Composer)? - Maybe use a docker sidecar ?
- Or maybe use GCS Cloud Run Volume Mounts . This sounds amazing.
🤔 Migrate storage (open ended)
[Open Ended] In this exercise, we want you to find a solution to move your images in a way which is persisted in some way.
Acceptance test
I don't want to tell you the solution, but I want this to happen:
- You upload
newpic.jpg. You see it in the app. - You upgrade the app to a new version.
-
newpic.jpgis still there, visible.
💡 Possible solution (GCS Cloud Run Volume Mounts)
This is a very elegant solution which allows us to achieve stateful file uploads while not touching the code AT ALL (apart from showing an image description, but that's trivial and just for eye satisfaction).
This should allow you to mount a folder from Cloud Run to GCS, so:
- All uploads to GCS will actually be visible in your app.
- All uploads to your app will actually be uploaded to GCS
- Magic will happen tyo objects uploaded in GCS (chapter 7).
Note . Please read the FUSE fine print. This is NOT ok if performance is an issue.
Create a GCS bucket
GCS is the omni-present storage service of Google Cloud. It's battle-tested, and is used by every GCP service needing storage.
Note that Cloud Shell export PROJECT_ID as GOOGLE_CLOUD_PROJECT:
$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT
#!/bin/bash
set -euo pipefail
# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"
# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"
# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"
Configure Cloud Run to mount the bucket in the /uploads/ folder
Now let's come to the elegant part. We create a volume php_uploads and instruct Cloud Run to do a FUSE mount on MOUNT_PATH (something like /var/www/html/uploads/ ):
#!/bin/bash
set -euo pipefail
# .. keep variables from previous script..
# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'
# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
--region $GCP_REGION \
--execution-environment gen2 \
--add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET" \
--add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"
Now, repeat this step for all the endpoints you want to point to Cloud Storage.
You can also achieve the same from UI
- Under "Volumes" tab, create a Volume Mounts pointing to your bucket, of type "Cloud Storage bucket", for example with name "php_uploads".
- Under Container(s) > Volume Mounts mount the volume you just created on the volume point requested by your app. It depends on the dockerfile, but it might look like
var/www/html/uploads/.
Either way, if it works, editing the new Cloud Run revision should show you something like this:

Now test the new application uploading one new image to the /upload.php endpoint.
The images should flow seamlessly on GCS without writing a single line of PHP:

কি হয়েছে?
Something very magical has happened.
An old application with old code is still doing its job. A new, modernized stack allows us to have all the images/pictures in our app comfortably sitting in a stateful Cloud Bucket. Now the sky is the limit:
- Want to send an email every time an image with "dangerous" or "nude" comes in? You can do that without touching the PHP code.
- Want to use a Gemini Multimodal model every time an image comes in to describe it, and upload the DB with its description? You can do that without touching the PHP code. You don't believe me? Keep reading on in chapter 7.
We've just unlocked a big space of opportunity here.
9. Module 7: Empower your App with Google Gemini

Now you have an awesome modernized, shiny new PHP app (like a 2024 Fiat 126 ) with Cloudified storage.
What can you do with it?
পূর্বশর্ত
In the previous chapter, a model solution allowed us to mount images /uploads/ on GCS, de facto separating the App logic from the image storage.
This exercise requires you to:
- Have successfully completed exercise in chapter 6 (storage).
- Have a GCS bucket with the image uploads, where people upload pictures on your app and pictures flow to your bucket.
Set up a Cloud function (in python)
Have you ever wondered how to implement an event-driven application ? Something like:
- when <event> happens => send an email
- when <event> happens => if <condition> is true, then update the Database.
Event can be anything, from new record available in BigQuery, a new object changed in a folder in GCS, or a new message is waiting in a queue in Pub/Sub.
Google Cloud supports multiple paradigms to achieve this. Most notably:
- EventArc . See how to receive GCS events . Great to create DAGs and orchestrate actions based on if-then-else in the CLoud.
- Cloud Scheduler . Great for a midnight cron job in the Cloud, for instance.
- Cloud Workflows . Similarly to Event Arc, allows you to
- Cloud Run Functions (familiarly known as
lambdas). - Cloud Composer . Basically Google version of Apache Airflow , also great for DAG s.
In this exercise, we'll delve into Cloud Function to achieve a quite spectacular result. And we will provide optional exercises for you.
Note that sample code is provided under .solutions/
Set up a Cloud function (🐍 python)
We are trying to create a very ambitious GCF.
- When a new image is created on GCS.. (probably as someone has uploaded it on the app - but not only)
- .. call Gemini to describe it and get a textual description of the image .. (would be nice to check the MIME and ensure its an image and not a PDF, MP3, or Text)
- .. and update the DB with this description. (this might require patching the DB to add a
descriptioncolumn to theimagestable).
Patch the DB to add description to images
- Open Cloud SQL Studio:

- Put your user and password for the Images DB
- Inject this SQL which adds a column for an image description:
ALTER TABLE images ADD COLUMN description TEXT;

And bingo! Try now to check if it worked:
SELECT * FROM images;
You should see the new description column:

Write the Gemini f(x)
Note . This function was actually created with Gemini Code assist help.
Note . Creating this function you might incur into IAM permission errors. Some are documented below under "Possible errors" paragraph.
- Enable the APIs
- Go to https://console.cloud.google.com/functions/list
- Click "Create Function"
- Enable APIs from API wizard:

You can either create the GCF from UI or from command line. Here we will use the command line.
A possible code can be found under .solutions/
- Create a folder to host your code, eg "gcf/". Enter the folder.
- Create a
requirements.txtfile:
google-cloud-storage
google-cloud-aiplatform
pymysql
- Create a python function. Sample code here: gcf/main.py .
#!/usr/bin/env python
"""Complete this"""
from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors
# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "
def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
pass
def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
pass
def generate_caption(event, context):
"""
Cloud Function triggered by a GCS event.
Args:
event (dict): The dictionary with data specific to this type of event.
context (google.cloud.functions.Context): The context parameter contains
event metadata such as event ID
and timestamp.
"""
pass
- Push the function. You can use a script similar to this: gcf/push-to-gcf.sh .
Note 1 . Make sure to source the ENVs with the right values, or just add them on top ( GS_BUCKET=blah , ..):
Note 2 . This will push all the local code ( . ) so make sure to surround your code in a specific folder and to use .gcloudignore like a pro to avoid pushing huge libraries. ( example ).
#!/bin/bash
set -euo pipefail
# add your logic here, for instance:
source .env || exit 2
echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"
gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
--runtime python310 \
--region "$GCP_REGION" \
--trigger-event google.cloud.storage.object.v1.finalized \
--trigger-resource "$BUCKET" \
--set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
--source . \
--entry-point generate_caption \
--gen2
Note : in this example, generate_caption will be the invoked method, and Cloud Function will pass the GCS event to it with all the relevant info (bucket name, object name, ..). Take some time to debug that event python dict.
Testing the function
ইউনিট পরীক্ষা
The function has many moving parts. You might want to be able to test all the single ones.
An example is in gcf/test.py .
Cloud Functions UI
Also take some time to explore your function on the UI. Every tab is worth exploring, particularly the Source (my favourite), Variables , Trigger , and Logs ; You'll spend a lot of time in the Logs to troubleshoots errors (also see possible errors on the bottom of this page). also make sure to check Permissions .

E2E Test
Time to manually test the function!
- Go to your app, and login
- Upload a picture (not too big, we've seen issues with big images)
- check on UI the picture is uploaded.
- Check on Cloud SQL Studio that the description has been updated. Login and run this query:
SELECT * FROM images.

And it works! We might also want to update the frontend to show that description.
Update PHP to show [optional]
We have proven the app works. However, it would be nice that the users could also see that description.
We don't need to be PHP experts to add the description to the index.php . This code should do (yes, Gemini wrote it for me too!):
<?php if (!empty($image['description'])): ?>
<p class="font-bold">Gemini Caption:</p>
<p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>
Position this code inside the foreach at your own taste.
In the next steps we also see a prettier UI version, thanks to Gemini Code Assist. A pretty version might look like this:

উপসংহার
You got a Cloud Function triggered on new objects landing on GCS which is able to annotate the content of the image like a human could do, and automatically update the DB. Wow!
What's next? You could follow the same reasoning to achieve two great functionalities.
[optional] Add further Cloud Functions [open ended]
A couple of additional features come to mind.
📩 Email Trigger
An email trigger which sends you an email every time someone sends a picture.
- Too often? Add a further constraint: A BIG picture, or a picture whose Gemini content contains the words "nude/nudity/violent".
- Consider checking
EventArcfor this.
🚫 Auto-moderate inappropriate pics
Currently a human admin is flagging images for "inappropriate". How about having Gemini doing the heavy lifting and moderating the space? Add a test to flag inappropriate trigger content and update the DB as we learnt in the previous function. This means basically taking the previous function, changing the prompt, and updating the DB based on the answer.
Caveat . Generative AI has unpredictable outputs. Make sure the "creative output" from Gemini is put "on rails". You might ask a deterministic answer like a confidence score from 0 to 1, a JSON, .. You can achieve this in many ways, for example: * Using python libraries pydantic , langchain , .. * Use Gemini Structured Output .
Tip . You could have MULTIPLE functions or have a single prompt which enforces a JSON answer (works greta with "Gemini Structured Output"as highlighted above) like:
What would the prompt be to generate this?
{
"description": "This is the picture of an arrosticino",
"suitable": TRUE
}
You could add in the prompt additional fields to get insights like: is there something good about it? Bad about it? Do you recognize the place? Is there some text (OCR has never been easier):
-
goods: "It looks like yummie food" -
bads: "It looks like unhealthy food" -
OCR: "Da consumare preferibilmente prima del 10 Novembre 2024" -
location: "Pescara, Lungomare"
While it's usually better to have N function for N outcomes, it's incredibly rewarding to do one which does 10 things. Check this article by Riccardo to see how.
Possible errors (mostly IAM / permissions)
The first I've developed this solution I came onto some IAM permission issues. I will add them here for empathy and to give some ideas on how to fix them.
Error: not enough permissions for Service Account
- Note that for deploying a GCF function which listens to a GCS bucket you need to set up proper permissions to the Service Account you are using for the job, as in figure:

You might also have to enable EventArc APIs - what a few minutes before they become fully available.
Error: Missing Cloud Run invoker
- Another comment from UI for GCF permissioning is this ( Cloud run Invoker role ):

This error can be fixed running the command in the image, which is similar to fix-permissions.sh
This issue is described here: https://cloud.google.com/functions/docs/securing/authenticating
Error: Memory limit exceeded
The first time I ran it, my logs could said: "'Memory limit of 244 MiB exceeded with 270 MiB used. Consider increasing the memory limit, see https://cloud.google.com/functions/docs/configuring/memory '". Again, add RAM to your GCF. This is super easy to do in the UI. Here's a possible bump:

Alternatively, you can also fix your Cloud run deployment script to bump MEM/CPU. This takes a bit longer.
Error: PubSub Published
Creatuing a trigger with GCF v1 gave once this error:

Again, this is easy to fix by going to IAM and giving your Service Account the "Pub/Sub Publisher" role.
Error: Vertex AI has not been used
If you receive this error:
Permission Denied: 403 Vertex AI API has not been used in project YOUR_PROJECT before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT
You just need to enable Vertex AI APis. The easiest way to enable ALL needed APIs is this:
- https://console.cloud.google.com/vertex-ai
- Click the "enable all recommended APIS".

Error: EventArc Trigger not found.
If you get this, please redeploy the function.

Error: 400 Service agents are being provisioned
400 Service agents are being provisioned ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents ). Service agents are needed to read the Cloud Storage file provided. So please try again in a few minutes.
If this happens, wait some time or ask a Googler.
10. Module 8: Create Availability SLOs
In the Chapter we try to achieve this:
- Creating SLIs
- Creating SLOs based on the SLIs
- Creating Alerts based on SLOs

This is a very dear topic to the author, since Riccardo works in the SRE / DevOps area of Google Cloud.
(open-ended) Create SLIs and SLOs for this app
How good is an app if you can't tell when it's down?
What is an SLO?
Oh my! Google invented SLOs! To read more about it I can suggest:
- SRE Book - chapter 2 - Implementing SLOs . ( 👉 more SREbooks )
- Art of SLOs ( awesome video ). It's a fantastic training to learn more about how to craft a perfect SLO for your service.
- SRE course on Coursera . I contributed to it!
Step 1: Create Availability SLI/SLO
Let's start with Availability SLO, as it's the easiest and possibly the most important thing you want to measure.
Luckily Cloud run comes with pre built SLO support, thanks to Istio .
Once your app is on Cloud run, this is super simple to achieve, it takes me 30 seconds.
- Go to your Cloud Run page.
- Click/select your app.
- Select the
SLOstab. - Click "+ Create SLO".
- Availability , Request-based
- চালিয়ে যান
- Calendar Month / 99%.
- click "Create SLO".

Step 2: set up Alerting on this SLO
I suggest to create 2 alerts:
- One with a low burnrate ("Slowburn") to alert you via email (simulates low pri ticket).
- One with a high burnrate ("Fastburn") to alert you via SMS (simulates high pri ticket / pager)
Go to your SLO tab from before.
Do this twice:

- Click "Create SLO Alert" (the 🔔 button with a plus inside, to the right)
- Lookback duration, Burn Rate threshold:
- [FAST]. First:
60min /10x - [SLOW]. Second:
720min /2x - Notification channel: click on Manage notification channels
- First, "Email" -> Add new -> ..
- Second, "SMS" -> Add new -> Verify on the phone.
- Tip: I like to use emoji in the names! It's fun for demos.
- when done, click the big X on top right.
- Select phone first (fast), email next (slow).
- Add some sample documentation like:
-
[PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking.
Bingo!
Final result
We can consider this exercise finished once you have 1 working SLO + 2x alerts for your availability, and it's alerting to your email and to your phone.
If you want you can add a Latency (and I strongly encourage you to do so) or even a more complex one. For latency, choose a latency you deem reasonable; when in doubt, choose 200ms .
11. Next steps
You've completed EVERYTHING, what's missing?
Some food for thought:
Play with Gemini
You can use Gemini in two flavours:
- Vertex AI. The "Enterprise way", intertwined with your GCP, which we've explored in chapter 7 (GCF+Gemini). All authentication magically works, and services beautifully interconnect.
- Google AI. The "Consumer way". You get a Gemini API Key from here and start building little scripts which can be tied onto any workload you already have (proprietary work, other clouds, localhost, ..). You just substitute your API key and the code starts magically to work.
We encourage you to try exploring the (2) with your own pet projects.
UI Lifting
I'm no good at UIs. But Gemini is! You can just take a single PHP page, and say something like this:
I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:
1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?
Here's the code:
-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]
You can easily get this in less than 5 minutes, one Cloud Build away! :)
The response from Gemini was perfect (meaning, I didn't have to change a thing):

And here's the new layout in the author's personal app:

Note: the code is pasted as image as we don't want to encourage you to take the code, but to get Gemini to write the code for you, with your own creative UI/frontend constraints; trust me, you're left with very minor changes afterwards.
নিরাপত্তা
Properly securing this app is a non-goal for this 4-hour workshop, as it would increase the time to complete this workshop by 1-2 orders of magnitude.
However, this topic is super-important! We've collected some ideas in SECURITY .
12. Congratulations!
Congratulations 🎉🎉🎉 , you've successfully modernized your legacy PHP application with Google Cloud.

In summary in this codelab you have learned:
- How to deploy a database in Google Cloud SQL and how to migrate your existing database into it.
- How to containerize your PHP application with Docker and Buildpacks and store its image to Google Cloud Artifact Registry
- How to deploy your containerized App to Cloud Run and make it run with Cloud SQL
- How to secretly store/use sensitive configuration parameters (such as DB password) using Google Secret Manager
- How to set up your CI/CD pipeline with Google Cloud Build to automatically build and deploy your PHP App at any code push to your GitHub repo.
- How to use Cloud Storage to "cloudify" your app resources
- How to leverage serverless technologies to build amazing workflows on top of Google Cloud without touching your app code.
- Use Gemini multimodal capabilities for a fitting use case.
- Implement SRE principles within Google Cloud
This is a great start for your journey into Application modernization with Google Cloud!
🔁 Feedback
If you want to tell us about your experience with this workshop, consider filing this feedback form .
We welcome your feedback as well as PR s for pieces of code you're particularly proud of.
🙏 Thanks
The author would like to thank Mirko Gilioli and Maurizio Ipsale from Datatonic for help on the writeup and testing the solution.
