Skip to main content

Accessing Other Tencent Cloud Database Resources via Private Network

Overview

If you want your CloudBase Run service to securely access other resources in your Tencent Cloud account — such as MySQL, Redis, Kafka, or even services deployed on CVM instances — you can use the Private Network Interconnection feature of CloudBase Run. Once enabled, you can access resources within the VPC via their private IP addresses.

Benefits of Private Network Interconnection

  • High Security: Data transmission stays off the public internet, reducing security risks
  • Excellent Performance: Low latency, high bandwidth, and fast access speeds on the private network
  • Cost Savings: Avoids public network traffic fees
  • Stable and Reliable: Private network environments are more stable with less network fluctuation

Configure Private Network Interconnection

Prerequisites

  1. Your Tencent Cloud account already has a VPC network configured
  2. The target resource (e.g., database instance) is deployed within that VPC
  3. CloudBase Run and the target resource are in the same region

Configuration Steps

1. Enable Private Network Interconnection

Configure private network interconnection in the CloudBase Run console:

  1. Log in to the [CloudBase Console]
  2. Select the corresponding CloudBase Run service, go to the Service Configuration page, and click Edit
  3. In the Private Network Settings section
  4. Select the target VPC and subnet
  5. Save the configuration

2. Configure Security Groups

Ensure security group rules allow CloudBase Run to access the target resource:

# Example: Allow CloudBase Run to access MySQL (port 3306)
Inbound Rules:
- Protocol: TCP
- Port: 3306
- Source: CIDR of the subnet where CloudBase Run resides (e.g., 10.0.1.0/24)

# Example: Allow CloudBase Run to access Redis (port 6379)
Inbound Rules:
- Protocol: TCP
- Port: 6379
- Source: CIDR of the subnet where CloudBase Run resides

3. Get the Private Network Address

Obtain the private network access address for the resource from the corresponding cloud service console:

Service TypeConsole LocationPrivate IP Example
MySQLDatabase MySQL > Instance Details10.0.1.100:3306
RedisDatabase Redis > Instance Details10.0.1.101:6379
KafkaMessage Queue CKafka > Instance Details10.0.1.102:9092
CVMCloud Virtual Machine > Instance Details10.0.1.103:80

Access Database Services

MySQL Database

const mysql = require("mysql2/promise");

// Connect to MySQL using the private network address
const pool = mysql.createPool({
host: "10.0.1.100", // MySQL private network address
port: 3306,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 10,
acquireTimeout: 60000,
timeout: 60000,
});

exports.main = async (event, context) => {
try {
const connection = await pool.getConnection();

try {
// Execute query
const [rows] = await connection.query("SELECT * FROM users LIMIT 10");

return {
statusCode: 200,
body: {
success: true,
data: rows,
message: "Query successful",
},
};
} finally {
connection.release();
}
} catch (error) {
console.error("MySQL connection failed:", error);
return {
statusCode: 500,
body: {
success: false,
error: error.message,
},
};
}
};

Redis Cache

const redis = require("redis");

// Create a Redis client (using private network address)
const client = redis.createClient({
host: "10.0.1.101", // Redis private network address
port: 6379,
password: process.env.REDIS_PASSWORD,
db: 0,
retry_strategy: (options) => {
if (options.error && options.error.code === "ECONNREFUSED") {
return new Error("Redis server refused connection");
}
if (options.total_retry_time > 1000 * 60 * 60) {
return new Error("Retry time exceeded 1 hour");
}
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 3000);
},
});

exports.main = async (event, context) => {
try {
// Connect to Redis
await client.connect();

const { action, key, value } = event;
let result;

switch (action) {
case "get":
result = await client.get(key);
break;

case "set":
await client.set(key, value, "EX", 3600); // Set 1-hour expiration
result = "OK";
break;

case "del":
result = await client.del(key);
break;

case "exists":
result = await client.exists(key);
break;

default:
throw new Error("Unsupported operation");
}

return {
statusCode: 200,
body: {
success: true,
data: result,
message: "Operation successful",
},
};
} catch (error) {
console.error("Redis operation failed:", error);
return {
statusCode: 500,
body: {
success: false,
error: error.message,
},
};
} finally {
await client.quit();
}
};

