ক্লাউড রান ফাংশনের জন্য সাইডকারে কীভাবে এলএলএম হোস্ট করবেন

১. ভূমিকা

সংক্ষিপ্ত বিবরণ

এই কোডল্যাবে, আপনি শিখবেন কিভাবে একটি ক্লাউড রান ফাংশনের জন্য সাইডকারে একটি gemma3:4b মডেল হোস্ট করতে হয়। যখন কোনো ফাইল ক্লাউড স্টোরেজ বাকেটে আপলোড করা হয়, তখন এটি ক্লাউড রান ফাংশনটিকে ট্রিগার করবে। ফাংশনটি ফাইলটির বিষয়বস্তু সামারাইজেশনের জন্য সাইডকারে থাকা Gemma 3-তে পাঠাবে।

আপনি যা শিখবেন

  • ক্লাউড রান ফাংশন এবং জিপিইউ ব্যবহার করে সাইডকারে হোস্ট করা এলএলএম-এর মাধ্যমে কীভাবে ইনফারেন্স করা যায়
  • মডেলের দ্রুত আপলোড ও পরিবেশনের জন্য ক্লাউড রান জিপিইউ-তে ডিরেক্ট ভিপিসি ইগ্রেস কনফিগারেশন কীভাবে ব্যবহার করবেন
  • আপনার হোস্ট করা ওল্লামা মডেলের সাথে ইন্টারফেস করতে জেনকিট কীভাবে ব্যবহার করবেন

২. শুরু করার আগে

জিপিইউ ফিচারটি ব্যবহার করতে হলে, আপনাকে একটি সমর্থিত অঞ্চলের জন্য কোটা বৃদ্ধির অনুরোধ করতে হবে। প্রয়োজনীয় কোটাটি হলো nvidia_l4_gpu_allocation_no_zonal_redundancy, যা ক্লাউড রান অ্যাডমিন এপিআই (Cloud Run Admin API)-এর অধীনে রয়েছে। কোটার অনুরোধ করার জন্য সরাসরি লিঙ্কটি এখানে দেওয়া হলো।

৩. সেটআপ এবং প্রয়োজনীয়তা

এই কোডল্যাব জুড়ে ব্যবহৃত হবে এমন এনভায়রনমেন্ট ভেরিয়েবলগুলো সেট করুন।

PROJECT_ID=<YOUR_PROJECT_ID>
REGION=<YOUR_REGION>

AR_REPO=codelab-crf-sidecar-gpu
FUNCTION_NAME=crf-sidecar-gpu
BUCKET_GEMMA_NAME=$PROJECT_ID-codelab-crf-sidecar-gpu-gemma3
BUCKET_DOCS_NAME=$PROJECT_ID-codelab-crf-sidecar-gpu-docs
SERVICE_ACCOUNT="crf-sidecar-gpu"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com
IMAGE_SIDECAR=$REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3

এই কমান্ডটি চালিয়ে সার্ভিস অ্যাকাউন্টটি তৈরি করুন:

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="SA for codelab crf sidecar with gpu"

ক্লাউড রান ফাংশনটিকে কল করার জন্য, আমরা ইভেন্টআর্ক ট্রিগারের সার্ভিস অ্যাকাউন্ট হিসেবে সেই একই সার্ভিস অ্যাকাউন্টটি ব্যবহার করব, যা ক্লাউড রান ফাংশনের আইডেন্টিটি হিসেবে ব্যবহৃত হচ্ছে। আপনি চাইলে ইভেন্টআর্কের জন্য একটি ভিন্ন SA তৈরি করতে পারেন।

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
    --role=roles/run.invoker

এছাড়াও সার্ভিস অ্যাকাউন্টটিকে ইভেন্টার্ক ইভেন্ট গ্রহণ করার অ্যাক্সেস দিন।

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS" \
    --role="roles/eventarc.eventReceiver"

