Como se conectar a uma instância do Redis a partir de um serviço do Cloud Run

É possível se conectar a uma instância do Redis a partir do Cloud Run usando a saída de VPC direta ou Acesso VPC sem servidor.

Configuração

Se você já instalou a Google Cloud CLI e criou um Redis é possível pular essas etapas.

  1. Instale a CLI gcloud e inicialize:

    gcloud init
    
  2. Siga o Guia de início rápido para criar uma instância do Redis. Anote a zona, o endereço IP e a porta da instância do Redis.

Preparar a saída de rede VPC para configuração

Para se conectar à instância do Redis, o serviço do Cloud Run precisa acessar a rede VPC autorizada da instância do Redis. Para ativar esse acesso, é preciso uma saída de VPC direta ou um Conector de acesso VPC sem servidor. Compare os dois métodos de saída de rede.

  1. Encontre o nome da rede autorizada da sua instância do Redis executando o seguinte comando:

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

    Anote o nome da rede.

  2. Se você estiver usando o acesso VPC sem servidor, criar um conector. Use a mesma região e rede VPC que foram usadas pela instância do Redis. Anote o nome do conector.

Exemplo de aplicativo

Este aplicativo de servidor HTTP de amostra estabelece uma conexão com uma instância do Redis a partir de um serviço do Cloud Run.

Clone o repositório para a linguagem de programação escolhida e navegue à pasta que contém o exemplo de código:

Go

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

Node.js

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

Python

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

Este aplicativo de amostra incrementa um contador do Redis sempre que o endpoint / é acessado.

Go

Este aplicativo usa o cliente github.com/gomodule/redigo/redis. Instale-o executando o comando a seguir:

go get github.com/gomodule/redigo/redis

// Command redis is a basic app that connects to a managed Redis instance.
package main

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

	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func incrementHandler(w http.ResponseWriter, r *http.Request) {
	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		http.Error(w, "Error incrementing visitor counter", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visitor number: %d", counter)
}

func main() {
	redisHost := os.Getenv("REDISHOST")
	redisPort := os.Getenv("REDISPORT")
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	redisPool = &redis.Pool{
		MaxIdle: maxConnections,
		Dial:    func() (redis.Conn, error) { return redis.Dial("tcp", redisAddr) },
	}

	http.HandleFunc("/", incrementHandler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

Node.js

Este aplicativo usa o módulo redis (em inglês).

{
  "name": "memorystore-redis",
  "description": "An example of using Memorystore(Redis) with Node.js",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "redis": "^4.0.0"
  }
}

'use strict';
const http = require('http');
const redis = require('redis');

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

const client = redis.createClient(REDISPORT, REDISHOST);
client.on('error', err => console.error('ERR:REDIS:', err));

// create a server
http
  .createServer((req, res) => {
    // increment the visit counter
    client.incr('visits', (err, reply) => {
      if (err) {
        console.log(err);
        res.status(500).send(err.message);
        return;
      }
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(`Visitor number: ${reply}\n`);
    });
  })
  .listen(8080);

Python

Este aplicativo usa o Flask para veiculação na Web e o pacote redis-py (links em inglês) para se comunicar com a instância do Redis.

Flask==3.0.3
gunicorn==22.0.0
redis==5.0.1
Werkzeug==3.0.3
import logging
import os

from flask import Flask
import redis

app = Flask(__name__)

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)


@app.route("/")
def index():
    value = redis_client.incr("counter", 1)
    return f"Visitor number: {value}"


@app.errorhandler(500)
def server_error(e):
    logging.exception("An error occurred during a request.")
    return (
        """
    An internal error occurred: <pre>{}</pre>
    See logs for full stacktrace.
    """.format(
            e
        ),
        500,
    )


if __name__ == "__main__":
    # This is used when running locally. Gunicorn is used to run the
    # application on Google App Engine and Cloud Run.
    # See entrypoint in app.yaml or Dockerfile.
    app.run(host="127.0.0.1", port=8080, debug=True)

Como implantar o aplicativo no Cloud Run

Para implantar o aplicativo:

  1. Copie Dockerfile no diretório de origem:

    cp cloud_run_deployment/Dockerfile .
    
  2. Crie uma imagem de contêiner usando o Cloud Build com o seguinte comando:

    gcloud builds submit --tag gcr.io/PROJECT_ID/visit-count
    
  3. Implantar o contêiner no Cloud Run.

    • Se você estiver usando a saída de VPC direta, execute o seguinte comando:

      gcloud run deploy \
      --image gcr.io/PROJECT_ID/visit-count \
      --platform managed \
      --allow-unauthenticated \
      --region REGION \
      --network NETWORK \
      --subnet SUBNET \
      --set-env-vars REDISHOST=REDIS_IP,REDISPORT=REDIS_PORT
      

      em que:

      • PROJECT_ID é o código do seu projeto do Google Cloud;
      • REGION é a região em que sua instância do Redis está localizado.
      • NETWORK é o nome do bloco Rede VPC à qual sua instância do Redis está anexada.
      • SUBNET é o nome da sub-rede. A sub-rede precisa ter /26 ou mais. A saída de VPC direta oferece suporte a intervalos IPv4 RFC 1918, RFC 6598, e Classe E.
      • REDIS_IP e REDIS_PORT são o endereço IP e o número da porta da instância do Redis.
    • Se você estiver usando um conector de acesso VPC sem servidor, execute o seguinte comando:

      gcloud run deploy \
      --image gcr.io/PROJECT_ID/visit-count \
      --platform managed \
      --allow-unauthenticated \
      --region REGION \
      --vpc-connector CONNECTOR_NAME \
      --set-env-vars REDISHOST=REDIS_IP,REDISPORT=REDIS_PORT
      

      em que:

      • PROJECT_ID é o código do seu projeto do Google Cloud;
      • REGION é a região em que o conector de acesso VPC sem servidor e a instância do Redis estão localizados;
      • CONNECTOR_NAME é o nome do conector.
      • REDIS_IP e REDIS_PORT são o endereço IP e o número da porta da instância do Redis.

Após a conclusão da implantação, a linha de comando exibirá o URL do serviço do Cloud Run. Acesse esse URL em um navegador da Web (ou use uma ferramenta como curl) e veja a contagem da instância do Redis aumentar a cada vez que o serviço é acessado.