Kafka Message Queue

const { Kafka } = require("kafkajs");

// Create a Kafka client (using private network address)
const kafka = Kafka({
clientId: "scf-kafka-client",
brokers: ["10.0.1.102:9092"], // Kafka private network address
sasl: {
mechanism: "plain",
username: process.env.KAFKA_USERNAME,
password: process.env.KAFKA_PASSWORD,
},
});

exports.main = async (event, context) => {
const { action, topic, message, groupId } = event;

try {
if (action === "produce") {
// Produce a message
const producer = kafka.producer();
await producer.connect();

await producer.send({
topic: topic,
messages: [
{
key: Date.now().toString(),
value: JSON.stringify(message),
timestamp: Date.now(),
},
],
});

await producer.disconnect();

return {
statusCode: 200,
body: {
success: true,
message: "Message sent successfully",
},
};
} else if (action === "consume") {
// Consume messages
const consumer = kafka.consumer({ groupId: groupId || "scf-group" });
await consumer.connect();
await consumer.subscribe({ topic: topic });

const messages = [];

await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
messages.push({
topic,
partition,
offset: message.offset,
key: message.key?.toString(),
value: message.value?.toString(),
timestamp: message.timestamp,
});

// Limit message count to avoid timeout
if (messages.length >= 10) {
await consumer.stop();
}
},
});

// Wait to collect messages
await new Promise((resolve) => setTimeout(resolve, 5000));
await consumer.disconnect();

return {
statusCode: 200,
body: {
success: true,
data: messages,
message: "Messages consumed successfully",
},
};
}
} catch (error) {
console.error("Kafka operation failed:", error);
return {
statusCode: 500,
body: {
success: false,
error: error.message,
},
};
}
};

Access Other Services

CVM Server

const axios = require("axios");

exports.main = async (event, context) => {
try {
// Access an HTTP service on CVM (using private network address)
const response = await axios({
method: "GET",
url: "http://10.0.1.103:8080/api/data", // CVM private network address
timeout: 10000,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.API_TOKEN}`,
},
});

return {
statusCode: 200,
body: {
success: true,
data: response.data,
message: "CVM service call successful",
},
};
} catch (error) {
console.error("CVM service call failed:", error);
return {
statusCode: 500,
body: {
success: false,
error: error.message,
},
};
}
};

Best Practices

Connection Pool Management

// Global connection pool to avoid creating a new connection on each invocation
let mysqlPool;
let redisClient;

function getMysqlPool() {
if (!mysqlPool) {
mysqlPool = mysql.createPool({
host: process.env.MYSQL_HOST,
port: 3306,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
connectionLimit: 5, // A smaller connection limit is recommended for cloud function environments
acquireTimeout: 60000,
timeout: 60000,
reconnect: true,
});
}
return mysqlPool;
}

function getRedisClient() {
if (!redisClient) {
redisClient = redis.createClient({
host: process.env.REDIS_HOST,
port: 6379,
password: process.env.REDIS_PASSWORD,
retry_strategy: (options) => {
if (options.attempt > 3) return undefined;
return Math.min(options.attempt * 100, 3000);
},
});
}
return redisClient;
}

Error Handling and Retry

// Database operation with retry mechanism
async function executeWithRetry(operation, maxRetries = 3) {
let lastError;

for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
lastError = error;

// Check if the error is retryable
if (isRetryableError(error) && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}

throw error;
}
}

throw lastError;
}

function isRetryableError(error) {
const retryableCodes = [
"ECONNRESET",
"ETIMEDOUT",
"ENOTFOUND",
"ECONNREFUSED",
];

return (
retryableCodes.includes(error.code) ||
error.message.includes("Connection lost")
);
}

Security Configuration

// Environment variable configuration example
const config = {
mysql: {
host: process.env.MYSQL_HOST,
port: parseInt(process.env.MYSQL_PORT) || 3306,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
},
redis: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
},
kafka: {
brokers: process.env.KAFKA_BROKERS?.split(",") || [],
username: process.env.KAFKA_USERNAME,
password: process.env.KAFKA_PASSWORD,
},
};

// Configuration validation
function validateConfig() {
const required = [
"MYSQL_HOST",
"MYSQL_USER",
"MYSQL_PASSWORD",
"MYSQL_DATABASE",
"REDIS_HOST",
"REDIS_PASSWORD",
"KAFKA_BROKERS",
"KAFKA_USERNAME",
"KAFKA_PASSWORD",
];

const missing = required.filter((key) => !process.env[key]);

if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(", ")}`);
}
}

