1. Giới thiệu
Tổng quan
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách lưu trữ mô hình gemma3:4b trong một ứng dụng hỗ trợ cho hàm Cloud Run. Khi một tệp được tải lên bộ chứa Cloud Storage, tệp đó sẽ kích hoạt hàm Cloud Run. Hàm này sẽ gửi nội dung của tệp đến Gemma 3 trong sidecar để tóm tắt.
Kiến thức bạn sẽ học được
- Cách suy luận bằng hàm Cloud Run và LLM được lưu trữ trong sidecar bằng GPU
- Cách sử dụng cấu hình lưu lượng truy cập trực tiếp ra khỏi VPC cho GPU Cloud Run để tải lên và phân phát mô hình nhanh hơn
- Cách sử dụng genkit để tương tác với mô hình ollama được lưu trữ
2. Trước khi bắt đầu
Để sử dụng tính năng GPU, bạn phải yêu cầu tăng hạn mức cho một khu vực được hỗ trợ. Hạn mức cần thiết là nvidia_l4_gpu_allocation_no_zonal_redundancy, nằm trong Cloud Run Admin API. Sau đây là đường liên kết trực tiếp để yêu cầu hạn mức.
3. Thiết lập và yêu cầu
Đặt các biến môi trường sẽ được dùng trong suốt lớp học lập trình này.
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
Tạo tài khoản dịch vụ bằng cách chạy lệnh sau:
gcloud iam service-accounts create $SERVICE_ACCOUNT \
--display-name="SA for codelab crf sidecar with gpu"
Chúng ta sẽ sử dụng cùng một tài khoản dịch vụ đang được dùng làm danh tính của hàm Cloud Run làm tài khoản dịch vụ cho trình kích hoạt Eventarc để gọi hàm Cloud Run. Bạn có thể tạo một SA khác cho Eventarc nếu muốn.
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/run.invoker
Ngoài ra, hãy cấp cho tài khoản dịch vụ quyền truy cập để nhận các sự kiện Eventarc.
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS" \
--role="roles/eventarc.eventReceiver"
Tạo một nhóm lưu trữ mô hình được tinh chỉnh. Lớp học lập trình này sử dụng một vùng lưu trữ theo khu vực. Bạn cũng có thể sử dụng một bộ chứa đa khu vực.
gsutil mb -l $REGION gs://$BUCKET_GEMMA_NAME
Sau đó, cấp quyền truy cập cho SA vào bộ chứa.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
Giờ đây, hãy tạo một vùng lưu trữ theo khu vực để lưu trữ những tài liệu bạn muốn tóm tắt. Bạn cũng có thể sử dụng một bộ chứa đa vùng, miễn là bạn cập nhật điều kiện kích hoạt Eventarc cho phù hợp (như minh hoạ ở cuối lớp học lập trình này).
gsutil mb -l $REGION gs://$BUCKET_DOCS_NAME
Sau đó, cấp cho SA quyền truy cập vào bộ chứa Gemma 3.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
và nhóm Tài liệu.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_DOCS_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
Tạo một kho lưu trữ Artifact Registry cho hình ảnh Ollama sẽ được dùng trong vùng chứa phụ
gcloud artifacts repositories create $AR_REPO \
--repository-format=docker \
--location=$REGION \
--description="codelab for CR function and gpu sidecar" \
--project=$PROJECT_ID
4. Tải mô hình Gemma 3 xuống
Trước tiên, bạn cần tải mô hình Gemma 3 4b xuống từ ollama. Bạn có thể thực hiện việc này bằng cách cài đặt ollama rồi chạy mô hình gemma3:4b cục bộ.
curl -fsSL https://ollama.com/install.sh | sh
ollama serve
Giờ đây, trong một cửa sổ dòng lệnh riêng, hãy chạy lệnh sau để kéo mô hình xuống. Nếu đang sử dụng Cloud Shell, bạn có thể mở một cửa sổ dòng lệnh khác bằng cách nhấp vào biểu tượng dấu cộng trong thanh trình đơn trên cùng bên phải.
ollama run gemma3:4b
Sau khi ollama chạy, bạn có thể đặt cho mô hình một số câu hỏi, chẳng hạn như
"why is the sky blue?"
Sau khi trò chuyện xong với ollama, bạn có thể thoát khỏi cuộc trò chuyện bằng cách chạy
/bye
Sau đó, trong cửa sổ dòng lệnh đầu tiên, hãy chạy lệnh sau để ngừng phân phát ollama cục bộ
# on Linux / Cloud Shell press Ctrl^C or equivalent for your shell
Bạn có thể tìm thấy vị trí Ollama tải các mô hình xuống, tuỳ thuộc vào hệ điều hành của bạn tại đây.
https://github.com/ollama/ollama/blob/main/docs/faq.md#where-are-models-stored
Nếu đang sử dụng Cloud Workstations, bạn có thể tìm thấy các mô hình ollama đã tải xuống tại đây /home/$USER/.ollama/models
Xác nhận rằng các mô hình của bạn được lưu trữ tại đây:
ls /home/$USER/.ollama/models
bây giờ, hãy di chuyển mô hình gemma3:4b vào bộ chứa GCS của bạn
gsutil cp -r /home/$USER/.ollama/models gs://$BUCKET_GEMMA_NAME
5. Tạo hàm Cloud Run
Tạo một thư mục gốc cho mã nguồn của bạn.
mkdir codelab-crf-sidecar-gpu &&
cd codelab-crf-sidecar-gpu &&
mkdir cr-function &&
mkdir ollama-gemma3 &&
cd cr-function
Tạo một thư mục con có tên là src. Trong thư mục này, hãy tạo một tệp có tên là index.ts
mkdir src &&
touch src/index.ts
Cập nhật index.ts bằng mã sau:
//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);
}
});
Bây giờ, trong thư mục gốc crf-sidecar-gpu, hãy tạo một tệp có tên là package.json với nội dung sau:
{
"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"
}
}
Tạo tsconfig.json ở cấp thư mục gốc với nội dung sau:
{
"compileOnSave": true,
"include": [
"src"
],
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017",
"skipLibCheck": true,
"esModuleInterop": true
}
}
6. Triển khai hàm
Trong bước này, bạn sẽ triển khai hàm Cloud Run bằng cách chạy lệnh sau.
Lưu ý: bạn nên đặt số lượng phiên bản tối đa thành một số nhỏ hơn hoặc bằng hạn mức GPU của bạn.
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
7. Tạo tệp trợ giúp
Bạn có thể tìm hiểu thêm về cách lưu trữ Ollama trong một dịch vụ Cloud Run tại https://cloud.google.com/run/docs/tutorials/gpu-gemma-with-ollama
Di chuyển vào thư mục cho sidecar:
cd ../ollama-gemma3
Tạo tệp Dockerfile có nội dung sau:
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"]
Xây dựng hình ảnh
gcloud builds submit \
--tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3 \
--machine-type e2-highcpu-32
8. Cập nhật hàm bằng sidecar
Để thêm một tệp trợ giúp vào dịch vụ, công việc hoặc hàm hiện có, bạn có thể cập nhật tệp YAML để chứa tệp trợ giúp.
Truy xuất tệp YAML cho hàm Cloud Run mà bạn vừa triển khai bằng cách chạy:
gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml
Bây giờ, hãy thêm sidecar vào CRf bằng cách cập nhật YAML như sau:
- chèn đoạn mã YAML sau đây ngay phía trên dòng
runtimeClassName: run.googleapis.com/linux-base-image-update.-imagephải thẳng hàng với mục vùng chứa đầu vào-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
- Chạy lệnh sau để cập nhật đoạn mã YAML bằng các biến môi trường của bạn:
sed -i "s|YOUR_IMAGE_SIDECAR|$IMAGE_SIDECAR|; s|YOUR_BUCKET_GEMMA_NAME|$BUCKET_GEMMA_NAME|" add-sidecar-service.yaml
Tệp YAML hoàn chỉnh sẽ có dạng như sau:
##############################################
# 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
##############################################
Bây giờ, hãy cập nhật hàm bằng sidecar bằng cách chạy lệnh sau.
gcloud run services replace add-sidecar-service.yaml
Cuối cùng, hãy tạo trình kích hoạt eventarc cho hàm. Lệnh này cũng thêm hàm vào đó.
Lưu ý: nếu đã tạo một bộ chứa đa khu vực, bạn nên thay đổi tham số --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
9. Kiểm thử hàm
Tải tệp văn bản thuần tuý lên để tóm tắt. Bạn không biết nên tóm tắt nội dung nào? Yêu cầu Gemini mô tả nhanh lịch sử của loài chó trong 1 đến 2 trang! Sau đó, hãy tải tệp văn bản thuần tuý đó lên vùng chứa $BUCKET_DOCS_NAME để mô hình Gemma3:4b ghi nội dung tóm tắt vào nhật ký hàm.
Trong nhật ký, bạn sẽ thấy nội dung tương tự như sau:
---------------
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.
10. Khắc phục sự cố
Sau đây là một số lỗi chính tả mà bạn có thể gặp phải:
- Nếu bạn gặp lỗi
PORT 8080 is in use, hãy đảm bảo rằng Dockerfile cho Ollama sidecar đang sử dụng cổng 11434. Ngoài ra, hãy đảm bảo rằng bạn đang sử dụng tệp trợ giúp hình ảnh chính xác trong trường hợp bạn có nhiều hình ảnh Ollama trong kho lưu trữ thực tế tăng cường. Hàm Cloud Run hoạt động trên cổng 8080 và nếu bạn sử dụng một hình ảnh Ollama khác làm vùng chứa phụ cũng hoạt động trên cổng 8080, thì bạn sẽ gặp phải lỗi này. - Nếu bạn gặp lỗi
failed to build: (error ID: 7485c5b6): function.js does not exist, hãy đảm bảo rằng các tệp package.json và tsconfig.json nằm ở cùng cấp với thư mục src. - Nếu bạn gặp lỗi
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., trong tệp YAML, hãy thay đổiautoscaling.knative.dev/maxScale: '100'thành 1 hoặc thành một giá trị nhỏ hơn hoặc bằng hạn mức GPU của bạn.