התחברות למופע Redis מפונקציות Cloud Run

אפשר להתחבר למופע Redis מפונקציות Cloud Run באמצעות תעבורת נתונים יוצאת (egress) ישירה של VPC.

הגדרה

אם כבר התקנתם את Google Cloud CLI ויצרתם מופע Redis, אתם יכולים לדלג על השלבים האלה.

  1. מתקינים את ה-CLI של gcloud ומפעילים אותו:

    gcloud init
    
  2. פועלים לפי המדריך למתחילים כדי ליצור מכונת Redis. חשוב לשים לב לאזור, לכתובת ה-IP ולפורט של מכונת Redis.

הכנה של יציאת נתונים מרשת VPC להגדרה

כדי להתחבר למופע Redis, לפונקציית Cloud Run צריכה להיות גישה לרשת ה-VPC המורשית של מופע Redis.

כדי למצוא את השם של הרשת הזו, מריצים את הפקודה הבאה:

  gcloud redis instances describe INSTANCE_ID --region REGION --format "value(authorizedNetwork)"

רושמים את שם הרשת.

פונקציית דגימה

הפונקציה לדוגמה הזו יוצרת חיבור למכונת Redis מפונקציות Cloud Run.

משכפלים את המאגר בשפת התכנות הרצויה ועוברים לתיקייה שמכילה את הקוד לדוגמה:

המשך

git clone https://github.com/GoogleCloudPlatform/golang-samples
cd golang-samples/functions/memorystore/redis

Node.js

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples
cd nodejs-docs-samples/functions/memorystore/redis

Python

git clone https://github.com/GoogleCloudPlatform/python-docs-samples
cd python-docs-samples/functions/memorystore/redis

קוד הדוגמה מגדיל מונה Redis בכל פעם שהפונקציה מופעלת:

המשך

הפונקציה הזו משתמשת בלקוח github.com/gomodule/redigo/redis.


// Package visitcount provides a Cloud Function that connects
// to a managed Redis instance.
package visitcount

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func init() {
	// Register the HTTP handler with the Functions Framework
	functions.HTTP("VisitCount", visitCount)
}

// initializeRedis initializes and returns a connection pool
func initializeRedis() (*redis.Pool, error) {
	redisHost := os.Getenv("REDISHOST")
	if redisHost == "" {
		return nil, errors.New("REDISHOST must be set")
	}
	redisPort := os.Getenv("REDISPORT")
	if redisPort == "" {
		return nil, errors.New("REDISPORT must be set")
	}
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	return &redis.Pool{
		MaxIdle: maxConnections,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", redisAddr)
			if err != nil {
				return nil, fmt.Errorf("redis.Dial: %w", err)
			}
			return c, err
		},
	}, nil
}

// visitCount increments the visit count on the Redis instance
// and prints the current count in the HTTP response.
func visitCount(w http.ResponseWriter, r *http.Request) {
	// Initialize connection pool on first invocation
	if redisPool == nil {
		// Pre-declare err to avoid shadowing redisPool
		var err error
		redisPool, err = initializeRedis()
		if err != nil {
			log.Printf("initializeRedis: %v", err)
			http.Error(w, "Error initializing connection pool", http.StatusInternalServerError)
			return
		}
	}

	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		log.Printf("redis.Int: %v", err)
		http.Error(w, "Error incrementing visit count", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visit count: %d", counter)
}

Node.js

הפונקציה הזו משתמשת במודול redis.


const functions = require('@google-cloud/functions-framework');
const redis = require('redis');

const REDISHOST = process.env.REDISHOST || 'localhost';
const REDISPORT = process.env.REDISPORT || 6379;

const redisClient = redis.createClient({
  socket: {
    host: REDISHOST,
    port: REDISPORT,
  },
});
redisClient.on('error', err => console.error('ERR:REDIS:', err));
redisClient.connect();

functions.http('visitCount', async (req, res) => {
  try {
    const response = await redisClient.incr('visits');
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(`Visit count: ${response}`);
  } catch (err) {
    console.log(err);
    res.status(500).send(err.message);
  }
});

Python

הפונקציה הזו משתמשת בחבילה redis-py.


import os

import functions_framework
import redis

redis_host = os.environ.get("REDISHOST", "localhost")
redis_port = int(os.environ.get("REDISPORT", 6379))
redis_client = redis.StrictRedis(host=redis_host, port=redis_port)


@functions_framework.http
def visit_count(request):
    value = redis_client.incr("visits", 1)
    return f"Visit count: {value}"

פריסת הדוגמה לפונקציות Cloud Run

כדי לפרוס את הפונקציה:

  1. מעתיקים את Dockerfile לספריית קובצי המקור:

    cp ../../../memorystore/redis/cloud_run_deployment/Dockerfile .
    
  2. כדי ליצור קובץ אימג' של קונטיינר באמצעות Cloud Build, מריצים את הפקודה הבאה:

    gcloud artifacts repositories create --location REPO_REGION --repository-format=docker REPO_ID
    gcloud builds submit --pack image=REPO_REGION-docker.pkg.dev/PROJECT_ID/REPO_ID/visit-counter:v1,builder=gcr.io/buildpacks/builder:latest,env=GOOGLE_FUNCTION_SIGNATURE_TYPE=http,env=GOOGLE_FUNCTION_TARGET=VisitCount
    
  3. כדי לפרוס את הקונטיינר ב-Cloud Run, מריצים את הפקודה הבאה:

    gcloud run deploy \
      --image REPO_REGION-docker.pkg.dev/PROJECT_ID/REPO_ID/visit-counter:v1 \
      --allow-unauthenticated \
      --region REGION \
      --network NETWORK \
      --subnet SUBNET \
      --set-env-vars REDISHOST=REDIS_IP,REDISPORT=REDIS_PORT
    

    where:

    • REPO_REGION הוא האזור של המאגר.
    • REPO_ID הוא שם המאגר שמכיל את תמונת האפליקציה.
    • PROJECT_ID הוא מזהה הפרויקט. Google Cloud
    • REGION הוא האזור שבו נמצאת מכונת ה-Redis.
    • NETWORK הוא השם של רשת ה-VPC המורשית שאליה מחובר מופע Redis.
    • SUBNET הוא שם תת-הרשת. תת-הרשת צריכה להיות /26 או גדולה יותר. יציאה ישירה מ-VPC תומכת ב-RFC 1918, ב-RFC 6598 ובטווחים של Class E IPv4.
    • REDIS_IP ו-REDIS_PORT הן כתובת ה-IP ומספר היציאה של מופע Redis.

אחרי שפריסת הפונקציה מסתיימת, מאחזרים את כתובת ה-URL של הפונקציה:

gcloud run services describe visit-count \
--region=REGION

אפשר לראות את המונה גדל בכל פעם שמפעילים את הפונקציה על ידי שליחת בקשת GET לכתובת ה-URL שלה.