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