একটি বাকেট তৈরি করুন যা আপনার ফাইন-টিউনড মডেলটিকে হোস্ট করবে। এই কোডল্যাবে একটি রিজিওনাল বাকেট ব্যবহার করা হয়েছে। আপনি একটি মাল্টি-রিজিওনাল বাকেটও ব্যবহার করতে পারেন।

gsutil mb -l $REGION gs://$BUCKET_GEMMA_NAME

এবং তারপর SA-কে বাকেটটিতে অ্যাক্সেস দিন।

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

এখন একটি আঞ্চলিক বাকেট তৈরি করুন যেখানে আপনার সারসংক্ষেপ করতে চাওয়া ডকুমেন্টগুলো সংরক্ষিত হবে। আপনি একটি বহু-আঞ্চলিক বাকেটও ব্যবহার করতে পারেন, তবে সেক্ষেত্রে আপনাকে Eventarc ট্রিগারটি সেই অনুযায়ী আপডেট করতে হবে (যা এই কোডল্যাবের শেষে দেখানো হয়েছে)।

gsutil mb -l $REGION gs://$BUCKET_DOCS_NAME

এবং তারপর SA-কে Gemma 3 বাকেটটিতে অ্যাক্সেস দিন।

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

এবং ডকস বাকেট।

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_DOCS_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

সাইডকারে ব্যবহৃত হবে এমন Ollama ইমেজের জন্য একটি আর্টিফ্যাক্ট রেজিস্ট্রি রিপোজিটরি তৈরি করুন।

gcloud artifacts repositories create $AR_REPO \
    --repository-format=docker \
    --location=$REGION \
    --description="codelab for CR function and gpu sidecar" \
    --project=$PROJECT_ID

৪. জেমা ৩ মডেলটি ডাউনলোড করুন

প্রথমে, আপনাকে ollama থেকে Gemma 3 4b মডেলটি ডাউনলোড করতে হবে। এটি করার জন্য, প্রথমে ollama ইনস্টল করুন এবং তারপর আপনার কম্পিউটারে gemma3:4b মডেলটি চালান।

curl -fsSL https://ollama.com/install.sh | sh
ollama serve

এখন একটি আলাদা টার্মিনাল উইন্ডোতে, মডেলটি ডাউনলোড করতে নিম্নলিখিত কমান্ডটি চালান। আপনি যদি ক্লাউড শেল ব্যবহার করেন, তবে উপরের ডানদিকের মেনু বারে থাকা প্লাস আইকনে ক্লিক করে একটি অতিরিক্ত টার্মিনাল উইন্ডো খুলতে পারেন।

ollama run gemma3:4b

একবার ওলামা চালু হয়ে গেলে, মডেলটিকে নির্দ্বিধায় কিছু প্রশ্ন করতে পারেন, যেমন—

"why is the sky blue?"

ওলামার সাথে চ্যাট করা শেষ হলে, আপনি দৌড়ে চ্যাট থেকে বেরিয়ে যেতে পারেন।

/bye

তারপর, প্রথম টার্মিনাল উইন্ডোতে, স্থানীয়ভাবে ওলামা পরিবেশন বন্ধ করতে নিম্নলিখিত কমান্ডটি চালান।

# on Linux / Cloud Shell press Ctrl^C or equivalent for your shell

আপনার অপারেটিং সিস্টেমের ওপর নির্ভর করে ওলামা কোথা থেকে মডেলগুলো ডাউনলোড করে, তা আপনি এখানে খুঁজে পেতে পারেন।

https://github.com/ollama/ollama/blob/main/docs/faq.md#where-are-models-stored

আপনি যদি ক্লাউড ওয়ার্কস্টেশন ব্যবহার করেন, তাহলে ওলামা মডেলগুলো এখানে ডাউনলোড করতে পারবেন /home/$USER/.ollama/models

আপনার মডেলগুলো এখানে হোস্ট করা আছে কিনা তা নিশ্চিত করুন:

