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 no Cloud Run usando saída direta de VPC (prévia) ou acesso VPC sem servidor.

Configuração

Se você já tiver instalado a Google Cloud CLI e criado uma instância do Redis, pule estas 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, você precisa da saída VPC direta ou de 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, crie um conector. Use a mesma região e rede VPC 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 da linguagem de programação escolhida e acesse a pasta que contém o código de amostra:

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.0
gunicorn==22.0.0
redis==5.0.1
Werkzeug==3.0.1
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
      

      onde:

      • PROJECT_ID é o código do seu projeto do Google Cloud;
      • REGION é a região em que a instância do Redis está localizada.
      • NETWORK é o nome da rede VPC autorizada à qual sua instância do Redis está anexada.
      • SUBNET é o nome da sub-rede. A sub-rede precisa ser /26 ou maior. A saída de VPC direta é compatível com os 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
      

      onde:

      • 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.