Performance Monitoring

// Performance monitoring decorator
function withMonitoring(operation, operationName) {
return async function (...args) {
const startTime = Date.now();
const requestId = Math.random().toString(36).substr(2, 9);

console.log(`[${requestId}] ${operationName} started`);

try {
const result = await operation.apply(this, args);
const duration = Date.now() - startTime;

console.log(`[${requestId}] ${operationName} completed: ${duration}ms`);

// Log slow operations
if (duration > 5000) {
console.warn(
`[${requestId}] Slow operation detected: ${operationName} ${duration}ms`,
);
}

return result;
} catch (error) {
const duration = Date.now() - startTime;
console.error(
`[${requestId}] ${operationName} failed: ${duration}ms`,
error.message,
);
throw error;
}
};
}

// Usage example
const monitoredMysqlQuery = withMonitoring(async (sql, params) => {
const pool = getMysqlPool();
const connection = await pool.getConnection();
try {
return await connection.query(sql, params);
} finally {
connection.release();
}
}, "MySQL Query");

Troubleshooting

Common Issues

Unable to connect to private network resources

Possible causes:

  1. Private network interconnection is not configured correctly
  2. Security group rules are blocking access
  3. The target service is not running or the address is incorrect

Troubleshooting steps:

  1. Check whether the VPC configuration of CloudBase Run is correct
  2. Verify that security group rules allow the required ports
  3. Confirm the private network address and port of the target resource
  4. Use ping or telnet inside the function to test connectivity
// Connectivity test code
const net = require("net");

function testConnection(host, port, timeout = 5000) {
return new Promise((resolve, reject) => {
const socket = new net.Socket();

socket.setTimeout(timeout);

socket.on("connect", () => {
socket.destroy();
resolve(true);
});

socket.on("timeout", () => {
socket.destroy();
reject(new Error("Connection timed out"));
});

socket.on("error", (error) => {
reject(error);
});

socket.connect(port, host);
});
}
Connection drops frequently

Solutions:

  1. Configure connection pooling and reconnection mechanisms
  2. Set appropriate timeout values
  3. Implement health checks
// Health check example
async function healthCheck() {
try {
await testConnection(process.env.MYSQL_HOST, 3306);
await testConnection(process.env.REDIS_HOST, 6379);
return { status: "healthy" };
} catch (error) {
return { status: "unhealthy", error: error.message };
}
}

Monitoring and Logging

// Unified logging
function logger(level, message, extra = {}) {
const logEntry = {
timestamp: new Date().toISOString(),
level,
message,
requestId: context.requestId,
...extra,
};

console.log(JSON.stringify(logEntry));
}

// Usage example
exports.main = async (event, context) => {
logger("INFO", "Function execution started", { event });

try {
// Business logic
const result = await processRequest(event);

logger("INFO", "Function execution succeeded", { result });
return result;
} catch (error) {
logger("ERROR", "Function execution failed", {
error: error.message,
stack: error.stack,
});
throw error;
}
};
Tips
  • Private network interconnection only supports accessing resources within the same region
  • Use connection pools to improve performance and resource utilization
  • Always implement retry mechanisms and error handling for critical operations
  • Regularly monitor connection status and performance metrics :::
  • Ensure security group rules are configured correctly to avoid security risks
  • Private network addresses may change; consider using domain names or a configuration center
  • Be mindful of cloud function execution time limits to avoid long-running connections
  • Always configure appropriate timeouts and retry strategies in production environments :::