ls /home/$USER/.ollama/models

এখন gemma3:4b মডেলটি আপনার GCS বাকেটে সরান।

gsutil cp -r /home/$USER/.ollama/models gs://$BUCKET_GEMMA_NAME

৫. ক্লাউড রান ফাংশনটি তৈরি করুন

আপনার সোর্স কোডের জন্য একটি রুট ফোল্ডার তৈরি করুন।

mkdir codelab-crf-sidecar-gpu &&
cd codelab-crf-sidecar-gpu &&
mkdir cr-function &&
mkdir ollama-gemma3 &&
cd cr-function

src নামে একটি সাবফোল্ডার তৈরি করুন। ফোল্ডারটির ভিতরে index.ts নামে একটি ফাইল তৈরি করুন।

mkdir src &&
touch src/index.ts

নিম্নলিখিত কোড দিয়ে index.ts ফাইলটি আপডেট করুন:

//import util from 'util';
import { cloudEvent, CloudEvent } from "@google-cloud/functions-framework";
import { StorageObjectData } from "@google/events/cloud/storage/v1/StorageObjectData";
import { Storage } from "@google-cloud/storage";

// Initialize the Cloud Storage client
const storage = new Storage();

import { genkit } from 'genkit';
import { ollama } from 'genkitx-ollama';

const ai = genkit({
    plugins: [
        ollama({
            models: [
                {
                    name: 'gemma3:4b',
                    type: 'generate', // type: 'chat' | 'generate' | undefined
                },
            ],
            serverAddress: 'http://127.0.0.1:11434', // default local address
        }),
    ],
});


// Register a CloudEvent callback with the Functions Framework that will
// be triggered by Cloud Storage.

//functions.cloudEvent('helloGCS', await cloudEvent => {
cloudEvent("gcs-cloudevent", async (cloudevent: CloudEvent<StorageObjectData>) => {
    console.log("---------------\nProcessing for ", cloudevent.subject, "\n---------------");

    if (cloudevent.data) {

        const data = cloudevent.data;

        if (data && data.bucket && data.name) {
            const bucketName = cloudevent.data.bucket;
            const fileName = cloudevent.data.name;
            const filePath = `${cloudevent.data.bucket}/${cloudevent.data.name}`;

            console.log(`Attempting to download: ${filePath}`);

            try {
                // Get a reference to the bucket
                const bucket = storage.bucket(bucketName!);

                // Get a reference to the file
                const file = bucket.file(fileName!);

                // Download the file's contents
                const [content] = await file.download();

                // 'content' is a Buffer. Convert it to a string.
                const fileContent = content.toString('utf8');

                console.log(`Sending file to Gemma 3 for summarization`);
                const { text } = await ai.generate({
                    model: 'ollama/gemma3:4b',
                    prompt: `Summarize the following document in just a few sentences ${fileContent}`,
                });

                console.log(text);

            } catch (error: any) {

                console.error('An error occurred:', error.message);
            }
        } else {
            console.warn("CloudEvent bucket name is missing!", cloudevent);
        }
    } else {
        console.warn("CloudEvent data is missing!", cloudevent);
    }
});

এখন crf-sidecar-gpu রুট ডিরেক্টরিতে package.json নামে একটি ফাইল তৈরি করুন এবং তাতে নিম্নলিখিত বিষয়বস্তু যোগ করুন:

{
    "main": "lib/index.js",
    "name": "ingress-crf-genkit",
    "version": "1.0.0",
    "scripts": {
        "build": "tsc"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "dependencies": {
        "@google-cloud/functions-framework": "^3.4.0",
        "@google-cloud/storage": "^7.0.0",
        "genkit": "^1.1.0",
        "genkitx-ollama": "^1.1.0",
        "@google/events": "^5.4.0"
    },
    "devDependencies": {
        "typescript": "^5.5.2"
    }
}

রুট ডিরেক্টরি লেভেলে নিম্নলিখিত বিষয়বস্তু সহ একটি tsconfig.json তৈরি করুন:

{
  "compileOnSave": true,
  "include": [
    "src"
  ],
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017",
    "skipLibCheck": true,
    "esModuleInterop": true
  }
}

