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
Learn how to configure and enable private network interconnection in CloudBase Run
📄️ Access Database Services
Detailed examples for connecting to various Tencent Cloud database services via private network
📄️ Access Other Services
Connect to other Tencent Cloud resources such as CVM and container services
📄️ Best Practices
Security configuration, performance optimization, and troubleshooting for private network interconnection
Configure Private Network Interconnection
Prerequisites
- Your Tencent Cloud account already has a VPC network configured
- The target resource (e.g., database instance) is deployed within that VPC
- 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:
- Log in to the [CloudBase Console]
- Select the corresponding CloudBase Run service, go to the Service Configuration page, and click Edit
- In the Private Network Settings section
- Select the target VPC and subnet
- 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 Type | Console Location | Private IP Example |
|---|---|---|
| MySQL | Database MySQL > Instance Details | 10.0.1.100:3306 |
| Redis | Database Redis > Instance Details | 10.0.1.101:6379 |
| Kafka | Message Queue CKafka > Instance Details | 10.0.1.102:9092 |
| CVM | Cloud Virtual Machine > Instance Details | 10.0.1.103:80 |
Access Database Services
MySQL Database
- Node.js
- Python
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,
},
};
}
};
import pymysql
import json
import os
def main_handler(event, context):
try:
# Connect to MySQL using the private network address
connection = pymysql.connect(
host='10.0.1.100', # MySQL private network address
port=3306,
user=os.environ['DB_USER'],
password=os.environ['DB_PASSWORD'],
database=os.environ['DB_NAME'],
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
with connection:
with connection.cursor() as cursor:
# Execute query
cursor.execute("SELECT * FROM users LIMIT 10")
result = cursor.fetchall()
return {
'statusCode': 200,
'body': json.dumps({
'success': True,
'data': result,
'message': 'Query successful'
}, ensure_ascii=False)
}
except Exception as e:
print(f'MySQL connection failed: {str(e)}')
return {
'statusCode': 500,
'body': json.dumps({
'success': False,
'error': str(e)
}, ensure_ascii=False)
}
Redis Cache
- Node.js
- Python
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();
}
};
import redis
import json
import os
def main_handler(event, context):
try:
# Connect to Redis using the private network address
r = redis.Redis(
host='10.0.1.101', # Redis private network address
port=6379,
password=os.environ.get('REDIS_PASSWORD'),
db=0,
decode_responses=True,
socket_timeout=5,
socket_connect_timeout=5
)
action = event.get('action')
key = event.get('key')
value = event.get('value')
if action == 'get':
result = r.get(key)
elif action == 'set':
r.setex(key, 3600, value) # Set 1-hour expiration
result = 'OK'
elif action == 'del':
result = r.delete(key)
elif action == 'exists':
result = r.exists(key)
else:
raise ValueError('Unsupported operation')
return {
'statusCode': 200,
'body': json.dumps({
'success': True,
'data': result,
'message': 'Operation successful'
}, ensure_ascii=False)
}
except Exception as e:
print(f'Redis operation failed: {str(e)}')
return {
'statusCode': 500,
'body': json.dumps({
'success': False,
'error': str(e)
}, ensure_ascii=False)
}
Kafka Message Queue
- Node.js
- Python
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,
},
};
}
};
from kafka import KafkaProducer, KafkaConsumer
import json
import os
from datetime import datetime
def main_handler(event, context):
action = event.get('action')
topic = event.get('topic')
try:
if action == 'produce':
# Produce a message
producer = KafkaProducer(
bootstrap_servers=['10.0.1.102:9092'], # Kafka private network address
security_protocol='SASL_PLAINTEXT',
sasl_mechanism='PLAIN',
sasl_plain_username=os.environ['KAFKA_USERNAME'],
sasl_plain_password=os.environ['KAFKA_PASSWORD'],
value_serializer=lambda v: json.dumps(v).encode('utf-8')
)
message = event.get('message', {})
message['timestamp'] = datetime.now().isoformat()
future = producer.send(topic, message)
producer.flush()
producer.close()
return {
'statusCode': 200,
'body': json.dumps({
'success': True,
'message': 'Message sent successfully'
}, ensure_ascii=False)
}
elif action == 'consume':
# Consume messages
consumer = KafkaConsumer(
topic,
bootstrap_servers=['10.0.1.102:9092'],
security_protocol='SASL_PLAINTEXT',
sasl_mechanism='PLAIN',
sasl_plain_username=os.environ['KAFKA_USERNAME'],
sasl_plain_password=os.environ['KAFKA_PASSWORD'],
group_id=event.get('groupId', 'scf-group'),
value_deserializer=lambda m: json.loads(m.decode('utf-8')),
consumer_timeout_ms=5000 # 5-second timeout
)
messages = []
for message in consumer:
messages.append({
'topic': message.topic,
'partition': message.partition,
'offset': message.offset,
'key': message.key.decode('utf-8') if message.key else None,
'value': message.value,
'timestamp': message.timestamp
})
# Limit message count
if len(messages) >= 10:
break
consumer.close()
return {
'statusCode': 200,
'body': json.dumps({
'success': True,
'data': messages,
'message': 'Messages consumed successfully'
}, ensure_ascii=False)
}
except Exception as e:
print(f'Kafka operation failed: {str(e)}')
return {
'statusCode': 500,
'body': json.dumps({
'success': False,
'error': str(e)
}, ensure_ascii=False)
}
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:
- Private network interconnection is not configured correctly
- Security group rules are blocking access
- The target service is not running or the address is incorrect
Troubleshooting steps:
- Check whether the VPC configuration of CloudBase Run is correct
- Verify that security group rules allow the required ports
- Confirm the private network address and port of the target resource
- 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:
- Configure connection pooling and reconnection mechanisms
- Set appropriate timeout values
- 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;
}
};
- 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 :::