Google Cloud SDK 教程
1. 什么是 Google Cloud SDK?
Google Cloud SDK (Software Development Kit) 是 Google Cloud Platform (GCP) 提供的开发工具包,它允许开发者在自己的应用中轻松集成 Google Cloud 服务。Google Cloud SDK for Node.js 是专门为 Node.js 开发者设计的 SDK,支持在 Node.js 环境中与 Google Cloud 服务进行交互。
2. Google Cloud SDK 的核心概念
2.1 客户端库 (Client Library)
客户端库是与 Google Cloud 服务交互的主要接口,每个 Google Cloud 服务都有对应的客户端库。
2.2 认证 (Authentication)
认证用于验证对 Google Cloud 服务的访问权限,Google Cloud SDK 支持多种认证方式,包括服务账号密钥、应用默认凭证、OAuth 2.0 等。
2.3 项目 (Project)
项目是 Google Cloud 资源的组织单元,每个 Google Cloud 资源都属于一个项目。
2.4 区域和区域 (Region and Zone)
区域是 Google Cloud 服务的地理区域,区域是区域内的特定位置。选择合适的区域和区域可以减少延迟并满足合规要求。
2.5 错误处理 (Error Handling)
Google Cloud SDK 提供了统一的错误处理机制,包括重试策略和错误分类。
2.6 Promise 和异步操作
Google Cloud SDK for Node.js 使用 Promise 和 async/await 语法处理异步操作。
3. Google Cloud SDK 的安装和配置
3.1 安装 Google Cloud SDK
使用 npm 或 yarn 安装 Google Cloud SDK for Node.js:
# 安装核心包
npm install @google-cloud/storage @google-cloud/firestore @google-cloud/secret-manager
# 安装命令行工具(可选)
# 访问 https://cloud.google.com/sdk/docs/install 下载并安装 gcloud CLI3.2 配置认证
Google Cloud SDK 支持多种认证方式:
- 应用默认凭证:使用
gcloud auth application-default login命令设置 - 服务账号密钥:使用服务账号密钥文件进行认证
- 环境变量:使用环境变量设置认证信息
- Compute Engine 元数据:在 Google Cloud 资源中使用内置的认证
3.3 初始化客户端
// 使用应用默认凭证进行认证
const { Storage } = require('@google-cloud/storage');
const storage = new Storage();
// 使用服务账号密钥进行认证
const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore({
projectId: 'your-project-id',
keyFilename: '/path/to/service-account-key.json'
});
// 使用环境变量进行认证
// 导出环境变量:export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const secretManagerClient = new SecretManagerServiceClient();4. Google Cloud SDK 的基本使用
4.1 使用 Cloud Storage 服务
上传文件到 Cloud Storage:
const { Storage } = require('@google-cloud/storage');
const fs = require('fs');
const storage = new Storage();
const bucketName = 'my-bucket';
async function uploadFile(filePath, destination) {
// 上传文件
await storage.bucket(bucketName).upload(filePath, {
destination: destination,
gzip: true,
metadata: {
cacheControl: 'public, max-age=31536000'
}
});
console.log(`${filePath} uploaded to ${bucketName}/${destination}`);
}
// 使用示例
uploadFile('./local-file.txt', 'remote-file.txt');下载 Cloud Storage 中的文件:
const { Storage } = require('@google-cloud/storage');
const fs = require('fs');
const path = require('path');
const storage = new Storage();
const bucketName = 'my-bucket';
async function downloadFile(srcFilename, destFilename) {
// 下载文件
const options = {
destination: destFilename
};
await storage.bucket(bucketName).file(srcFilename).download(options);
console.log(`File ${srcFilename} downloaded to ${destFilename}`);
}
// 使用示例
downloadFile('remote-file.txt', './downloaded-file.txt');4.2 使用 Firestore 服务
创建文档:
const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();
const collectionName = 'users';
async function createDocument() {
// 创建文档
const documentRef = firestore.collection(collectionName).doc('user1');
await documentRef.set({
name: 'John Doe',
email: 'john@example.com',
age: 30,
createdAt: new Date()
});
console.log('Document created successfully');
}
// 使用示例
createDocument();读取文档:
const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();
const collectionName = 'users';
async function readDocument() {
// 读取文档
const documentRef = firestore.collection(collectionName).doc('user1');
const document = await documentRef.get();
if (!document.exists) {
console.log('Document does not exist');
return;
}
console.log('Document data:', document.data());
}
// 使用示例
readDocument();查询文档:
const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();
const collectionName = 'users';
async function queryDocuments() {
// 查询文档
const snapshot = await firestore.collection(collectionName)
.where('age', '>', 25)
.orderBy('age', 'desc')
.limit(5)
.get();
if (snapshot.empty) {
console.log('No documents found');
return;
}
console.log('Documents found:');
snapshot.forEach(doc => {
console.log(`${doc.id}: ${JSON.stringify(doc.data())}`);
});
}
// 使用示例
queryDocuments();4.3 使用 Secret Manager 服务
创建密钥:
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const secretManagerClient = new SecretManagerServiceClient();
const projectId = 'your-project-id';
const secretName = 'my-secret';
async function createSecret() {
// 创建密钥
const [secret] = await secretManagerClient.createSecret({
parent: `projects/${projectId}`,
secretId: secretName,
secret: {
replication: {
automatic: {}
}
}
});
console.log('Secret created:', secret.name);
return secret;
}
async function addSecretVersion(secretPath, payload) {
// 添加密钥版本
const [version] = await secretManagerClient.addSecretVersion({
parent: secretPath,
payload: {
data: Buffer.from(payload, 'utf8')
}
});
console.log('Secret version added:', version.name);
return version;
}
// 使用示例
async function main() {
const secret = await createSecret();
await addSecretVersion(secret.name, 'my-secret-value');
}
main();访问密钥:
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const secretManagerClient = new SecretManagerServiceClient();
const projectId = 'your-project-id';
const secretName = 'my-secret';
async function accessSecret() {
// 访问密钥
const secretVersionName = `projects/${projectId}/secrets/${secretName}/versions/latest`;
const [version] = await secretManagerClient.accessSecretVersion({
name: secretVersionName
});
const payload = version.payload.data.toString('utf8');
console.log('Secret payload:', payload);
return payload;
}
// 使用示例
accessSecret();4. Google Cloud SDK 的高级功能
4.1 使用重试策略
Google Cloud SDK 提供了内置的重试策略,可以配置重试次数、延迟和错误分类:
const { Storage } = require('@google-cloud/storage');
const storage = new Storage({
retryOptions: {
autoRetry: true,
maxRetries: 3,
maxRetryDelay: 60000,
retryDelayMultiplier: 1.3,
totalTimeout: 600000
}
});4.2 使用分页器
分页器用于处理返回大量数据的 API 操作,例如列出存储桶中的所有对象:
const { Storage } = require('@google-cloud/storage');
const storage = new Storage();
const bucketName = 'my-bucket';
async function listAllObjects() {
const [files] = await storage.bucket(bucketName).getFiles({
autoPaginate: true
});
console.log('All objects retrieved:', files.length);
files.forEach(file => {
console.log(file.name);
});
return files;
}
// 使用示例
listAllObjects();4.3 使用流式处理
Google Cloud SDK 支持流式处理,例如流式上传和下载大文件:
const { Storage } = require('@google-cloud/storage');
const fs = require('fs');
const storage = new Storage();
const bucketName = 'my-bucket';
async function streamUpload() {
// 流式上传
const fileStream = fs.createReadStream('./large-file.txt');
const remoteFile = storage.bucket(bucketName).file('large-file.txt');
await new Promise((resolve, reject) => {
const writeStream = remoteFile.createWriteStream({
metadata: {
contentType: 'text/plain'
}
});
writeStream.on('finish', resolve);
writeStream.on('error', reject);
fileStream.pipe(writeStream);
});
console.log('File uploaded as stream');
}
// 使用示例
streamUpload();4.4 使用批量操作
批量操作允许在单个请求中执行多个操作,例如批量写入多个 Firestore 文档:
const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();
const collectionName = 'users';
async function batchWrite() {
// 创建批量写入
const batch = firestore.batch();
// 添加写入操作
const docRef1 = firestore.collection(collectionName).doc('user1');
batch.set(docRef1, { name: 'John Doe', age: 30 });
const docRef2 = firestore.collection(collectionName).doc('user2');
batch.set(docRef2, { name: 'Jane Smith', age: 25 });
const docRef3 = firestore.collection(collectionName).doc('user3');
batch.set(docRef3, { name: 'Bob Johnson', age: 35 });
// 执行批量写入
await batch.commit();
console.log('Batch write completed');
}
// 使用示例
batchWrite();5. Google Cloud SDK 的最佳实践
5.1 安全最佳实践
- 使用最小权限原则:为服务账号授予必要的最小权限
- 保护服务账号密钥:不要将服务账号密钥文件提交到版本控制系统
- 定期轮换密钥:定期更新服务账号密钥
- 使用 Secret Manager:将敏感信息存储在 Secret Manager 中,而不是硬编码在应用中
5.2 性能最佳实践
- 重用客户端实例:避免频繁创建客户端实例
- 使用连接池:对于需要频繁连接的服务,使用连接池
- 选择合适的区域:选择离用户最近的区域,减少延迟
- 使用流式处理:对于大文件,使用流式上传和下载
- 批量操作:对于多个相似操作,使用批量 API 减少网络往返
5.3 错误处理最佳实践
- 实现重试策略:对于临时错误,实现指数退避重试
- 捕获和处理特定错误:根据错误类型采取不同的处理策略
- 记录错误信息:详细记录错误信息,便于调试
- 设置合理的超时:避免请求无限期等待
5.4 代码组织最佳实践
- 模块化:将 Google Cloud 服务相关代码组织成模块
- 使用异步/await:使用现代 JavaScript 语法处理异步操作
- 编写单元测试:为 Google Cloud SDK 代码编写单元测试
- 使用 TypeScript:使用 TypeScript 提高代码可靠性
6. 实际应用示例
6.1 构建一个文件上传服务
const express = require('express');
const multer = require('multer');
const { Storage } = require('@google-cloud/storage');
const { v4: uuidv4 } = require('uuid');
const app = express();
const upload = multer({ storage: multer.memoryStorage() });
const storage = new Storage();
const bucketName = 'my-file-upload-bucket';
app.post('/upload', upload.single('file'), async (req, res) => {
try {
const file = req.file;
const fileName = `${uuidv4()}-${file.originalname}`;
const bucket = storage.bucket(bucketName);
const blob = bucket.file(fileName);
const blobStream = blob.createWriteStream({
metadata: {
contentType: file.mimetype
}
});
await new Promise((resolve, reject) => {
blobStream.on('finish', resolve);
blobStream.on('error', reject);
blobStream.end(file.buffer);
});
// 生成可公开访问的 URL
await blob.makePublic();
const fileUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
res.json({ success: true, fileUrl });
} catch (error) {
console.error('Error uploading file:', error);
res.status(500).json({ success: false, error: 'Failed to upload file' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});6.2 构建一个用户数据存储服务
const express = require('express');
const { Firestore } = require('@google-cloud/firestore');
const { v4: uuidv4 } = require('uuid');
const app = express();
app.use(express.json());
const firestore = new Firestore();
const collectionName = 'users';
app.post('/users', async (req, res) => {
try {
const user = {
id: uuidv4(),
...req.body,
createdAt: new Date()
};
await firestore.collection(collectionName).doc(user.id).set(user);
res.json({ success: true, user });
} catch (error) {
console.error('Error creating user:', error);
res.status(500).json({ success: false, error: 'Failed to create user' });
}
});
app.get('/users/:id', async (req, res) => {
try {
const { id } = req.params;
const document = await firestore.collection(collectionName).doc(id).get();
if (!document.exists) {
return res.status(404).json({ success: false, error: 'User not found' });
}
const user = document.data();
res.json({ success: true, user });
} catch (error) {
console.error('Error getting user:', error);
res.status(500).json({ success: false, error: 'Failed to get user' });
}
});
app.get('/users', async (req, res) => {
try {
const snapshot = await firestore.collection(collectionName).get();
const users = [];
snapshot.forEach(doc => {
users.push(doc.data());
});
res.json({ success: true, users });
} catch (error) {
console.error('Error getting users:', error);
res.status(500).json({ success: false, error: 'Failed to get users' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});6.3 构建一个密钥管理服务
const express = require('express');
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const app = express();
app.use(express.json());
const secretManagerClient = new SecretManagerServiceClient();
const projectId = 'your-project-id';
app.post('/secrets', async (req, res) => {
try {
const { name, value } = req.body;
// 创建密钥
const [secret] = await secretManagerClient.createSecret({
parent: `projects/${projectId}`,
secretId: name,
secret: {
replication: {
automatic: {}
}
}
});
// 添加密钥版本
await secretManagerClient.addSecretVersion({
parent: secret.name,
payload: {
data: Buffer.from(value, 'utf8')
}
});
res.json({ success: true, secret: { name } });
} catch (error) {
console.error('Error creating secret:', error);
res.status(500).json({ success: false, error: 'Failed to create secret' });
}
});
app.get('/secrets/:name', async (req, res) => {
try {
const { name } = req.params;
// 访问密钥
const secretVersionName = `projects/${projectId}/secrets/${name}/versions/latest`;
const [version] = await secretManagerClient.accessSecretVersion({
name: secretVersionName
});
const value = version.payload.data.toString('utf8');
res.json({ success: true, secret: { name, value } });
} catch (error) {
console.error('Error accessing secret:', error);
res.status(500).json({ success: false, error: 'Failed to access secret' });
}
});
app.get('/secrets', async (req, res) => {
try {
// 列出所有密钥
const [secrets] = await secretManagerClient.listSecrets({
parent: `projects/${projectId}`
});
const secretList = secrets.map(secret => {
const secretName = secret.name.split('/').pop();
return { name: secretName };
});
res.json({ success: true, secrets: secretList });
} catch (error) {
console.error('Error listing secrets:', error);
res.status(500).json({ success: false, error: 'Failed to list secrets' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});7. Google Cloud SDK 与其他云 SDK 的比较
7.1 Google Cloud SDK vs AWS SDK
- 认证方式:Google Cloud SDK 使用服务账号密钥和应用默认凭证,而 AWS SDK 使用访问密钥和秘密访问密钥
- 客户端初始化:Google Cloud SDK 需要项目 ID,而 AWS SDK 需要区域和认证信息
- API 设计:两者都使用 Promise 和 async/await,但 API 设计风格不同
- 服务覆盖:两者都覆盖了各自云平台的主要服务,但具体服务和 API 不同
7.2 Google Cloud SDK vs Azure SDK
- 认证方式:Google Cloud SDK 使用服务账号密钥,而 Azure SDK 使用 AAD (Azure Active Directory)
- 客户端初始化:Google Cloud SDK 需要项目 ID,而 Azure SDK 需要 endpoint
- 服务覆盖:两者都覆盖了各自云平台的主要服务,但具体服务和 API 不同
- 性能:两者都针对各自平台进行了优化,性能相近
8. 总结
Google Cloud SDK for Node.js 是一个强大的工具包,它允许开发者在 Node.js 应用中轻松集成 Google Cloud 服务。通过本教程的学习,你应该已经掌握了 Google Cloud SDK 的核心概念、安装配置、基本使用和高级功能。
Google Cloud SDK 的主要优势包括:
- 全面的服务支持:支持所有 Google Cloud 服务
- 现代 JavaScript 语法:使用 Promise 和 async/await
- 统一的认证机制:支持多种认证方式
- 内置的重试策略:提高应用的可靠性
- 丰富的功能:包括批量操作、流式处理和分页器等
通过遵循最佳实践,你可以构建安全、高性能、可靠的 Google Cloud 集成应用。无论是构建 Web 应用、移动应用后端还是云原生应用,Google Cloud SDK 都能为你提供强大的支持。