৬. ফাংশনটি স্থাপন করুন

এই ধাপে, আপনি নিম্নলিখিত কমান্ডটি চালিয়ে ক্লাউড রান ফাংশনটি ডেপ্লয় করবেন।

দ্রষ্টব্য: সর্বোচ্চ ইনস্ট্যান্সের সংখ্যা আপনার জিপিইউ কোটার সমান বা তার চেয়ে কম নির্ধারণ করা উচিত।

gcloud beta run deploy $FUNCTION_NAME \
  --region $REGION \
  --function gcs-cloudevent \
  --base-image nodejs22 \
  --source . \
  --no-allow-unauthenticated \
  --max-instances 2 # this should be less than or equal to your GPU quota

৭. সাইডকার তৈরি করুন

ক্লাউড রান পরিষেবার মধ্যে ওলামা হোস্টিং সম্পর্কে আরও জানতে আপনি https://cloud.google.com/run/docs/tutorials/gpu-gemma-with-ollama এই লিঙ্কে যেতে পারেন।

আপনার সাইডকারের ডিরেক্টরিতে প্রবেশ করুন:

cd ../ollama-gemma3

নিম্নলিখিত বিষয়বস্তু সহ একটি Dockerfile ফাইল তৈরি করুন:

FROM ollama/ollama:latest

# Listen on all interfaces, port 11434
ENV OLLAMA_HOST 0.0.0.0:11434

# Store model weight files in /models
ENV OLLAMA_MODELS /models

# Reduce logging verbosity
ENV OLLAMA_DEBUG false

# Never unload model weights from the GPU
ENV OLLAMA_KEEP_ALIVE -1

# Store the model weights in the container image
ENV MODEL gemma3:4b
RUN ollama serve & sleep 5 && ollama pull $MODEL

# Start Ollama
ENTRYPOINT ["ollama", "serve"]

ছবিটি তৈরি করুন

gcloud builds submit \
   --tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3 \
   --machine-type e2-highcpu-32

৮. সাইডকার দিয়ে ফাংশনটি আপডেট করুন।

বিদ্যমান কোনো সার্ভিস, জব বা ফাংশনে সাইডকার যোগ করতে, আপনি YAML ফাইলটি আপডেট করে তাতে সাইডকারটি অন্তর্ভুক্ত করতে পারেন।

এইমাত্র ডিপ্লয় করা ক্লাউড রান ফাংশনটির YAML ফাইলটি পেতে নিম্নলিখিত কমান্ডটি চালান:

gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml

এখন নিম্নলিখিতভাবে YAML আপডেট করে CRf-এ সাইডকারটি যোগ করুন:

  1. runtimeClassName: run.googleapis.com/linux-base-image-update লাইনের ঠিক উপরে নিম্নলিখিত YAML অংশটি যোগ করুন। -image অবশ্যই `ingress container item -image এর সাথে সামঞ্জস্যপূর্ণ হতে হবে।
    - image: YOUR_IMAGE_SIDECAR:latest
        name: gemma-sidecar
        env:
        - name: OLLAMA_FLASH_ATTENTION
          value: '1'
        resources:
          limits:
            cpu: 6000m
            nvidia.com/gpu: '1'
            memory: 16Gi
        volumeMounts:
        - name: gcs-1
          mountPath: /root/.ollama
        startupProbe:
          failureThreshold: 2
          httpGet:
            path: /
            port: 11434
          initialDelaySeconds: 60
          periodSeconds: 60
          timeoutSeconds: 60
      nodeSelector:
        run.googleapis.com/accelerator: nvidia-l4
      volumes:
        - csi:
            driver: gcsfuse.run.googleapis.com
            volumeAttributes:
              bucketName: YOUR_BUCKET_GEMMA_NAME
          name: gcs-1
  1. আপনার এনভায়রনমেন্ট ভেরিয়েবল দিয়ে YAML ফ্র্যাগমেন্টটি আপডেট করতে নিম্নলিখিত কমান্ডটি চালান:
sed -i "s|YOUR_IMAGE_SIDECAR|$IMAGE_SIDECAR|; s|YOUR_BUCKET_GEMMA_NAME|$BUCKET_GEMMA_NAME|" add-sidecar-service.yaml

আপনার সম্পূর্ণ YAML ফাইলটি দেখতে অনেকটা এইরকম হবে:

##############################################
# DO NOT COPY - For illustration purposes only
##############################################

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:    
    run.googleapis.com/build-base-image: us-central1-docker.pkg.dev/serverless-runtimes/google-22/runtimes/nodejs22
    run.googleapis.com/build-enable-automatic-updates: 'true'
    run.googleapis.com/build-function-target: gcs-cloudevent
    run.googleapis.com/build-id: f0122905-a556-4000-ace4-5c004a9f9ec6
    run.googleapis.com/build-image-uri:<YOUR_IMAGE_CRF>
    run.googleapis.com/build-name: <YOUR_BUILD_NAME>
    run.googleapis.com/build-source-location: <YOUR_SOURCE_LOCATION>
    run.googleapis.com/ingress: all
    run.googleapis.com/ingress-status: all
    run.googleapis.com/urls: '["<YOUR_CLOUD_RUN_FUNCTION_URLS"]'
  labels:
    cloud.googleapis.com/location: <YOUR_REGION>
  name: <YOUR_FUNCTION_NAME>
  namespace: '392295011265'
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/maxScale: '4'
        run.googleapis.com/base-images: '{"":"us-central1-docker.pkg.dev/serverless-runtimes/google-22/runtimes/nodejs22"}'
        run.googleapis.com/client-name: gcloud
        run.googleapis.com/client-version: 514.0.0
        run.googleapis.com/startup-cpu-boost: 'true'
      labels:
        client.knative.dev/nonce: hzhhrhheyd
        run.googleapis.com/startupProbeType: Default
    spec:
      containerConcurrency: 80
      containers:
      - image: <YOUR_FUNCTION_IMAGE>
        ports:
        - containerPort: 8080
          name: http1
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
        startupProbe:
          failureThreshold: 1
          periodSeconds: 240
          tcpSocket:
            port: 8080
          timeoutSeconds: 240
      - image: <YOUR_SIDECAR_IMAGE>:latest
        name: gemma-sidecar
        env:
        - name: OLLAMA_FLASH_ATTENTION
          value: '1'
        resources:
          limits:
            cpu: 6000m
            nvidia.com/gpu: '1'
            memory: 16Gi
        volumeMounts:
        - name: gcs-1
          mountPath: /root/.ollama
        startupProbe:
          failureThreshold: 2
          httpGet:
            path: /
            port: 11434
          initialDelaySeconds: 60
          periodSeconds: 60
          timeoutSeconds: 60
      nodeSelector:
        run.googleapis.com/accelerator: nvidia-l4
      volumes:
        - csi:
            driver: gcsfuse.run.googleapis.com
            volumeAttributes:
              bucketName: <YOUR_BUCKET_NAME>
          name: gcs-1
      runtimeClassName: run.googleapis.com/linux-base-image-update
      serviceAccountName: <YOUR_SA_ADDRESS>
      timeoutSeconds: 300
  traffic:
  - latestRevision: true
    percent: 100

##############################################
# DO NOT COPY - For illustration purposes only
##############################################

এখন নিচের কমান্ডটি চালিয়ে সাইডকার সহ ফাংশনটি আপডেট করুন।

gcloud run services replace add-sidecar-service.yaml

সবশেষে, ফাংশনটির জন্য ইভেন্টআর্ক ট্রিগার তৈরি করুন। এই কমান্ডটি ট্রিগারটিকে ফাংশনের সাথেও যুক্ত করে দেয়।

দ্রষ্টব্য: আপনি যদি একটি বহু-আঞ্চলিক বাকেট তৈরি করে থাকেন, তাহলে আপনাকে --location প্যারামিটারটি পরিবর্তন করতে হবে।

gcloud eventarc triggers create my-crf-summary-trigger  \
    --location=$REGION \
    --destination-run-service=$FUNCTION_NAME  \
    --destination-run-region=$REGION \
    --event-filters="type=google.cloud.storage.object.v1.finalized" \
    --event-filters="bucket=$BUCKET_DOCS_NAME" \
    --service-account=$SERVICE_ACCOUNT_ADDRESS

৯. আপনার ফাংশনটি পরীক্ষা করুন

সারাংশ তৈরির জন্য একটি প্লেইন টেক্সট ফাইল আপলোড করুন। কীসের সারাংশ করবেন তা জানেন না? কুকুরের ইতিহাস সম্পর্কে ১-২ পৃষ্ঠার একটি সংক্ষিপ্ত বিবরণের জন্য জেমিনিকে বলুন! তারপর, ফাংশন লগে সারাংশ লেখার জন্য সেই প্লেইন টেক্সট ফাইলটি আপনার $BUCKET_DOCS_NAME বাকেটে Gemma3:4b মডেলের জন্য আপলোড করুন।

লগগুলোতে আপনি নিচের মতো কিছু দেখতে পাবেন:

---------------
Processing for objects/dogs.txt
---------------
Attempting to download: <YOUR_PROJECT_ID>-codelab-crf-sidecar-gpu-docs/dogs.txt
Sending file to Gemma 3 for summarization
...
Here's a concise summary of the document "Humanity's Best Friend":
The dog's domestication, beginning roughly 20,000-40,000 years ago, represents a unique, deeply intertwined evolutionary partnership with humans, predating the domestication of any other animal
<...>
solidifying their long-standing role as humanity's best friend.

১০. সমস্যা সমাধান

এখানে কিছু টাইপো বা মুদ্রণজনিত ভুল দেওয়া হলো, যেগুলোর সম্মুখীন আপনি হতে পারেন:

  1. যদি আপনি PORT 8080 is in use এমন কোনো ত্রুটি পান, তাহলে নিশ্চিত করুন যে আপনার Ollama সাইডকারের জন্য Dockerfile-টি ১১৪৩৪ পোর্ট ব্যবহার করছে। এছাড়াও, আপনার AR রিপো-তে একাধিক Ollama ইমেজ থাকলে, আপনি সঠিক সাইডকার ইমেজটি ব্যবহার করছেন কিনা তাও নিশ্চিত করুন। Cloud Run ফাংশনটি ৮০৮০ পোর্টে পরিষেবা দেয়, এবং আপনি যদি সাইডকার হিসেবে এমন একটি ভিন্ন Ollama ইমেজ ব্যবহার করেন যা নিজেও ৮০৮০ পোর্টে পরিষেবা দিচ্ছে, তাহলে আপনি এই ত্রুটির সম্মুখীন হবেন।
  2. যদি failed to build: (error ID: 7485c5b6): function.js does not exist এই এররটি আসে, তাহলে নিশ্চিত করুন যে আপনার package.json এবং tsconfig.json ফাইল দুটি src ডিরেক্টরির একই লেভেলে রয়েছে।
  3. যদি আপনি ERROR: (gcloud.run.services.replace) spec.template.spec.node_selector: Max instances must be set to 4 or fewer in order to set GPU requirements. পান, তাহলে আপনার YAML ফাইলে autoscaling.knative.dev/maxScale: '100' কে পরিবর্তন করে 1 অথবা আপনার GPU কোটার সমান বা তার চেয়ে কম কোনো মান দিন।